v2019.08.19

This commit is contained in:
pypy
2019-08-19 23:21:08 +09:00
parent d725c8f1e3
commit 26b371fd0f
19 changed files with 768 additions and 515 deletions

415
VRCXVR.cs
View File

@@ -21,7 +21,7 @@ namespace VRCX
{
public static class VRCXVR
{
private static readonly object m_LockObject = new object();
private static readonly ReaderWriterLockSlim m_Lock = new ReaderWriterLockSlim();
private static List<string[]> m_Devices = new List<string[]>();
private static Thread m_Thread;
private static Device m_Device;
@@ -29,6 +29,7 @@ namespace VRCX
private static Texture2D m_Texture2;
private static Browser m_Browser1;
private static Browser m_Browser2;
private static bool m_Active;
private static float[] m_Rotation = { 0f, 0f, 0f };
private static float[] m_Translation = { 0f, 0f, 0f };
private static float[] m_L_Translation = { -7f / 100f, -5f / 100f, 6f / 100f };
@@ -38,7 +39,7 @@ namespace VRCX
// NOTE
// 메모리 릭 때문에 미리 생성해놓고 계속 사용함
public static void Setup()
public static void Init()
{
m_Device = new Device(DriverType.Hardware, DeviceCreationFlags.SingleThreaded | DeviceCreationFlags.BgraSupport);
m_Texture1 = new Texture2D(m_Device, new Texture2DDescription()
@@ -67,38 +68,139 @@ namespace VRCX
});
m_Browser1 = new Browser(m_Texture1, Application.StartupPath + "/html/vr.html?1");
m_Browser2 = new Browser(m_Texture2, Application.StartupPath + "/html/vr.html?2");
}
public static void Start()
{
lock (m_LockObject)
m_Thread = new Thread(() =>
{
if (m_Thread == null)
var active = false;
var e = new VREvent_t();
var nextInit = DateTime.MinValue;
var nextDeviceUpdate = DateTime.MinValue;
var nextOverlay = DateTime.MinValue;
var overlayIndex = OpenVR.k_unTrackedDeviceIndexInvalid;
var overlayVisible1 = false;
var overlayVisible2 = false;
var dashboardHandle = 0UL;
var overlayHandle1 = 0UL;
var overlayHandle2 = 0UL;
while (m_Thread != null)
{
m_Thread = new Thread(ThreadProc);
m_Thread.Start();
}
}
}
public static void Stop()
{
lock (m_LockObject)
{
var thread = m_Thread;
if (thread != null)
{
m_Thread = null;
try
{
thread.Interrupt();
thread.Join();
Thread.Sleep(10);
}
catch
{
// ThreadInterruptedException
}
if (m_Active)
{
m_Browser1.Render();
m_Browser2.Render();
var system = OpenVR.System;
if (system == null)
{
if (DateTime.Now.CompareTo(nextInit) <= 0)
{
continue;
}
var _err = EVRInitError.None;
system = OpenVR.Init(ref _err, EVRApplicationType.VRApplication_Overlay);
nextInit = DateTime.Now.AddSeconds(5);
if (system == null)
{
continue;
}
active = true;
}
while (system.PollNextEvent(ref e, (uint)Marshal.SizeOf(e)))
{
var type = (EVREventType)e.eventType;
if (type == EVREventType.VREvent_Quit)
{
active = false;
OpenVR.Shutdown();
nextInit = DateTime.Now.AddSeconds(10);
system = null;
break;
}
}
if (system != null)
{
if (DateTime.Now.CompareTo(nextDeviceUpdate) >= 0)
{
overlayIndex = OpenVR.k_unTrackedDeviceIndexInvalid;
UpdateDevices(system, ref overlayIndex);
if (overlayIndex != OpenVR.k_unTrackedDeviceIndexInvalid)
{
nextOverlay = DateTime.Now.AddSeconds(10);
}
nextDeviceUpdate = DateTime.Now.AddSeconds(0.1);
}
var overlay = OpenVR.Overlay;
if (overlay != null)
{
var dashboardVisible = overlay.IsDashboardVisible();
var err = ProcessDashboard(overlay, ref dashboardHandle, dashboardVisible);
if (err != EVROverlayError.None &&
dashboardHandle != 0)
{
overlay.DestroyOverlay(dashboardHandle);
dashboardHandle = 0;
}
err = ProcessOverlay1(overlay, ref overlayHandle1, ref overlayVisible1, dashboardVisible, overlayIndex, nextOverlay);
if (err != EVROverlayError.None &&
overlayHandle1 != 0)
{
overlay.DestroyOverlay(overlayHandle1);
overlayHandle1 = 0;
}
err = ProcessOverlay2(overlay, ref overlayHandle2, ref overlayVisible2, dashboardVisible);
if (err != EVROverlayError.None &&
overlayHandle2 != 0)
{
overlay.DestroyOverlay(overlayHandle2);
overlayHandle2 = 0;
}
}
}
}
else if (active)
{
active = false;
OpenVR.Shutdown();
m_Lock.EnterWriteLock();
try
{
m_Devices.Clear();
}
finally
{
m_Lock.ExitWriteLock();
}
}
}
}
})
{
IsBackground = true
};
m_Thread.Start();
}
public static void Exit()
{
var T = m_Thread;
m_Thread = null;
T.Interrupt();
T.Join();
m_Browser2.Dispose();
m_Browser1.Dispose();
m_Texture2.Dispose();
m_Texture1.Dispose();
m_Device.Dispose();
}
public static void SetActive(bool active)
{
m_Active = active;
}
public static void Refresh()
@@ -109,86 +211,105 @@ namespace VRCX
public static string[][] GetDevices()
{
lock (m_Devices)
m_Lock.EnterReadLock();
try
{
return m_Devices.ToArray();
}
finally
{
m_Lock.ExitReadLock();
}
}
private static void UpdateDevices(CVRSystem system, ref uint trackingIndex)
private static void UpdateDevices(CVRSystem system, ref uint overlayIndex)
{
lock (m_Devices)
m_Lock.EnterWriteLock();
try
{
m_Devices.Clear();
var sb = new StringBuilder(256);
var state = new VRControllerState_t();
for (var i = 0u; i < OpenVR.k_unMaxTrackedDeviceCount; ++i)
}
finally
{
m_Lock.ExitWriteLock();
}
var sb = new StringBuilder(256);
var state = new VRControllerState_t();
for (var i = 0u; i < OpenVR.k_unMaxTrackedDeviceCount; ++i)
{
var devClass = system.GetTrackedDeviceClass(i);
if (devClass == ETrackedDeviceClass.Controller ||
devClass == ETrackedDeviceClass.GenericTracker)
{
var devClass = system.GetTrackedDeviceClass(i);
if (devClass == ETrackedDeviceClass.Controller ||
devClass == ETrackedDeviceClass.GenericTracker)
var err = ETrackedPropertyError.TrackedProp_Success;
var batteryPercentage = system.GetFloatTrackedDeviceProperty(i, ETrackedDeviceProperty.Prop_DeviceBatteryPercentage_Float, ref err);
if (err != ETrackedPropertyError.TrackedProp_Success)
{
var err = ETrackedPropertyError.TrackedProp_Success;
var batteryPercentage = system.GetFloatTrackedDeviceProperty(i, ETrackedDeviceProperty.Prop_DeviceBatteryPercentage_Float, ref err);
if (err != ETrackedPropertyError.TrackedProp_Success)
{
batteryPercentage = 1f;
}
sb.Clear();
system.GetStringTrackedDeviceProperty(i, ETrackedDeviceProperty.Prop_TrackingSystemName_String, sb, (uint)sb.Capacity, ref err);
var isOculus = sb.ToString().IndexOf("oculus", StringComparison.OrdinalIgnoreCase) >= 0;
// Oculus : B/Y, Bit 1, Mask 2
// Oculus : A/X, Bit 7, Mask 128
// Vive : Menu, Bit 1, Mask 2,
// Vive : Grip, Bit 2, Mask 4
var role = system.GetControllerRoleForTrackedDeviceIndex(i);
if (role == ETrackedControllerRole.LeftHand ||
role == ETrackedControllerRole.RightHand)
{
if (system.GetControllerState(i, ref state, (uint)Marshal.SizeOf(state)) &&
(state.ulButtonPressed & (isOculus ? 2u : 4u)) != 0)
{
if (role == ETrackedControllerRole.LeftHand)
{
Array.Copy(m_L_Translation, m_Translation, 3);
Array.Copy(m_L_Rotation, m_Rotation, 3);
}
else
{
Array.Copy(m_R_Translation, m_Translation, 3);
Array.Copy(m_R_Rotation, m_Rotation, 3);
}
trackingIndex = i;
}
}
var type = string.Empty;
if (devClass == ETrackedDeviceClass.Controller)
batteryPercentage = 1f;
}
sb.Clear();
system.GetStringTrackedDeviceProperty(i, ETrackedDeviceProperty.Prop_TrackingSystemName_String, sb, (uint)sb.Capacity, ref err);
var isOculus = sb.ToString().IndexOf("oculus", StringComparison.OrdinalIgnoreCase) >= 0;
// Oculus : B/Y, Bit 1, Mask 2
// Oculus : A/X, Bit 7, Mask 128
// Vive : Menu, Bit 1, Mask 2,
// Vive : Grip, Bit 2, Mask 4
var role = system.GetControllerRoleForTrackedDeviceIndex(i);
if (role == ETrackedControllerRole.LeftHand ||
role == ETrackedControllerRole.RightHand)
{
if (system.GetControllerState(i, ref state, (uint)Marshal.SizeOf(state)) &&
(state.ulButtonPressed & (isOculus ? 2u : 4u)) != 0)
{
if (role == ETrackedControllerRole.LeftHand)
{
type = "leftController";
}
else if (role == ETrackedControllerRole.RightHand)
{
type = "rightController";
Array.Copy(m_L_Translation, m_Translation, 3);
Array.Copy(m_L_Rotation, m_Rotation, 3);
}
else
{
type = "controller";
Array.Copy(m_R_Translation, m_Translation, 3);
Array.Copy(m_R_Rotation, m_Rotation, 3);
}
overlayIndex = i;
}
else if (devClass == ETrackedDeviceClass.GenericTracker)
}
var type = string.Empty;
if (devClass == ETrackedDeviceClass.Controller)
{
if (role == ETrackedControllerRole.LeftHand)
{
type = "tracker";
type = "leftController";
}
m_Devices.Add(new[]
else if (role == ETrackedControllerRole.RightHand)
{
type,
system.IsTrackedDeviceConnected(i)
? "connected"
: "disconnected",
(batteryPercentage * 100).ToString()
});
type = "rightController";
}
else
{
type = "controller";
}
}
else if (devClass == ETrackedDeviceClass.GenericTracker)
{
type = "tracker";
}
var item = new[]
{
type,
system.IsTrackedDeviceConnected(i)
? "connected"
: "disconnected",
(batteryPercentage * 100).ToString()
};
m_Lock.EnterWriteLock();
try
{
m_Devices.Add(item);
}
finally
{
m_Lock.ExitWriteLock();
}
}
}
@@ -267,7 +388,7 @@ namespace VRCX
return err;
}
private static EVROverlayError ProcessOverlay1(CVROverlay overlay, ref ulong overlayHandle, ref bool overlayVisible, bool dashboardVisible, uint trackingIndex, DateTime nextRender)
private static EVROverlayError ProcessOverlay1(CVROverlay overlay, ref ulong overlayHandle, ref bool overlayVisible, bool dashboardVisible, uint overlayIndex, DateTime nextOverlay)
{
var err = EVROverlayError.None;
@@ -304,7 +425,7 @@ namespace VRCX
}
}
if (trackingIndex != OpenVR.k_unTrackedDeviceIndexInvalid)
if (overlayIndex != OpenVR.k_unTrackedDeviceIndexInvalid)
{
// http://www.opengl-tutorial.org/beginners-tutorials/tutorial-3-matrices
// Scaling-Rotation-Translation
@@ -328,7 +449,7 @@ namespace VRCX
m10 = m.M33,
m11 = m.M43,
};
err = overlay.SetOverlayTransformTrackedDeviceRelative(overlayHandle, trackingIndex, ref hm34);
err = overlay.SetOverlayTransformTrackedDeviceRelative(overlayHandle, overlayIndex, ref hm34);
if (err != EVROverlayError.None)
{
return err;
@@ -336,7 +457,7 @@ namespace VRCX
}
if (!dashboardVisible &&
DateTime.Now.CompareTo(nextRender) <= 0)
DateTime.Now.CompareTo(nextOverlay) <= 0)
{
var texture = new Texture_t
{
@@ -462,123 +583,5 @@ namespace VRCX
return err;
}
private static void ThreadProc()
{
var e = new VREvent_t();
var nextOpenVRInit = DateTime.MinValue;
var nextDeviceInfoUpdate = DateTime.MinValue;
var nextRender = DateTime.MinValue;
var trackingIndex = OpenVR.k_unTrackedDeviceIndexInvalid;
var overlayVisible1 = false;
var overlayVisible2 = false;
var dashboardHandle = 0UL;
var overlayHandle1 = 0UL;
var overlayHandle2 = 0UL;
while (m_Thread != null)
{
m_Browser1.Render();
m_Browser2.Render();
try
{
Thread.Sleep(10);
}
catch
{
// ThreadInterruptedException
}
var system = OpenVR.System;
if (system == null)
{
if (DateTime.Now.CompareTo(nextOpenVRInit) < 0)
{
continue;
}
var _err = EVRInitError.None;
system = OpenVR.Init(ref _err, EVRApplicationType.VRApplication_Overlay);
nextOpenVRInit = DateTime.Now.AddSeconds(5);
if (system == null)
{
continue;
}
}
while (system.PollNextEvent(ref e, (uint)Marshal.SizeOf(e)))
{
var type = (EVREventType)e.eventType;
if (type == EVREventType.VREvent_Quit)
{
OpenVR.Shutdown();
// VRChat이 실행 중일 때만 켜는 옵션이 생겨서 시간을 줄임
nextOpenVRInit = DateTime.Now.AddSeconds(10);
system = null;
break;
}
}
if (system == null)
{
continue;
}
if (DateTime.Now.CompareTo(nextDeviceInfoUpdate) >= 0)
{
trackingIndex = OpenVR.k_unTrackedDeviceIndexInvalid;
UpdateDevices(system, ref trackingIndex);
if (trackingIndex != OpenVR.k_unTrackedDeviceIndexInvalid)
{
nextRender = DateTime.Now.AddSeconds(10);
}
nextDeviceInfoUpdate = DateTime.Now.AddSeconds(0.1);
}
var overlay = OpenVR.Overlay;
if (overlay == null)
{
continue;
}
var dashboardVisible = overlay.IsDashboardVisible();
var err = ProcessDashboard(overlay, ref dashboardHandle, dashboardVisible);
if (err != EVROverlayError.None &&
dashboardHandle != 0)
{
overlay.DestroyOverlay(dashboardHandle);
dashboardHandle = 0;
}
err = ProcessOverlay1(overlay, ref overlayHandle1, ref overlayVisible1, dashboardVisible, trackingIndex, nextRender);
if (err != EVROverlayError.None &&
overlayHandle1 != 0)
{
overlay.DestroyOverlay(overlayHandle1);
overlayHandle1 = 0;
}
err = ProcessOverlay2(overlay, ref overlayHandle2, ref overlayVisible2, dashboardVisible);
if (err != EVROverlayError.None &&
overlayHandle2 != 0)
{
overlay.DestroyOverlay(overlayHandle2);
overlayHandle2 = 0;
}
}
lock (m_Devices)
{
m_Devices.Clear();
}
OpenVR.Shutdown();
}
}
}