TaiZhouCangChu_VRanime/Assets/HTC.UnityPlugin/VRModule/VRModuleManager.cs

511 lines
18 KiB
C#

//========= Copyright 2016-2023, HTC Corporation. All rights reserved. ===========
using HTC.UnityPlugin.Utility;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using UnityEngine;
#if VIU_STEAMVR_2_0_0_OR_NEWER && UNITY_STANDALONE
using Valve.VR;
#endif
namespace HTC.UnityPlugin.VRModuleManagement
{
public partial class VRModule : SingletonBehaviour<VRModule>
{
private static DeviceState s_defaultState;
private static SimulatorVRModule s_simulator;
private static Dictionary<string, uint> s_deviceSerialNumberTable;
[SerializeField]
private bool m_dontDestroyOnLoad = true;
[SerializeField]
private bool m_lockPhysicsUpdateRateToRenderFrequency = true;
[SerializeField]
private VRModuleSelectEnum m_selectModule = VRModuleSelectEnum.Auto;
[SerializeField]
private VRModuleTrackingSpaceType m_trackingSpaceType = VRModuleTrackingSpaceType.RoomScale;
[SerializeField]
private NewPosesEvent m_onNewPoses = new NewPosesEvent();
[SerializeField]
private NewInputEvent m_onNewInput = new NewInputEvent();
[SerializeField]
private ControllerRoleChangedEvent m_onControllerRoleChanged = new ControllerRoleChangedEvent();
[SerializeField]
private InputFocusEvent m_onInputFocus = new InputFocusEvent();
[SerializeField]
private DeviceConnectedEvent m_onDeviceConnected = new DeviceConnectedEvent();
[SerializeField]
private ActiveModuleChangedEvent m_onActiveModuleChanged = new ActiveModuleChangedEvent();
private bool m_delayDeactivate = false;
private bool m_isDestoryed = false;
private ModuleBase[] m_modules;
private ModuleBase[] m_modulesOrdered;
private VRModuleActiveEnum m_activatedModule = VRModuleActiveEnum.Uninitialized;
private ModuleBase m_activatedModuleBase;
private DeviceState[] m_prevStates;
private DeviceState[] m_currStates;
[RuntimeInitializeOnLoadMethod]
private static void TryInitializeOnStartup()
{
if (VRModuleSettings.initializeOnStartup)
{
Initialize();
}
}
private static GameObject GetDefaultInitGameObject()
{
return new GameObject("[ViveInputUtility]");
}
public static GameObject GetInstanceGameObject()
{
return Instance.gameObject;
}
protected override void OnSingletonBehaviourInitialized()
{
if (m_dontDestroyOnLoad && transform.parent == null && Application.isPlaying)
{
DontDestroyOnLoad(gameObject);
}
SetDefaultInitGameObjectGetter(GetDefaultInitGameObject);
s_defaultState = new DeviceState(INVALID_DEVICE_INDEX);
s_simulator = new SimulatorVRModule();
s_deviceSerialNumberTable = new Dictionary<string, uint>(16);
m_activatedModule = VRModuleActiveEnum.Uninitialized;
m_activatedModuleBase = null;
try
{
var modules = new List<ModuleBase>();
var modulesOrdered = new List<ModuleBase>();
foreach (var type in Assembly.GetAssembly(typeof(ModuleBase)).GetTypes().Where(t => t.IsClass && !t.IsAbstract && t.IsSubclassOf(typeof(ModuleBase))))
{
var inst = type == typeof(SimulatorVRModule) ? s_simulator : (ModuleBase)Activator.CreateInstance(type);
var index = inst.moduleIndex;
if (index < 0)
{
Debug.LogWarning("Invalid module index, module will not be activated! module name=" + type.Name + " index=" + index);
}
else if (index < modules.Count && modules[index] != null)
{
Debug.LogWarning("Duplicated module index, module will not be activated! module name=" + type.Name + " index=" + index);
}
else
{
while (index >= modules.Count) { modules.Add(null); }
modules[index] = inst;
}
var order = inst.moduleOrder;
if (order < 0)
{
Debug.LogWarning("Invalid module order, module will not be activated! module name=" + type.Name + " order=" + order);
}
else if (order < modulesOrdered.Count && modulesOrdered[order] != null)
{
Debug.LogWarning("Duplicated module order, module will not be activated! module name=" + type.Name + " order=" + order);
}
else
{
while (order >= modulesOrdered.Count) { modulesOrdered.Add(null); }
modulesOrdered[order] = inst;
}
}
m_modules = modules.ToArray();
m_modulesOrdered = modulesOrdered.ToArray();
}
catch (Exception e)
{
m_modules = new ModuleBase[] { new DefaultModule() };
m_modulesOrdered = new ModuleBase[] { new DefaultModule() };
Debug.LogError(e);
}
}
private uint GetDeviceStateLength() { return m_currStates == null ? 0u : (uint)m_currStates.Length; }
private void EnsureDeviceStateLength(uint capacity)
{
// NOTE: this will clear out the array
var cap = (int)(capacity < MAX_DEVICE_COUNT ? capacity : MAX_DEVICE_COUNT);
if (GetDeviceStateLength() < cap)
{
if (m_currStates == null) { m_currStates = new DeviceState[cap]; }
else { Array.Resize(ref m_currStates, cap); }
if (m_prevStates == null) { m_prevStates = new DeviceState[cap]; }
else { Array.Resize(ref m_prevStates, cap); }
}
}
private bool TryGetValidDeviceState(uint index, out IVRModuleDeviceState prevState, out IVRModuleDeviceStateRW currState)
{
DeviceState prevRawState;
DeviceState currRawState;
if (TryGetValidDeviceState(index, out prevRawState, out currRawState))
{
prevState = prevRawState;
currState = currRawState;
return true;
}
else
{
prevState = null;
currState = null;
return false;
}
}
private bool TryGetValidDeviceState(uint index, out DeviceState prevState, out DeviceState currState)
{
if (m_currStates == null || index >= m_currStates.Length || m_currStates[index] == null)
{
prevState = null;
currState = null;
return false;
}
else
{
prevState = m_prevStates[index];
currState = m_currStates[index];
return true;
}
}
private void EnsureValidDeviceState(uint index, out IVRModuleDeviceState prevState, out IVRModuleDeviceStateRW currState)
{
EnsureDeviceStateLength(index + 1);
if (!TryGetValidDeviceState(index, out prevState, out currState))
{
prevState = m_prevStates[index] = new DeviceState(index);
currState = m_currStates[index] = new DeviceState(index);
}
}
// this function will skip VRModule.HMD_DEVICE_INDEX (preserved index for HMD)
private uint FindAndEnsureUnusedNotHMDDeviceState(out IVRModuleDeviceState prevState, out IVRModuleDeviceStateRW currState)
{
var index = (m_activatedModuleBase == null ? VRModule.HMD_DEVICE_INDEX : m_activatedModuleBase.reservedDeviceIndex) + 1u;
var len = GetDeviceStateLength();
for (; index < len; ++index)
{
if (TryGetValidDeviceState(index, out prevState, out currState))
{
if (prevState.isConnected) { continue; }
if (currState.isConnected) { continue; }
return index;
}
break;
}
EnsureValidDeviceState(index, out prevState, out currState);
return index;
}
private void Update()
{
if (!IsInstance) { return; }
// Get should activate module
var shouldActivateModule = GetShouldActivateModule();
// Update module activity
if (m_activatedModule != shouldActivateModule)
{
// Do clean up
if (m_activatedModule != VRModuleActiveEnum.Uninitialized)
{
DeactivateModule();
}
if (shouldActivateModule != VRModuleActiveEnum.Uninitialized)
{
ActivateModule(shouldActivateModule);
}
}
if (m_activatedModuleBase != null)
{
m_activatedModuleBase.Update();
}
}
private void FixedUpdate()
{
if (!IsInstance) { return; }
if (m_activatedModuleBase != null)
{
m_activatedModuleBase.FixedUpdate();
}
}
private void LateUpdate()
{
if (!IsInstance) { return; }
if (m_activatedModuleBase != null)
{
m_activatedModuleBase.LateUpdate();
}
}
protected override void OnDestroy()
{
if (IsInstance)
{
m_isDestoryed = true;
if (!m_delayDeactivate)
{
DeactivateModule();
}
}
base.OnDestroy();
}
private VRModuleActiveEnum GetShouldActivateModule()
{
if (IsApplicationQuitting || m_isDestoryed) { return VRModuleActiveEnum.Uninitialized; }
if (m_selectModule == VRModuleSelectEnum.Auto)
{
for (int i = m_modulesOrdered.Length - 1; i >= 0; --i)
{
if (m_modulesOrdered[i] != null && m_modulesOrdered[i].ShouldActiveModule())
{
return (VRModuleActiveEnum)m_modulesOrdered[i].moduleIndex;
}
}
}
else if (m_selectModule >= 0 && (int)m_selectModule < m_modules.Length)
{
return (VRModuleActiveEnum)m_selectModule;
}
else
{
return VRModuleActiveEnum.None;
}
return VRModuleActiveEnum.Uninitialized;
}
private void ActivateModule(VRModuleActiveEnum module)
{
if (m_activatedModule != VRModuleActiveEnum.Uninitialized)
{
Debug.LogError("Must deactivate before activate module! Current activatedModule:" + m_activatedModule);
return;
}
if (module == VRModuleActiveEnum.Uninitialized)
{
Debug.LogError("Activate module cannot be Uninitialized! Use DeactivateModule instead");
return;
}
m_activatedModule = module;
m_activatedModuleBase = m_modules[(int)module];
m_activatedModuleBase.Activated();
#if UNITY_2017_1_OR_NEWER
Application.onBeforeRender += BeforeRenderUpdateModule;
#else
Camera.onPreCull += OnCameraPreCull;
#endif
InvokeActiveModuleChangedEvent(m_activatedModule);
}
#if !UNITY_2017_1_OR_NEWER
private int m_preCullOnceFrame = -1;
private void OnCameraPreCull(Camera cam)
{
var thisFrame = Time.frameCount;
if (m_preCullOnceFrame == thisFrame) { return; }
#if UNITY_5_5_OR_NEWER
if ((cam.cameraType & (CameraType.Game | CameraType.VR)) == 0) { return; }
#else
if ((cam.cameraType & CameraType.Game) == 0) { return; }
#endif
m_preCullOnceFrame = thisFrame;
BeforeRenderUpdateModule();
}
#endif
private void BeforeRenderUpdateModule()
{
if (m_activatedModuleBase != null)
{
m_activatedModuleBase.BeforeRenderUpdate();
}
}
private void DeactivateModule()
{
if (m_activatedModule == VRModuleActiveEnum.Uninitialized)
{
return;
}
if (m_activatedModuleBase == null)
{
return;
}
m_delayDeactivate = false;
#if UNITY_2017_1_OR_NEWER
Application.onBeforeRender -= BeforeRenderUpdateModule;
#else
Camera.onPreCull -= OnCameraPreCull;
#endif
DeviceState prevState;
DeviceState currState;
// copy status to from current state to previous state, and reset current state
for (uint i = 0u, imax = GetDeviceStateLength(); i < imax; ++i)
{
if (!TryGetValidDeviceState(i, out prevState, out currState)) { continue; }
if (prevState.isConnected || currState.isConnected)
{
prevState.CopyFrom(currState);
currState.Reset();
}
}
s_deviceSerialNumberTable.Clear();
// send disconnect event
SendAllDeviceConnectedEvent();
var deactivatedModuleBase = m_activatedModuleBase;
m_activatedModule = VRModuleActiveEnum.Uninitialized;
m_activatedModuleBase = null;
deactivatedModuleBase.Deactivated();
InvokeActiveModuleChangedEvent(VRModuleActiveEnum.Uninitialized);
}
private void ModuleFlushDeviceState()
{
DeviceState prevState;
DeviceState currState;
// copy status to from current state to previous state
for (uint i = 0u, imax = GetDeviceStateLength(); i < imax; ++i)
{
if (!TryGetValidDeviceState(i, out prevState, out currState)) { continue; }
if (prevState.isConnected || currState.isConnected)
{
prevState.CopyFrom(currState);
}
}
}
private void ModuleConnectedDeviceChanged()
{
DeviceState prevState;
DeviceState currState;
m_delayDeactivate = true;
List<uint> connected = null;
List<uint> disconnected = null;
// send connect/disconnect event
for (uint i = 0u, imax = GetDeviceStateLength(); i < imax; ++i)
{
if (!TryGetValidDeviceState(i, out prevState, out currState)) { continue; }
if (!prevState.isConnected)
{
if (currState.isConnected)
{
if (connected == null) { connected = ListPool<uint>.Get(); }
connected.Add(i);
}
}
else
{
if (!currState.isConnected)
{
if (disconnected == null) { disconnected = ListPool<uint>.Get(); }
disconnected.Add(i);
}
}
}
if (disconnected != null)
{
for (int i = 0, imax = disconnected.Count; i < imax; ++i)
{
var index = disconnected[i];
var state = m_prevStates[index];
s_deviceSerialNumberTable.Remove(state.serialNumber);
}
ListPool<uint>.Release(disconnected);
}
if (connected != null)
{
for (int i = 0, imax = connected.Count; i < imax; ++i)
{
var index = connected[i];
var state = m_currStates[index];
if (string.IsNullOrEmpty(state.serialNumber))
{
Debug.LogError("Device connected with empty serialNumber. index:" + state.deviceIndex);
}
else if (s_deviceSerialNumberTable.ContainsKey(state.serialNumber))
{
Debug.LogError("Device connected with duplicate serialNumber: " + state.serialNumber + " index:" + state.deviceIndex + "(" + s_deviceSerialNumberTable[state.serialNumber] + ")");
}
else
{
s_deviceSerialNumberTable.Add(state.serialNumber, index);
}
}
ListPool<uint>.Release(connected);
}
SendAllDeviceConnectedEvent();
m_delayDeactivate = false;
if (m_isDestoryed)
{
DeactivateModule();
}
}
private void SendAllDeviceConnectedEvent()
{
DeviceState prevState;
DeviceState currState;
for (uint i = 0u, imax = GetDeviceStateLength(); i < imax; ++i)
{
if (!TryGetValidDeviceState(i, out prevState, out currState)) { continue; }
if (prevState.isConnected != currState.isConnected)
{
InvokeDeviceConnectedEvent(i, currState.isConnected);
}
}
}
}
}