// Copyright PICO Technology Co., Ltd. All rights reserved. // This plugin incorporates portions of the UnrealĀ® Engine. UnrealĀ® is a trademark or registered trademark of Epic Games, Inc. in the United States of America and elsewhere. // Copyright Epic Games, Inc. All Rights Reserved. #include "PXR_InputFunctionLibrary.h" #include "PXR_HMDPrivate.h" #include "PXR_Utils.h" #include "PXR_Input.h" #include "PXR_Log.h" #include "UObject/ConstructorHelpers.h" #include "Misc/Paths.h" #include "Misc/FileHelper.h" FPICOXRInput* GetPICOXRInput() { TArray MotionControllers = IModularFeatures::Get().GetModularFeatureImplementations(IMotionController::GetModularFeatureName()); for (auto MotionController : MotionControllers) { if (MotionController != nullptr && MotionController->GetMotionControllerDeviceTypeName() == FName(TEXT("PICOXRInput"))) { return static_cast(MotionController); } } return nullptr; } UDataTable* UPICOXRInputFunctionLibrary::PHFDataTable = nullptr; UPICOXRInputFunctionLibrary::UPICOXRInputFunctionLibrary() { static ConstructorHelpers::FObjectFinder DT(TEXT("DataTable'/PICOXR/Blueprint/PHFDataTable.PHFDataTable'")); PHFDataTable = DT.Object; #if !PLATFORM_ANDROID if (PHFDataTable) { TArray PHFFiles; FString PHFFilesDir = FPaths::ProjectPluginsDir() / FString::Printf(TEXT("PICOXR/Content/Phf/")); IFileManager::Get().FindFiles(PHFFiles, *PHFFilesDir); PHFDataTable->EmptyTable(); FString CSVString = "Name,PHFData\n"; for (auto item : PHFFiles) { FString Content; FFileHelper::LoadFileToString(Content, *(FPaths::Combine(PHFFilesDir, item))); item.RemoveFromEnd(".phf"); FPHFData Data; Data.PHFDataContent.data = Content; Data.PHFDataContent.size = Content.Len(); PHFDataTable->AddRow(*item, Data); } } #endif } IPXR_HandTracker* GetHandTracker() { TArray HandTrackers = IModularFeatures::Get().GetModularFeatureImplementations(IPXR_HandTracker::GetModularFeatureName()); for (auto HandTracker : HandTrackers) { if (HandTracker != nullptr && HandTracker->GetHandTrackerDeviceTypeName() == FName(TEXT("PICOHandTracking"))) { return HandTracker; } } return nullptr; } bool UPICOXRInputFunctionLibrary::PXR_GetControllerPower(EPICOXRControllerType ControllerType, int32& Power) { #if PLATFORM_ANDROID FPICOXRInput* PICOXRInputInstence = GetPICOXRInput(); if (PICOXRInputInstence) { Power = PICOXRInputInstence->UPxr_GetControllerPower((uint8_t)ControllerType); return true; } #endif return false; } bool UPICOXRInputFunctionLibrary::PXR_GetControllerConnectionState(EPICOXRControllerType ControllerType, bool& Status) { #if PLATFORM_WINDOWS && UE_EDITOR if (FPICOXRHMDModule::Get().PreInit()) { int nStatus=FPICOXRHMDModule::GetPluginWrapper().GetControllerConnectStatus(static_cast(ControllerType)); Status=static_cast(nStatus); return true; } #else FPICOXRInput* Input = GetPICOXRInput(); if (Input) { if (ControllerType ==EPICOXRControllerType::LeftHand || ControllerType == EPICOXRControllerType::RightHand) { Status = Input->UPxr_GetControllerConnectState(static_cast(ControllerType)); } else if (ControllerType == EPICOXRControllerType::G2Hand) { Status = Input->UPxr_GetControllerConnectState(0); } else { return false; } return true; } #endif return false; } bool UPICOXRInputFunctionLibrary::PXR_GetMainControllerHandle( EPICOXRHandedness& Handedness) { bool Ret = false; #if PLATFORM_ANDROID FPICOXRInput* Input = GetPICOXRInput(); if (Input) { int32 MainHandle = 0; Ret = Input->UPxr_GetControllerMainInputHandle(MainHandle); Handedness = MainHandle == 0? EPICOXRHandedness::LeftHand: EPICOXRHandedness::RightHand; return Ret; } #endif return Ret; } bool UPICOXRInputFunctionLibrary::PXR_SetMainControllerHandle(EPICOXRHandedness Handedness) { #if PLATFORM_ANDROID FPICOXRInput *PxrInput = GetPICOXRInput(); if (PxrInput) { PxrInput->UPxr_SetControllerMainInputHandle(int32(Handedness)); return true; } #endif return false; } bool UPICOXRInputFunctionLibrary::PXR_GetControllerAngularVelocity(EPICOXRControllerType ControllerType,FVector& AngularVelocity) { #if PLATFORM_ANDROID PxrControllerTracking Tracking; uint32_t Hand; if (ControllerType == EPICOXRControllerType::LeftHand) { Hand = EPICOXRControllerHandness::LeftController; } else { Hand = EPICOXRControllerHandness::RightController; } float HeadSensorData[7] = {0}; FPICOXRHMDModule::GetPluginWrapper().GetControllerTrackingState(Hand, 0, HeadSensorData, &Tracking); float Data[3] = {0.0f}; Data[0] = Tracking.localControllerPose.angularVelocity.x; Data[1] = Tracking.localControllerPose.angularVelocity.y; Data[2] = Tracking.localControllerPose.angularVelocity.z; PXR_LOGD(PxrUnrealFunctionLibrary,"Pxr_GetControllerAngularVelocityState %f,%f,%f",Data[0],Data[1],Data[2]); AngularVelocity = FVector(Data[0],Data[1],Data[2]); AngularVelocity = FVector(-AngularVelocity.Z , AngularVelocity.X , AngularVelocity.Y); return true; #endif return false; } bool UPICOXRInputFunctionLibrary::PXR_GetControllerAcceleration(EPICOXRControllerType ControllerType,FVector& Acceleration) { #if PLATFORM_ANDROID PxrControllerTracking Tracking; uint32_t Hand; if (ControllerType == EPICOXRControllerType::LeftHand) { Hand = EPICOXRControllerHandness::LeftController; } else { Hand = EPICOXRControllerHandness::RightController; } float HeadSensorData[7] = { 0 }; FPICOXRHMDModule::GetPluginWrapper().GetControllerTrackingState(Hand, 0, HeadSensorData, &Tracking); float Data[3] = {0.0f}; Data[0] = Tracking.localControllerPose.angularAcceleration.x; Data[1] = Tracking.localControllerPose.angularAcceleration.y; Data[2] = Tracking.localControllerPose.angularAcceleration.z; PXR_LOGD(PxrUnrealFunctionLibrary,"Pxr_GetControllerAccelerationState %f,%f,%f",Data[0],Data[1],Data[2]); Acceleration = FVector(Data[0],Data[1],Data[2]); Acceleration = FVector(-Acceleration.Z , Acceleration.X , Acceleration.Y); return true; #endif return false; } bool UPICOXRInputFunctionLibrary::PXR_GetControllerLinearVelocity(EPICOXRControllerType ControllerType, FVector& LinearVelocity) { #if PLATFORM_ANDROID PxrControllerTracking Tracking; uint32_t Hand; if (ControllerType == EPICOXRControllerType::LeftHand) { Hand = EPICOXRControllerHandness::LeftController; } else { Hand = EPICOXRControllerHandness::RightController; } float HeadSensorData[7] = { 0 }; FPICOXRHMDModule::GetPluginWrapper().GetControllerTrackingState(Hand, 0, HeadSensorData, &Tracking); float Data[3] = {0.0f}; Data[0] = Tracking.localControllerPose.linearVelocity.x; Data[1] = Tracking.localControllerPose.linearVelocity.y; Data[2] = Tracking.localControllerPose.linearVelocity.z; PXR_LOGD(PxrUnrealFunctionLibrary,"Pxr_GetControllerLinearVelocityState %f,%f,%f",Data[0],Data[1],Data[2]); LinearVelocity = FVector(Data[0],Data[1],Data[2]); LinearVelocity = FVector(-LinearVelocity.Z , LinearVelocity.X , LinearVelocity.Y); return true; #endif return false; } bool UPICOXRInputFunctionLibrary::PXR_VibrateController(EPICOXRControllerType ControllerType,float Strength, int Time) { #if PLATFORM_ANDROID if (FPICOXRHMDModule::GetPluginWrapper().SetControllerVibration((uint32_t)ControllerType, Strength, Time) == 0) { return true; } #endif return false; } void UPICOXRInputFunctionLibrary::PXR_GetControllerDeviceType(EPICOXRControllerDeviceType& OutControllerType) { int32 ControllerType = 0; #if PLATFORM_ANDROID PxrControllerCapability Cap; FPICOXRHMDModule::GetPluginWrapper().GetControllerCapabilities(PXR_CONTROLLER_LEFT, &Cap); ControllerType = Cap.type; #endif #if PLATFORM_WINDOWS && WITH_EDITOR //Todo:For Now, we can not get Controller Type on PC ControllerType = static_cast(EPICOXRControllerDeviceType::PICO_4); #endif OutControllerType = static_cast(ControllerType); } int UPICOXRInputFunctionLibrary::PXR_ResetController(int Device) { int result = -1; #if PLATFORM_ANDROID result = FPICOXRHMDModule::GetPluginWrapper().ResetController(Device); #endif return result; } int UPICOXRInputFunctionLibrary::PXR_SetArmModelParameters(EPICOXRGazeBehavior GazeType, EPICOXRArmModelJoint ArmJoint, float ElbowHeight, float ElbowDepth, float PointerTiltAngle) { float pxrElbowHeight = FMath::Clamp(ElbowHeight, 0.0f, 20.0f) / 100.0f; float pxrElbowDepth = FMath::Clamp(ElbowDepth, 0.0f, 20.0f) / 100.0f; float pxrPointerTiltAngle = FMath::Clamp(PointerTiltAngle, 0.0f, 30.0f); int result = -1; #if PLATFORM_ANDROID PxrGazeType pxrgazetype = PxrGazeType((uint8)GazeType); PxrArmmodelType pxrarmjoint = PxrArmmodelType((uint8)ArmJoint); result = FPICOXRHMDModule::GetPluginWrapper().SetArmModelParameters(pxrgazetype, pxrarmjoint, pxrElbowHeight, pxrElbowDepth, pxrPointerTiltAngle); #endif return result; } int UPICOXRInputFunctionLibrary::PXR_GetHandedness(EPICOXRHandedness &Handedness) { int result = -1; #if PLATFORM_ANDROID int handness; result = FPICOXRHMDModule::GetPluginWrapper().GetControllerHandness(&handness); Handedness = handness == 0 ? EPICOXRHandedness::RightHand : EPICOXRHandedness::LeftHand; #endif return result; } bool UPICOXRInputFunctionLibrary::PXR_GetControllerEnableHomekey() { #if PLATFORM_ANDROID FPICOXRInput* PxrInput = GetPICOXRInput(); if (PxrInput) { return PxrInput->UPxr_GetControllerEnableHomeKey(); } #endif return false; } void UPICOXRInputFunctionLibrary::PXR_SetControllerOriginOffset(EPICOXRControllerType Controller, FVector Offset) { #if PLATFORM_ANDROID if (Controller == EPICOXRControllerType::LeftHand) { FPICOXRInput::OriginOffsetL = Offset; } else if (Controller == EPICOXRControllerType::RightHand) { FPICOXRInput::OriginOffsetR = Offset; } #endif } bool UPICOXRInputFunctionLibrary::PXR_GetControllerPredictedLocationAndRotation(EControllerHand DeviceHand, float PredictedTime, FVector& OutLocation, FRotator& OutRotation) { bool Result = false; #if PLATFORM_ANDROID FVector PredictedLocation; FRotator PredictedRotation; PredictedLocation = FVector::ZeroVector; PredictedRotation = FRotator::ZeroRotator; FPICOXRInput* PxrInput = GetPICOXRInput(); if (PxrInput) { Result = PxrInput->GetPredictedLocationAndRotation(DeviceHand, PredictedTime, PredictedRotation, PredictedLocation); } OutLocation = PredictedLocation; OutRotation = PredictedRotation; #endif return Result; } int UPICOXRInputFunctionLibrary::PXR_StartControllerVCMotor(FString file, EPICOXRVibrateController slot) { //0-Left And Right 1-Left 2-Right 3-Left And Right //1-Reversal 0-No Reversal int state = 0; #if PLATFORM_ANDROID if (FPICOXRVersionHelper::IsThisVersionOrGreater(0x2000308)) { state = FPICOXRHMDModule::GetPluginWrapper().StartControllerVCMotor(TCHAR_TO_UTF8(*file), static_cast(slot)); } #endif return state; } int UPICOXRInputFunctionLibrary::PXR_SetControllerAmp(float mode) { int state = 0; #if PLATFORM_ANDROID if (FPICOXRVersionHelper::IsThisVersionOrGreater(0x2000308)) { state = FPICOXRHMDModule::GetPluginWrapper().SetControllerAmp(mode); } #endif return state; } int UPICOXRInputFunctionLibrary::PXR_StopControllerVCMotor(int SourceId) { int state = 0; #if PLATFORM_ANDROID if (FPICOXRVersionHelper::IsThisVersionOrGreater(0x2000308)) { state = FPICOXRHMDModule::GetPluginWrapper().StopControllerVCMotor(SourceId); } #endif return state; } int UPICOXRInputFunctionLibrary::PXR_SetControllerVibrationEvent(int deviceID, int frequency, float strength, int time) { int state = 0; #if PLATFORM_ANDROID if (FPICOXRVersionHelper::IsThisVersionOrGreater(0x2000305)) { PXR_LOGD(PxrUnreal, "PXR_SetControllerVibrationEvent :%d", deviceID); state = FPICOXRHMDModule::GetPluginWrapper().SetControllerVibrationEvent((uint32)deviceID, frequency, strength, time); } #endif return state; } Audio::FSampleBuffer tSampleBuffer; int UPICOXRInputFunctionLibrary::PXR_StartVibrateBySharem(USoundWave* InSoundWave, EPICOXRVibrateController slot, EPICOXRChannelFlip slotConfig,int& SourceId) { int state = 0; if (InSoundWave == nullptr) { PXR_LOGI(PxrUnreal, "PXR_StartVibrateBySharem : InSoundWave is nullptr"); return state; } #if PLATFORM_ANDROID if (FPICOXRVersionHelper::IsThisVersionOrGreater(0x2000308)) { int32 delaytag; int32 buffersize; int32 sampleRate; int32 channelMask; int32 bitrate = 16; float OutSampleDuration; uint8* data = nullptr; PxrVibrate_config parameter; FString TempString; int Value = 1024; if (GConfig->GetString(FPlatformProperties::GetRuntimeSettingsClassName(), TEXT("AudioCallbackBufferFrameSize"), TempString, GEngineIni)) { Value = FCString::Atoi(*TempString); PXR_LOGI(PxrUnreal, "AudioCallbackBufferFrameSize = %d", Value); } Audio::FSoundWavePCMLoader SoundWaveLoader; if (InSoundWave) { TFunction OnLoaded = [](const USoundWave* SoundWave, const Audio::FSampleBuffer& SampleBuffer) { tSampleBuffer = SampleBuffer; }; SoundWaveLoader.LoadSoundWave(InSoundWave, MoveTemp(OnLoaded), true); } data = InSoundWave->RawPCMData; buffersize = tSampleBuffer.GetNumSamples() * tSampleBuffer.GetNumChannels(); //OutNumFrames = tSampleBuffer.GetNumFrames(); channelMask = tSampleBuffer.GetNumChannels(); sampleRate = tSampleBuffer.GetSampleRate(); OutSampleDuration = tSampleBuffer.GetSampleDuration(); parameter.slot = static_cast(slot); parameter.buffersize = static_cast(buffersize); parameter.sampleRate = sampleRate; parameter.channelCounts = channelMask; parameter.bitrate = bitrate; parameter.reversal = static_cast(slotConfig); parameter.isCache = 0; state = FPICOXRHMDModule::GetPluginWrapper().StartVibrateBySharemU(data, ¶meter, &SourceId); } #endif return state; } int UPICOXRInputFunctionLibrary::PXR_SaveVibrateByCache(USoundWave* InSoundWave, EPICOXRVibrateController slot, EPICOXRChannelFlip slotConfig, EPICOXRCacheConfig enableV, int& SourceId) { int state = 0; if (InSoundWave == nullptr) { PXR_LOGI(PxrUnreal, "PXR_SaveVibrateByCache : InSoundWave is nullptr"); return state; } #if PLATFORM_ANDROID if (FPICOXRVersionHelper::IsThisVersionOrGreater(0x2000308)) { int32 delaytag; int32 buffersize; int32 sampleRate; int32 channelMask; int32 bitrate = 16; float OutSampleDuration; uint8* data = nullptr; PxrVibrate_config parameter; FString TempString; int Value = 1024; if (GConfig->GetString(FPlatformProperties::GetRuntimeSettingsClassName(), TEXT("AudioCallbackBufferFrameSize"), TempString, GEngineIni)) { Value = FCString::Atoi(*TempString); PXR_LOGI(PxrUnreal, "AudioCallbackBufferFrameSize = %d", Value); } Audio::FSoundWavePCMLoader SoundWaveLoader; if (InSoundWave) { TFunction OnLoaded = [](const USoundWave* SoundWave, const Audio::FSampleBuffer& SampleBuffer) { tSampleBuffer = SampleBuffer; }; SoundWaveLoader.LoadSoundWave(InSoundWave, MoveTemp(OnLoaded), true); } data = InSoundWave->RawPCMData; PXR_LOGI(PxrUnreal, "AudioCallbackBufferFrameSize = %d", data[0]); buffersize = tSampleBuffer.GetNumSamples() * tSampleBuffer.GetNumChannels(); //OutNumFrames = tSampleBuffer.GetNumFrames(); channelMask = tSampleBuffer.GetNumChannels(); sampleRate = tSampleBuffer.GetSampleRate(); OutSampleDuration = tSampleBuffer.GetSampleDuration(); parameter.slot = static_cast(slot); parameter.buffersize = static_cast(buffersize); parameter.sampleRate = sampleRate; parameter.channelCounts = channelMask; parameter.bitrate = bitrate; parameter.reversal = static_cast(slotConfig); int isVibrate = 0; if (enableV == EPICOXRCacheConfig::CacheAndVibrate) { isVibrate = 1; } else if(enableV == EPICOXRCacheConfig::CacheNoVibrate) { isVibrate = 2; } parameter.isCache = isVibrate; state = FPICOXRHMDModule::GetPluginWrapper().StartVibrateBySharemU(data, ¶meter, &SourceId); } #endif return state; } int UPICOXRInputFunctionLibrary::PXR_StartVibrateByCache(int SourceId) { int state = 0; #if PLATFORM_ANDROID if (FPICOXRVersionHelper::IsThisVersionOrGreater(0x2000308)) { return FPICOXRHMDModule::GetPluginWrapper().StartVibrateByCache(SourceId); } #endif return 0; } int UPICOXRInputFunctionLibrary::PXR_ClearVibrateByCache(int SourceId) { int state = 0; #if PLATFORM_ANDROID if (FPICOXRVersionHelper::IsThisVersionOrGreater(0x2000308)) { return FPICOXRHMDModule::GetPluginWrapper().ClearVibrateByCache(SourceId); } #endif return 0; } FQuat UPICOXRInputFunctionLibrary::GetBoneRotation(EPICOXRHandType SkeletonType, EPICOXRHandJoint Key) { IPXR_HandTracker* HandTracker=GetHandTracker(); if (HandTracker) { return HandTracker->GetBoneRotation(SkeletonType,Key); } return FQuat(); } FVector UPICOXRInputFunctionLibrary::GetBoneLocation(EPICOXRHandType DeviceHand, EPICOXRHandJoint Key) { IPXR_HandTracker* HandTracker=GetHandTracker(); if (HandTracker) { return HandTracker->GetBoneLocation(DeviceHand,Key); } return FVector(); } float UPICOXRInputFunctionLibrary::GetBoneRadii(const EPICOXRHandType DeviceHand, const EPICOXRHandJoint Key) { IPXR_HandTracker* HandTracker=GetHandTracker(); if (HandTracker) { return HandTracker->GetBoneRadii(DeviceHand,Key); } return 0.f; } bool UPICOXRInputFunctionLibrary::IsBoneOrientationValid(const EPICOXRHandType DeviceHand, const EPICOXRHandJoint Key) { IPXR_HandTracker* HandTracker=GetHandTracker(); if (HandTracker) { return HandTracker->IsBoneOrientationValid(DeviceHand,Key); } return false; } bool UPICOXRInputFunctionLibrary::IsBonePositionValid(const EPICOXRHandType DeviceHand, const EPICOXRHandJoint Key) { IPXR_HandTracker* HandTracker=GetHandTracker(); if (HandTracker) { return HandTracker->IsBonePositionValid(DeviceHand,Key); } return false; } bool UPICOXRInputFunctionLibrary::IsBoneOrientationTracked(const EPICOXRHandType DeviceHand, const EPICOXRHandJoint Key) { IPXR_HandTracker* HandTracker=GetHandTracker(); if (HandTracker) { return HandTracker->IsBoneOrientationTracked(DeviceHand,Key); } return false; } bool UPICOXRInputFunctionLibrary::IsBonePositionTracked(const EPICOXRHandType DeviceHand, const EPICOXRHandJoint Key) { IPXR_HandTracker* HandTracker=GetHandTracker(); if (HandTracker) { return HandTracker->IsBonePositionTracked(DeviceHand,Key); } return false; } FTransform UPICOXRInputFunctionLibrary::GetHandRootPose(EPICOXRHandType SkeletonType) { IPXR_HandTracker* HandTracker=GetHandTracker(); if (HandTracker) { return HandTracker->GetHandRootPose(SkeletonType); } return FTransform(); } FTransform UPICOXRInputFunctionLibrary::GetRayPose(const EPICOXRHandType DeviceHand) { IPXR_HandTracker* HandTracker=GetHandTracker(); if (HandTracker) { return HandTracker->GetRayPose(DeviceHand); } return FTransform(); } bool UPICOXRInputFunctionLibrary::IsComputed(const EPICOXRHandType DeviceHand) { IPXR_HandTracker* HandTracker=GetHandTracker(); if (HandTracker) { return HandTracker->IsComputed(DeviceHand); } return false; } bool UPICOXRInputFunctionLibrary::IsRayValid(const EPICOXRHandType DeviceHand) { IPXR_HandTracker* HandTracker=GetHandTracker(); if (HandTracker) { return HandTracker->IsRayValid(DeviceHand); } return false; } bool UPICOXRInputFunctionLibrary::IsPinchValid(const EPICOXRHandType DeviceHand) { IPXR_HandTracker* HandTracker=GetHandTracker(); if (HandTracker) { return HandTracker->IsPinchValid(DeviceHand); } return false; } EPICOXRHandTrackingConfidence UPICOXRInputFunctionLibrary::GetTrackingConfidence(const EPICOXRHandType DeviceHand) { IPXR_HandTracker* HandTracker=GetHandTracker(); if (HandTracker) { return HandTracker->GetTrackingConfidence(DeviceHand); } return EPICOXRHandTrackingConfidence::Low; } float UPICOXRInputFunctionLibrary::GetHandScale(const EPICOXRHandType DeviceHand) { IPXR_HandTracker* HandTracker=GetHandTracker(); if (HandTracker) { float NewScale=HandTracker->GetHandScale(DeviceHand); return FMath::IsFinite(NewScale)? 1.0f:NewScale; } return 1.0f; } float UPICOXRInputFunctionLibrary::GetPinchStrength(const EPICOXRHandType DeviceHand) { IPXR_HandTracker* HandTracker=GetHandTracker(); if (HandTracker) { return HandTracker->GetPinchStrength(DeviceHand); } return 0.f; } bool UPICOXRInputFunctionLibrary::IsHandTrackingEnabled() { const UPICOXRSettings* Settings = GetDefault(); IPXR_HandTracker* HandTracker=GetHandTracker(); if (Settings&&HandTracker&&Settings->HandTrackingSupport != EPICOXRHandTrackingSupport::ControllersOnly) { return GetHandTracker()->IsHandTrackingStateValid(); } return false; } EPICOXRActiveInputDevice UPICOXRInputFunctionLibrary::GetActiveInputDevice() { IPXR_HandTracker* HandTracker=GetHandTracker(); if (HandTracker) { return HandTracker->GetActiveInputDevice(); } return EPICOXRActiveInputDevice::NoneActive; } int UPICOXRInputFunctionLibrary::PXR_StartVibrateByPHF(FName DataName,EPICOXRVibrateController slot, EPICOXRChannelFlip slotConfig,float ampValue ,int& SourceID) { FString ContextString = TEXT("UPICOXRInputFunctionLibrary::PXR_StartVibrateByPHF"); SourceID = 0; UDataTable* Table = PHFDataTable; if (Table) { FPHFData* PHF_ST = Table->FindRow(DataName, ContextString); if (PHF_ST) { #if PLATFORM_ANDROID if (PHF_ST->PHFDataContent.size != 0) { if (FPICOXRVersionHelper::IsThisVersionOrGreater(0x2000308)) { int result = 0; PxrVibrate_info vibrateInfo; vibrateInfo.slot = (uint32)(static_cast(slot)); vibrateInfo.reversal = (uint32)(static_cast(slotConfig)); vibrateInfo.amp = ampValue; int ID; result = FPICOXRHMDModule::GetPluginWrapper().StartVibrateByPHF(TCHAR_TO_UTF8(*(PHF_ST->PHFDataContent.data)), PHF_ST->PHFDataContent.size, &ID, &vibrateInfo); SourceID = ID; return result; } } #endif } } return 0; } int UPICOXRInputFunctionLibrary::PXR_PauseVibrate(int SourceID) { #if PLATFORM_ANDROID if (FPICOXRVersionHelper::IsThisVersionOrGreater(0x2000308)) { return FPICOXRHMDModule::GetPluginWrapper().PauseVibrate(SourceID); } #endif return 0; } int UPICOXRInputFunctionLibrary::PXR_ResumeVibrate(int SourceID) { #if PLATFORM_ANDROID int SdkVersion = 0; if (FPICOXRVersionHelper::IsThisVersionOrGreater(0x2000308)) { return FPICOXRHMDModule::GetPluginWrapper().ResumeVibrate(SourceID); } #endif return 0; } void UPICOXRInputFunctionLibrary::PXR_GetVibrateDelayTime(FString &data) { int length = 10; data = nullptr; #if PLATFORM_ANDROID if (FPICOXRVersionHelper::IsThisVersionOrGreater(0x2000305)) { data = FPICOXRHMDModule::GetPluginWrapper().GetVibrateDelayTime(&length); } #endif } int UPICOXRInputFunctionLibrary::PXR_SetControllerEnableKey(bool isEnable, EPxrControllerKeyMap Key) { #if PLATFORM_ANDROID PxrControllerKeyMap PxrKey = static_cast(Key); return FPICOXRHMDModule::GetPluginWrapper().SetControllerEnableKey(isEnable, PxrKey); #endif return 0; } int UPICOXRInputFunctionLibrary::PXR_UpdateVibrateParams(int SourceID, EPICOXRVibrateController slot, EPICOXRChannelFlip slotConfig, float AmpValue) { #if PLATFORM_ANDROID if (FPICOXRVersionHelper::IsThisVersionOrGreater(0x2000308)) { PxrVibrate_info vibrateInfo; vibrateInfo.slot = (uint32)(static_cast(slot)); vibrateInfo.reversal = (uint32)(static_cast(slotConfig)); vibrateInfo.amp = AmpValue; return FPICOXRHMDModule::GetPluginWrapper().UpdateVibrateParams(SourceID, &vibrateInfo); } #endif return 0; } int UPICOXRInputFunctionLibrary::PXR_CreateHapticStream(FString PHFVersion, int FrameDurationMs, int Slot, int Reversal, float Amp, float Speed, int& SourceID) { int result = 0; #if PLATFORM_ANDROID if (FPICOXRVersionHelper::IsThisVersionOrGreater(0x200030A)) { PxrVibrate_info info; info.amp = Amp; info.reversal = Reversal; info.slot = Slot; int32_t id = 0; result = FPICOXRHMDModule::GetPluginWrapper().CreateHapticStream(TCHAR_TO_UTF8(*PHFVersion), FrameDurationMs, &info, Speed, &id); SourceID = id; } #endif return result; } int UPICOXRInputFunctionLibrary::PXR_RemovePHFHaptic(int SourceID) { int result = 0; #if PLATFORM_ANDROID if (FPICOXRVersionHelper::IsThisVersionOrGreater(0x200030A)) { result = FPICOXRHMDModule::GetPluginWrapper().RemovePHFHaptic(SourceID); } #endif return result; } int UPICOXRInputFunctionLibrary::PXR_StartPHFHaptic(int SourceID) { int result = 0; #if PLATFORM_ANDROID if (FPICOXRVersionHelper::IsThisVersionOrGreater(0x200030A)) { result = FPICOXRHMDModule::GetPluginWrapper().StartPHFHaptic(SourceID); } #endif return result; } int UPICOXRInputFunctionLibrary::PXR_StopPHFHaptic(int SourceID) { int result = 0; #if PLATFORM_ANDROID if (FPICOXRVersionHelper::IsThisVersionOrGreater(0x200030A)) { result = FPICOXRHMDModule::GetPluginWrapper().StopPHFHaptic(SourceID); } #endif return result; } int UPICOXRInputFunctionLibrary::PXR_WriteHapticStream(int SourceID, const FPHFJsonData& frames, int From, int NumFrames) { int result = 0; #if PLATFORM_ANDROID if (FPICOXRVersionHelper::IsThisVersionOrGreater(0x200030A)) { PxrPhf_params ppfpara = {}; int buffernum = FMath::Min(frames.patternData_L.Num(), frames.patternData_R.Num()); int rest = buffernum - From; int maxtosent = FMath::Min(rest, 25); int numtosent = NumFrames > maxtosent ? maxtosent : NumFrames; for (int32 L = 0; L < numtosent; L++) { ppfpara.params[L * 2].frameseq = frames.patternData_L[From + L].frameseq; ppfpara.params[L * 2].frequency = frames.patternData_L[From + L].frequency; ppfpara.params[L * 2].gain = frames.patternData_L[From + L].gain; ppfpara.params[L * 2].loop = frames.patternData_L[From + L].loop; ppfpara.params[L * 2].play = frames.patternData_L[From + L].play; } for (int32 R = 0; R < numtosent; R++) { ppfpara.params[R * 2 + 1].frameseq = frames.patternData_R[From + R].frameseq; ppfpara.params[R * 2 + 1].frequency = frames.patternData_R[From + R].frequency; ppfpara.params[R * 2 + 1].gain = frames.patternData_R[From + R].gain; ppfpara.params[R * 2 + 1].loop = frames.patternData_R[From + R].loop; ppfpara.params[R * 2 + 1].play = frames.patternData_R[From + R].play; } result = FPICOXRHMDModule::GetPluginWrapper().WriteHapticStream(SourceID, &ppfpara, numtosent * 2); } #endif return result; } int UPICOXRInputFunctionLibrary::PXR_GetCurrentFrameSequence(int SourceID, int& FrameSequence) { int result = 0; #if PLATFORM_ANDROID if (FPICOXRVersionHelper::IsThisVersionOrGreater(0x200030A)) { uint64_t frame = 0; result = FPICOXRHMDModule::GetPluginWrapper().GetCurrentFrameSequence(SourceID, &frame); FrameSequence = frame; } #endif return result; } int UPICOXRInputFunctionLibrary::PXR_SetPHFHapticSpeed(int SourceID, float Speed) { int result = 0; #if PLATFORM_ANDROID if (FPICOXRVersionHelper::IsThisVersionOrGreater(0x200030A)) { result = FPICOXRHMDModule::GetPluginWrapper().SetPHFHapticSpeed(SourceID, Speed); } #endif return result; } int UPICOXRInputFunctionLibrary::PXR_GetPHFHapticSpeed(int SourceID, float& Speed) { int result = 0; #if PLATFORM_ANDROID if (FPICOXRVersionHelper::IsThisVersionOrGreater(0x200030A)) { result = FPICOXRHMDModule::GetPluginWrapper().GetPHFHapticSpeed(SourceID, &Speed); } #endif return result; } bool UPICOXRInputFunctionLibrary::PXR_SetBodyTrackingStaticCalibState(int calibstate) { bool bSucceeded=false; if(FPICOXRVersionHelper::IsThisVersionOrGreater(0x2000308)) { #if PLATFORM_ANDROID if(FPICOXRHMDModule::GetPluginWrapper().SetBodyTrackingStaticCalibState(calibstate)) { return bSucceeded; } bSucceeded=true; #endif } return bSucceeded; } bool UPICOXRInputFunctionLibrary::PXR_GetBodyTrackingImuData(int deviceId, FPxrBodyTrackingImu& res) { bool bSucceeded = false; if(FPICOXRVersionHelper::IsThisVersionOrGreater(0x2000308)) { #if PLATFORM_ANDROID PxrBodyTrackingImu imudata={}; if(FPICOXRHMDModule::GetPluginWrapper().GetBodyTrackingImuData(deviceId, &imudata)) { return bSucceeded; } bSucceeded = true; res.TimeStamp = static_cast(imudata.TimeStamp); res.temperature = static_cast(imudata.temperature); res.AccData = FVector(-static_cast(imudata.AccData[2]), static_cast(imudata.AccData[0]), static_cast(imudata.AccData[1])); res.GyroData = FVector(-static_cast(imudata.GyroData[2]), static_cast(imudata.GyroData[0]), static_cast(imudata.GyroData[1])); res.MagData = FVector(-static_cast(imudata.MagData[2]), static_cast(imudata.MagData[0]), static_cast(imudata.MagData[1])); #endif } return bSucceeded; } bool UPICOXRInputFunctionLibrary::PXR_GetBodyTrackingPose(TArray& BodyTrackingData,float WorldToMetersScale) { bool bSucceeded = false; if(FPICOXRVersionHelper::IsThisVersionOrGreater(0x2000308)) { #if PLATFORM_ANDROID double dPredictTime=0; if (FPICOXRHMDModule::GetPluginWrapper().GetPredictedDisplayTime(&dPredictTime)) { return false; } PxrBodyTrackingResult bodydata={}; PXR_LOGV(PxrUnreal, "PXR_GetBodyTrackingPose: dPredictTime %f",dPredictTime); if (FPICOXRHMDModule::GetPluginWrapper().GetBodyTrackingPose(dPredictTime,&bodydata)) { return false; } for (int i = 0; i < 24; i++) { FPxrBodyTrackingTransform element = FPxrBodyTrackingTransform(); element.bone=static_cast(bodydata.trackingdata[i].bone); element.TimeStamp=static_cast(bodydata.trackingdata[i].localpose.TimeStamp); FPose UnrealBodyPose=FPose(); PxrPosef RuntimeBodyPose={}; RuntimeBodyPose.position.x=static_cast(bodydata.trackingdata[i].localpose.PosX); RuntimeBodyPose.position.y=static_cast(bodydata.trackingdata[i].localpose.PosY); RuntimeBodyPose.position.z=static_cast(bodydata.trackingdata[i].localpose.PosZ); RuntimeBodyPose.orientation.x=static_cast(bodydata.trackingdata[i].localpose.RotQx); RuntimeBodyPose.orientation.y=static_cast(bodydata.trackingdata[i].localpose.RotQy); RuntimeBodyPose.orientation.z=static_cast(bodydata.trackingdata[i].localpose.RotQz); RuntimeBodyPose.orientation.w=static_cast(bodydata.trackingdata[i].localpose.RotQw); UPICOXRHMDFunctionLibrary::GetPICOXRHMD()->ConvertPose_Internal(RuntimeBodyPose, UnrealBodyPose, UPICOXRHMDFunctionLibrary::GetPICOXRHMD()->GameSettings.Get(), WorldToMetersScale); if (!UnrealBodyPose.Position.ContainsNaN()&&!UnrealBodyPose.Orientation.ContainsNaN()&&UnrealBodyPose.Orientation.IsNormalized()) { element.LocalPose.SetLocation(UnrealBodyPose.Position); element.LocalPose.SetRotation(UnrealBodyPose.Orientation); } element.velo = FVector(-static_cast(bodydata.trackingdata[i].velo[2]), static_cast(bodydata.trackingdata[i].velo[0]), static_cast(bodydata.trackingdata[i].velo[1])); element.acce = FVector(-static_cast(bodydata.trackingdata[i].acce[2]), static_cast(bodydata.trackingdata[i].acce[0]), static_cast(bodydata.trackingdata[i].acce[1])); element.wvelo = FVector(-static_cast(bodydata.trackingdata[i].wvelo[2]), static_cast(bodydata.trackingdata[i].wvelo[0]), static_cast(bodydata.trackingdata[i].wvelo[1])); element.wacce = FVector(-static_cast(bodydata.trackingdata[i].wacce[2]), static_cast(bodydata.trackingdata[i].wacce[0]), static_cast(bodydata.trackingdata[i].wacce[1])); int Action=static_cast(bodydata.trackingdata[i].bodyAction); if ((Action&PxrBodyActionList::PxrTouchGround)&&(Action&PxrBodyActionList::PxrKeepStatic)) { element.bodyAction=EPxrBodyActionList::TouchGroundAndKeepStatic; } else if (Action&PxrBodyActionList::PxrTouchGround) { element.bodyAction = EPxrBodyActionList::TouchGround; } else if (Action&PxrBodyActionList::PxrKeepStatic) { element.bodyAction = EPxrBodyActionList::KeepStatic; } else if (Action&PxrBodyActionList::PxrTouchGroundToe) { element.bodyAction = EPxrBodyActionList::TouchGroundToe; } else { element.bodyAction = EPxrBodyActionList::NoneAction; } BodyTrackingData.Add(element); PXR_LOGV(PxrUnreal, "PXR_GetBodyTrackingPose:%f---%f---%f---%f---%f---%f---%f", BodyTrackingData[i].LocalPose.GetLocation().X, BodyTrackingData[i].LocalPose.GetLocation().Y, BodyTrackingData[i].LocalPose.GetLocation().Z, BodyTrackingData[i].LocalPose.GetRotation().X, BodyTrackingData[i].LocalPose.GetRotation().Y, BodyTrackingData[i].LocalPose.GetRotation().Z, BodyTrackingData[i].LocalPose.GetRotation().W); } bSucceeded=true; #endif } return bSucceeded; } bool UPICOXRInputFunctionLibrary::PXR_GetBodyTrackingPoseByRole(EPxrBodyTrackerRole RoleType, FPxrBodyTrackingTransform& RoleBodyTrackingData,float WorldToMetersScale) { bool bSucceeded=false; TArray BodyTrackingData; const int32 Index=static_cast(RoleType); if(PXR_GetBodyTrackingPose(BodyTrackingData,WorldToMetersScale) &&BodyTrackingData.IsValidIndex(Index)) { RoleBodyTrackingData=BodyTrackingData[Index]; bSucceeded=true; } return bSucceeded; } bool UPICOXRInputFunctionLibrary::PXR_SetBodyTrackingEnable(int32 Mode) { bool bSucceeded=false; if(FPICOXRVersionHelper::IsThisVersionOrGreater(0x2000308)) { #if PLATFORM_ANDROID if(FPICOXRHMDModule::GetPluginWrapper().SetBodyTrackingMode(Mode)) { return false; } bSucceeded=true; #endif } return bSucceeded; } bool UPICOXRInputFunctionLibrary::PXR_GetMotionTrackerConnectStateWithId(FMotionTrackerConnectState& State) { bool bSucceeded=false; if(FPICOXRVersionHelper::IsThisVersionOrGreater(0x2000308)) { #if PLATFORM_ANDROID PxrFitnessBandConnectState ConnectState= {}; if (FPICOXRHMDModule::GetPluginWrapper().GetFitnessBandConnectState(&ConnectState)) { return false; } State.Num=ConnectState.num; State.TrackerIDArray.Empty(); State.TrackerIDArray.Insert(ConnectState.trackerID,ConnectState.num,0); bSucceeded=true; #endif } return bSucceeded; } bool UPICOXRInputFunctionLibrary::PXR_GetMotionTrackerBattery(int32 TrackerId, int32& Battery) { bool bSucceeded=false; if(FPICOXRVersionHelper::IsThisVersionOrGreater(0x2000308)) { #if PLATFORM_ANDROID if (FPICOXRHMDModule::GetPluginWrapper().GetFitnessBandBattery(TrackerId,&Battery)) { return false; } bSucceeded=true; #endif } return bSucceeded; } bool UPICOXRInputFunctionLibrary::PXR_GetMotionTrackerCalibState(int32& CalibrateState) { bool bSucceeded=false; if(FPICOXRVersionHelper::IsThisVersionOrGreater(0x2000308)) { #if PLATFORM_ANDROID if (FPICOXRHMDModule::GetPluginWrapper().GetFitnessBandCalibState(&CalibrateState)) { return false; } bSucceeded=true; #endif } return bSucceeded; } bool UPICOXRInputFunctionLibrary::PXR_SetBodyTrackingMode(EBodyTrackingMode Mode, int32 OtherMode) { bool bSucceeded = false; if (FPICOXRVersionHelper::IsThisVersionOrGreater(0x200030C)) { #if PLATFORM_ANDROID PxrBodyTrackingAlgParam cBodyTrackingAlgParam = {}; cBodyTrackingAlgParam.BodyJointSet = OtherMode == -1 ? static_cast(Mode) : OtherMode; if (FPICOXRHMDModule::GetPluginWrapper().SetBodyTrackingAlgParam(PxrBodyTrackingAlgParamType::Pxr_SWIFT_MODE, &cBodyTrackingAlgParam)) { return false; } bSucceeded = true; #endif } return bSucceeded; } bool UPICOXRInputFunctionLibrary::PXR_SetBodyTrackingBoneLength(const FBodyTrackingBoneLength& BoneLength,int32 OtherMode) { bool bSucceeded=false; if(FPICOXRVersionHelper::IsThisVersionOrGreater(0x200030C)) { #if PLATFORM_ANDROID PxrBodyTrackingAlgParam cBodyTrackingAlgParam={}; cBodyTrackingAlgParam.BodyJointSet = OtherMode == -1 ? static_cast(EBodyTrackingMode::BODY_TRACKING_MODE_2) : OtherMode; cBodyTrackingAlgParam.BoneLength.HeadLen=BoneLength.headLen; cBodyTrackingAlgParam.BoneLength.NeckLen=BoneLength.neckLen; cBodyTrackingAlgParam.BoneLength.TorsoLen=BoneLength.torsoLen; cBodyTrackingAlgParam.BoneLength.HipLen=BoneLength.hipLen; cBodyTrackingAlgParam.BoneLength.UpperLegLen=BoneLength.upperLegLen; cBodyTrackingAlgParam.BoneLength.LowerLegLen=BoneLength.lowerLegLen; cBodyTrackingAlgParam.BoneLength.FootLen=BoneLength.footLen; cBodyTrackingAlgParam.BoneLength.ShoulderLen=BoneLength.shoulderLen; cBodyTrackingAlgParam.BoneLength.UpperArmLen=BoneLength.upperArmLen; cBodyTrackingAlgParam.BoneLength.LowerArmLen=BoneLength.lowerArmLen; cBodyTrackingAlgParam.BoneLength.HandLen=BoneLength.handLen; if (FPICOXRHMDModule::GetPluginWrapper().SetBodyTrackingAlgParam(PxrBodyTrackingAlgParamType::Pxr_BONE_PARAM,&cBodyTrackingAlgParam)) { return false; } bSucceeded=true; #endif } return bSucceeded; }