1876 lines
91 KiB
C++
1876 lines
91 KiB
C++
|
// @lint-ignore-every LICENSELINT
|
||
|
// Copyright Epic Games, Inc. All Rights Reserved.
|
||
|
|
||
|
#include "OculusXRInput.h"
|
||
|
|
||
|
#if OCULUS_INPUT_SUPPORTED_PLATFORMS
|
||
|
#include "OculusXRHMD.h"
|
||
|
#include "OculusXRHandTracking.h"
|
||
|
#include "OculusXRMRFunctionLibrary.h"
|
||
|
#include "Misc/CoreDelegates.h"
|
||
|
#include "Features/IModularFeatures.h"
|
||
|
#include "Misc/ConfigCacheIni.h"
|
||
|
#include "Haptics/HapticFeedbackEffect_Base.h"
|
||
|
#include "GenericPlatform/GenericPlatformInputDeviceMapper.h"
|
||
|
|
||
|
#define OVR_DEBUG_LOGGING 0
|
||
|
#define OVR_HAP_LOGGING 0
|
||
|
|
||
|
#define LOCTEXT_NAMESPACE "OculusXRInput"
|
||
|
|
||
|
static TAutoConsoleVariable<int32> CVarOculusPCMBatchDuration(
|
||
|
TEXT("r.Mobile.Oculus.PCMBatchDuration"),
|
||
|
36,
|
||
|
TEXT("The duration that each PCM haptic batch lasts in ms. Default is 36ms.\n"),
|
||
|
ECVF_Scalability | ECVF_RenderThreadSafe);
|
||
|
|
||
|
static TAutoConsoleVariable<int32> CVarOculusControllerPose(
|
||
|
TEXT("r.Oculus.ControllerPose"),
|
||
|
0,
|
||
|
TEXT("0 Default controller pose.\n")
|
||
|
TEXT("1 Legacy controller pose.\n")
|
||
|
TEXT("2 Grip controller pose.\n")
|
||
|
TEXT("3 Aim controller pose.\n"),
|
||
|
ECVF_Scalability | ECVF_RenderThreadSafe);
|
||
|
|
||
|
static TAutoConsoleVariable<int32> CVarOculusResetUntrackedInputStates(
|
||
|
TEXT("r.Mobile.Oculus.ResetUntrackedInputStates"),
|
||
|
0,
|
||
|
TEXT("If true, reset input states of input devices if they are untracked (for example, controllers or hands after Oculus button is held to pause the app).\n"),
|
||
|
ECVF_Scalability | ECVF_RenderThreadSafe);
|
||
|
|
||
|
namespace OculusXRInput
|
||
|
{
|
||
|
|
||
|
const FKey FOculusKey::OculusTouch_Left_Thumbstick("OculusTouch_Left_Thumbstick");
|
||
|
const FKey FOculusKey::OculusTouch_Left_Trigger("OculusTouch_Left_Trigger");
|
||
|
const FKey FOculusKey::OculusTouch_Left_FaceButton1("OculusTouch_Left_FaceButton1");
|
||
|
const FKey FOculusKey::OculusTouch_Left_FaceButton2("OculusTouch_Left_FaceButton2");
|
||
|
const FKey FOculusKey::OculusTouch_Left_IndexPointing("OculusTouch_Left_IndexPointing");
|
||
|
const FKey FOculusKey::OculusTouch_Left_ThumbUp("OculusTouch_Left_ThumbUp");
|
||
|
const FKey FOculusKey::OculusTouch_Left_ThumbRest("OculusTouch_Left_ThumbRest");
|
||
|
const FKey FOculusKey::OculusTouch_Left_ThumbRest_Force("OculusTouch_Left_ThumbRest_Force");
|
||
|
const FKey FOculusKey::OculusTouch_Left_Stylus_Force("OculusTouch_Left_Stylus_Force");
|
||
|
const FKey FOculusKey::OculusTouch_Left_IndexTrigger_Curl("OculusTouch_Left_IndexTrigger_Curl");
|
||
|
const FKey FOculusKey::OculusTouch_Left_IndexTrigger_Slide("OculusTouch_Left_IndexTrigger_Slide");
|
||
|
const FKey FOculusKey::OculusTouch_Left_IndexTrigger_Force("OculusTouch_Left_IndexTrigger_Force");
|
||
|
|
||
|
const FKey FOculusKey::OculusTouch_Right_Thumbstick("OculusTouch_Right_Thumbstick");
|
||
|
const FKey FOculusKey::OculusTouch_Right_Trigger("OculusTouch_Right_Trigger");
|
||
|
const FKey FOculusKey::OculusTouch_Right_FaceButton1("OculusTouch_Right_FaceButton1");
|
||
|
const FKey FOculusKey::OculusTouch_Right_FaceButton2("OculusTouch_Right_FaceButton2");
|
||
|
const FKey FOculusKey::OculusTouch_Right_IndexPointing("OculusTouch_Right_IndexPointing");
|
||
|
const FKey FOculusKey::OculusTouch_Right_ThumbUp("OculusTouch_Right_ThumbUp");
|
||
|
const FKey FOculusKey::OculusTouch_Right_ThumbRest("OculusTouch_Right_ThumbRest");
|
||
|
|
||
|
const FKey FOculusKey::OculusTouch_Right_ThumbRest_Force("OculusTouch_Right_ThumbRest_Force");
|
||
|
const FKey FOculusKey::OculusTouch_Right_Stylus_Force("OculusTouch_Right_Stylus_Force");
|
||
|
const FKey FOculusKey::OculusTouch_Right_IndexTrigger_Curl("OculusTouch_Right_IndexTrigger_Curl");
|
||
|
const FKey FOculusKey::OculusTouch_Right_IndexTrigger_Slide("OculusTouch_Right_IndexTrigger_Slide");
|
||
|
const FKey FOculusKey::OculusTouch_Right_IndexTrigger_Force("OculusTouch_Right_IndexTrigger_Force");
|
||
|
|
||
|
const FKey FOculusKey::OculusRemote_DPad_Down("OculusRemote_DPad_Down");
|
||
|
const FKey FOculusKey::OculusRemote_DPad_Up("OculusRemote_DPad_Up");
|
||
|
const FKey FOculusKey::OculusRemote_DPad_Left("OculusRemote_DPad_Left");
|
||
|
const FKey FOculusKey::OculusRemote_DPad_Right("OculusRemote_DPad_Right");
|
||
|
const FKey FOculusKey::OculusRemote_Enter("OculusRemote_Enter");
|
||
|
const FKey FOculusKey::OculusRemote_Back("OculusRemote_Back");
|
||
|
const FKey FOculusKey::OculusRemote_VolumeUp("OculusRemote_VolumeUp");
|
||
|
const FKey FOculusKey::OculusRemote_VolumeDown("OculusRemote_VolumeDown");
|
||
|
const FKey FOculusKey::OculusRemote_Home("OculusRemote_Home");
|
||
|
|
||
|
const FKey FOculusKey::OculusHand_Left_ThumbPinch("OculusHand_Left_ThumbPinch");
|
||
|
const FKey FOculusKey::OculusHand_Left_IndexPinch("OculusHand_Left_IndexPinch");
|
||
|
const FKey FOculusKey::OculusHand_Left_MiddlePinch("OculusHand_Left_MiddlePinch");
|
||
|
const FKey FOculusKey::OculusHand_Left_RingPinch("OculusHand_Left_RingPinch");
|
||
|
const FKey FOculusKey::OculusHand_Left_PinkyPinch("OculusHand_Left_PinkPinch");
|
||
|
|
||
|
const FKey FOculusKey::OculusHand_Right_ThumbPinch("OculusHand_Right_ThumbPinch");
|
||
|
const FKey FOculusKey::OculusHand_Right_IndexPinch("OculusHand_Right_IndexPinch");
|
||
|
const FKey FOculusKey::OculusHand_Right_MiddlePinch("OculusHand_Right_MiddlePinch");
|
||
|
const FKey FOculusKey::OculusHand_Right_RingPinch("OculusHand_Right_RingPinch");
|
||
|
const FKey FOculusKey::OculusHand_Right_PinkyPinch("OculusHand_Right_PinkPinch");
|
||
|
|
||
|
const FKey FOculusKey::OculusHand_Left_SystemGesture("OculusHand_Left_SystemGesture");
|
||
|
const FKey FOculusKey::OculusHand_Right_SystemGesture("OculusHand_Right_SystemGesture");
|
||
|
|
||
|
const FKey FOculusKey::OculusHand_Left_ThumbPinchStrength("OculusHand_Left_ThumbPinchStrength");
|
||
|
const FKey FOculusKey::OculusHand_Left_IndexPinchStrength("OculusHand_Left_IndexPinchStrength");
|
||
|
const FKey FOculusKey::OculusHand_Left_MiddlePinchStrength("OculusHand_Left_MiddlePinchStrength");
|
||
|
const FKey FOculusKey::OculusHand_Left_RingPinchStrength("OculusHand_Left_RingPinchStrength");
|
||
|
const FKey FOculusKey::OculusHand_Left_PinkyPinchStrength("OculusHand_Left_PinkPinchStrength");
|
||
|
|
||
|
const FKey FOculusKey::OculusHand_Right_ThumbPinchStrength("OculusHand_Right_ThumbPinchStrength");
|
||
|
const FKey FOculusKey::OculusHand_Right_IndexPinchStrength("OculusHand_Right_IndexPinchStrength");
|
||
|
const FKey FOculusKey::OculusHand_Right_MiddlePinchStrength("OculusHand_Right_MiddlePinchStrength");
|
||
|
const FKey FOculusKey::OculusHand_Right_RingPinchStrength("OculusHand_Right_RingPinchStrength");
|
||
|
const FKey FOculusKey::OculusHand_Right_PinkyPinchStrength("OculusHand_Right_PinkPinchStrength");
|
||
|
|
||
|
const FOculusKeyNames::Type FOculusKeyNames::OculusTouch_Left_Thumbstick("OculusTouch_Left_Thumbstick");
|
||
|
const FOculusKeyNames::Type FOculusKeyNames::OculusTouch_Left_Trigger("OculusTouch_Left_Trigger");
|
||
|
const FOculusKeyNames::Type FOculusKeyNames::OculusTouch_Left_FaceButton1("OculusTouch_Left_FaceButton1");
|
||
|
const FOculusKeyNames::Type FOculusKeyNames::OculusTouch_Left_FaceButton2("OculusTouch_Left_FaceButton2");
|
||
|
const FOculusKeyNames::Type FOculusKeyNames::OculusTouch_Left_IndexPointing("OculusTouch_Left_IndexPointing");
|
||
|
const FOculusKeyNames::Type FOculusKeyNames::OculusTouch_Left_ThumbUp("OculusTouch_Left_ThumbUp");
|
||
|
const FOculusKeyNames::Type FOculusKeyNames::OculusTouch_Left_ThumbRest("OculusTouch_Left_ThumbRest");
|
||
|
|
||
|
const FOculusKeyNames::Type FOculusKeyNames::OculusTouch_Right_Thumbstick("OculusTouch_Right_Thumbstick");
|
||
|
const FOculusKeyNames::Type FOculusKeyNames::OculusTouch_Right_Trigger("OculusTouch_Right_Trigger");
|
||
|
const FOculusKeyNames::Type FOculusKeyNames::OculusTouch_Right_FaceButton1("OculusTouch_Right_FaceButton1");
|
||
|
const FOculusKeyNames::Type FOculusKeyNames::OculusTouch_Right_FaceButton2("OculusTouch_Right_FaceButton2");
|
||
|
const FOculusKeyNames::Type FOculusKeyNames::OculusTouch_Right_IndexPointing("OculusTouch_Right_IndexPointing");
|
||
|
const FOculusKeyNames::Type FOculusKeyNames::OculusTouch_Right_ThumbUp("OculusTouch_Right_ThumbUp");
|
||
|
const FOculusKeyNames::Type FOculusKeyNames::OculusTouch_Right_ThumbRest("OculusTouch_Right_ThumbRest");
|
||
|
|
||
|
const FOculusKeyNames::Type FOculusKeyNames::OculusRemote_DPad_Down("OculusRemote_DPad_Down");
|
||
|
const FOculusKeyNames::Type FOculusKeyNames::OculusRemote_DPad_Up("OculusRemote_DPad_Up");
|
||
|
const FOculusKeyNames::Type FOculusKeyNames::OculusRemote_DPad_Left("OculusRemote_DPad_Left");
|
||
|
const FOculusKeyNames::Type FOculusKeyNames::OculusRemote_DPad_Right("OculusRemote_DPad_Right");
|
||
|
const FOculusKeyNames::Type FOculusKeyNames::OculusRemote_Enter("OculusRemote_Enter");
|
||
|
const FOculusKeyNames::Type FOculusKeyNames::OculusRemote_Back("OculusRemote_Back");
|
||
|
const FOculusKeyNames::Type FOculusKeyNames::OculusRemote_VolumeUp("OculusRemote_VolumeUp");
|
||
|
const FOculusKeyNames::Type FOculusKeyNames::OculusRemote_VolumeDown("OculusRemote_VolumeDown");
|
||
|
const FOculusKeyNames::Type FOculusKeyNames::OculusRemote_Home("OculusRemote_Home");
|
||
|
|
||
|
const FOculusKeyNames::Type FOculusKeyNames::OculusHand_Left_ThumbPinch("OculusHand_Left_ThumbPinch");
|
||
|
const FOculusKeyNames::Type FOculusKeyNames::OculusHand_Left_IndexPinch("OculusHand_Left_IndexPinch");
|
||
|
const FOculusKeyNames::Type FOculusKeyNames::OculusHand_Left_MiddlePinch("OculusHand_Left_MiddlePinch");
|
||
|
const FOculusKeyNames::Type FOculusKeyNames::OculusHand_Left_RingPinch("OculusHand_Left_RingPinch");
|
||
|
const FOculusKeyNames::Type FOculusKeyNames::OculusHand_Left_PinkyPinch("OculusHand_Left_PinkPinch");
|
||
|
|
||
|
const FOculusKeyNames::Type FOculusKeyNames::OculusHand_Right_ThumbPinch("OculusHand_Right_ThumbPinch");
|
||
|
const FOculusKeyNames::Type FOculusKeyNames::OculusHand_Right_IndexPinch("OculusHand_Right_IndexPinch");
|
||
|
const FOculusKeyNames::Type FOculusKeyNames::OculusHand_Right_MiddlePinch("OculusHand_Right_MiddlePinch");
|
||
|
const FOculusKeyNames::Type FOculusKeyNames::OculusHand_Right_RingPinch("OculusHand_Right_RingPinch");
|
||
|
const FOculusKeyNames::Type FOculusKeyNames::OculusHand_Right_PinkyPinch("OculusHand_Right_PinkPinch");
|
||
|
|
||
|
const FOculusKeyNames::Type FOculusKeyNames::OculusHand_Left_SystemGesture("OculusHand_Left_SystemGesture");
|
||
|
const FOculusKeyNames::Type FOculusKeyNames::OculusHand_Right_SystemGesture("OculusHand_Right_SystemGesture");
|
||
|
|
||
|
const FOculusKeyNames::Type FOculusKeyNames::OculusHand_Left_ThumbPinchStrength("OculusHand_Left_ThumbPinchStrength");
|
||
|
const FOculusKeyNames::Type FOculusKeyNames::OculusHand_Left_IndexPinchStrength("OculusHand_Left_IndexPinchStrength");
|
||
|
const FOculusKeyNames::Type FOculusKeyNames::OculusHand_Left_MiddlePinchStrength("OculusHand_Left_MiddlePinchStrength");
|
||
|
const FOculusKeyNames::Type FOculusKeyNames::OculusHand_Left_RingPinchStrength("OculusHand_Left_RingPinchStrength");
|
||
|
const FOculusKeyNames::Type FOculusKeyNames::OculusHand_Left_PinkyPinchStrength("OculusHand_Left_PinkPinchStrength");
|
||
|
|
||
|
const FOculusKeyNames::Type FOculusKeyNames::OculusHand_Right_ThumbPinchStrength("OculusHand_Right_ThumbPinchStrength");
|
||
|
const FOculusKeyNames::Type FOculusKeyNames::OculusHand_Right_IndexPinchStrength("OculusHand_Right_IndexPinchStrength");
|
||
|
const FOculusKeyNames::Type FOculusKeyNames::OculusHand_Right_MiddlePinchStrength("OculusHand_Right_MiddlePinchStrength");
|
||
|
const FOculusKeyNames::Type FOculusKeyNames::OculusHand_Right_RingPinchStrength("OculusHand_Right_RingPinchStrength");
|
||
|
const FOculusKeyNames::Type FOculusKeyNames::OculusHand_Right_PinkyPinchStrength("OculusHand_Right_PinkPinchStrength");
|
||
|
|
||
|
/** Threshold for treating trigger pulls as button presses, from 0.0 to 1.0 */
|
||
|
float FOculusXRInput::TriggerThreshold = 0.8f;
|
||
|
|
||
|
/** Are Remote keys mapped to gamepad or not. */
|
||
|
bool FOculusXRInput::bRemoteKeysMappedToGamepad = true;
|
||
|
|
||
|
float FOculusXRInput::InitialButtonRepeatDelay = 0.2f;
|
||
|
float FOculusXRInput::ButtonRepeatDelay = 0.1f;
|
||
|
bool FOculusXRInput::bPulledHapticsDesc = false;
|
||
|
|
||
|
FOculusXRInput::FOculusXRInput(const TSharedRef<FGenericApplicationMessageHandler>& InMessageHandler)
|
||
|
: MessageHandler(InMessageHandler)
|
||
|
, ControllerPairs()
|
||
|
{
|
||
|
// take care of backward compatibility of Remote with Gamepad
|
||
|
if (bRemoteKeysMappedToGamepad)
|
||
|
{
|
||
|
Remote.MapKeysToGamepad();
|
||
|
}
|
||
|
|
||
|
FOculusControllerPair& ControllerPair = *new (ControllerPairs) FOculusControllerPair();
|
||
|
|
||
|
// TODO: Map the oculus controllers uniquely instead of using the default
|
||
|
ControllerPair.DeviceId = IPlatformInputDeviceMapper::Get().GetDefaultInputDevice();
|
||
|
|
||
|
IModularFeatures::Get().RegisterModularFeature(GetModularFeatureName(), this);
|
||
|
|
||
|
LocalTrackingSpaceRecenterCount = 0;
|
||
|
|
||
|
UE_LOG(LogOcInput, Log, TEXT("OculusXRInput is initialized"));
|
||
|
}
|
||
|
|
||
|
FOculusXRInput::~FOculusXRInput()
|
||
|
{
|
||
|
IModularFeatures::Get().UnregisterModularFeature(GetModularFeatureName(), this);
|
||
|
}
|
||
|
|
||
|
void FOculusXRInput::PreInit()
|
||
|
{
|
||
|
// Load the config, even if we failed to initialize a controller
|
||
|
LoadConfig();
|
||
|
|
||
|
// Register the FKeys
|
||
|
EKeys::AddKey(FKeyDetails(FOculusKey::OculusTouch_Left_Thumbstick, LOCTEXT("OculusTouch_Left_Thumbstick", "Oculus Touch (L) Thumbstick CapTouch"), FKeyDetails::GamepadKey | FKeyDetails::Axis1D));
|
||
|
EKeys::AddKey(FKeyDetails(FOculusKey::OculusTouch_Left_FaceButton1, LOCTEXT("OculusTouch_Left_FaceButton1", "Oculus Touch (L) X Button CapTouch"), FKeyDetails::GamepadKey | FKeyDetails::Axis1D));
|
||
|
EKeys::AddKey(FKeyDetails(FOculusKey::OculusTouch_Left_Trigger, LOCTEXT("OculusTouch_Left_Trigger", "Oculus Touch (L) Trigger CapTouch"), FKeyDetails::GamepadKey | FKeyDetails::Axis1D));
|
||
|
EKeys::AddKey(FKeyDetails(FOculusKey::OculusTouch_Left_FaceButton2, LOCTEXT("OculusTouch_Left_FaceButton2", "Oculus Touch (L) Y Button CapTouch"), FKeyDetails::GamepadKey | FKeyDetails::Axis1D));
|
||
|
EKeys::AddKey(FKeyDetails(FOculusKey::OculusTouch_Left_IndexPointing, LOCTEXT("OculusTouch_Left_IndexPointing", "Oculus Touch (L) Pointing CapTouch"), FKeyDetails::GamepadKey | FKeyDetails::Axis1D | FKeyDetails::NotBlueprintBindableKey, "OculusTouch"));
|
||
|
EKeys::AddKey(FKeyDetails(FOculusKey::OculusTouch_Left_ThumbUp, LOCTEXT("OculusTouch_Left_ThumbUp", "Oculus Touch (L) Thumb Up CapTouch"), FKeyDetails::GamepadKey | FKeyDetails::Axis1D | FKeyDetails::NotBlueprintBindableKey, "OculusTouch"));
|
||
|
EKeys::AddKey(FKeyDetails(FOculusKey::OculusTouch_Left_ThumbRest, LOCTEXT("OculusTouch_Left_ThumbRest", "Oculus Touch (L) Thumb Rest CapTouch"), FKeyDetails::GamepadKey | FKeyDetails::Axis1D | FKeyDetails::NotBlueprintBindableKey, "OculusTouch"));
|
||
|
EKeys::AddKey(FKeyDetails(FOculusKey::OculusTouch_Left_ThumbRest_Force, LOCTEXT("OculusTouch_Left_ThumbRest_Force", "Oculus Touch (L) Thumb Rest Force"), FKeyDetails::GamepadKey | FKeyDetails::Axis1D | FKeyDetails::NotBlueprintBindableKey, "OculusTouch"));
|
||
|
EKeys::AddKey(FKeyDetails(FOculusKey::OculusTouch_Left_Stylus_Force, LOCTEXT("OculusTouch_Left_Stylus_Force", "Oculus Touch (L) Stylus Force"), FKeyDetails::GamepadKey | FKeyDetails::Axis1D | FKeyDetails::NotBlueprintBindableKey, "OculusTouch"));
|
||
|
EKeys::AddKey(FKeyDetails(FOculusKey::OculusTouch_Left_IndexTrigger_Curl, LOCTEXT("OculusTouch_Left_IndexTrigger_Curl", "Oculus Touch (L) Trigger Curl CapTouch"), FKeyDetails::GamepadKey | FKeyDetails::Axis1D | FKeyDetails::NotBlueprintBindableKey, "OculusTouch"));
|
||
|
EKeys::AddKey(FKeyDetails(FOculusKey::OculusTouch_Left_IndexTrigger_Slide, LOCTEXT("OculusTouch_Left_IndexTrigger_Slide", "Oculus Touch (L) Trigger Slide CapTouch"), FKeyDetails::GamepadKey | FKeyDetails::Axis1D | FKeyDetails::NotBlueprintBindableKey, "OculusTouch"));
|
||
|
EKeys::AddKey(FKeyDetails(FOculusKey::OculusTouch_Left_IndexTrigger_Force, LOCTEXT("OculusTouch_Left_IndexTrigger_Force", "Oculus Touch (L) Trigger Force"), FKeyDetails::GamepadKey | FKeyDetails::Axis1D | FKeyDetails::NotBlueprintBindableKey, "OculusTouch"));
|
||
|
|
||
|
EKeys::AddKey(FKeyDetails(FOculusKey::OculusTouch_Right_Thumbstick, LOCTEXT("OculusTouch_Right_Thumbstick", "Oculus Touch (R) Thumbstick CapTouch"), FKeyDetails::GamepadKey | FKeyDetails::Axis1D | FKeyDetails::NotBlueprintBindableKey));
|
||
|
EKeys::AddKey(FKeyDetails(FOculusKey::OculusTouch_Right_FaceButton1, LOCTEXT("OculusTouch_Right_FaceButton1", "Oculus Touch (R) A Button CapTouch"), FKeyDetails::GamepadKey | FKeyDetails::Axis1D | FKeyDetails::NotBlueprintBindableKey));
|
||
|
EKeys::AddKey(FKeyDetails(FOculusKey::OculusTouch_Right_Trigger, LOCTEXT("OculusTouch_Right_Trigger", "Oculus Touch (R) Trigger CapTouch"), FKeyDetails::GamepadKey | FKeyDetails::Axis1D | FKeyDetails::NotBlueprintBindableKey));
|
||
|
EKeys::AddKey(FKeyDetails(FOculusKey::OculusTouch_Right_FaceButton2, LOCTEXT("OculusTouch_Right_FaceButton2", "Oculus Touch (R) B Button CapTouch"), FKeyDetails::GamepadKey | FKeyDetails::Axis1D | FKeyDetails::NotBlueprintBindableKey));
|
||
|
EKeys::AddKey(FKeyDetails(FOculusKey::OculusTouch_Right_IndexPointing, LOCTEXT("OculusTouch_Right_IndexPointing", "Oculus Touch (R) Pointing CapTouch"), FKeyDetails::GamepadKey | FKeyDetails::Axis1D | FKeyDetails::NotBlueprintBindableKey, "OculusTouch"));
|
||
|
EKeys::AddKey(FKeyDetails(FOculusKey::OculusTouch_Right_ThumbUp, LOCTEXT("OculusTouch_Right_ThumbUp", "Oculus Touch (R) Thumb Up CapTouch"), FKeyDetails::GamepadKey | FKeyDetails::Axis1D | FKeyDetails::NotBlueprintBindableKey, "OculusTouch"));
|
||
|
EKeys::AddKey(FKeyDetails(FOculusKey::OculusTouch_Right_ThumbRest, LOCTEXT("OculusTouch_Right_ThumbRest", "Oculus Touch (R) Thumb Rest CapTouch"), FKeyDetails::GamepadKey | FKeyDetails::Axis1D | FKeyDetails::NotBlueprintBindableKey, "OculusTouch"));
|
||
|
EKeys::AddKey(FKeyDetails(FOculusKey::OculusTouch_Right_ThumbRest_Force, LOCTEXT("OculusTouch_Right_ThumbRest_Force", "Oculus Touch (R) Thumb Rest Force"), FKeyDetails::GamepadKey | FKeyDetails::Axis1D | FKeyDetails::NotBlueprintBindableKey, "OculusTouch"));
|
||
|
EKeys::AddKey(FKeyDetails(FOculusKey::OculusTouch_Right_Stylus_Force, LOCTEXT("OculusTouch_Right_Stylus_Force", "Oculus Touch (R) Stylus Force"), FKeyDetails::GamepadKey | FKeyDetails::Axis1D | FKeyDetails::NotBlueprintBindableKey, "OculusTouch"));
|
||
|
EKeys::AddKey(FKeyDetails(FOculusKey::OculusTouch_Right_IndexTrigger_Curl, LOCTEXT("OculusTouch_Right_IndexTrigger_Curl", "Oculus Touch (R) Trigger Curl CapTouch"), FKeyDetails::GamepadKey | FKeyDetails::Axis1D | FKeyDetails::NotBlueprintBindableKey, "OculusTouch"));
|
||
|
EKeys::AddKey(FKeyDetails(FOculusKey::OculusTouch_Right_IndexTrigger_Slide, LOCTEXT("OculusTouch_Right_IndexTrigger_Slide", "Oculus Touch (R) Trigger Slide CapTouch"), FKeyDetails::GamepadKey | FKeyDetails::Axis1D | FKeyDetails::NotBlueprintBindableKey, "OculusTouch"));
|
||
|
EKeys::AddKey(FKeyDetails(FOculusKey::OculusTouch_Right_IndexTrigger_Force, LOCTEXT("OculusTouch_Right_IndexTrigger_Force", "Oculus Touch (R) Trigger Force"), FKeyDetails::GamepadKey | FKeyDetails::Axis1D | FKeyDetails::NotBlueprintBindableKey, "OculusTouch"));
|
||
|
|
||
|
EKeys::AddMenuCategoryDisplayInfo("OculusRemote", LOCTEXT("OculusRemoteSubCategory", "Oculus Remote"), TEXT("GraphEditor.PadEvent_16x"));
|
||
|
|
||
|
EKeys::AddKey(FKeyDetails(FOculusKey::OculusRemote_DPad_Up, LOCTEXT("OculusRemote_DPad_Up", "Oculus Remote D-pad Up"), FKeyDetails::GamepadKey, "OculusRemote"));
|
||
|
EKeys::AddKey(FKeyDetails(FOculusKey::OculusRemote_DPad_Down, LOCTEXT("OculusRemote_DPad_Down", "Oculus Remote D-pad Down"), FKeyDetails::GamepadKey, "OculusRemote"));
|
||
|
EKeys::AddKey(FKeyDetails(FOculusKey::OculusRemote_DPad_Left, LOCTEXT("OculusRemote_DPad_Left", "Oculus Remote D-pad Left"), FKeyDetails::GamepadKey, "OculusRemote"));
|
||
|
EKeys::AddKey(FKeyDetails(FOculusKey::OculusRemote_DPad_Right, LOCTEXT("OculusRemote_DPad_Right", "Oculus Remote D-pad Right"), FKeyDetails::GamepadKey, "OculusRemote"));
|
||
|
|
||
|
EKeys::AddKey(FKeyDetails(FOculusKey::OculusRemote_Enter, LOCTEXT("OculusRemote_Enter", "Oculus Remote Enter"), FKeyDetails::GamepadKey, "OculusRemote"));
|
||
|
EKeys::AddKey(FKeyDetails(FOculusKey::OculusRemote_Back, LOCTEXT("OculusRemote_Back", "Oculus Remote Back"), FKeyDetails::GamepadKey, "OculusRemote"));
|
||
|
|
||
|
EKeys::AddKey(FKeyDetails(FOculusKey::OculusRemote_VolumeUp, LOCTEXT("OculusRemote_VolumeUp", "Oculus Remote Volume Up"), FKeyDetails::GamepadKey, "OculusRemote"));
|
||
|
EKeys::AddKey(FKeyDetails(FOculusKey::OculusRemote_VolumeDown, LOCTEXT("OculusRemote_VolumeDown", "Oculus Remote Volume Down"), FKeyDetails::GamepadKey, "OculusRemote"));
|
||
|
EKeys::AddKey(FKeyDetails(FOculusKey::OculusRemote_Home, LOCTEXT("OculusRemote_Home", "Oculus Remote Home"), FKeyDetails::GamepadKey, "OculusRemote"));
|
||
|
|
||
|
EKeys::AddMenuCategoryDisplayInfo("OculusHand", LOCTEXT("OculusHandSubCategory", "Oculus Hand"), TEXT("GraphEditor.PadEvent_16x"));
|
||
|
|
||
|
EKeys::AddKey(FKeyDetails(FOculusKey::OculusHand_Left_ThumbPinch, LOCTEXT("OculusHand_Left_ThumbPinch", "Oculus Hand (L) Thumb Pinch"), FKeyDetails::GamepadKey | FKeyDetails::NotBlueprintBindableKey, "OculusHand"));
|
||
|
EKeys::AddKey(FKeyDetails(FOculusKey::OculusHand_Left_IndexPinch, LOCTEXT("OculusHand_Left_IndexPinch", "Oculus Hand (L) Index Pinch"), FKeyDetails::GamepadKey | FKeyDetails::NotBlueprintBindableKey, "OculusHand"));
|
||
|
EKeys::AddKey(FKeyDetails(FOculusKey::OculusHand_Left_MiddlePinch, LOCTEXT("OculusHand_Left_MiddlePinch", "Oculus Hand (L) Middle Pinch"), FKeyDetails::GamepadKey | FKeyDetails::NotBlueprintBindableKey, "OculusHand"));
|
||
|
EKeys::AddKey(FKeyDetails(FOculusKey::OculusHand_Left_RingPinch, LOCTEXT("OculusHand_Left_RingPinch", "Oculus Hand (L) Ring Pinch"), FKeyDetails::GamepadKey | FKeyDetails::NotBlueprintBindableKey, "OculusHand"));
|
||
|
EKeys::AddKey(FKeyDetails(FOculusKey::OculusHand_Left_PinkyPinch, LOCTEXT("OculusHand_Left_PinkyPinch", "Oculus Hand (L) Pinky Pinch"), FKeyDetails::GamepadKey | FKeyDetails::NotBlueprintBindableKey, "OculusHand"));
|
||
|
|
||
|
EKeys::AddKey(FKeyDetails(FOculusKey::OculusHand_Right_ThumbPinch, LOCTEXT("OculusHand_Right_ThumbPinch", "Oculus Hand (R) Thumb Pinch"), FKeyDetails::GamepadKey | FKeyDetails::NotBlueprintBindableKey, "OculusHand"));
|
||
|
EKeys::AddKey(FKeyDetails(FOculusKey::OculusHand_Right_IndexPinch, LOCTEXT("OculusHand_Right_IndexPinch", "Oculus Hand (R) Index Pinch"), FKeyDetails::GamepadKey | FKeyDetails::NotBlueprintBindableKey, "OculusHand"));
|
||
|
EKeys::AddKey(FKeyDetails(FOculusKey::OculusHand_Right_MiddlePinch, LOCTEXT("OculusHand_Right_MiddlePinch", "Oculus Hand (R) Middle Pinch"), FKeyDetails::GamepadKey | FKeyDetails::NotBlueprintBindableKey, "OculusHand"));
|
||
|
EKeys::AddKey(FKeyDetails(FOculusKey::OculusHand_Right_RingPinch, LOCTEXT("OculusHand_Right_RingPinch", "Oculus Hand (R) Ring Pinch"), FKeyDetails::GamepadKey | FKeyDetails::NotBlueprintBindableKey, "OculusHand"));
|
||
|
EKeys::AddKey(FKeyDetails(FOculusKey::OculusHand_Right_PinkyPinch, LOCTEXT("OculusHand_Right_PinkyPinch", "Oculus Hand (R) Pinky Pinch"), FKeyDetails::GamepadKey | FKeyDetails::NotBlueprintBindableKey, "OculusHand"));
|
||
|
|
||
|
EKeys::AddKey(FKeyDetails(FOculusKey::OculusHand_Left_SystemGesture, LOCTEXT("OculusHand_Left_SystemGesture", "Oculus Hand (L) System Gesture"), FKeyDetails::GamepadKey | FKeyDetails::NotBlueprintBindableKey, "OculusHand"));
|
||
|
EKeys::AddKey(FKeyDetails(FOculusKey::OculusHand_Right_SystemGesture, LOCTEXT("OculusHand_Right_SystemGesture", "Oculus Hand (R) System Gesture"), FKeyDetails::GamepadKey | FKeyDetails::NotBlueprintBindableKey, "OculusHand"));
|
||
|
|
||
|
EKeys::AddKey(FKeyDetails(FOculusKey::OculusHand_Left_ThumbPinchStrength, LOCTEXT("OculusHand_Left_ThumbPinchStrength", "Oculus Hand (L) Thumb Pinch Strength"), FKeyDetails::GamepadKey | FKeyDetails::Axis1D, "OculusHand"));
|
||
|
EKeys::AddKey(FKeyDetails(FOculusKey::OculusHand_Left_IndexPinchStrength, LOCTEXT("OculusHand_Left_IndexPinchStrength", "Oculus Hand (L) Index Pinch Strength"), FKeyDetails::GamepadKey | FKeyDetails::Axis1D, "OculusHand"));
|
||
|
EKeys::AddKey(FKeyDetails(FOculusKey::OculusHand_Left_MiddlePinchStrength, LOCTEXT("OculusHand_Left_MiddlePinchStrength", "Oculus Hand (L) Middle Pinch Strength"), FKeyDetails::GamepadKey | FKeyDetails::Axis1D, "OculusHand"));
|
||
|
EKeys::AddKey(FKeyDetails(FOculusKey::OculusHand_Left_RingPinchStrength, LOCTEXT("OculusHand_Left_RingPinchStrength", "Oculus Hand (L) Ring Pinch Strength"), FKeyDetails::GamepadKey | FKeyDetails::Axis1D, "OculusHand"));
|
||
|
EKeys::AddKey(FKeyDetails(FOculusKey::OculusHand_Left_PinkyPinchStrength, LOCTEXT("OculusHand_Left_PinkyPinchStrength", "Oculus Hand (L) Pinky Pinch Strength"), FKeyDetails::GamepadKey | FKeyDetails::Axis1D, "OculusHand"));
|
||
|
|
||
|
EKeys::AddKey(FKeyDetails(FOculusKey::OculusHand_Right_ThumbPinchStrength, LOCTEXT("OculusHand_Right_ThumbPinchStrength", "Oculus Hand (R) Thumb Pinch Strength"), FKeyDetails::GamepadKey | FKeyDetails::Axis1D, "OculusHand"));
|
||
|
EKeys::AddKey(FKeyDetails(FOculusKey::OculusHand_Right_IndexPinchStrength, LOCTEXT("OculusHand_Right_IndexPinchStrength", "Oculus Hand (R) Index Pinch Strength"), FKeyDetails::GamepadKey | FKeyDetails::Axis1D, "OculusHand"));
|
||
|
EKeys::AddKey(FKeyDetails(FOculusKey::OculusHand_Right_MiddlePinchStrength, LOCTEXT("OculusHand_Right_MiddlePinchStrength", "Oculus Hand (R) Middle Pinch Strength"), FKeyDetails::GamepadKey | FKeyDetails::Axis1D, "OculusHand"));
|
||
|
EKeys::AddKey(FKeyDetails(FOculusKey::OculusHand_Right_RingPinchStrength, LOCTEXT("OculusHand_Right_RingPinchStrength", "Oculus Hand (R) Ring Pinch Strength"), FKeyDetails::GamepadKey | FKeyDetails::Axis1D, "OculusHand"));
|
||
|
EKeys::AddKey(FKeyDetails(FOculusKey::OculusHand_Right_PinkyPinchStrength, LOCTEXT("OculusHand_Right_PinkyPinchStrength", "Oculus Hand (R) Pinky Pinch Strength"), FKeyDetails::GamepadKey | FKeyDetails::Axis1D, "OculusHand"));
|
||
|
|
||
|
UE_LOG(LogOcInput, Log, TEXT("OculusXRInput pre-init called"));
|
||
|
}
|
||
|
|
||
|
void FOculusXRInput::LoadConfig()
|
||
|
{
|
||
|
const TCHAR* OculusTouchSettings = TEXT("OculusTouch.Settings");
|
||
|
float ConfigThreshold = TriggerThreshold;
|
||
|
if (GConfig->GetFloat(OculusTouchSettings, TEXT("TriggerThreshold"), ConfigThreshold, GEngineIni))
|
||
|
{
|
||
|
TriggerThreshold = ConfigThreshold;
|
||
|
}
|
||
|
|
||
|
const TCHAR* OculusRemoteSettings = TEXT("OculusRemote.Settings");
|
||
|
bool bConfigRemoteKeysMappedToGamepad;
|
||
|
if (GConfig->GetBool(OculusRemoteSettings, TEXT("bRemoteKeysMappedToGamepad"), bConfigRemoteKeysMappedToGamepad, GEngineIni))
|
||
|
{
|
||
|
bRemoteKeysMappedToGamepad = bConfigRemoteKeysMappedToGamepad;
|
||
|
}
|
||
|
|
||
|
GConfig->GetFloat(TEXT("/Script/Engine.InputSettings"), TEXT("InitialButtonRepeatDelay"), InitialButtonRepeatDelay, GInputIni);
|
||
|
GConfig->GetFloat(TEXT("/Script/Engine.InputSettings"), TEXT("ButtonRepeatDelay"), ButtonRepeatDelay, GInputIni);
|
||
|
}
|
||
|
|
||
|
void FOculusXRInput::Tick(float DeltaTime)
|
||
|
{
|
||
|
// Nothing to do when ticking, for now. SendControllerEvents() handles everything.
|
||
|
}
|
||
|
|
||
|
void FOculusXRInput::SendControllerEvents()
|
||
|
{
|
||
|
const double CurrentTime = FPlatformTime::Seconds();
|
||
|
const float AnalogButtonPressThreshold = TriggerThreshold;
|
||
|
float DeltaTime = 0.0;
|
||
|
if (StartTime < CurrentTime)
|
||
|
{
|
||
|
DeltaTime = (float)(CurrentTime - StartTime);
|
||
|
StartTime = CurrentTime;
|
||
|
}
|
||
|
|
||
|
if (IOculusXRHMDModule::IsAvailable() && FOculusXRHMDModule::GetPluginWrapper().GetInitialized() && FApp::HasVRFocus())
|
||
|
{
|
||
|
if (MessageHandler.IsValid() && GEngine->XRSystem->GetHMDDevice())
|
||
|
{
|
||
|
FPlatformUserId PlatUser = IPlatformInputDeviceMapper::Get().GetPrimaryPlatformUser();
|
||
|
FInputDeviceId DeviceId = IPlatformInputDeviceMapper::Get().GetDefaultInputDevice();
|
||
|
|
||
|
OculusXRHMD::FOculusXRHMD* OculusXRHMD = static_cast<OculusXRHMD::FOculusXRHMD*>(GEngine->XRSystem->GetHMDDevice());
|
||
|
OculusXRHMD->StartGameFrame_GameThread();
|
||
|
|
||
|
ovrpControllerState6 OvrpControllerState;
|
||
|
if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetControllerState6(ovrpController_Remote, &OvrpControllerState)) && (OvrpControllerState.ConnectedControllerTypes & ovrpController_Remote))
|
||
|
{
|
||
|
for (int32 ButtonIndex = 0; ButtonIndex < (int32)EOculusRemoteControllerButton::TotalButtonCount; ++ButtonIndex)
|
||
|
{
|
||
|
FOculusButtonState& ButtonState = Remote.Buttons[ButtonIndex];
|
||
|
check(!ButtonState.Key.IsNone()); // is button's name initialized?
|
||
|
|
||
|
// Determine if the button is pressed down
|
||
|
bool bButtonPressed = false;
|
||
|
switch ((EOculusRemoteControllerButton)ButtonIndex)
|
||
|
{
|
||
|
case EOculusRemoteControllerButton::DPad_Up:
|
||
|
bButtonPressed = (OvrpControllerState.Buttons & ovrpButton_Up) != 0;
|
||
|
break;
|
||
|
|
||
|
case EOculusRemoteControllerButton::DPad_Down:
|
||
|
bButtonPressed = (OvrpControllerState.Buttons & ovrpButton_Down) != 0;
|
||
|
break;
|
||
|
|
||
|
case EOculusRemoteControllerButton::DPad_Left:
|
||
|
bButtonPressed = (OvrpControllerState.Buttons & ovrpButton_Left) != 0;
|
||
|
break;
|
||
|
|
||
|
case EOculusRemoteControllerButton::DPad_Right:
|
||
|
bButtonPressed = (OvrpControllerState.Buttons & ovrpButton_Right) != 0;
|
||
|
break;
|
||
|
|
||
|
case EOculusRemoteControllerButton::Enter:
|
||
|
bButtonPressed = (OvrpControllerState.Buttons & ovrpButton_Start) != 0;
|
||
|
break;
|
||
|
|
||
|
case EOculusRemoteControllerButton::Back:
|
||
|
bButtonPressed = (OvrpControllerState.Buttons & ovrpButton_Back) != 0;
|
||
|
break;
|
||
|
|
||
|
case EOculusRemoteControllerButton::VolumeUp:
|
||
|
#ifdef SUPPORT_INTERNAL_BUTTONS
|
||
|
bButtonPressed = (OvrpControllerState.Buttons & ovrpButton_VolUp) != 0;
|
||
|
#endif
|
||
|
break;
|
||
|
|
||
|
case EOculusRemoteControllerButton::VolumeDown:
|
||
|
#ifdef SUPPORT_INTERNAL_BUTTONS
|
||
|
bButtonPressed = (OvrpControllerState.Buttons & ovrpButton_VolDown) != 0;
|
||
|
#endif
|
||
|
break;
|
||
|
|
||
|
case EOculusRemoteControllerButton::Home:
|
||
|
#ifdef SUPPORT_INTERNAL_BUTTONS
|
||
|
bButtonPressed = (OvrpControllerState.Buttons & ovrpButton_Home) != 0;
|
||
|
#endif
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
check(0); // unhandled button, shouldn't happen
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// Update button state
|
||
|
if (bButtonPressed != ButtonState.bIsPressed)
|
||
|
{
|
||
|
ButtonState.bIsPressed = bButtonPressed;
|
||
|
if (ButtonState.bIsPressed)
|
||
|
{
|
||
|
OnControllerButtonPressed(ButtonState, PlatUser, DeviceId, false);
|
||
|
|
||
|
// Set the timer for the first repeat
|
||
|
ButtonState.NextRepeatTime = CurrentTime + InitialButtonRepeatDelay;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
OnControllerButtonReleased(ButtonState, PlatUser, DeviceId, false);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Apply key repeat, if its time for that
|
||
|
if (ButtonState.bIsPressed && ButtonState.NextRepeatTime <= CurrentTime)
|
||
|
{
|
||
|
OnControllerButtonPressed(ButtonState, PlatUser, DeviceId, true);
|
||
|
|
||
|
// Set the timer for the next repeat
|
||
|
ButtonState.NextRepeatTime = CurrentTime + ButtonRepeatDelay;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetControllerState6((ovrpController)(ovrpController_LTrackedRemote | ovrpController_RTrackedRemote | ovrpController_Touch), &OvrpControllerState)))
|
||
|
{
|
||
|
UE_CLOG(OVR_DEBUG_LOGGING, LogOcInput, Log, TEXT("SendControllerEvents: ButtonState = 0x%X"), OvrpControllerState.Buttons);
|
||
|
UE_CLOG(OVR_DEBUG_LOGGING, LogOcInput, Log, TEXT("SendControllerEvents: Touches = 0x%X"), OvrpControllerState.Touches);
|
||
|
|
||
|
// If using touch controllers (Quest) use the local tracking space recentering as a signal for recenter
|
||
|
if ((OvrpControllerState.ConnectedControllerTypes & ovrpController_LTouch) != 0 || (OvrpControllerState.ConnectedControllerTypes & ovrpController_RTouch) != 0)
|
||
|
{
|
||
|
int32 recenterCount = 0;
|
||
|
if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetLocalTrackingSpaceRecenterCount(&recenterCount)))
|
||
|
{
|
||
|
if (LocalTrackingSpaceRecenterCount != recenterCount)
|
||
|
{
|
||
|
FCoreDelegates::VRControllerRecentered.Broadcast();
|
||
|
LocalTrackingSpaceRecenterCount = recenterCount;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
for (FOculusControllerPair& ControllerPair : ControllerPairs)
|
||
|
{
|
||
|
FPlatformUserId PlatformUser = IPlatformInputDeviceMapper::Get().GetUserForInputDevice(ControllerPair.DeviceId);
|
||
|
|
||
|
for (int32 HandIndex = 0; HandIndex < UE_ARRAY_COUNT(ControllerPair.TouchControllerStates); ++HandIndex)
|
||
|
{
|
||
|
FOculusTouchControllerState& State = ControllerPair.TouchControllerStates[HandIndex];
|
||
|
bool bIsLeft = (HandIndex == (int32)EControllerHand::Left);
|
||
|
|
||
|
bool bIsMobileController = bIsLeft ? (OvrpControllerState.ConnectedControllerTypes & ovrpController_LTrackedRemote) != 0 : (OvrpControllerState.ConnectedControllerTypes & ovrpController_RTrackedRemote) != 0;
|
||
|
bool bIsTouchController = bIsLeft ? (OvrpControllerState.ConnectedControllerTypes & ovrpController_LTouch) != 0 : (OvrpControllerState.ConnectedControllerTypes & ovrpController_RTouch) != 0;
|
||
|
bool bIsCurrentlyTracked = bIsMobileController || bIsTouchController;
|
||
|
|
||
|
if (bIsCurrentlyTracked)
|
||
|
{
|
||
|
ovrpNode OvrpNode = (HandIndex == (int32)EControllerHand::Left) ? ovrpNode_HandLeft : ovrpNode_HandRight;
|
||
|
|
||
|
State.bIsConnected = true;
|
||
|
ovrpBool bResult = true;
|
||
|
State.bIsPositionTracked = OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetNodePositionTracked2(OvrpNode, &bResult)) && bResult;
|
||
|
State.bIsPositionValid = OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetNodePositionValid(OvrpNode, &bResult)) && bResult;
|
||
|
State.bIsOrientationTracked = OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetNodeOrientationTracked2(OvrpNode, &bResult)) && bResult;
|
||
|
State.bIsOrientationValid = OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetNodeOrientationValid(OvrpNode, &bResult)) && bResult;
|
||
|
|
||
|
const float OvrTriggerAxis = OvrpControllerState.IndexTrigger[HandIndex];
|
||
|
const float OvrGripAxis = OvrpControllerState.HandTrigger[HandIndex];
|
||
|
const float OvrThumbRestForce = OvrpControllerState.ThumbRestForce[HandIndex];
|
||
|
const float OvrStylusForce = OvrpControllerState.StylusForce[HandIndex];
|
||
|
const float OvrIndexTriggerCurl = OvrpControllerState.IndexTriggerCurl[HandIndex];
|
||
|
const float OvrIndexTriggerSlide = OvrpControllerState.IndexTriggerSlide[HandIndex];
|
||
|
const float OvrIndexTriggerForce = OvrpControllerState.IndexTriggerForce[HandIndex];
|
||
|
|
||
|
UE_CLOG(OVR_DEBUG_LOGGING, LogOcInput, Log, TEXT("SendControllerEvents: IndexTrigger[%d] = %f"), int(HandIndex), OvrTriggerAxis);
|
||
|
UE_CLOG(OVR_DEBUG_LOGGING, LogOcInput, Log, TEXT("SendControllerEvents: HandTrigger[%d] = %f"), int(HandIndex), OvrGripAxis);
|
||
|
UE_CLOG(OVR_DEBUG_LOGGING, LogOcInput, Log, TEXT("SendControllerEvents: ThumbStick[%d] = { %f, %f }"), int(HandIndex), OvrpControllerState.Thumbstick[HandIndex].x, OvrpControllerState.Thumbstick[HandIndex].y);
|
||
|
UE_CLOG(OVR_DEBUG_LOGGING, LogOcInput, Log, TEXT("SendControllerEvents: ThumbRestForce[%d] = %f"), int(HandIndex), OvrThumbRestForce);
|
||
|
UE_CLOG(OVR_DEBUG_LOGGING, LogOcInput, Log, TEXT("SendControllerEvents: StylusForce[%d] = %f"), int(HandIndex), OvrStylusForce);
|
||
|
UE_CLOG(OVR_DEBUG_LOGGING, LogOcInput, Log, TEXT("SendControllerEvents: IndexTriggerCurl[%d] = %f"), int(HandIndex), OvrIndexTriggerCurl);
|
||
|
UE_CLOG(OVR_DEBUG_LOGGING, LogOcInput, Log, TEXT("SendControllerEvents: IndexTriggerSlide[%d] = %f"), int(HandIndex), OvrIndexTriggerSlide);
|
||
|
UE_CLOG(OVR_DEBUG_LOGGING, LogOcInput, Log, TEXT("SendControllerEvents: IndexTriggerForce[%d] = %f"), int(HandIndex), OvrIndexTriggerForce);
|
||
|
if (bIsMobileController)
|
||
|
{
|
||
|
if (OvrpControllerState.RecenterCount[HandIndex] != State.RecenterCount)
|
||
|
{
|
||
|
State.RecenterCount = OvrpControllerState.RecenterCount[HandIndex];
|
||
|
FCoreDelegates::VRControllerRecentered.Broadcast();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (OvrTriggerAxis != State.TriggerAxis)
|
||
|
{
|
||
|
State.TriggerAxis = OvrTriggerAxis;
|
||
|
MessageHandler->OnControllerAnalog(bIsLeft ? EKeys::OculusTouch_Left_Trigger_Axis.GetFName() : EKeys::OculusTouch_Right_Trigger_Axis.GetFName(), PlatformUser, ControllerPair.DeviceId, State.TriggerAxis);
|
||
|
}
|
||
|
|
||
|
if (OvrGripAxis != State.GripAxis)
|
||
|
{
|
||
|
State.GripAxis = OvrGripAxis;
|
||
|
MessageHandler->OnControllerAnalog(bIsLeft ? EKeys::OculusTouch_Left_Grip_Axis.GetFName() : EKeys::OculusTouch_Right_Grip_Axis.GetFName(), PlatformUser, ControllerPair.DeviceId, State.GripAxis);
|
||
|
}
|
||
|
|
||
|
ovrpVector2f ThumbstickValue = OvrpControllerState.Thumbstick[HandIndex];
|
||
|
ovrpVector2f TouchpadValue = OvrpControllerState.Touchpad[HandIndex];
|
||
|
|
||
|
if (ThumbstickValue.x != State.ThumbstickAxes.X)
|
||
|
{
|
||
|
State.ThumbstickAxes.X = ThumbstickValue.x;
|
||
|
MessageHandler->OnControllerAnalog(bIsLeft ? EKeys::OculusTouch_Left_Thumbstick_X.GetFName() : EKeys::OculusTouch_Right_Thumbstick_X.GetFName(), PlatformUser, ControllerPair.DeviceId, State.ThumbstickAxes.X);
|
||
|
}
|
||
|
|
||
|
if (ThumbstickValue.y != State.ThumbstickAxes.Y)
|
||
|
{
|
||
|
State.ThumbstickAxes.Y = ThumbstickValue.y;
|
||
|
MessageHandler->OnControllerAnalog(bIsLeft ? EKeys::OculusTouch_Left_Thumbstick_Y.GetFName() : EKeys::OculusTouch_Right_Thumbstick_Y.GetFName(), PlatformUser, ControllerPair.DeviceId, State.ThumbstickAxes.Y);
|
||
|
}
|
||
|
|
||
|
if (TouchpadValue.x != State.TouchpadAxes.X)
|
||
|
{
|
||
|
State.TouchpadAxes.X = TouchpadValue.x;
|
||
|
}
|
||
|
|
||
|
if (TouchpadValue.y != State.TouchpadAxes.Y)
|
||
|
{
|
||
|
State.TouchpadAxes.Y = TouchpadValue.y;
|
||
|
}
|
||
|
|
||
|
if (OvrThumbRestForce != State.ThumbRestForce)
|
||
|
{
|
||
|
State.ThumbRestForce = OvrThumbRestForce;
|
||
|
MessageHandler->OnControllerAnalog(bIsLeft ? FOculusKey::OculusTouch_Left_ThumbRest_Force.GetFName() : FOculusKey::OculusTouch_Right_ThumbRest_Force.GetFName(), PlatformUser, ControllerPair.DeviceId, State.ThumbRestForce);
|
||
|
}
|
||
|
|
||
|
if (OvrStylusForce != State.StylusForce)
|
||
|
{
|
||
|
State.StylusForce = OvrStylusForce;
|
||
|
MessageHandler->OnControllerAnalog(bIsLeft ? FOculusKey::OculusTouch_Left_Stylus_Force.GetFName() : FOculusKey::OculusTouch_Right_Stylus_Force.GetFName(), PlatformUser, ControllerPair.DeviceId, State.StylusForce);
|
||
|
}
|
||
|
|
||
|
if (OvrIndexTriggerCurl != State.IndexTriggerCurl)
|
||
|
{
|
||
|
State.IndexTriggerCurl = OvrIndexTriggerCurl;
|
||
|
MessageHandler->OnControllerAnalog(bIsLeft ? FOculusKey::OculusTouch_Left_IndexTrigger_Curl.GetFName() : FOculusKey::OculusTouch_Right_IndexTrigger_Curl.GetFName(), PlatformUser, ControllerPair.DeviceId, State.IndexTriggerCurl);
|
||
|
}
|
||
|
|
||
|
if (OvrIndexTriggerSlide != State.IndexTriggerSlide)
|
||
|
{
|
||
|
State.IndexTriggerSlide = OvrIndexTriggerSlide;
|
||
|
MessageHandler->OnControllerAnalog(bIsLeft ? FOculusKey::OculusTouch_Left_IndexTrigger_Slide.GetFName() : FOculusKey::OculusTouch_Right_IndexTrigger_Slide.GetFName(), PlatformUser, ControllerPair.DeviceId, State.IndexTriggerSlide);
|
||
|
}
|
||
|
|
||
|
if (OvrIndexTriggerForce != State.IndexTriggerForce)
|
||
|
{
|
||
|
State.IndexTriggerForce = OvrIndexTriggerForce;
|
||
|
MessageHandler->OnControllerAnalog(bIsLeft ? FOculusKey::OculusTouch_Left_IndexTrigger_Force.GetFName() : FOculusKey::OculusTouch_Right_IndexTrigger_Force.GetFName(), PlatformUser, ControllerPair.DeviceId, State.IndexTriggerForce);
|
||
|
}
|
||
|
for (int32 ButtonIndex = 0; ButtonIndex < (int32)EOculusTouchControllerButton::TotalButtonCount; ++ButtonIndex)
|
||
|
{
|
||
|
FOculusButtonState& ButtonState = State.Buttons[ButtonIndex];
|
||
|
check(!ButtonState.Key.IsNone()); // is button's name initialized?
|
||
|
|
||
|
// Determine if the button is pressed down
|
||
|
bool bButtonPressed = false;
|
||
|
switch ((EOculusTouchControllerButton)ButtonIndex)
|
||
|
{
|
||
|
case EOculusTouchControllerButton::Trigger:
|
||
|
bButtonPressed = State.TriggerAxis >= AnalogButtonPressThreshold;
|
||
|
break;
|
||
|
|
||
|
case EOculusTouchControllerButton::Grip:
|
||
|
bButtonPressed = State.GripAxis >= AnalogButtonPressThreshold;
|
||
|
break;
|
||
|
|
||
|
case EOculusTouchControllerButton::XA:
|
||
|
bButtonPressed = bIsLeft ? (OvrpControllerState.Buttons & ovrpButton_X) != 0 : (OvrpControllerState.Buttons & ovrpButton_A) != 0;
|
||
|
break;
|
||
|
|
||
|
case EOculusTouchControllerButton::YB:
|
||
|
bButtonPressed = bIsLeft ? (OvrpControllerState.Buttons & ovrpButton_Y) != 0 : (OvrpControllerState.Buttons & ovrpButton_B) != 0;
|
||
|
break;
|
||
|
|
||
|
case EOculusTouchControllerButton::Thumbstick:
|
||
|
bButtonPressed = bIsLeft ? (OvrpControllerState.Buttons & ovrpButton_LThumb) != 0 : (OvrpControllerState.Buttons & ovrpButton_RThumb) != 0;
|
||
|
break;
|
||
|
|
||
|
case EOculusTouchControllerButton::Thumbstick_Up:
|
||
|
if (bIsTouchController && State.ThumbstickAxes.Size() > 0.7f || bIsMobileController && State.Buttons[(int)EOculusTouchControllerButton::Thumbstick].bIsPressed && State.ThumbstickAxes.Size() > 0.5f)
|
||
|
{
|
||
|
float Angle = FMath::Atan2(State.ThumbstickAxes.Y, State.ThumbstickAxes.X);
|
||
|
bButtonPressed = Angle >= (1.0f / 8.0f) * PI && Angle <= (7.0f / 8.0f) * PI;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case EOculusTouchControllerButton::Thumbstick_Down:
|
||
|
if (bIsTouchController && State.ThumbstickAxes.Size() > 0.7f || bIsMobileController && State.Buttons[(int)EOculusTouchControllerButton::Thumbstick].bIsPressed && State.ThumbstickAxes.Size() > 0.5f)
|
||
|
{
|
||
|
float Angle = FMath::Atan2(State.ThumbstickAxes.Y, State.ThumbstickAxes.X);
|
||
|
bButtonPressed = Angle >= (-7.0f / 8.0f) * PI && Angle <= (-1.0f / 8.0f) * PI;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case EOculusTouchControllerButton::Thumbstick_Left:
|
||
|
if (bIsTouchController && State.ThumbstickAxes.Size() > 0.7f || bIsMobileController && State.Buttons[(int)EOculusTouchControllerButton::Thumbstick].bIsPressed && State.ThumbstickAxes.Size() > 0.5f)
|
||
|
{
|
||
|
float Angle = FMath::Atan2(State.ThumbstickAxes.Y, State.ThumbstickAxes.X);
|
||
|
bButtonPressed = Angle <= (-5.0f / 8.0f) * PI || Angle >= (5.0f / 8.0f) * PI;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case EOculusTouchControllerButton::Thumbstick_Right:
|
||
|
if (bIsTouchController && State.ThumbstickAxes.Size() > 0.7f || bIsMobileController && State.Buttons[(int)EOculusTouchControllerButton::Thumbstick].bIsPressed && State.ThumbstickAxes.Size() > 0.5f)
|
||
|
{
|
||
|
float Angle = FMath::Atan2(State.ThumbstickAxes.Y, State.ThumbstickAxes.X);
|
||
|
bButtonPressed = Angle >= (-3.0f / 8.0f) * PI && Angle <= (3.0f / 8.0f) * PI;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case EOculusTouchControllerButton::Menu:
|
||
|
bButtonPressed = bIsLeft && (OvrpControllerState.Buttons & ovrpButton_Start);
|
||
|
break;
|
||
|
|
||
|
case EOculusTouchControllerButton::Thumbstick_Touch:
|
||
|
bButtonPressed = bIsLeft ? (OvrpControllerState.Touches & ovrpTouch_LThumb) != 0 : (OvrpControllerState.Touches & ovrpTouch_RThumb) != 0;
|
||
|
break;
|
||
|
|
||
|
case EOculusTouchControllerButton::Trigger_Touch:
|
||
|
bButtonPressed = bIsLeft ? (OvrpControllerState.Touches & ovrpTouch_LIndexTrigger) != 0 : (OvrpControllerState.Touches & ovrpTouch_RIndexTrigger) != 0;
|
||
|
break;
|
||
|
|
||
|
case EOculusTouchControllerButton::XA_Touch:
|
||
|
bButtonPressed = bIsLeft ? (OvrpControllerState.Touches & ovrpTouch_X) != 0 : (OvrpControllerState.Touches & ovrpTouch_A) != 0;
|
||
|
break;
|
||
|
|
||
|
case EOculusTouchControllerButton::YB_Touch:
|
||
|
bButtonPressed = bIsLeft ? (OvrpControllerState.Touches & ovrpTouch_Y) != 0 : (OvrpControllerState.Touches & ovrpTouch_B) != 0;
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
check(0);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// Update button state
|
||
|
if (bButtonPressed != ButtonState.bIsPressed)
|
||
|
{
|
||
|
ButtonState.bIsPressed = bButtonPressed;
|
||
|
if (ButtonState.bIsPressed)
|
||
|
{
|
||
|
OnControllerButtonPressed(ButtonState, PlatformUser, ControllerPair.DeviceId, false);
|
||
|
|
||
|
// Set the timer for the first repeat
|
||
|
ButtonState.NextRepeatTime = CurrentTime + InitialButtonRepeatDelay;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
OnControllerButtonReleased(ButtonState, PlatformUser, ControllerPair.DeviceId, false);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Apply key repeat, if its time for that
|
||
|
if (ButtonState.bIsPressed && ButtonState.NextRepeatTime <= CurrentTime)
|
||
|
{
|
||
|
OnControllerButtonPressed(ButtonState, PlatformUser, ControllerPair.DeviceId, true);
|
||
|
|
||
|
// Set the timer for the next repeat
|
||
|
ButtonState.NextRepeatTime = CurrentTime + ButtonRepeatDelay;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Handle Capacitive States
|
||
|
for (int32 CapTouchIndex = 0; CapTouchIndex < (int32)EOculusTouchCapacitiveAxes::TotalAxisCount; ++CapTouchIndex)
|
||
|
{
|
||
|
FOculusAxisState& CapState = State.CapacitiveAxes[CapTouchIndex];
|
||
|
|
||
|
float CurrentAxisVal = 0.f;
|
||
|
switch ((EOculusTouchCapacitiveAxes)CapTouchIndex)
|
||
|
{
|
||
|
case EOculusTouchCapacitiveAxes::XA:
|
||
|
{
|
||
|
const uint32 mask = (bIsLeft) ? ovrpTouch_X : ovrpTouch_A;
|
||
|
CurrentAxisVal = (OvrpControllerState.Touches & mask) != 0 ? 1.f : 0.f;
|
||
|
break;
|
||
|
}
|
||
|
case EOculusTouchCapacitiveAxes::YB:
|
||
|
{
|
||
|
const uint32 mask = (bIsLeft) ? ovrpTouch_Y : ovrpTouch_B;
|
||
|
CurrentAxisVal = (OvrpControllerState.Touches & mask) != 0 ? 1.f : 0.f;
|
||
|
break;
|
||
|
}
|
||
|
case EOculusTouchCapacitiveAxes::Thumbstick:
|
||
|
{
|
||
|
const uint32 mask = bIsMobileController ? ((bIsLeft) ? ovrpTouch_LTouchpad : ovrpTouch_RTouchpad) : ((bIsLeft) ? ovrpTouch_LThumb : ovrpTouch_RThumb);
|
||
|
CurrentAxisVal = (OvrpControllerState.Touches & mask) != 0 ? 1.f : 0.f;
|
||
|
break;
|
||
|
}
|
||
|
case EOculusTouchCapacitiveAxes::Trigger:
|
||
|
{
|
||
|
const uint32 mask = (bIsLeft) ? ovrpTouch_LIndexTrigger : ovrpTouch_RIndexTrigger;
|
||
|
CurrentAxisVal = (OvrpControllerState.Touches & mask) != 0 ? 1.f : 0.f;
|
||
|
break;
|
||
|
}
|
||
|
case EOculusTouchCapacitiveAxes::IndexPointing:
|
||
|
{
|
||
|
const uint32 mask = (bIsLeft) ? ovrpNearTouch_LIndexTrigger : ovrpNearTouch_RIndexTrigger;
|
||
|
CurrentAxisVal = (OvrpControllerState.NearTouches & mask) != 0 ? 0.f : 1.f;
|
||
|
break;
|
||
|
}
|
||
|
case EOculusTouchCapacitiveAxes::ThumbUp:
|
||
|
{
|
||
|
const uint32 mask = (bIsLeft) ? ovrpNearTouch_LThumbButtons : ovrpNearTouch_RThumbButtons;
|
||
|
CurrentAxisVal = (OvrpControllerState.NearTouches & mask) != 0 ? 0.f : 1.f;
|
||
|
break;
|
||
|
}
|
||
|
case EOculusTouchCapacitiveAxes::ThumbRest:
|
||
|
{
|
||
|
const uint32 mask = (bIsLeft) ? ovrpTouch_LThumbRest : ovrpTouch_RThumbRest;
|
||
|
CurrentAxisVal = (OvrpControllerState.Touches & mask) != 0 ? 1.f : 0.f;
|
||
|
break;
|
||
|
}
|
||
|
default:
|
||
|
check(0);
|
||
|
}
|
||
|
|
||
|
if (CurrentAxisVal != CapState.State)
|
||
|
{
|
||
|
MessageHandler->OnControllerAnalog(CapState.Axis, PlatformUser, ControllerPair.DeviceId, CurrentAxisVal);
|
||
|
|
||
|
CapState.State = CurrentAxisVal;
|
||
|
}
|
||
|
}
|
||
|
ProcessHaptics(DeltaTime);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Controller isn't available right now.
|
||
|
if (CVarOculusResetUntrackedInputStates.GetValueOnAnyThread())
|
||
|
{
|
||
|
//Zero out input state, so that if controller comes back it will send fresh event deltas
|
||
|
State = FOculusTouchControllerState((EControllerHand)HandIndex);
|
||
|
UE_CLOG(OVR_DEBUG_LOGGING, LogOcInput, Log, TEXT("SendControllerEvents: Controller for the hand %d is not tracked and input states are reset"), int(HandIndex));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//Cache input state, so that if controller comes back it will send event deltas
|
||
|
UE_CLOG(OVR_DEBUG_LOGGING, LogOcInput, Log, TEXT("SendControllerEvents: Controller for the hand %d is not tracked and input states are saved"), int(HandIndex));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Controller isn't available right now. Zero out input state, so that if it comes back it will send fresh event deltas
|
||
|
for (FOculusControllerPair& ControllerPair : ControllerPairs)
|
||
|
{
|
||
|
for (int32 HandIndex = 0; HandIndex < UE_ARRAY_COUNT(ControllerPair.TouchControllerStates); ++HandIndex)
|
||
|
{
|
||
|
FOculusTouchControllerState& State = ControllerPair.TouchControllerStates[HandIndex];
|
||
|
State = FOculusTouchControllerState((EControllerHand)HandIndex);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetControllerState6((ovrpController)(ovrpController_LHand | ovrpController_RHand | ovrpController_Hands), &OvrpControllerState)))
|
||
|
{
|
||
|
for (FOculusControllerPair& ControllerPair : ControllerPairs)
|
||
|
{
|
||
|
FPlatformUserId PlatformUser = IPlatformInputDeviceMapper::Get().GetUserForInputDevice(ControllerPair.DeviceId);
|
||
|
|
||
|
for (int32 HandIndex = 0; HandIndex < UE_ARRAY_COUNT(ControllerPair.HandControllerStates); ++HandIndex)
|
||
|
{
|
||
|
FOculusHandControllerState& State = ControllerPair.HandControllerStates[HandIndex];
|
||
|
|
||
|
bool bIsLeft = (HandIndex == (int32)EControllerHand::Left);
|
||
|
bool bIsCurrentlyTracked = bIsLeft ? (OvrpControllerState.ConnectedControllerTypes & ovrpController_LHand) != 0 : (OvrpControllerState.ConnectedControllerTypes & ovrpController_RHand) != 0;
|
||
|
|
||
|
if (bIsCurrentlyTracked)
|
||
|
{
|
||
|
State.bIsConnected = true;
|
||
|
ovrpBool bResult = true;
|
||
|
|
||
|
// Hand Tracking requires the frame number for accurate results
|
||
|
OculusXRHMD::FGameFrame* CurrentFrame;
|
||
|
if (IsInGameThread())
|
||
|
{
|
||
|
CurrentFrame = OculusXRHMD->GetNextFrameToRender();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
CurrentFrame = OculusXRHMD->GetFrame_RenderThread();
|
||
|
}
|
||
|
|
||
|
// Poll for Hand Tracking State
|
||
|
ovrpHandState HandState;
|
||
|
if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetHandState2(ovrpStep_Render, CurrentFrame ? CurrentFrame->FrameNumber : OVRP_CURRENT_FRAMEINDEX, (ovrpHand)HandIndex, &HandState)))
|
||
|
{
|
||
|
// Update various data about hands
|
||
|
State.HandScale = HandState.HandScale;
|
||
|
|
||
|
// Update Bone Rotations
|
||
|
for (uint32 BoneIndex = 0; BoneIndex < UE_ARRAY_COUNT(State.BoneRotations); BoneIndex++)
|
||
|
{
|
||
|
ovrpQuatf RawRotation = HandState.BoneRotations[BoneIndex];
|
||
|
FQuat BoneRotation = FOculusHandTracking::OvrBoneQuatToFQuat(RawRotation);
|
||
|
BoneRotation.Normalize();
|
||
|
State.BoneRotations[BoneIndex] = BoneRotation;
|
||
|
}
|
||
|
|
||
|
// Update Pinch State and Pinch Strength
|
||
|
bool bTracked = (HandState.Status & ovrpHandStatus_HandTracked) != 0;
|
||
|
State.TrackingConfidence = FOculusHandTracking::ToEOculusXRTrackingConfidence(HandState.HandConfidence);
|
||
|
|
||
|
State.bIsPositionTracked = bTracked && State.TrackingConfidence == EOculusXRTrackingConfidence::High;
|
||
|
State.bIsPositionValid = bTracked;
|
||
|
State.bIsOrientationTracked = bTracked && State.TrackingConfidence == EOculusXRTrackingConfidence::High;
|
||
|
State.bIsOrientationValid = bTracked;
|
||
|
|
||
|
State.bIsPointerPoseValid = (HandState.Status & ovrpHandStatus_InputValid) != 0;
|
||
|
|
||
|
ovrpPosef PointerPose = HandState.PointerPose;
|
||
|
State.PointerPose.SetTranslation(OculusXRHMD::ToFVector(PointerPose.Position));
|
||
|
State.PointerPose.SetRotation(OculusXRHMD::ToFQuat(PointerPose.Orientation));
|
||
|
|
||
|
State.bIsDominantHand = (HandState.Status & ovrpHandStatus_DominantHand) != 0;
|
||
|
|
||
|
// Poll for finger confidence
|
||
|
for (uint32 FingerIndex = 0; FingerIndex < (int32)EOculusHandAxes::TotalAxisCount; FingerIndex++)
|
||
|
{
|
||
|
State.FingerConfidences[FingerIndex] = FOculusHandTracking::ToEOculusXRTrackingConfidence(HandState.FingerConfidences[FingerIndex]);
|
||
|
}
|
||
|
|
||
|
// Poll for finger pinches
|
||
|
for (uint32 FingerIndex = 0; FingerIndex < (uint32)EOculusHandButton::TotalButtonCount; FingerIndex++)
|
||
|
{
|
||
|
FOculusButtonState& PinchState = State.HandButtons[FingerIndex];
|
||
|
check(!PinchState.Key.IsNone());
|
||
|
|
||
|
bool bPressed = false;
|
||
|
if (FingerIndex < (uint32)EOculusHandButton::System)
|
||
|
{
|
||
|
bPressed = (((uint32)HandState.Pinches & (1 << FingerIndex)) != 0);
|
||
|
bPressed &= (HandState.HandConfidence == ovrpTrackingConfidence_High) && (HandState.FingerConfidences[FingerIndex] == ovrpTrackingConfidence_High);
|
||
|
}
|
||
|
else if (FingerIndex == (uint32)EOculusHandButton::System)
|
||
|
{
|
||
|
bPressed = (HandState.Status & ovrpHandStatus_SystemGestureInProgress) != 0;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
bPressed = (OvrpControllerState.Buttons & ovrpButton_Start) != 0 && !State.bIsDominantHand;
|
||
|
}
|
||
|
|
||
|
if (bPressed != PinchState.bIsPressed)
|
||
|
{
|
||
|
PinchState.bIsPressed = bPressed;
|
||
|
if (PinchState.bIsPressed)
|
||
|
{
|
||
|
OnControllerButtonPressed(PinchState, PlatformUser, ControllerPair.DeviceId, false);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
OnControllerButtonReleased(PinchState, PlatformUser, ControllerPair.DeviceId, false);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Poll for finger strength
|
||
|
for (uint32 FingerIndex = 0; FingerIndex < (uint32)EOculusHandAxes::TotalAxisCount; FingerIndex++)
|
||
|
{
|
||
|
FOculusAxisState& PinchStrength = State.HandAxes[FingerIndex];
|
||
|
check(!PinchStrength.Axis.IsNone());
|
||
|
|
||
|
float PinchValue = 0.0f;
|
||
|
if (HandState.HandConfidence == ovrpTrackingConfidence_High)
|
||
|
{
|
||
|
PinchValue = HandState.PinchStrength[FingerIndex];
|
||
|
}
|
||
|
|
||
|
if (PinchValue != PinchStrength.State)
|
||
|
{
|
||
|
MessageHandler->OnControllerAnalog(PinchStrength.Axis, PlatformUser, ControllerPair.DeviceId, PinchValue);
|
||
|
PinchStrength.State = PinchValue;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Hand isn't available right now.
|
||
|
if (CVarOculusResetUntrackedInputStates.GetValueOnAnyThread())
|
||
|
{
|
||
|
//Zero out input state, so that if hand comes back it will send fresh event deltas
|
||
|
State = FOculusHandControllerState((EControllerHand)HandIndex);
|
||
|
UE_CLOG(OVR_DEBUG_LOGGING, LogOcInput, Log, TEXT("SendControllerEvents: Hand for the hand %d is not tracked and input states are reset"), int32(HandIndex));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//Cache input state, so that if hand comes back it will send event deltas
|
||
|
UE_CLOG(OVR_DEBUG_LOGGING, LogOcInput, Log, TEXT("SendControllerEvents: Hand for the hand %d is not tracked and input states are saved"), int(HandIndex));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Hands are not availble right now, zero out the hand state
|
||
|
for (FOculusControllerPair& ControllerPair : ControllerPairs)
|
||
|
{
|
||
|
for (int32 HandIndex = 0; HandIndex < UE_ARRAY_COUNT(ControllerPair.HandControllerStates); ++HandIndex)
|
||
|
{
|
||
|
FOculusHandControllerState& State = ControllerPair.HandControllerStates[HandIndex];
|
||
|
State = FOculusHandControllerState((EControllerHand)HandIndex);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
UE_CLOG(OVR_DEBUG_LOGGING, LogOcInput, Log, TEXT(""));
|
||
|
}
|
||
|
|
||
|
void FOculusXRInput::SetMessageHandler(const TSharedRef<FGenericApplicationMessageHandler>& InMessageHandler)
|
||
|
{
|
||
|
MessageHandler = InMessageHandler;
|
||
|
}
|
||
|
|
||
|
bool FOculusXRInput::Exec(UWorld* InWorld, const TCHAR* Cmd, FOutputDevice& Ar)
|
||
|
{
|
||
|
// No exec commands supported, for now.
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
void FOculusXRInput::SetChannelValue(int32 ControllerId, FForceFeedbackChannelType ChannelType, float Value)
|
||
|
{
|
||
|
const EControllerHand Hand = (ChannelType == FForceFeedbackChannelType::LEFT_LARGE || ChannelType == FForceFeedbackChannelType::LEFT_SMALL) ? EControllerHand::Left : EControllerHand::Right;
|
||
|
|
||
|
IPlatformInputDeviceMapper& DeviceMapper = IPlatformInputDeviceMapper::Get();
|
||
|
FPlatformUserId InPlatformUser = FGenericPlatformMisc::GetPlatformUserForUserIndex(ControllerId);
|
||
|
FInputDeviceId InDeviceId = INPUTDEVICEID_NONE;
|
||
|
DeviceMapper.RemapControllerIdToPlatformUserAndDevice(ControllerId, InPlatformUser, InDeviceId);
|
||
|
|
||
|
for (FOculusControllerPair& ControllerPair : ControllerPairs)
|
||
|
{
|
||
|
if (ControllerPair.DeviceId == InDeviceId)
|
||
|
{
|
||
|
FOculusTouchControllerState& ControllerState = ControllerPair.TouchControllerStates[(int32)Hand];
|
||
|
|
||
|
if (ControllerState.bPlayingHapticEffect)
|
||
|
{
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
// @todo: The SMALL channel controls frequency, the LARGE channel controls amplitude. This is a bit of a weird fit.
|
||
|
if (ChannelType == FForceFeedbackChannelType::LEFT_SMALL || ChannelType == FForceFeedbackChannelType::RIGHT_SMALL)
|
||
|
{
|
||
|
ControllerState.ForceFeedbackHapticFrequency = Value;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ControllerState.ForceFeedbackHapticAmplitude = Value;
|
||
|
}
|
||
|
|
||
|
UpdateForceFeedback(ControllerPair, Hand);
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void FOculusXRInput::SetChannelValues(int32 ControllerId, const FForceFeedbackValues& Values)
|
||
|
{
|
||
|
IPlatformInputDeviceMapper& DeviceMapper = IPlatformInputDeviceMapper::Get();
|
||
|
FPlatformUserId InPlatformUser = FGenericPlatformMisc::GetPlatformUserForUserIndex(ControllerId);
|
||
|
FInputDeviceId InDeviceId = INPUTDEVICEID_NONE;
|
||
|
DeviceMapper.RemapControllerIdToPlatformUserAndDevice(ControllerId, InPlatformUser, InDeviceId);
|
||
|
|
||
|
for (FOculusControllerPair& ControllerPair : ControllerPairs)
|
||
|
{
|
||
|
if (ControllerPair.DeviceId == InDeviceId)
|
||
|
{
|
||
|
// @todo: The SMALL channel controls frequency, the LARGE channel controls amplitude. This is a bit of a weird fit.
|
||
|
FOculusTouchControllerState& LeftControllerState = ControllerPair.TouchControllerStates[(int32)EControllerHand::Left];
|
||
|
if (!LeftControllerState.bPlayingHapticEffect)
|
||
|
{
|
||
|
LeftControllerState.ForceFeedbackHapticFrequency = Values.LeftSmall;
|
||
|
LeftControllerState.ForceFeedbackHapticAmplitude = Values.LeftLarge;
|
||
|
UpdateForceFeedback(ControllerPair, EControllerHand::Left);
|
||
|
}
|
||
|
|
||
|
FOculusTouchControllerState& RightControllerState = ControllerPair.TouchControllerStates[(int32)EControllerHand::Right];
|
||
|
if (!RightControllerState.bPlayingHapticEffect)
|
||
|
{
|
||
|
RightControllerState.ForceFeedbackHapticFrequency = Values.RightSmall;
|
||
|
RightControllerState.ForceFeedbackHapticAmplitude = Values.RightLarge;
|
||
|
UpdateForceFeedback(ControllerPair, EControllerHand::Right);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool FOculusXRInput::SupportsForceFeedback(int32 ControllerId)
|
||
|
{
|
||
|
IPlatformInputDeviceMapper& DeviceMapper = IPlatformInputDeviceMapper::Get();
|
||
|
FPlatformUserId InPlatformUser = FGenericPlatformMisc::GetPlatformUserForUserIndex(ControllerId);
|
||
|
FInputDeviceId InDeviceId = INPUTDEVICEID_NONE;
|
||
|
DeviceMapper.RemapControllerIdToPlatformUserAndDevice(ControllerId, InPlatformUser, InDeviceId);
|
||
|
|
||
|
for (FOculusControllerPair& ControllerPair : ControllerPairs)
|
||
|
{
|
||
|
if (ControllerPair.DeviceId == InDeviceId)
|
||
|
{
|
||
|
const FOculusTouchControllerState& ControllerStateLeft = ControllerPair.TouchControllerStates[(int32)EControllerHand::Left];
|
||
|
const FOculusTouchControllerState& ControllerStateRight = ControllerPair.TouchControllerStates[(int32)EControllerHand::Right];
|
||
|
|
||
|
if (!(ControllerStateLeft.bIsConnected || ControllerStateRight.bIsConnected))
|
||
|
{
|
||
|
// neither hand connected, won't be receiving force feedback
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if (IOculusXRHMDModule::IsAvailable() && FOculusXRHMDModule::GetPluginWrapper().GetInitialized())
|
||
|
{
|
||
|
// available so could receive feedback
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// not handling force feedback
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
void FOculusXRInput::UpdateForceFeedback(const FOculusControllerPair& ControllerPair, const EControllerHand Hand)
|
||
|
{
|
||
|
const FOculusTouchControllerState& ControllerState = ControllerPair.TouchControllerStates[(int32)Hand];
|
||
|
|
||
|
if (ControllerState.bIsConnected && !ControllerState.bPlayingHapticEffect)
|
||
|
{
|
||
|
if (IOculusXRHMDModule::IsAvailable() && FOculusXRHMDModule::GetPluginWrapper().GetInitialized() && FApp::HasVRFocus())
|
||
|
{
|
||
|
ovrpControllerState6 OvrpControllerState;
|
||
|
if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetControllerState6((ovrpController)(ovrpController_Active | ovrpController_LTrackedRemote | ovrpController_RTrackedRemote), &OvrpControllerState)) && (OvrpControllerState.ConnectedControllerTypes & (ovrpController_Touch | ovrpController_LTrackedRemote | ovrpController_RTrackedRemote)))
|
||
|
{
|
||
|
float FreqMin, FreqMax = 0.f;
|
||
|
GetHapticFrequencyRange(FreqMin, FreqMax);
|
||
|
|
||
|
// Map the [0.0 - 1.0] range to a useful range of frequencies for the Oculus controllers
|
||
|
const float ActualFrequency = FMath::Lerp(FreqMin, FreqMax, FMath::Clamp(ControllerState.ForceFeedbackHapticFrequency, 0.0f, 1.0f));
|
||
|
|
||
|
// Oculus SDK wants amplitude values between 0.0 and 1.0
|
||
|
const float ActualAmplitude = ControllerState.ForceFeedbackHapticAmplitude * GetHapticAmplitudeScale();
|
||
|
|
||
|
ovrpController OvrController = ovrpController_None;
|
||
|
if (OvrpControllerState.ConnectedControllerTypes & (ovrpController_Touch))
|
||
|
{
|
||
|
OvrController = (Hand == EControllerHand::Left) ? ovrpController_LTouch : ovrpController_RTouch;
|
||
|
}
|
||
|
else if (OvrpControllerState.ConnectedControllerTypes & (ovrpController_LTrackedRemote | ovrpController_RTrackedRemote))
|
||
|
{
|
||
|
OvrController = (Hand == EControllerHand::Left) ? ovrpController_LTrackedRemote : ovrpController_RTrackedRemote;
|
||
|
}
|
||
|
|
||
|
static float LastAmplitudeSent = -1;
|
||
|
if (ActualAmplitude != LastAmplitudeSent)
|
||
|
{
|
||
|
ovrpHapticsLocation hapticsLocationMask = ovrpHapticsLocation::ovrpHapticsLocation_Hand;
|
||
|
FOculusXRHMDModule::GetPluginWrapper().SetControllerLocalizedVibration(OvrController, hapticsLocationMask, ActualFrequency, ActualAmplitude);
|
||
|
LastAmplitudeSent = ActualAmplitude;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool FOculusXRInput::OnControllerButtonPressed(const FOculusButtonState& ButtonState, FPlatformUserId UserId, FInputDeviceId DeviceId, bool IsRepeat)
|
||
|
{
|
||
|
bool result = MessageHandler->OnControllerButtonPressed(ButtonState.Key, UserId, DeviceId, IsRepeat);
|
||
|
|
||
|
if (!ButtonState.EmulatedKey.IsNone())
|
||
|
{
|
||
|
MessageHandler->OnControllerButtonPressed(ButtonState.EmulatedKey, UserId, DeviceId, IsRepeat);
|
||
|
}
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
bool FOculusXRInput::OnControllerButtonReleased(const FOculusButtonState& ButtonState, FPlatformUserId UserId, FInputDeviceId DeviceId, bool IsRepeat)
|
||
|
{
|
||
|
bool result = MessageHandler->OnControllerButtonReleased(ButtonState.Key, UserId, DeviceId, IsRepeat);
|
||
|
|
||
|
if (!ButtonState.EmulatedKey.IsNone())
|
||
|
{
|
||
|
MessageHandler->OnControllerButtonReleased(ButtonState.EmulatedKey, UserId, DeviceId, IsRepeat);
|
||
|
}
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
FName FOculusXRInput::GetMotionControllerDeviceTypeName() const
|
||
|
{
|
||
|
const static FName DefaultName(TEXT("OculusXRInputDevice"));
|
||
|
return DefaultName;
|
||
|
}
|
||
|
|
||
|
// Supported motion sources
|
||
|
const TMap<FName, ovrpNode> MotionSourceMap{
|
||
|
{ FName("Left"), ovrpNode_HandLeft },
|
||
|
{ FName("Right"), ovrpNode_HandRight },
|
||
|
{ FName("LeftGrip"), ovrpNode_HandLeft },
|
||
|
{ FName("RightGrip"), ovrpNode_HandRight },
|
||
|
{ FName("LeftAim"), ovrpNode_HandLeft },
|
||
|
{ FName("RightAim"), ovrpNode_HandRight },
|
||
|
// Sometimes we can get an enum as the motion source name
|
||
|
{ FName("EControllerHand::Left"), ovrpNode_HandLeft },
|
||
|
{ FName("EControllerHand::Right"), ovrpNode_HandRight }
|
||
|
};
|
||
|
|
||
|
#if UE_VERSION_OLDER_THAN(5, 3, 0)
|
||
|
bool FOculusXRInput::GetControllerOrientationAndPosition(const int32 ControllerIndex, const EControllerHand DeviceHand, FRotator& OutOrientation, FVector& OutPosition, float WorldToMetersScale) const
|
||
|
{
|
||
|
FName MotionSource;
|
||
|
switch (DeviceHand)
|
||
|
{
|
||
|
case EControllerHand::Left:
|
||
|
MotionSource = FName("Left");
|
||
|
break;
|
||
|
case EControllerHand::Right:
|
||
|
MotionSource = FName("Right");
|
||
|
break;
|
||
|
default:
|
||
|
MotionSource = FName("Unknown");
|
||
|
break;
|
||
|
}
|
||
|
return GetControllerOrientationAndPosition(ControllerIndex, MotionSource, OutOrientation, OutPosition, WorldToMetersScale);
|
||
|
}
|
||
|
|
||
|
ETrackingStatus FOculusXRInput::GetControllerTrackingStatus(const int32 ControllerIndex, const EControllerHand DeviceHand) const
|
||
|
{
|
||
|
ETrackingStatus TrackingStatus = ETrackingStatus::NotTracked;
|
||
|
|
||
|
if (DeviceHand != EControllerHand::Left && DeviceHand != EControllerHand::Right)
|
||
|
{
|
||
|
return TrackingStatus;
|
||
|
}
|
||
|
|
||
|
IPlatformInputDeviceMapper& DeviceMapper = IPlatformInputDeviceMapper::Get();
|
||
|
FPlatformUserId InPlatformUser = FGenericPlatformMisc::GetPlatformUserForUserIndex(ControllerIndex);
|
||
|
FInputDeviceId InDeviceId = INPUTDEVICEID_NONE;
|
||
|
DeviceMapper.RemapControllerIdToPlatformUserAndDevice(ControllerIndex, InPlatformUser, InDeviceId);
|
||
|
|
||
|
for (const FOculusControllerPair& ControllerPair : ControllerPairs)
|
||
|
{
|
||
|
if (ControllerPair.DeviceId == InDeviceId)
|
||
|
{
|
||
|
const FOculusTouchControllerState& ControllerState = ControllerPair.TouchControllerStates[(int32)DeviceHand];
|
||
|
if (ControllerState.bIsConnected)
|
||
|
{
|
||
|
if (ControllerState.bIsPositionTracked && ControllerState.bIsOrientationTracked)
|
||
|
{
|
||
|
TrackingStatus = ETrackingStatus::Tracked;
|
||
|
}
|
||
|
else if (ControllerState.bIsPositionValid && ControllerState.bIsOrientationValid)
|
||
|
{
|
||
|
TrackingStatus = ETrackingStatus::InertialOnly;
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
const FOculusHandControllerState& HandState = ControllerPair.HandControllerStates[(int32)DeviceHand];
|
||
|
if (HandState.bIsConnected)
|
||
|
{
|
||
|
if (HandState.bIsPositionTracked && HandState.bIsOrientationTracked)
|
||
|
{
|
||
|
TrackingStatus = ETrackingStatus::Tracked;
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return TrackingStatus;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
bool FOculusXRInput::GetControllerOrientationAndPosition(const int32 ControllerIndex, const FName MotionSource, FRotator& OutOrientation, FVector& OutPosition, float WorldToMetersScale) const
|
||
|
{
|
||
|
IPlatformInputDeviceMapper& DeviceMapper = IPlatformInputDeviceMapper::Get();
|
||
|
FPlatformUserId InPlatformUser = FGenericPlatformMisc::GetPlatformUserForUserIndex(ControllerIndex);
|
||
|
FInputDeviceId InDeviceId = INPUTDEVICEID_NONE;
|
||
|
DeviceMapper.RemapControllerIdToPlatformUserAndDevice(ControllerIndex, InPlatformUser, InDeviceId);
|
||
|
|
||
|
// Don't do renderthread pose update if MRC is active due to controller jitter issues with SceneCaptures
|
||
|
if (IsInGameThread() || !UOculusXRMRFunctionLibrary::IsMrcActive())
|
||
|
{
|
||
|
for (const FOculusControllerPair& ControllerPair : ControllerPairs)
|
||
|
{
|
||
|
if (ControllerPair.DeviceId == InDeviceId)
|
||
|
{
|
||
|
if (MotionSourceMap.Contains(MotionSource))
|
||
|
{
|
||
|
if (IOculusXRHMDModule::IsAvailable() && FOculusXRHMDModule::GetPluginWrapper().GetInitialized())
|
||
|
{
|
||
|
OculusXRHMD::FOculusXRHMD* OculusXRHMD = static_cast<OculusXRHMD::FOculusXRHMD*>(GEngine->XRSystem->GetHMDDevice());
|
||
|
ovrpNode Node = MotionSourceMap[MotionSource];
|
||
|
|
||
|
ovrpBool bResult = true;
|
||
|
bool bIsPositionValid = OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetNodePositionValid(Node, &bResult)) && bResult;
|
||
|
bool bIsOrientationValid = OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetNodeOrientationValid(Node, &bResult)) && bResult;
|
||
|
|
||
|
if (bIsPositionValid || bIsOrientationValid)
|
||
|
{
|
||
|
OculusXRHMD::FSettings* Settings;
|
||
|
OculusXRHMD::FGameFrame* CurrentFrame;
|
||
|
|
||
|
if (IsInGameThread())
|
||
|
{
|
||
|
Settings = OculusXRHMD->GetSettings();
|
||
|
CurrentFrame = OculusXRHMD->GetNextFrameToRender();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Settings = OculusXRHMD->GetSettings_RenderThread();
|
||
|
CurrentFrame = OculusXRHMD->GetFrame_RenderThread();
|
||
|
}
|
||
|
|
||
|
if (Settings)
|
||
|
{
|
||
|
ovrpPoseStatef InPoseState;
|
||
|
OculusXRHMD::FPose OutPose;
|
||
|
|
||
|
EOculusXRControllerPoseAlignment ControllerPoseAlignment = Settings->ControllerPoseAlignment;
|
||
|
switch (CVarOculusControllerPose.GetValueOnAnyThread())
|
||
|
{
|
||
|
case 1:
|
||
|
ControllerPoseAlignment = EOculusXRControllerPoseAlignment::Default;
|
||
|
break;
|
||
|
case 2:
|
||
|
ControllerPoseAlignment = EOculusXRControllerPoseAlignment::Grip;
|
||
|
break;
|
||
|
case 3:
|
||
|
ControllerPoseAlignment = EOculusXRControllerPoseAlignment::Aim;
|
||
|
break;
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetNodePoseState3(ovrpStep_Render, CurrentFrame ? CurrentFrame->FrameNumber : OVRP_CURRENT_FRAMEINDEX, Node, &InPoseState)) && OculusXRHMD->ConvertPose_Internal(InPoseState.Pose, OutPose, Settings, WorldToMetersScale))
|
||
|
{
|
||
|
FName FinalMotionSource = MotionSource;
|
||
|
FString MotionSourceStr = MotionSource.ToString();
|
||
|
|
||
|
// Converting controller hand enum to motion source can leave behind the enum name in the resulting motion source, so just remove that before handling it
|
||
|
MotionSourceStr.RemoveFromStart("EControllerHand::");
|
||
|
|
||
|
if (MotionSourceStr.Equals("Left") || MotionSourceStr.Equals("Right"))
|
||
|
{
|
||
|
switch (ControllerPoseAlignment)
|
||
|
{
|
||
|
case EOculusXRControllerPoseAlignment::Grip:
|
||
|
FinalMotionSource = FName(MotionSourceStr.Append(FString("Grip")));
|
||
|
break;
|
||
|
case EOculusXRControllerPoseAlignment::Aim:
|
||
|
FinalMotionSource = FName(MotionSourceStr.Append(FString("Aim")));
|
||
|
break;
|
||
|
case EOculusXRControllerPoseAlignment::Default:
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// TODO: Just pass the pose info to OVRPlugin instead of doing the conversion between poses here
|
||
|
if (FinalMotionSource == FName("LeftGrip") || FinalMotionSource == FName("RightGrip"))
|
||
|
{
|
||
|
OutPose = OutPose * OculusXRHMD::FPose(FQuat(FVector(0, 1, 0), -FMath::DegreesToRadians(double(60))), FVector(-0.04, 0, -0.03) * WorldToMetersScale);
|
||
|
}
|
||
|
else if (FinalMotionSource == FName("LeftAim") || FinalMotionSource == FName("RightAim"))
|
||
|
{
|
||
|
OutPose = OutPose * OculusXRHMD::FPose(FQuat::Identity, FVector(0.055, 0, 0) * WorldToMetersScale);
|
||
|
}
|
||
|
|
||
|
if (bIsPositionValid)
|
||
|
{
|
||
|
OutPosition = OutPose.Position;
|
||
|
}
|
||
|
|
||
|
if (bIsOrientationValid)
|
||
|
{
|
||
|
OutOrientation = OutPose.Orientation.Rotator();
|
||
|
}
|
||
|
|
||
|
// Avoid any broadcasting in other threads than the game thread because that is undefined behavior
|
||
|
if (IsInGameThread())
|
||
|
{
|
||
|
auto bSuccess = true;
|
||
|
EControllerHand ControllerHand;
|
||
|
if (GetHandEnumForSourceName(MotionSource, ControllerHand))
|
||
|
{
|
||
|
// TODO: Just use the motion source name here instead of the legacy enum
|
||
|
UOculusXRInputFunctionLibrary::HandMovementFilter.Broadcast(
|
||
|
ControllerHand,
|
||
|
&OutPosition,
|
||
|
&OutOrientation,
|
||
|
&bSuccess);
|
||
|
}
|
||
|
return bSuccess;
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Avoid any broadcasting in other threads than the game thread because that is undefined behavior
|
||
|
auto bSuccess = false;
|
||
|
if (IsInGameThread())
|
||
|
{
|
||
|
EControllerHand ControllerHand;
|
||
|
if (GetHandEnumForSourceName(MotionSource, ControllerHand))
|
||
|
{
|
||
|
// TODO: Just use the motion source name here instead of the legacy enum
|
||
|
UOculusXRInputFunctionLibrary::HandMovementFilter.Broadcast(
|
||
|
ControllerHand,
|
||
|
&OutPosition,
|
||
|
&OutOrientation,
|
||
|
&bSuccess);
|
||
|
}
|
||
|
}
|
||
|
return bSuccess;
|
||
|
}
|
||
|
|
||
|
ETrackingStatus FOculusXRInput::GetControllerTrackingStatus(const int32 ControllerIndex, const FName MotionSource) const
|
||
|
{
|
||
|
ETrackingStatus TrackingStatus = ETrackingStatus::NotTracked;
|
||
|
|
||
|
bool IsLeftHand = MotionSource == FName("Left") || MotionSource == FName("EControllerHand::Left") || MotionSource == FName("LeftGrip") || MotionSource == FName("LeftAim");
|
||
|
bool IsRightHand = MotionSource == FName("Right") || MotionSource == FName("EControllerHand::Right") || MotionSource == FName("RightGrip") || MotionSource == FName("RightAim");
|
||
|
|
||
|
if (!IsLeftHand && !IsRightHand)
|
||
|
{
|
||
|
return TrackingStatus;
|
||
|
}
|
||
|
|
||
|
IPlatformInputDeviceMapper& DeviceMapper = IPlatformInputDeviceMapper::Get();
|
||
|
FPlatformUserId InPlatformUser = FGenericPlatformMisc::GetPlatformUserForUserIndex(ControllerIndex);
|
||
|
FInputDeviceId InDeviceId = INPUTDEVICEID_NONE;
|
||
|
DeviceMapper.RemapControllerIdToPlatformUserAndDevice(ControllerIndex, InPlatformUser, InDeviceId);
|
||
|
|
||
|
for (const FOculusControllerPair& ControllerPair : ControllerPairs)
|
||
|
{
|
||
|
if (ControllerPair.DeviceId == InDeviceId)
|
||
|
{
|
||
|
const FOculusTouchControllerState& ControllerState = ControllerPair.TouchControllerStates[IsLeftHand ? 0 : 1];
|
||
|
if (ControllerState.bIsConnected)
|
||
|
{
|
||
|
if (ControllerState.bIsPositionTracked && ControllerState.bIsOrientationTracked)
|
||
|
{
|
||
|
TrackingStatus = ETrackingStatus::Tracked;
|
||
|
}
|
||
|
else if (ControllerState.bIsPositionValid && ControllerState.bIsOrientationValid)
|
||
|
{
|
||
|
TrackingStatus = ETrackingStatus::InertialOnly;
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
const FOculusHandControllerState& HandState = ControllerPair.HandControllerStates[IsLeftHand ? 0 : 1];
|
||
|
if (HandState.bIsConnected)
|
||
|
{
|
||
|
if (HandState.bIsPositionTracked && HandState.bIsOrientationTracked)
|
||
|
{
|
||
|
TrackingStatus = ETrackingStatus::Tracked;
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return TrackingStatus;
|
||
|
}
|
||
|
|
||
|
void FOculusXRInput::SetHapticFeedbackValues(int32 ControllerId, int32 Hand, const FHapticFeedbackValues& Values)
|
||
|
{
|
||
|
SetHapticFeedbackValues(ControllerId, Hand, Values, nullptr);
|
||
|
}
|
||
|
|
||
|
void FOculusXRInput::SetHapticFeedbackValues(int32 ControllerId, int32 Hand, const FHapticFeedbackValues& Values, TSharedPtr<FOculusXRHapticsDesc> HapticsDesc)
|
||
|
{
|
||
|
IPlatformInputDeviceMapper& DeviceMapper = IPlatformInputDeviceMapper::Get();
|
||
|
FPlatformUserId InPlatformUser = FGenericPlatformMisc::GetPlatformUserForUserIndex(ControllerId);
|
||
|
FInputDeviceId InDeviceId = INPUTDEVICEID_NONE;
|
||
|
DeviceMapper.RemapControllerIdToPlatformUserAndDevice(ControllerId, InPlatformUser, InDeviceId);
|
||
|
|
||
|
for (FOculusControllerPair& ControllerPair : ControllerPairs)
|
||
|
{
|
||
|
if (ControllerPair.DeviceId == InDeviceId)
|
||
|
{
|
||
|
FOculusTouchControllerState& ControllerState = ControllerPair.TouchControllerStates[Hand];
|
||
|
if (ControllerState.bIsConnected)
|
||
|
{
|
||
|
if (IOculusXRHMDModule::IsAvailable() && FOculusXRHMDModule::GetPluginWrapper().GetInitialized() && FApp::HasVRFocus())
|
||
|
{
|
||
|
ovrpController ControllerTypes = (ovrpController)(ovrpController_Active | ovrpController_LTrackedRemote | ovrpController_RTrackedRemote);
|
||
|
#ifdef USE_ANDROID_INPUT
|
||
|
ControllerTypes = (ovrpController)(ControllerTypes | ovrpController_Touch);
|
||
|
#endif
|
||
|
ovrpControllerState6 OvrpControllerState;
|
||
|
if (OVRP_FAILURE(FOculusXRHMDModule::GetPluginWrapper().GetControllerState6(ControllerTypes, &OvrpControllerState)))
|
||
|
{
|
||
|
UE_LOG(LogOcInput, Error, TEXT("GetControllerState6 failed."));
|
||
|
return;
|
||
|
}
|
||
|
if (OvrpControllerState.ConnectedControllerTypes & (ovrpController_Touch | ovrpController_LTrackedRemote | ovrpController_RTrackedRemote))
|
||
|
{
|
||
|
// Buffered haptics is currently only supported on Touch
|
||
|
FHapticFeedbackBuffer* HapticBuffer = Values.HapticBuffer;
|
||
|
bool bHapticBuffer = (HapticBuffer && HapticBuffer->BufferLength > 0);
|
||
|
if ((OvrpControllerState.ConnectedControllerTypes & (ovrpController_Touch)) && bHapticBuffer)
|
||
|
{
|
||
|
const ovrpController OvrpController = (EControllerHand(Hand) == EControllerHand::Left) ? ovrpController_LTouch : ovrpController_RTouch;
|
||
|
ovrpHapticsState OvrpHapticsState;
|
||
|
if (OVRP_FAILURE(FOculusXRHMDModule::GetPluginWrapper().GetControllerHapticsState2(OvrpController, &OvrpHapticsState)))
|
||
|
{
|
||
|
UE_LOG(LogOcInput, Error, TEXT("ControllerHapticsState2 failed."));
|
||
|
return;
|
||
|
}
|
||
|
double StartTimePCM = FPlatformTime::Seconds();
|
||
|
float TimeToSend = GetMaxHapticDuration(EControllerHand(Hand));
|
||
|
int WantToSend = (int)(TimeToSend * HapticBuffer->SamplingRate);
|
||
|
if (WantToSend == 0)
|
||
|
return;
|
||
|
WantToSend = FMath::Min(WantToSend, OvrpHapticsDesc.MaximumBufferSamplesCount);
|
||
|
WantToSend = FMath::Max(WantToSend, OvrpHapticsDesc.MinimumBufferSamplesCount);
|
||
|
|
||
|
ovrpUInt32 SamplesSent = 0;
|
||
|
if (OvrpHapticsState.SamplesQueued < OvrpHapticsDesc.MinimumSafeSamplesQueued + WantToSend) //trying to minimize latency
|
||
|
{
|
||
|
WantToSend = (OvrpHapticsDesc.MinimumSafeSamplesQueued + WantToSend - OvrpHapticsState.SamplesQueued);
|
||
|
void* BufferToFree = nullptr;
|
||
|
ovrpHapticsBuffer OvrpHapticsBuffer;
|
||
|
WantToSend = FMath::Min(WantToSend, HapticBuffer->BufferLength - HapticBuffer->SamplesSent);
|
||
|
WantToSend = FMath::Min(WantToSend, (int)(0.001f * CVarOculusPCMBatchDuration.GetValueOnAnyThread() * HapticBuffer->SamplingRate));
|
||
|
TimeToSend = 1.f * WantToSend / HapticBuffer->SamplingRate;
|
||
|
OvrpHapticsBuffer.SamplesCount = WantToSend;
|
||
|
if (OvrpHapticsBuffer.SamplesCount == 0 && OvrpHapticsState.SamplesQueued == 0)
|
||
|
{
|
||
|
Values.HapticBuffer->bFinishedPlaying = HapticBuffer->bFinishedPlaying = true;
|
||
|
|
||
|
ControllerState.bPlayingHapticEffect = false;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (OvrpHapticsDesc.SampleSizeInBytes == 1)
|
||
|
{
|
||
|
uint8* Samples = (uint8*)FMemory::Malloc(OvrpHapticsBuffer.SamplesCount * sizeof(*Samples));
|
||
|
for (int i = 0; i < OvrpHapticsBuffer.SamplesCount; i++)
|
||
|
{
|
||
|
Samples[i] = static_cast<uint8>(HapticBuffer->RawData[HapticBuffer->CurrentPtr + i] * HapticBuffer->ScaleFactor);
|
||
|
}
|
||
|
OvrpHapticsBuffer.Samples = BufferToFree = Samples;
|
||
|
}
|
||
|
else if (OvrpHapticsDesc.SampleSizeInBytes == 2)
|
||
|
{
|
||
|
uint16* Samples = (uint16*)FMemory::Malloc(OvrpHapticsBuffer.SamplesCount * sizeof(*Samples));
|
||
|
for (int i = 0; i < OvrpHapticsBuffer.SamplesCount; i++)
|
||
|
{
|
||
|
const uint32 DataIndex = HapticBuffer->CurrentPtr + (i * 2);
|
||
|
const uint16* const RawData = reinterpret_cast<const uint16*>(&HapticBuffer->RawData[DataIndex]);
|
||
|
Samples[i] = static_cast<uint16>(*RawData * HapticBuffer->ScaleFactor);
|
||
|
}
|
||
|
OvrpHapticsBuffer.Samples = BufferToFree = Samples;
|
||
|
}
|
||
|
else if (OvrpHapticsDesc.SampleSizeInBytes == 4)
|
||
|
{
|
||
|
uint32* Samples = (uint32*)FMemory::Malloc(OvrpHapticsBuffer.SamplesCount * sizeof(*Samples));
|
||
|
for (int i = 0; i < OvrpHapticsBuffer.SamplesCount; i++)
|
||
|
{
|
||
|
const uint32 DataIndex = HapticBuffer->CurrentPtr + (i * 4);
|
||
|
const uint32* const RawData = reinterpret_cast<const uint32*>(&HapticBuffer->RawData[DataIndex]);
|
||
|
Samples[i] = static_cast<uint32>(*RawData * HapticBuffer->ScaleFactor);
|
||
|
}
|
||
|
OvrpHapticsBuffer.Samples = BufferToFree = Samples;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
UE_LOG(LogOcInput, Error, TEXT("Unsupported OvrpHapticsDesc.SampleSizeInBytes: %d."), OvrpHapticsDesc.SampleSizeInBytes);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
ovrpHapticsPcmVibration HapticsVibration;
|
||
|
bool bAppend = HapticsDesc ? HapticsDesc->bAppend : false;
|
||
|
HapticsVibration.Append = (bAppend || HapticBuffer->SamplesSent > 0);
|
||
|
float* PCMBuffer = (float*)FMemory::Malloc(OvrpHapticsBuffer.SamplesCount * sizeof(*PCMBuffer));
|
||
|
for (int i = 0; i < OvrpHapticsBuffer.SamplesCount; i++)
|
||
|
{
|
||
|
float Amplitude = ((uint8_t*)OvrpHapticsBuffer.Samples)[i] / 255.0f;
|
||
|
Amplitude = FMath::Min(1.0f, Amplitude);
|
||
|
Amplitude = FMath::Max(-1.0f, Amplitude);
|
||
|
PCMBuffer[i] = Amplitude;
|
||
|
}
|
||
|
HapticsVibration.Buffer = PCMBuffer;
|
||
|
HapticsVibration.BufferSize = (ovrpUInt32)OvrpHapticsBuffer.SamplesCount;
|
||
|
HapticsVibration.SampleRateHz = HapticBuffer->SamplingRate;
|
||
|
HapticsVibration.SamplesConsumed = &SamplesSent;
|
||
|
FOculusXRHMDModule::GetPluginWrapper().SetControllerHapticsPcm(
|
||
|
OvrpController,
|
||
|
HapticsVibration);
|
||
|
double EndTimePCM = FPlatformTime::Seconds();
|
||
|
if (PCMBuffer)
|
||
|
{
|
||
|
FMemory::Free(PCMBuffer);
|
||
|
}
|
||
|
UE_CLOG(OVR_HAP_LOGGING, LogOcInput, Log, TEXT("PCMHaptics is finished: bAppend: %d, BufferSize: %d, SampleRate: %.3f, SamplesConsumed: %d, Total SamplesSent: %d, TimeSpent: %fms"),
|
||
|
(int)(HapticsVibration.Append),
|
||
|
HapticsVibration.BufferSize,
|
||
|
HapticsVibration.SampleRateHz,
|
||
|
SamplesSent,
|
||
|
HapticBuffer->SamplesSent + SamplesSent,
|
||
|
(EndTimePCM - StartTimePCM) * 1000.0);
|
||
|
|
||
|
if (BufferToFree)
|
||
|
{
|
||
|
FMemory::Free(BufferToFree);
|
||
|
}
|
||
|
|
||
|
HapticBuffer->CurrentPtr += (SamplesSent * OvrpHapticsDesc.SampleSizeInBytes);
|
||
|
HapticBuffer->SamplesSent += SamplesSent;
|
||
|
|
||
|
ControllerState.bPlayingHapticEffect = true;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
float FreqMin, FreqMax = 0.f;
|
||
|
GetHapticFrequencyRange(FreqMin, FreqMax);
|
||
|
|
||
|
const float InitialFreq = (Values.Frequency > 0.0f) ? Values.Frequency : 1.0f;
|
||
|
const float Frequency = FMath::Lerp(FreqMin, FreqMax, FMath::Clamp(InitialFreq, 0.f, 1.f));
|
||
|
|
||
|
const float Amplitude = Values.Amplitude * GetHapticAmplitudeScale();
|
||
|
|
||
|
if (ControllerState.HapticAmplitude != Amplitude || ControllerState.HapticFrequency != Frequency)
|
||
|
{
|
||
|
ControllerState.HapticAmplitude = Amplitude;
|
||
|
ControllerState.HapticFrequency = Frequency;
|
||
|
|
||
|
ovrpController OvrController = ovrpController_None;
|
||
|
if (OvrpControllerState.ConnectedControllerTypes & (ovrpController_Touch))
|
||
|
{
|
||
|
OvrController = (EControllerHand(Hand) == EControllerHand::Left) ? ovrpController_LTouch : ovrpController_RTouch;
|
||
|
}
|
||
|
else if (OvrpControllerState.ConnectedControllerTypes & (ovrpController_LTrackedRemote | ovrpController_RTrackedRemote))
|
||
|
{
|
||
|
OvrController = (EControllerHand(Hand) == EControllerHand::Left) ? ovrpController_LTrackedRemote : ovrpController_RTrackedRemote;
|
||
|
}
|
||
|
|
||
|
ovrpHapticsLocation Loc = (HapticsDesc ? GetOVRPHapticsLocation(HapticsDesc->Location) : ovrpHapticsLocation::ovrpHapticsLocation_Hand);
|
||
|
FOculusXRHMDModule::GetPluginWrapper().SetControllerLocalizedVibration(OvrController,
|
||
|
Loc,
|
||
|
Frequency,
|
||
|
Amplitude);
|
||
|
UE_CLOG(OVR_HAP_LOGGING, LogOcInput, Log, TEXT("LocalizedVibration is finished: Location: %d, Frequency: %f, Amplitude: %f"), (int)(Loc), Frequency, Amplitude);
|
||
|
|
||
|
ControllerState.bPlayingHapticEffect = (Amplitude != 0.f) && (Frequency != 0.f);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void FOculusXRInput::PlayHapticEffect(
|
||
|
UHapticFeedbackEffect_Base* HapticEffect,
|
||
|
EControllerHand Hand,
|
||
|
EOculusXRHandHapticsLocation Location,
|
||
|
bool bAppend,
|
||
|
float Scale,
|
||
|
bool bLoop)
|
||
|
{
|
||
|
if (HapticEffect)
|
||
|
{
|
||
|
switch (Hand)
|
||
|
{
|
||
|
case EControllerHand::Left:
|
||
|
ActiveHapticEffect_Left.Reset();
|
||
|
HapticsDesc_Left.Reset();
|
||
|
ActiveHapticEffect_Left = MakeShareable(new FActiveHapticFeedbackEffect(HapticEffect, Scale, bLoop));
|
||
|
HapticsDesc_Left = MakeShareable(new FOculusXRHapticsDesc(Location, bAppend));
|
||
|
break;
|
||
|
case EControllerHand::Right:
|
||
|
ActiveHapticEffect_Right.Reset();
|
||
|
HapticsDesc_Right.Reset();
|
||
|
ActiveHapticEffect_Right = MakeShareable(new FActiveHapticFeedbackEffect(HapticEffect, Scale, bLoop));
|
||
|
HapticsDesc_Right = MakeShareable(new FOculusXRHapticsDesc(Location, bAppend));
|
||
|
break;
|
||
|
default:
|
||
|
UE_LOG(LogOcInput, Warning, TEXT("Invalid hand specified (%d) for haptic feedback effect %s"), (int32)Hand, *HapticEffect->GetName());
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int FOculusXRInput::PlayHapticEffect(EControllerHand Hand, int SamplesCount, void* Samples, int InSampleRate, bool bPCM, bool bAppend)
|
||
|
{
|
||
|
int TimeToSend = GetMaxHapticDuration(Hand);
|
||
|
if (TimeToSend == 0)
|
||
|
return 0;
|
||
|
|
||
|
const ovrpController OvrpController = (EControllerHand(Hand) == EControllerHand::Left) ? ovrpController_LTouch : ovrpController_RTouch;
|
||
|
int SampleRate = (InSampleRate > 0 ? InSampleRate : OvrpHapticsDesc.SampleRateHz);
|
||
|
int MaxSamplesCount = TimeToSend * SampleRate;
|
||
|
if (SamplesCount > MaxSamplesCount || SamplesCount < OvrpHapticsDesc.MinimumBufferSamplesCount)
|
||
|
{
|
||
|
UE_LOG(LogOcInput, Error, TEXT("Sample count should be between %d and %d which last %d time."),
|
||
|
OvrpHapticsDesc.MinimumBufferSamplesCount, MaxSamplesCount, TimeToSend);
|
||
|
}
|
||
|
int WantToSend = FMath::Min(SamplesCount, MaxSamplesCount);
|
||
|
WantToSend = FMath::Max(WantToSend, OvrpHapticsDesc.MinimumBufferSamplesCount);
|
||
|
|
||
|
float* BufferToSend = (float*)FMemory::Malloc(WantToSend * sizeof(*BufferToSend));
|
||
|
for (int i = 0; i < WantToSend; i++)
|
||
|
{
|
||
|
float Amplitude = ((uint8_t*)Samples)[i] / 255.0f;
|
||
|
Amplitude = FMath::Min(1.0f, Amplitude);
|
||
|
Amplitude = FMath::Max((bPCM ? -1.f : 0.0f), Amplitude);
|
||
|
BufferToSend[i] = Amplitude;
|
||
|
UE_CLOG(OVR_HAP_LOGGING, LogOcInput, Log, TEXT("amplitude, %.3f"), Amplitude);
|
||
|
}
|
||
|
|
||
|
ovrpUInt32 SamplesSent = 0;
|
||
|
if (bPCM)
|
||
|
{ //PCM
|
||
|
ovrpHapticsPcmVibration HapticsVibration;
|
||
|
HapticsVibration.Buffer = BufferToSend;
|
||
|
HapticsVibration.BufferSize = (ovrpUInt32)WantToSend;
|
||
|
HapticsVibration.SampleRateHz = SampleRate;
|
||
|
HapticsVibration.SamplesConsumed = &SamplesSent;
|
||
|
FOculusXRHMDModule::GetPluginWrapper().SetControllerHapticsPcm(
|
||
|
OvrpController,
|
||
|
HapticsVibration);
|
||
|
UE_CLOG(OVR_HAP_LOGGING, LogOcInput, Log, TEXT("PCMHaptics is finished: bAppend: %d, BufferSize: %d, SampleRate: %.3f, SamplesConsumed: %d"),
|
||
|
(int)(HapticsVibration.Append),
|
||
|
HapticsVibration.BufferSize,
|
||
|
HapticsVibration.SampleRateHz,
|
||
|
SamplesSent);
|
||
|
}
|
||
|
else
|
||
|
{ //HAE
|
||
|
ovrpHapticsAmplitudeEnvelopeVibration HapticsVibration;
|
||
|
HapticsVibration.Duration = WantToSend / SampleRate;
|
||
|
HapticsVibration.AmplitudeCount = WantToSend;
|
||
|
HapticsVibration.Amplitudes = BufferToSend;
|
||
|
|
||
|
FOculusXRHMDModule::GetPluginWrapper().SetControllerHapticsAmplitudeEnvelope(
|
||
|
OvrpController,
|
||
|
HapticsVibration);
|
||
|
UE_CLOG(OVR_HAP_LOGGING, LogOcInput, Log, TEXT("HAEHaptics is finished: AmplitudeCount: %d, SampleRate: %d"),
|
||
|
HapticsVibration.AmplitudeCount,
|
||
|
SampleRate);
|
||
|
}
|
||
|
if (BufferToSend)
|
||
|
{
|
||
|
FMemory::Free(BufferToSend);
|
||
|
}
|
||
|
return (int)SamplesSent;
|
||
|
}
|
||
|
|
||
|
void FOculusXRInput::SetHapticsByValue(float Frequency, float Amplitude, EControllerHand Hand, EOculusXRHandHapticsLocation Location)
|
||
|
{
|
||
|
const ovrpController OvrpController = (EControllerHand(Hand) == EControllerHand::Left) ? ovrpController_LTouch : ovrpController_RTouch;
|
||
|
FOculusXRHMDModule::GetPluginWrapper().SetControllerLocalizedVibration(OvrpController, GetOVRPHapticsLocation(Location), Frequency, Amplitude);
|
||
|
UE_CLOG(OVR_HAP_LOGGING, LogOcInput, Log, TEXT("LocalizedVibration is finished: Location: %d, Frequency: %f, Amplitude: %f"), (int)(Location), Frequency, Amplitude);
|
||
|
}
|
||
|
|
||
|
void FOculusXRInput::ProcessHaptics(const float DeltaTime)
|
||
|
{
|
||
|
FHapticFeedbackValues LeftHaptics, RightHaptics;
|
||
|
bool bLeftHapticsNeedUpdate = false;
|
||
|
bool bRightHapticsNeedUpdate = false;
|
||
|
|
||
|
if (ActiveHapticEffect_Left.IsValid())
|
||
|
{
|
||
|
const bool bPlaying = ActiveHapticEffect_Left->Update(DeltaTime, LeftHaptics);
|
||
|
if (!bPlaying)
|
||
|
{
|
||
|
ActiveHapticEffect_Left->bLoop ? HapticsDesc_Left->Restart() : HapticsDesc_Left.Reset();
|
||
|
ActiveHapticEffect_Left->bLoop ? ActiveHapticEffect_Left->Restart() : ActiveHapticEffect_Left.Reset();
|
||
|
}
|
||
|
|
||
|
bLeftHapticsNeedUpdate = true;
|
||
|
}
|
||
|
|
||
|
if (ActiveHapticEffect_Right.IsValid())
|
||
|
{
|
||
|
const bool bPlaying = ActiveHapticEffect_Right->Update(DeltaTime, RightHaptics);
|
||
|
if (!bPlaying)
|
||
|
{
|
||
|
ActiveHapticEffect_Right->bLoop ? HapticsDesc_Right->Restart() : HapticsDesc_Right.Reset();
|
||
|
ActiveHapticEffect_Right->bLoop ? ActiveHapticEffect_Right->Restart() : ActiveHapticEffect_Right.Reset();
|
||
|
}
|
||
|
|
||
|
bRightHapticsNeedUpdate = true;
|
||
|
}
|
||
|
|
||
|
// Haptic Updates
|
||
|
if (bLeftHapticsNeedUpdate)
|
||
|
{
|
||
|
SetHapticFeedbackValues(0, (int32)(EControllerHand::Left), LeftHaptics, HapticsDesc_Left);
|
||
|
}
|
||
|
if (bRightHapticsNeedUpdate)
|
||
|
{
|
||
|
SetHapticFeedbackValues(0, (int32)(EControllerHand::Right), RightHaptics, HapticsDesc_Right);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void FOculusTouchControllerState::ResampleHapticBufferData(const FHapticFeedbackBuffer& HapticBuffer, TMap<const uint8*, TSharedPtr<TArray<uint8>>>& ResampledRawDataCache)
|
||
|
{
|
||
|
const uint8* OriginalRawData = HapticBuffer.RawData;
|
||
|
TSharedPtr<TArray<uint8>>* ResampledRawDataSharedPtrPtr = ResampledRawDataCache.Find(OriginalRawData);
|
||
|
if (ResampledRawDataSharedPtrPtr == nullptr)
|
||
|
{
|
||
|
// We need to resample and cache the resampled data.
|
||
|
|
||
|
ResampledHapticBuffer = HapticBuffer;
|
||
|
|
||
|
int32 SampleRate = HapticBuffer.SamplingRate;
|
||
|
int TargetFrequency = 320;
|
||
|
int TargetBufferSize = (HapticBuffer.BufferLength * TargetFrequency) / (SampleRate * 2) + 1; //2 because we're only using half of the 16bit source PCM buffer
|
||
|
ResampledHapticBuffer.BufferLength = TargetBufferSize;
|
||
|
ResampledHapticBuffer.CurrentPtr = 0;
|
||
|
ResampledHapticBuffer.SamplingRate = TargetFrequency;
|
||
|
|
||
|
TSharedPtr<TArray<uint8>>& NewResampledRawDataSharedPtr = ResampledRawDataCache.Add(OriginalRawData);
|
||
|
NewResampledRawDataSharedPtr = MakeShared<TArray<uint8>>();
|
||
|
ResampledRawDataSharedPtrPtr = &NewResampledRawDataSharedPtr;
|
||
|
TArray<uint8>& ResampledRawData = *NewResampledRawDataSharedPtr;
|
||
|
ResampledRawData.SetNum(TargetBufferSize);
|
||
|
|
||
|
const uint8* PCMData = HapticBuffer.RawData;
|
||
|
|
||
|
int previousTargetIndex = -1;
|
||
|
int currentMin = 0;
|
||
|
for (int i = 1; i < HapticBuffer.BufferLength; i += 2)
|
||
|
{
|
||
|
int targetIndex = i * TargetFrequency / (SampleRate * 2);
|
||
|
int val = PCMData[i];
|
||
|
if (val & 0x80)
|
||
|
{
|
||
|
val = ~val;
|
||
|
}
|
||
|
currentMin = FMath::Min(currentMin, val);
|
||
|
|
||
|
if (targetIndex != previousTargetIndex)
|
||
|
{
|
||
|
|
||
|
ResampledRawData[targetIndex] = val * 2; // *Scale;
|
||
|
previousTargetIndex = targetIndex;
|
||
|
currentMin = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
ResampledHapticBuffer.RawData = ResampledRawData.GetData();
|
||
|
}
|
||
|
else if (ResampledHapticBuffer.RawData != (*ResampledRawDataSharedPtrPtr)->GetData())
|
||
|
{
|
||
|
// If this a cached effect, but not the same one we played last so we need to copy the new one's buffer and reference its cached resampled data.
|
||
|
ResampledHapticBuffer = HapticBuffer;
|
||
|
ResampledHapticBuffer.RawData = (*ResampledRawDataSharedPtrPtr)->GetData();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void FOculusXRInput::GetHapticFrequencyRange(float& MinFrequency, float& MaxFrequency) const
|
||
|
{
|
||
|
MinFrequency = 0.f;
|
||
|
MaxFrequency = 1.f;
|
||
|
}
|
||
|
|
||
|
float FOculusXRInput::GetHapticAmplitudeScale() const
|
||
|
{
|
||
|
return 1.f;
|
||
|
}
|
||
|
|
||
|
uint32 FOculusXRInput::GetNumberOfTouchControllers() const
|
||
|
{
|
||
|
uint32 RetVal = 0;
|
||
|
|
||
|
for (FOculusControllerPair Pair : ControllerPairs)
|
||
|
{
|
||
|
RetVal += (Pair.TouchControllerStates[0].bIsConnected ? 1 : 0);
|
||
|
RetVal += (Pair.TouchControllerStates[1].bIsConnected ? 1 : 0);
|
||
|
}
|
||
|
|
||
|
return RetVal;
|
||
|
}
|
||
|
|
||
|
uint32 FOculusXRInput::GetNumberOfHandControllers() const
|
||
|
{
|
||
|
uint32 RetVal = 0;
|
||
|
|
||
|
for (FOculusControllerPair Pair : ControllerPairs)
|
||
|
{
|
||
|
RetVal += (Pair.HandControllerStates[0].bIsConnected ? 1 : 0);
|
||
|
RetVal += (Pair.HandControllerStates[1].bIsConnected ? 1 : 0);
|
||
|
}
|
||
|
|
||
|
return RetVal;
|
||
|
}
|
||
|
|
||
|
ovrpHapticsLocation FOculusXRInput::GetOVRPHapticsLocation(EOculusXRHandHapticsLocation Location)
|
||
|
{
|
||
|
switch (Location)
|
||
|
{
|
||
|
case EOculusXRHandHapticsLocation::Hand:
|
||
|
return ovrpHapticsLocation::ovrpHapticsLocation_Hand;
|
||
|
case EOculusXRHandHapticsLocation::Thumb:
|
||
|
return ovrpHapticsLocation::ovrpHapticsLocation_Thumb;
|
||
|
case EOculusXRHandHapticsLocation::Index:
|
||
|
return ovrpHapticsLocation::ovrpHapticsLocation_Index;
|
||
|
default:
|
||
|
UE_LOG(LogOcInput, Error, TEXT("Unsupported Haptics Location: %d"), Location);
|
||
|
return ovrpHapticsLocation::ovrpHapticsLocation_None;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool FOculusXRInput::GetOvrpHapticsDesc(int Hand)
|
||
|
{
|
||
|
if (!bPulledHapticsDesc)
|
||
|
{
|
||
|
const ovrpController OvrpController = (EControllerHand(Hand) == EControllerHand::Left) ? ovrpController_LTouch : ovrpController_RTouch;
|
||
|
// Buffered haptics is currently only supported on Touch
|
||
|
if (OVRP_FAILURE(FOculusXRHMDModule::GetPluginWrapper().GetControllerHapticsDesc2(OvrpController, &OvrpHapticsDesc)))
|
||
|
{
|
||
|
UE_LOG(LogOcInput, Error, TEXT("ControllerHapticsDesc2 failed."));
|
||
|
return false;
|
||
|
}
|
||
|
bPulledHapticsDesc = true;
|
||
|
if (OvrpHapticsDesc.SampleRateHz == 0)
|
||
|
{
|
||
|
UE_LOG(LogOcInput, Error, TEXT("GetControllerHapticsDesc2 returns OvrpHapticsDesc.SampleRateHz = %d"), OvrpHapticsDesc.SampleRateHz);
|
||
|
OvrpHapticsDesc.SampleRateHz = 2000;
|
||
|
return true;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
UE_CLOG(OVR_HAP_LOGGING, LogOcInput, Log, TEXT("GetControllerHapticsDesc2 returns OvrpHapticsDesc.SampleRateHz = %d"), OvrpHapticsDesc.SampleRateHz);
|
||
|
}
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
float FOculusXRInput::GetControllerSampleRateHz(EControllerHand Hand)
|
||
|
{
|
||
|
float sampleRateHz = 0.f;
|
||
|
const ovrpController OvrpController = (EControllerHand(Hand) == EControllerHand::Left) ? ovrpController_LTouch : ovrpController_RTouch;
|
||
|
if (OVRP_FAILURE(FOculusXRHMDModule::GetPluginWrapper().GetControllerSampleRateHz(OvrpController, &sampleRateHz)))
|
||
|
{
|
||
|
UE_LOG(LogOcInput, Error, TEXT("GetControllerSampleRateHz failed."));
|
||
|
}
|
||
|
return sampleRateHz;
|
||
|
}
|
||
|
|
||
|
int FOculusXRInput::GetMaxHapticDuration(EControllerHand Hand)
|
||
|
{
|
||
|
const ovrpController OvrpController = (EControllerHand(Hand) == EControllerHand::Left) ? ovrpController_LTouch : ovrpController_RTouch;
|
||
|
if (!GetOvrpHapticsDesc((int32)Hand))
|
||
|
return 0;
|
||
|
|
||
|
return OvrpHapticsDesc.MaximumBufferSamplesCount / OvrpHapticsDesc.SampleRateHz;
|
||
|
}
|
||
|
} // namespace OculusXRInput
|
||
|
|
||
|
#undef LOCTEXT_NAMESPACE
|
||
|
#endif // OCULUS_INPUT_SUPPORTED_PLATFORMS
|