695 lines
29 KiB
C#
695 lines
29 KiB
C#
//========= Copyright 2016-2023, HTC Corporation. All rights reserved. ===========
|
|
|
|
using HTC.UnityPlugin.Utility;
|
|
using Object = UnityEngine.Object;
|
|
#if UNITY_STANDALONE
|
|
|
|
using HTC.UnityPlugin.Vive;
|
|
using HTC.UnityPlugin.Vive.SteamVRExtension;
|
|
using UnityEngine;
|
|
using System;
|
|
using System.Text;
|
|
|
|
#if VIU_OPENVR_API
|
|
using Valve.VR;
|
|
#endif
|
|
|
|
#if UNITY_2017_2_OR_NEWER
|
|
using UnityEngine.XR;
|
|
#elif UNITY_5_4_OR_NEWER
|
|
using XRSettings = UnityEngine.VR.VRSettings;
|
|
#endif
|
|
|
|
#endif
|
|
|
|
namespace HTC.UnityPlugin.VRModuleManagement
|
|
{
|
|
public partial class VRModule : SingletonBehaviour<VRModule>
|
|
{
|
|
public static readonly bool isSteamVRPluginDetected =
|
|
#if VIU_STEAMVR
|
|
true;
|
|
#else
|
|
false;
|
|
#endif
|
|
public static readonly bool isOpenVRSupported =
|
|
#if VIU_OPENVR_SUPPORT
|
|
true;
|
|
#else
|
|
false;
|
|
#endif
|
|
}
|
|
|
|
public sealed partial class SteamVRModule : VRModule.ModuleBase
|
|
{
|
|
public override int moduleOrder { get { return (int)DefaultModuleOrder.SteamVR; } }
|
|
|
|
public override int moduleIndex { get { return (int)VRModuleSelectEnum.SteamVR; } }
|
|
|
|
#if VIU_OPENVR_API && UNITY_STANDALONE
|
|
private class IndexMap
|
|
{
|
|
private uint[] tracked2module = new uint[OpenVR.k_unMaxTrackedDeviceCount];
|
|
private uint[] module2tracked = new uint[VRModule.MAX_DEVICE_COUNT];
|
|
public IndexMap() { Clear(); }
|
|
|
|
private bool IsValidTracked(uint trackedIndex) { return trackedIndex < tracked2module.Length; }
|
|
private bool IsValidModule(uint moduleIndex) { return moduleIndex < module2tracked.Length; }
|
|
|
|
public uint Tracked2ModuleIndex(uint trackedIndex)
|
|
{
|
|
if (trackedIndex == OpenVR.k_unTrackedDeviceIndex_Hmd) { return VRModule.HMD_DEVICE_INDEX; }
|
|
if (!IsValidTracked(trackedIndex)) { return VRModule.INVALID_DEVICE_INDEX; }
|
|
return tracked2module[trackedIndex];
|
|
}
|
|
|
|
public bool TryGetModuleIndex(uint trackedIndex, out uint moduleIndex)
|
|
{
|
|
moduleIndex = Tracked2ModuleIndex(trackedIndex);
|
|
return IsValidModule(moduleIndex);
|
|
}
|
|
|
|
public uint Module2TrackedIndex(uint moduleIndex)
|
|
{
|
|
if (moduleIndex == VRModule.HMD_DEVICE_INDEX) { return OpenVR.k_unTrackedDeviceIndex_Hmd; }
|
|
if (!IsValidModule(moduleIndex)) { return OpenVR.k_unTrackedDeviceIndexInvalid; }
|
|
return module2tracked[moduleIndex];
|
|
}
|
|
|
|
public void Map(uint trackedIndex, uint moduleIndex)
|
|
{
|
|
if (trackedIndex == OpenVR.k_unTrackedDeviceIndex_Hmd) { throw new ArgumentException("Value cannot be OpenVR.k_unTrackedDeviceIndex_Hmd(" + OpenVR.k_unTrackedDeviceIndex_Hmd + ")", "trackedIndex"); }
|
|
if (moduleIndex == VRModule.HMD_DEVICE_INDEX) { throw new ArgumentException("Value cannot be VRModule.HMD_DEVICE_INDEX(" + VRModule.HMD_DEVICE_INDEX + ")", "moduleIndex"); }
|
|
if (!IsValidTracked(trackedIndex)) { throw new ArgumentException("Invalid value (" + trackedIndex + ")", "trackedIndex"); }
|
|
if (!IsValidModule(moduleIndex)) { throw new ArgumentException("Invalid value (" + moduleIndex + ")", "moduleIndex"); }
|
|
if (IsValidTracked(tracked2module[trackedIndex])) { throw new Exception("tracked2module at [" + trackedIndex + "] is not empty(" + tracked2module[trackedIndex] + ")"); }
|
|
if (IsValidModule(module2tracked[moduleIndex])) { throw new Exception("module2tracked at [" + moduleIndex + "] is not empty(" + module2tracked[moduleIndex] + ")"); }
|
|
tracked2module[trackedIndex] = moduleIndex;
|
|
module2tracked[moduleIndex] = trackedIndex;
|
|
}
|
|
|
|
public bool UnmapTracked(uint trackedIndex, out uint moduleIndex)
|
|
{
|
|
if (trackedIndex == OpenVR.k_unTrackedDeviceIndex_Hmd) { moduleIndex = VRModule.INVALID_DEVICE_INDEX; return false; }
|
|
if (!IsValidTracked(trackedIndex)) { throw new ArgumentException("Cannot unmap invalid trackedIndex(" + trackedIndex + ")", "trackedIndex"); }
|
|
if (!IsValidModule(tracked2module[trackedIndex])) { moduleIndex = VRModule.INVALID_DEVICE_INDEX; return false; }
|
|
moduleIndex = tracked2module[trackedIndex];
|
|
if (module2tracked[moduleIndex] != trackedIndex) { throw new Exception("Unexpected mapping t2m[" + trackedIndex + "]=" + tracked2module[trackedIndex] + " m2t[" + moduleIndex + "]=" + module2tracked[moduleIndex]); }
|
|
tracked2module[trackedIndex] = VRModule.INVALID_DEVICE_INDEX;
|
|
module2tracked[moduleIndex] = OpenVR.k_unTrackedDeviceIndexInvalid;
|
|
return true;
|
|
}
|
|
|
|
public void Clear()
|
|
{
|
|
for (int i = tracked2module.Length - 1; i >= 0; --i) { tracked2module[i] = VRModule.INVALID_DEVICE_INDEX; }
|
|
for (int i = module2tracked.Length - 1; i >= 0; --i) { module2tracked[i] = OpenVR.k_unTrackedDeviceIndexInvalid; }
|
|
}
|
|
}
|
|
|
|
public static VRModuleDeviceClass ToVRModuleDeviceClass(ETrackedDeviceClass deviceClass)
|
|
{
|
|
switch (deviceClass)
|
|
{
|
|
case ETrackedDeviceClass.HMD: return VRModuleDeviceClass.HMD;
|
|
case ETrackedDeviceClass.Controller: return VRModuleDeviceClass.Controller;
|
|
case ETrackedDeviceClass.GenericTracker: return VRModuleDeviceClass.GenericTracker;
|
|
case ETrackedDeviceClass.TrackingReference: return VRModuleDeviceClass.TrackingReference;
|
|
default: return VRModuleDeviceClass.Invalid;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#if VIU_STEAMVR && UNITY_STANDALONE
|
|
private class CameraCreator : VRCameraHook.CameraCreator
|
|
{
|
|
public override bool shouldActive { get { return s_moduleInstance == null ? false : s_moduleInstance.isActivated; } }
|
|
|
|
public override void CreateCamera(VRCameraHook hook)
|
|
{
|
|
#if UNITY_2019_3_OR_NEWER && VIU_XR_GENERAL_SETTINGS
|
|
if (hook.GetComponent<UnityEngine.SpatialTracking.TrackedPoseDriver>() == null)
|
|
{
|
|
hook.gameObject.AddComponent<UnityEngine.SpatialTracking.TrackedPoseDriver>();
|
|
}
|
|
#else
|
|
if (hook.GetComponent<SteamVR_Camera>() == null)
|
|
{
|
|
hook.gameObject.AddComponent<SteamVR_Camera>();
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
[RenderModelHook.CreatorPriorityAttirbute(0)]
|
|
private class RenderModelCreator : RenderModelHook.DefaultRenderModelCreator
|
|
{
|
|
private const string SKELETON_PREFAB_BASE_PATH = "Models/VIUModelSteamVRSkeleton";
|
|
|
|
private uint m_index = INVALID_DEVICE_INDEX;
|
|
private VIUSteamVRRenderModel m_renderModelComp;
|
|
private GameObject m_skeletonObj;
|
|
|
|
public override bool shouldActive { get { return s_moduleInstance == null ? false : s_moduleInstance.isActivated; } }
|
|
|
|
public override void UpdateRenderModel()
|
|
{
|
|
m_index = hook.GetModelDeviceIndex();
|
|
if (hook.enabled && VRModule.IsValidDeviceIndex(m_index))
|
|
{
|
|
if (VRModule.GetDeviceState(m_index).deviceClass == VRModuleDeviceClass.TrackedHand)
|
|
{
|
|
// VIUSteamVRRenderModel currently doesn't support tracked hand
|
|
// Fallback to default model instead
|
|
UpdateDefaultRenderModel(true);
|
|
|
|
if (m_renderModelComp != null)
|
|
{
|
|
m_renderModelComp.gameObject.SetActive(false);
|
|
}
|
|
|
|
if (m_skeletonObj != null)
|
|
{
|
|
m_skeletonObj.SetActive(false);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
UpdateDefaultRenderModel(false);
|
|
|
|
bool isLeft;
|
|
SteamVRSkeletonMode skeletonMode = GetDeviceSkeletonMode(out isLeft);
|
|
bool shouldShowHand = skeletonMode != SteamVRSkeletonMode.Disabled && IsSkeletonValid();
|
|
bool shouldShowController = !shouldShowHand || skeletonMode != SteamVRSkeletonMode.WithoutController;
|
|
|
|
if (shouldShowHand && m_skeletonObj == null)
|
|
{
|
|
// Create skeleton object
|
|
GameObject prefab = Resources.Load<GameObject>(GetSkeletonPrefabPath(isLeft));
|
|
m_skeletonObj = Object.Instantiate(prefab);
|
|
m_skeletonObj.transform.SetParent(hook.transform);
|
|
m_skeletonObj.transform.localPosition = Vector3.zero;
|
|
m_skeletonObj.transform.localRotation = Quaternion.identity;
|
|
}
|
|
|
|
if (m_skeletonObj != null)
|
|
{
|
|
m_skeletonObj.SetActive(shouldShowHand);
|
|
}
|
|
|
|
if (shouldShowController && m_renderModelComp == null)
|
|
{
|
|
// create object for render model
|
|
var go = new GameObject("Model");
|
|
go.SetActive(false);
|
|
go.transform.SetParent(hook.transform, false);
|
|
m_renderModelComp = go.AddComponent<VIUSteamVRRenderModel>();
|
|
}
|
|
|
|
if (m_renderModelComp != null)
|
|
{
|
|
m_renderModelComp.gameObject.SetActive(shouldShowController);
|
|
|
|
if (shouldShowController)
|
|
{
|
|
// set render model index
|
|
m_renderModelComp.shaderOverride = hook.overrideShader;
|
|
m_renderModelComp.SetDeviceIndex(m_index);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
UpdateDefaultRenderModel(false);
|
|
// deacitvate object for render model
|
|
if (m_renderModelComp != null)
|
|
{
|
|
m_renderModelComp.gameObject.SetActive(false);
|
|
}
|
|
|
|
if (m_skeletonObj != null)
|
|
{
|
|
m_skeletonObj.SetActive(false);
|
|
}
|
|
}
|
|
}
|
|
|
|
public override void CleanUpRenderModel()
|
|
{
|
|
base.CleanUpRenderModel();
|
|
|
|
if (m_renderModelComp != null)
|
|
{
|
|
m_renderModelComp.gameObject.SetActive(false);
|
|
}
|
|
|
|
if (m_skeletonObj != null)
|
|
{
|
|
m_skeletonObj.SetActive(false);
|
|
}
|
|
}
|
|
|
|
private bool IsLeft()
|
|
{
|
|
if (s_moduleInstance == null)
|
|
{
|
|
Debug.LogWarning("s_moduleInstance is null.");
|
|
return false;
|
|
}
|
|
|
|
return m_index == s_moduleInstance.GetLeftControllerDeviceIndex();
|
|
}
|
|
|
|
private static string GetSkeletonPrefabPath(bool isLeft)
|
|
{
|
|
return SKELETON_PREFAB_BASE_PATH + (isLeft ? "Left" : "Right");
|
|
}
|
|
|
|
private SteamVRSkeletonMode GetDeviceSkeletonMode(out bool isLeft)
|
|
{
|
|
if (s_moduleInstance == null)
|
|
{
|
|
Debug.LogWarning("s_moduleInstance is null.");
|
|
isLeft = false;
|
|
return SteamVRSkeletonMode.Disabled;
|
|
}
|
|
|
|
if (VRModule.GetDeviceState(m_index).deviceClass == VRModuleDeviceClass.Controller)
|
|
{
|
|
if (m_index == s_moduleInstance.GetLeftControllerDeviceIndex()) { isLeft = true; return VIUSettings.steamVRLeftSkeletonMode; }
|
|
if (m_index == s_moduleInstance.GetRightControllerDeviceIndex()) { isLeft = false; return VIUSettings.steamVRRightSkeletonMode; }
|
|
}
|
|
|
|
isLeft = false;
|
|
return SteamVRSkeletonMode.Disabled;
|
|
}
|
|
|
|
private bool IsSkeletonValid()
|
|
{
|
|
return VRModule.GetDeviceState(m_index).GetValidHandJointCount() > 0;
|
|
}
|
|
}
|
|
|
|
private static SteamVRModule s_moduleInstance;
|
|
#endif
|
|
|
|
#if VIU_STEAMVR && !VIU_STEAMVR_2_0_0_OR_NEWER
|
|
private static readonly uint s_sizeOfControllerStats = (uint)System.Runtime.InteropServices.Marshal.SizeOf(typeof(VRControllerState_t));
|
|
|
|
private ETrackingUniverseOrigin m_prevTrackingSpace;
|
|
private bool m_hasInputFocus = true;
|
|
private IndexMap m_indexMap = new IndexMap();
|
|
private VRModule.SubmoduleBase.Collection m_submodules = new VRModule.SubmoduleBase.Collection(new ViveHandTrackingSubmodule());
|
|
private bool m_openvrCtrlRoleDirty;
|
|
private uint m_openvrRightIndex;
|
|
private uint m_openvrLeftIndex;
|
|
private uint m_moduleRightIndex;
|
|
private uint m_moduleLeftIndex;
|
|
|
|
public override bool ShouldActiveModule()
|
|
{
|
|
#if UNITY_5_4_OR_NEWER
|
|
return VIUSettings.activateSteamVRModule && XRSettings.enabled && XRSettings.loadedDeviceName == "OpenVR";
|
|
#else
|
|
return VIUSettings.activateSteamVRModule && SteamVR.enabled;
|
|
#endif
|
|
}
|
|
|
|
public override void OnActivated()
|
|
{
|
|
// Make sure SteamVR_Render instance exist. It Polls New Poses Event
|
|
if (SteamVR_Render.instance == null) { }
|
|
|
|
// setup tracking space
|
|
m_prevTrackingSpace = trackingSpace;
|
|
UpdateTrackingSpaceType();
|
|
|
|
EnsureDeviceStateLength(OpenVR.k_unMaxTrackedDeviceCount);
|
|
|
|
m_hasInputFocus = inputFocus;
|
|
|
|
#if VIU_STEAMVR_1_2_1_OR_NEWER
|
|
SteamVR_Events.NewPoses.AddListener(OnSteamVRNewPose);
|
|
SteamVR_Events.InputFocus.AddListener(OnInputFocus);
|
|
SteamVR_Events.System(EVREventType.VREvent_TrackedDeviceRoleChanged).AddListener(OnTrackedDeviceRoleChanged);
|
|
#elif VIU_STEAMVR_1_2_0_OR_NEWER
|
|
SteamVR_Events.NewPoses.AddListener(OnSteamVRNewPose);
|
|
SteamVR_Events.InputFocus.AddListener(OnInputFocus);
|
|
SteamVR_Events.System("TrackedDeviceRoleChanged").AddListener(OnTrackedDeviceRoleChanged);
|
|
#elif VIU_STEAMVR_1_1_1
|
|
SteamVR_Utils.Event.Listen("new_poses", OnSteamVRNewPoseArgs);
|
|
SteamVR_Utils.Event.Listen("input_focus", OnInputFocusArgs);
|
|
SteamVR_Utils.Event.Listen("TrackedDeviceRoleChanged", OnTrackedDeviceRoleChangedArgs);
|
|
#endif
|
|
m_submodules.ActivateAllModules();
|
|
|
|
s_moduleInstance = this;
|
|
}
|
|
|
|
public override void OnDeactivated()
|
|
{
|
|
m_submodules.DeactivateAllModules();
|
|
|
|
trackingSpace = m_prevTrackingSpace;
|
|
|
|
#if VIU_STEAMVR_1_2_1_OR_NEWER
|
|
SteamVR_Events.NewPoses.RemoveListener(OnSteamVRNewPose);
|
|
SteamVR_Events.InputFocus.RemoveListener(OnInputFocus);
|
|
SteamVR_Events.System(EVREventType.VREvent_TrackedDeviceRoleChanged).RemoveListener(OnTrackedDeviceRoleChanged);
|
|
#elif VIU_STEAMVR_1_2_0_OR_NEWER
|
|
SteamVR_Events.NewPoses.RemoveListener(OnSteamVRNewPose);
|
|
SteamVR_Events.InputFocus.RemoveListener(OnInputFocus);
|
|
SteamVR_Events.System("TrackedDeviceRoleChanged").RemoveListener(OnTrackedDeviceRoleChanged);
|
|
#elif VIU_STEAMVR_1_1_1
|
|
SteamVR_Utils.Event.Remove("new_poses", OnSteamVRNewPoseArgs);
|
|
SteamVR_Utils.Event.Remove("input_focus", OnInputFocusArgs);
|
|
SteamVR_Utils.Event.Remove("TrackedDeviceRoleChanged", OnTrackedDeviceRoleChangedArgs);
|
|
#endif
|
|
m_indexMap.Clear();
|
|
s_moduleInstance = null;
|
|
}
|
|
|
|
public override void Update()
|
|
{
|
|
if (SteamVR.active)
|
|
{
|
|
SteamVR_Render.instance.lockPhysicsUpdateRateToRenderFrequency = VRModule.lockPhysicsUpdateRateToRenderFrequency;
|
|
}
|
|
|
|
UpdateDeviceInput();
|
|
|
|
m_submodules.UpdateAllModulesActivity();
|
|
m_submodules.UpdateModulesDeviceInput();
|
|
|
|
ProcessDeviceInputChanged();
|
|
}
|
|
|
|
private void UpdateConnectedDevice(TrackedDevicePose_t[] poses)
|
|
{
|
|
IVRModuleDeviceState prevState;
|
|
IVRModuleDeviceStateRW currState;
|
|
var vrSystem = OpenVR.System;
|
|
|
|
if (vrSystem == null)
|
|
{
|
|
m_openvrCtrlRoleDirty = true;
|
|
for (uint moduleIndex = 0, imax = GetDeviceStateLength(); moduleIndex < imax; ++moduleIndex)
|
|
{
|
|
if (TryGetValidDeviceState(moduleIndex, out prevState, out currState) && currState.isConnected)
|
|
{
|
|
currState.Reset();
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (uint trackedIndex = 0u, imax = (uint)poses.Length; trackedIndex < imax; ++trackedIndex)
|
|
{
|
|
if (!poses[trackedIndex].bDeviceIsConnected)
|
|
{
|
|
uint moduleIndex;
|
|
if (m_indexMap.UnmapTracked(trackedIndex, out moduleIndex))
|
|
{
|
|
m_openvrCtrlRoleDirty = true;
|
|
if (TryGetValidDeviceState(moduleIndex, out prevState, out currState) && prevState.isConnected)
|
|
{
|
|
currState.Reset();
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
uint moduleIndex;
|
|
if (!m_indexMap.TryGetModuleIndex(trackedIndex, out moduleIndex))
|
|
{
|
|
moduleIndex = FindAndEnsureUnusedNotHMDDeviceState(out prevState, out currState);
|
|
m_indexMap.Map(trackedIndex, moduleIndex);
|
|
}
|
|
else
|
|
{
|
|
EnsureValidDeviceState(moduleIndex, out prevState, out currState);
|
|
}
|
|
|
|
if (!prevState.isConnected)
|
|
{
|
|
m_openvrCtrlRoleDirty = true;
|
|
currState.isConnected = true;
|
|
currState.deviceClass = ToVRModuleDeviceClass(vrSystem.GetTrackedDeviceClass(trackedIndex));
|
|
currState.serialNumber = QueryDeviceStringProperty(vrSystem, trackedIndex, ETrackedDeviceProperty.Prop_SerialNumber_String);
|
|
currState.modelNumber = QueryDeviceStringProperty(vrSystem, trackedIndex, ETrackedDeviceProperty.Prop_ModelNumber_String);
|
|
currState.renderModelName = QueryDeviceStringProperty(vrSystem, trackedIndex, ETrackedDeviceProperty.Prop_RenderModelName_String);
|
|
|
|
SetupKnownDeviceModel(currState);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void UpdateDevicePose(TrackedDevicePose_t[] poses)
|
|
{
|
|
IVRModuleDeviceState prevState;
|
|
IVRModuleDeviceStateRW currState;
|
|
|
|
for (uint trackedIndex = 0u, imax = (uint)poses.Length; trackedIndex < imax; ++trackedIndex)
|
|
{
|
|
var moduleIndex = m_indexMap.Tracked2ModuleIndex(trackedIndex);
|
|
if (!TryGetValidDeviceState(moduleIndex, out prevState, out currState)) { continue; }
|
|
if (!currState.isConnected) { continue; }
|
|
|
|
// update device status
|
|
currState.isPoseValid = poses[trackedIndex].bPoseIsValid;
|
|
currState.isOutOfRange = poses[trackedIndex].eTrackingResult == ETrackingResult.Running_OutOfRange || poses[trackedIndex].eTrackingResult == ETrackingResult.Calibrating_OutOfRange;
|
|
currState.isCalibrating = poses[trackedIndex].eTrackingResult == ETrackingResult.Calibrating_InProgress || poses[trackedIndex].eTrackingResult == ETrackingResult.Calibrating_OutOfRange;
|
|
currState.isUninitialized = poses[trackedIndex].eTrackingResult == ETrackingResult.Uninitialized;
|
|
currState.velocity = new Vector3(poses[trackedIndex].vVelocity.v0, poses[trackedIndex].vVelocity.v1, -poses[trackedIndex].vVelocity.v2);
|
|
currState.angularVelocity = new Vector3(-poses[trackedIndex].vAngularVelocity.v0, -poses[trackedIndex].vAngularVelocity.v1, poses[trackedIndex].vAngularVelocity.v2);
|
|
|
|
// update poses
|
|
if (poses[trackedIndex].bPoseIsValid)
|
|
{
|
|
var rigidTransform = new SteamVR_Utils.RigidTransform(poses[trackedIndex].mDeviceToAbsoluteTracking);
|
|
currState.position = rigidTransform.pos;
|
|
currState.rotation = rigidTransform.rot;
|
|
}
|
|
else if (prevState.isPoseValid)
|
|
{
|
|
currState.pose = RigidPose.identity;
|
|
}
|
|
}
|
|
}
|
|
|
|
private bool UpdateControllerRole()
|
|
{
|
|
// process hand role
|
|
if (m_openvrCtrlRoleDirty)
|
|
{
|
|
m_openvrCtrlRoleDirty = false;
|
|
|
|
var vrSystem = OpenVR.System;
|
|
if (vrSystem == null)
|
|
{
|
|
m_openvrRightIndex = INVALID_DEVICE_INDEX;
|
|
m_openvrLeftIndex = INVALID_DEVICE_INDEX;
|
|
}
|
|
else
|
|
{
|
|
var right = vrSystem.GetTrackedDeviceIndexForControllerRole(ETrackedControllerRole.RightHand);
|
|
var left = vrSystem.GetTrackedDeviceIndexForControllerRole(ETrackedControllerRole.LeftHand);
|
|
m_indexMap.TryGetModuleIndex(right, out m_openvrRightIndex);
|
|
m_indexMap.TryGetModuleIndex(left, out m_openvrLeftIndex);
|
|
}
|
|
}
|
|
|
|
var moduleRight = m_openvrRightIndex != INVALID_DEVICE_INDEX ? m_openvrRightIndex : m_submodules.GetFirstRightHandedIndex();
|
|
var moduleLeft = m_openvrLeftIndex != INVALID_DEVICE_INDEX ? m_openvrLeftIndex : m_submodules.GetFirstLeftHandedIndex();
|
|
var roleChanged = ChangeProp.Set(ref m_moduleRightIndex, moduleRight);
|
|
roleChanged |= ChangeProp.Set(ref m_moduleLeftIndex, moduleLeft);
|
|
|
|
return roleChanged;
|
|
}
|
|
|
|
private void UpdateDeviceInput()
|
|
{
|
|
IVRModuleDeviceState prevState;
|
|
IVRModuleDeviceStateRW currState;
|
|
VRControllerState_t ctrlState;
|
|
var system = OpenVR.System;
|
|
|
|
for (uint trackedIndex = 0; trackedIndex < OpenVR.k_unMaxTrackedDeviceCount; ++trackedIndex)
|
|
{
|
|
var moduleIndex = m_indexMap.Tracked2ModuleIndex(trackedIndex);
|
|
if (!TryGetValidDeviceState(moduleIndex, out prevState, out currState)) { continue; }
|
|
if (!currState.isConnected) { continue; }
|
|
|
|
// get device state from openvr api
|
|
GetConrollerState(system, trackedIndex, out ctrlState);
|
|
|
|
// update device input button
|
|
currState.buttonPressed = ctrlState.ulButtonPressed;
|
|
currState.buttonTouched = ctrlState.ulButtonTouched;
|
|
|
|
// update device input axis
|
|
currState.SetAxisValue(VRModuleRawAxis.Axis0X, ctrlState.rAxis0.x);
|
|
currState.SetAxisValue(VRModuleRawAxis.Axis0Y, ctrlState.rAxis0.y);
|
|
currState.SetAxisValue(VRModuleRawAxis.Axis1X, ctrlState.rAxis1.x);
|
|
currState.SetAxisValue(VRModuleRawAxis.Axis1Y, ctrlState.rAxis1.y);
|
|
currState.SetAxisValue(VRModuleRawAxis.Axis2X, ctrlState.rAxis2.x);
|
|
currState.SetAxisValue(VRModuleRawAxis.Axis2Y, ctrlState.rAxis2.y);
|
|
currState.SetAxisValue(VRModuleRawAxis.Axis3X, ctrlState.rAxis3.x);
|
|
currState.SetAxisValue(VRModuleRawAxis.Axis3Y, ctrlState.rAxis3.y);
|
|
currState.SetAxisValue(VRModuleRawAxis.Axis4X, ctrlState.rAxis4.x);
|
|
currState.SetAxisValue(VRModuleRawAxis.Axis4Y, ctrlState.rAxis4.y);
|
|
}
|
|
}
|
|
|
|
private void UpdateInputFocusState()
|
|
{
|
|
if (ChangeProp.Set(ref m_hasInputFocus, inputFocus))
|
|
{
|
|
InvokeInputFocusEvent(m_hasInputFocus);
|
|
}
|
|
}
|
|
|
|
private static ETrackingUniverseOrigin trackingSpace
|
|
{
|
|
get
|
|
{
|
|
var compositor = OpenVR.Compositor;
|
|
if (compositor == null) { return default(ETrackingUniverseOrigin); }
|
|
|
|
return compositor.GetTrackingSpace();
|
|
}
|
|
set
|
|
{
|
|
var compositor = OpenVR.Compositor;
|
|
if (compositor == null) { return; }
|
|
|
|
compositor.SetTrackingSpace(value);
|
|
}
|
|
}
|
|
|
|
private static bool inputFocus
|
|
{
|
|
get
|
|
{
|
|
var system = OpenVR.System;
|
|
if (system == null) { return false; }
|
|
|
|
#if VIU_STEAMVR_1_2_3_OR_NEWER
|
|
return system.IsInputAvailable();
|
|
#else
|
|
return !system.IsInputFocusCapturedByAnotherProcess();
|
|
#endif
|
|
}
|
|
}
|
|
|
|
public override void UpdateTrackingSpaceType()
|
|
{
|
|
switch (VRModule.trackingSpaceType)
|
|
{
|
|
case VRModuleTrackingSpaceType.RoomScale:
|
|
trackingSpace = ETrackingUniverseOrigin.TrackingUniverseStanding;
|
|
break;
|
|
case VRModuleTrackingSpaceType.Stationary:
|
|
trackingSpace = ETrackingUniverseOrigin.TrackingUniverseSeated;
|
|
break;
|
|
}
|
|
}
|
|
|
|
private static void GetConrollerState(CVRSystem system, uint index, out VRControllerState_t ctrlState)
|
|
{
|
|
ctrlState = default(VRControllerState_t);
|
|
|
|
if (system != null)
|
|
{
|
|
#if VIU_STEAMVR_1_2_0_OR_NEWER
|
|
system.GetControllerState(index, ref ctrlState, s_sizeOfControllerStats);
|
|
#else
|
|
system.GetControllerState(index, ref ctrlState);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
private void OnSteamVRNewPoseArgs(params object[] args) { OnSteamVRNewPose((TrackedDevicePose_t[])args[0]); }
|
|
private void OnSteamVRNewPose(TrackedDevicePose_t[] poses)
|
|
{
|
|
FlushDeviceState();
|
|
|
|
UpdateConnectedDevice(poses);
|
|
UpdateDevicePose(poses);
|
|
|
|
m_submodules.UpdateAllModulesActivity();
|
|
m_submodules.UpdateModulesDeviceConnectionAndPoses();
|
|
|
|
var roleChanged = UpdateControllerRole();
|
|
|
|
ProcessConnectedDeviceChanged();
|
|
ProcessDevicePoseChanged();
|
|
|
|
if (roleChanged)
|
|
{
|
|
InvokeControllerRoleChangedEvent();
|
|
}
|
|
|
|
UpdateInputFocusState();
|
|
}
|
|
|
|
private void OnInputFocusArgs(params object[] args) { OnInputFocus((bool)args[0]); }
|
|
private void OnInputFocus(bool value)
|
|
{
|
|
m_hasInputFocus = value;
|
|
InvokeInputFocusEvent(value);
|
|
}
|
|
|
|
private void OnTrackedDeviceRoleChangedArgs(params object[] args) { OnTrackedDeviceRoleChanged((VREvent_t)args[0]); }
|
|
private void OnTrackedDeviceRoleChanged(VREvent_t arg) { m_openvrCtrlRoleDirty = true; }
|
|
|
|
public override bool HasInputFocus()
|
|
{
|
|
return m_hasInputFocus;
|
|
}
|
|
|
|
public override uint GetLeftControllerDeviceIndex() { return m_moduleLeftIndex; }
|
|
|
|
public override uint GetRightControllerDeviceIndex() { return m_moduleRightIndex; }
|
|
|
|
public override void TriggerViveControllerHaptic(uint deviceIndex, ushort durationMicroSec = 500)
|
|
{
|
|
var system = OpenVR.System;
|
|
if (system != null)
|
|
{
|
|
var trackedIndex = m_indexMap.Module2TrackedIndex(deviceIndex);
|
|
system.TriggerHapticPulse(trackedIndex, (uint)EVRButtonId.k_EButton_SteamVR_Touchpad - (uint)EVRButtonId.k_EButton_Axis0, (char)durationMicroSec);
|
|
}
|
|
}
|
|
|
|
public static uint GetTrackedIndexByModuleIndex(uint deviceIndex)
|
|
{
|
|
if (s_moduleInstance == null) { return OpenVR.k_unTrackedDeviceIndexInvalid; }
|
|
return s_moduleInstance.m_indexMap.Module2TrackedIndex(deviceIndex);
|
|
}
|
|
|
|
private StringBuilder m_sb;
|
|
private string QueryDeviceStringProperty(CVRSystem system, uint deviceIndex, ETrackedDeviceProperty prop)
|
|
{
|
|
var error = default(ETrackedPropertyError);
|
|
var capacity = (int)system.GetStringTrackedDeviceProperty(deviceIndex, prop, null, 0, ref error);
|
|
if (capacity <= 1 || capacity > 128) { return string.Empty; }
|
|
|
|
if (m_sb == null) { m_sb = new StringBuilder(capacity); }
|
|
else { m_sb.EnsureCapacity(capacity); }
|
|
|
|
system.GetStringTrackedDeviceProperty(deviceIndex, prop, m_sb, (uint)m_sb.Capacity, ref error);
|
|
if (error != ETrackedPropertyError.TrackedProp_Success) { return string.Empty; }
|
|
|
|
var result = m_sb.ToString();
|
|
m_sb.Length = 0;
|
|
|
|
return result;
|
|
}
|
|
#endif
|
|
}
|
|
}
|