Disable VR Overlay GPU Acceleration

This commit is contained in:
Natsumi
2024-11-18 16:52:11 +13:00
parent 78dc8ea42d
commit 5ed92aed82
12 changed files with 1065 additions and 28 deletions

View File

@@ -208,17 +208,17 @@ namespace VRCX
public void SetVR(bool active, bool hmdOverlay, bool wristOverlay, bool menuButton, int overlayHand)
{
VRCXVR.Instance.SetActive(active, hmdOverlay, wristOverlay, menuButton, overlayHand);
Program.VRCXVRInstance.SetActive(active, hmdOverlay, wristOverlay, menuButton, overlayHand);
}
public void RefreshVR()
{
VRCXVR.Instance.Restart();
Program.VRCXVRInstance.Restart();
}
public void RestartVR()
{
VRCXVR.Instance.Restart();
Program.VRCXVRInstance.Restart();
}
public void SetZoom(double zoomLevel)
@@ -355,18 +355,12 @@ namespace VRCX
public void ExecuteVrFeedFunction(string function, string json)
{
if (VRCXVR._wristOverlay == null) return;
if (VRCXVR._wristOverlay.IsLoading)
VRCXVR.Instance.Restart();
VRCXVR._wristOverlay.ExecuteScriptAsync($"$app.{function}", json);
Program.VRCXVRInstance.ExecuteVrFeedFunction(function, json);
}
public void ExecuteVrOverlayFunction(string function, string json)
{
if (VRCXVR._hmdOverlay == null) return;
if (VRCXVR._hmdOverlay.IsLoading)
VRCXVR.Instance.Restart();
VRCXVR._hmdOverlay.ExecuteScriptAsync($"$app.{function}", json);
Program.VRCXVRInstance.ExecuteVrOverlayFunction(function, json);
}
/// <summary>

View File

@@ -47,7 +47,7 @@ namespace VRCX
/// <returns>An array of arrays containing information about the connected VR devices.</returns>
public string[][] GetVRDevices()
{
return VRCXVR.Instance.GetDevices();
return Program.VRCXVRInstance.GetDevices();
}
/// <summary>

View File

@@ -37,7 +37,7 @@ namespace VRCX
isSteamVRRunning = true;
}
var isHmdAfk = VRCXVR.Instance.IsHmdAfk;
var isHmdAfk = Program.VRCXVRInstance.IsHmdAfk;
// TODO: fix this throwing an exception for being called before the browser is ready. somehow it gets past the checks
if (MainForm.Instance?.Browser != null && !MainForm.Instance.Browser.IsLoading && MainForm.Instance.Browser.CanExecuteJavascriptInMainFrame)

View File

@@ -0,0 +1,206 @@
// Copyright(c) 2019-2022 pypy, Natsumi and individual contributors.
// All rights reserved.
//
// This work is licensed under the terms of the MIT license.
// For a copy, see <https://opensource.org/licenses/MIT>.
using CefSharp;
using CefSharp.Enums;
using CefSharp.OffScreen;
using CefSharp.Structs;
using SharpDX.Direct3D11;
using System;
using System.Runtime.InteropServices;
using System.Threading;
using Range = CefSharp.Structs.Range;
namespace VRCX
{
public class OffScreenBrowserLegacy : ChromiumWebBrowser, IRenderHandler
{
private readonly ReaderWriterLockSlim _paintBufferLock;
private GCHandle _paintBuffer;
private int _width;
private int _height;
public OffScreenBrowserLegacy(string address, int width, int height)
: base(
address,
new BrowserSettings()
{
DefaultEncoding = "UTF-8"
}
)
{
_paintBufferLock = new ReaderWriterLockSlim();
Size = new System.Drawing.Size(width, height);
RenderHandler = this;
JavascriptBindings.ApplyVrJavascriptBindings(JavascriptObjectRepository);
}
public new void Dispose()
{
RenderHandler = null;
base.Dispose();
_paintBufferLock.EnterWriteLock();
try
{
if (_paintBuffer.IsAllocated == true)
{
_paintBuffer.Free();
}
}
finally
{
_paintBufferLock.ExitWriteLock();
}
_paintBufferLock.Dispose();
}
public void RenderToTexture(Texture2D texture)
{
// Safeguard against uninitialized texture
if (texture == null)
return;
_paintBufferLock.EnterReadLock();
try
{
if (_width > 0 &&
_height > 0)
{
var context = texture.Device.ImmediateContext;
var dataBox = context.MapSubresource(
texture,
0,
MapMode.WriteDiscard,
MapFlags.None
);
if (dataBox.IsEmpty == false)
{
var sourcePtr = _paintBuffer.AddrOfPinnedObject();
var destinationPtr = dataBox.DataPointer;
var pitch = _width * 4;
var rowPitch = dataBox.RowPitch;
if (pitch == rowPitch)
{
WinApi.RtlCopyMemory(
destinationPtr,
sourcePtr,
(uint)(_width * _height * 4)
);
}
else
{
for (var y = _height; y > 0; --y)
{
WinApi.RtlCopyMemory(
destinationPtr,
sourcePtr,
(uint)pitch
);
sourcePtr += pitch;
destinationPtr += rowPitch;
}
}
}
context.UnmapSubresource(texture, 0);
}
}
finally
{
_paintBufferLock.ExitReadLock();
}
}
ScreenInfo? IRenderHandler.GetScreenInfo()
{
return null;
}
bool IRenderHandler.GetScreenPoint(int viewX, int viewY, out int screenX, out int screenY)
{
screenX = viewX;
screenY = viewY;
return false;
}
Rect IRenderHandler.GetViewRect()
{
return new Rect(0, 0, Size.Width, Size.Height);
}
void IRenderHandler.OnAcceleratedPaint(PaintElementType type, Rect dirtyRect, AcceleratedPaintInfo paintInfo)
{
// NOT USED
}
void IRenderHandler.OnCursorChange(IntPtr cursor, CursorType type, CursorInfo customCursorInfo)
{
}
void IRenderHandler.OnImeCompositionRangeChanged(Range selectedRange, Rect[] characterBounds)
{
}
void IRenderHandler.OnPaint(PaintElementType type, Rect dirtyRect, IntPtr buffer, int width, int height)
{
if (type == PaintElementType.View)
{
_paintBufferLock.EnterWriteLock();
try
{
if (_width != width ||
_height != height)
{
_width = width;
_height = height;
if (_paintBuffer.IsAllocated == true)
{
_paintBuffer.Free();
}
_paintBuffer = GCHandle.Alloc(
new byte[_width * _height * 4],
GCHandleType.Pinned
);
}
WinApi.RtlCopyMemory(
_paintBuffer.AddrOfPinnedObject(),
buffer,
(uint)(width * height * 4)
);
}
finally
{
_paintBufferLock.ExitWriteLock();
}
}
}
void IRenderHandler.OnPopupShow(bool show)
{
}
void IRenderHandler.OnPopupSize(Rect rect)
{
}
void IRenderHandler.OnVirtualKeyboardRequested(IBrowser browser, TextInputMode inputMode)
{
}
bool IRenderHandler.StartDragging(IDragData dragData, DragOperationsMask mask, int x, int y)
{
return false;
}
void IRenderHandler.UpdateDragCursor(DragOperationsMask operation)
{
}
}
}

View File

@@ -23,9 +23,9 @@ using Device4 = SharpDX.Direct3D11.Device4;
namespace VRCX
{
public class VRCXVR
public class VRCXVR : VRCXVRInterface
{
public static VRCXVR Instance;
public static VRCXVRInterface Instance;
private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
private static readonly float[] _rotation = { 0f, 0f, 0f };
private static readonly float[] _translation = { 0f, 0f, 0f };
@@ -33,8 +33,8 @@ namespace VRCX
private static readonly float[] _translationRight = { 7f / 100f, -5f / 100f, 6f / 100f };
private static readonly float[] _rotationLeft = { 90f * (float)(Math.PI / 180f), 90f * (float)(Math.PI / 180f), -90f * (float)(Math.PI / 180f) };
private static readonly float[] _rotationRight = { -90f * (float)(Math.PI / 180f), -90f * (float)(Math.PI / 180f), -90f * (float)(Math.PI / 180f) };
public static OffScreenBrowser _wristOverlay;
public static OffScreenBrowser _hmdOverlay;
private static OffScreenBrowser _wristOverlay;
private static OffScreenBrowser _hmdOverlay;
private readonly List<string[]> _deviceList;
private readonly ReaderWriterLockSlim _deviceListLock;
private bool _active;
@@ -74,12 +74,12 @@ namespace VRCX
// NOTE
// 메모리 릭 때문에 미리 생성해놓고 계속 사용함
internal void Init()
public override void Init()
{
_thread.Start();
}
internal void Exit()
public override void Exit()
{
var thread = _thread;
_thread = null;
@@ -87,7 +87,7 @@ namespace VRCX
thread?.Join();
}
public void Restart()
public override void Restart()
{
Exit();
Instance = new VRCXVR();
@@ -327,7 +327,7 @@ namespace VRCX
_device?.Dispose();
}
public void SetActive(bool active, bool hmdOverlay, bool wristOverlay, bool menuButton, int overlayHand)
public override void SetActive(bool active, bool hmdOverlay, bool wristOverlay, bool menuButton, int overlayHand)
{
_active = active;
_hmdOverlayActive = hmdOverlay;
@@ -352,13 +352,13 @@ namespace VRCX
_wristOverlayWasActive = _wristOverlayActive;
}
public void Refresh()
public override void Refresh()
{
_wristOverlay.Reload();
_hmdOverlay.Reload();
}
public string[][] GetDevices()
public override string[][] GetDevices()
{
_deviceListLock.EnterReadLock();
try
@@ -371,7 +371,7 @@ namespace VRCX
}
}
internal void UpdateDevices(CVRSystem system, ref uint overlayIndex)
private void UpdateDevices(CVRSystem system, ref uint overlayIndex)
{
_deviceListLock.EnterWriteLock();
try
@@ -833,5 +833,21 @@ namespace VRCX
return err;
}
public override void ExecuteVrFeedFunction(string function, string json)
{
if (_wristOverlay == null) return;
if (_wristOverlay.IsLoading)
Restart();
_wristOverlay.ExecuteScriptAsync($"$app.{function}", json);
}
public override void ExecuteVrOverlayFunction(string function, string json)
{
if (_hmdOverlay == null) return;
if (_hmdOverlay.IsLoading)
Restart();
_hmdOverlay.ExecuteScriptAsync($"$app.{function}", json);
}
}
}

View File

@@ -0,0 +1,15 @@
namespace VRCX;
public abstract class VRCXVRInterface
{
public bool IsHmdAfk;
public abstract void Init();
public abstract void Exit();
public abstract void Refresh();
public abstract void Restart();
public abstract void SetActive(bool active, bool hmdOverlay, bool wristOverlay, bool menuButton, int overlayHand);
public abstract string[][] GetDevices();
public abstract void ExecuteVrFeedFunction(string function, string json);
public abstract void ExecuteVrOverlayFunction(string function, string json);
}

View File

@@ -0,0 +1,781 @@
// Copyright(c) 2019-2022 pypy, Natsumi and individual contributors.
// All rights reserved.
//
// This work is licensed under the terms of the MIT license.
// For a copy, see <https://opensource.org/licenses/MIT>.
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using CefSharp;
using SharpDX;
using SharpDX.Direct3D11;
using SharpDX.DXGI;
using Valve.VR;
using Device = SharpDX.Direct3D11.Device;
namespace VRCX
{
public class VRCXVRLegacy : VRCXVRInterface
{
public static VRCXVRInterface Instance;
private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
private static readonly float[] _rotation = { 0f, 0f, 0f };
private static readonly float[] _translation = { 0f, 0f, 0f };
private static readonly float[] _translationLeft = { -7f / 100f, -5f / 100f, 6f / 100f };
private static readonly float[] _translationRight = { 7f / 100f, -5f / 100f, 6f / 100f };
private static readonly float[] _rotationLeft = { 90f * (float)(Math.PI / 180f), 90f * (float)(Math.PI / 180f), -90f * (float)(Math.PI / 180f) };
private static readonly float[] _rotationRight = { -90f * (float)(Math.PI / 180f), -90f * (float)(Math.PI / 180f), -90f * (float)(Math.PI / 180f) };
private static OffScreenBrowserLegacy _wristOverlay;
private static OffScreenBrowserLegacy _hmdOverlay;
private readonly List<string[]> _deviceList;
private readonly ReaderWriterLockSlim _deviceListLock;
private bool _active;
private Device _device;
private bool _hmdOverlayActive;
private bool _menuButton;
private int _overlayHand;
private Texture2D _texture1;
private Texture2D _texture2;
private Thread _thread;
private bool _wristOverlayActive;
private DateTime _nextOverlayUpdate;
public bool IsHmdAfk { get; private set; }
static VRCXVRLegacy()
{
Instance = new VRCXVRLegacy();
}
public VRCXVRLegacy()
{
_deviceListLock = new ReaderWriterLockSlim();
_deviceList = new List<string[]>();
_thread = new Thread(ThreadLoop)
{
IsBackground = true
};
}
// NOTE
// 메모리 릭 때문에 미리 생성해놓고 계속 사용함
public override void Init()
{
_thread.Start();
}
public override void Exit()
{
var thread = _thread;
_thread = null;
thread?.Interrupt();
thread?.Join();
}
public override void Restart()
{
Exit();
Instance = new VRCXVRLegacy();
Instance.Init();
MainForm.Instance.Browser.ExecuteScriptAsync("console.log('VRCXVR Restarted');");
}
private void SetupTextures()
{
Factory f = new Factory1();
_device = new Device(f.GetAdapter(OpenVR.System.GetD3D9AdapterIndex()),
DeviceCreationFlags.SingleThreaded | DeviceCreationFlags.BgraSupport);
_texture1?.Dispose();
_texture1 = new Texture2D(
_device,
new Texture2DDescription
{
Width = 512,
Height = 512,
MipLevels = 1,
ArraySize = 1,
Format = Format.B8G8R8A8_UNorm,
SampleDescription = new SampleDescription(1, 0),
Usage = ResourceUsage.Dynamic,
BindFlags = BindFlags.ShaderResource,
CpuAccessFlags = CpuAccessFlags.Write
}
);
_texture2?.Dispose();
_texture2 = new Texture2D(
_device,
new Texture2DDescription
{
Width = 1024,
Height = 1024,
MipLevels = 1,
ArraySize = 1,
Format = Format.B8G8R8A8_UNorm,
SampleDescription = new SampleDescription(1, 0),
Usage = ResourceUsage.Dynamic,
BindFlags = BindFlags.ShaderResource,
CpuAccessFlags = CpuAccessFlags.Write
}
);
}
private void ThreadLoop()
{
var active = false;
var e = new VREvent_t();
var nextInit = DateTime.MinValue;
var nextDeviceUpdate = DateTime.MinValue;
_nextOverlayUpdate = DateTime.MinValue;
var overlayIndex = OpenVR.k_unTrackedDeviceIndexInvalid;
var overlayVisible1 = false;
var overlayVisible2 = false;
var dashboardHandle = 0UL;
var overlayHandle1 = 0UL;
var overlayHandle2 = 0UL;
_wristOverlay = new OffScreenBrowserLegacy(
"file://vrcx/vr.html?1",
512,
512
);
_hmdOverlay = new OffScreenBrowserLegacy(
"file://vrcx/vr.html?2",
1024,
1024
);
while (_thread != null)
{
if (_wristOverlayActive)
_wristOverlay.RenderToTexture(_texture1);
if (_hmdOverlayActive)
_hmdOverlay.RenderToTexture(_texture2);
try
{
Thread.Sleep(32);
}
catch (ThreadInterruptedException)
{
}
if (_active)
{
var system = OpenVR.System;
if (system == null)
{
if (DateTime.UtcNow.CompareTo(nextInit) <= 0)
{
continue;
}
var _err = EVRInitError.None;
system = OpenVR.Init(ref _err, EVRApplicationType.VRApplication_Background);
nextInit = DateTime.UtcNow.AddSeconds(5);
if (system == null)
{
continue;
}
active = true;
SetupTextures();
}
while (system.PollNextEvent(ref e, (uint)Marshal.SizeOf(e)))
{
var type = (EVREventType)e.eventType;
if (type == EVREventType.VREvent_Quit)
{
active = false;
IsHmdAfk = false;
OpenVR.Shutdown();
nextInit = DateTime.UtcNow.AddSeconds(10);
system = null;
break;
}
}
if (system != null)
{
if (DateTime.UtcNow.CompareTo(nextDeviceUpdate) >= 0)
{
overlayIndex = OpenVR.k_unTrackedDeviceIndexInvalid;
UpdateDevices(system, ref overlayIndex);
if (overlayIndex != OpenVR.k_unTrackedDeviceIndexInvalid)
{
_nextOverlayUpdate = DateTime.UtcNow.AddSeconds(10);
}
nextDeviceUpdate = DateTime.UtcNow.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;
logger.Error(err);
}
err = ProcessOverlay1(overlay, ref overlayHandle1, ref overlayVisible1, dashboardVisible, overlayIndex);
if (err != EVROverlayError.None &&
overlayHandle1 != 0)
{
overlay.DestroyOverlay(overlayHandle1);
overlayHandle1 = 0;
logger.Error(err);
}
err = ProcessOverlay2(overlay, ref overlayHandle2, ref overlayVisible2, dashboardVisible);
if (err != EVROverlayError.None &&
overlayHandle2 != 0)
{
overlay.DestroyOverlay(overlayHandle2);
overlayHandle2 = 0;
logger.Error(err);
}
}
}
}
else if (active)
{
active = false;
IsHmdAfk = false;
OpenVR.Shutdown();
_deviceListLock.EnterWriteLock();
try
{
_deviceList.Clear();
}
finally
{
_deviceListLock.ExitWriteLock();
}
}
}
_hmdOverlay?.Dispose();
_wristOverlay?.Dispose();
_texture2?.Dispose();
_texture1?.Dispose();
_device?.Dispose();
}
public override void SetActive(bool active, bool hmdOverlay, bool wristOverlay, bool menuButton, int overlayHand)
{
_active = active;
_hmdOverlayActive = hmdOverlay;
_wristOverlayActive = wristOverlay;
_menuButton = menuButton;
_overlayHand = overlayHand;
}
public override void Refresh()
{
_wristOverlay.Reload();
_hmdOverlay.Reload();
}
public override string[][] GetDevices()
{
_deviceListLock.EnterReadLock();
try
{
return _deviceList.ToArray();
}
finally
{
_deviceListLock.ExitReadLock();
}
}
private void UpdateDevices(CVRSystem system, ref uint overlayIndex)
{
_deviceListLock.EnterWriteLock();
try
{
_deviceList.Clear();
}
finally
{
_deviceListLock.ExitWriteLock();
}
var sb = new StringBuilder(256);
var state = new VRControllerState_t();
var poses = new TrackedDevicePose_t[OpenVR.k_unMaxTrackedDeviceCount];
system.GetDeviceToAbsoluteTrackingPose(ETrackingUniverseOrigin.TrackingUniverseStanding, 0, poses);
for (var i = 0u; i < OpenVR.k_unMaxTrackedDeviceCount; ++i)
{
var devClass = system.GetTrackedDeviceClass(i);
switch (devClass)
{
case ETrackedDeviceClass.HMD:
var success = system.GetControllerState(i, ref state, (uint)Marshal.SizeOf(state));
if (!success)
break; // this fails while SteamVR overlay is open
var prox = state.ulButtonPressed & (1UL << ((int)EVRButtonId.k_EButton_ProximitySensor));
var isHmdAfk = prox == 0;
if (isHmdAfk != IsHmdAfk)
{
IsHmdAfk = isHmdAfk;
AppApi.Instance.CheckGameRunning();
}
var headsetErr = ETrackedPropertyError.TrackedProp_Success;
var headsetBatteryPercentage = system.GetFloatTrackedDeviceProperty(i, ETrackedDeviceProperty.Prop_DeviceBatteryPercentage_Float, ref headsetErr);
if (headsetErr != ETrackedPropertyError.TrackedProp_Success)
{
// Headset has no battery, skip displaying it
break;
}
var headset = new[]
{
"headset",
system.IsTrackedDeviceConnected(i)
? "connected"
: "disconnected",
// Currently neither VD or SteamLink report charging state
"discharging",
(headsetBatteryPercentage * 100).ToString(),
poses[i].eTrackingResult.ToString()
};
_deviceListLock.EnterWriteLock();
try
{
_deviceList.Add(headset);
}
finally
{
_deviceListLock.ExitWriteLock();
}
break;
case ETrackedDeviceClass.Controller:
case ETrackedDeviceClass.GenericTracker:
case ETrackedDeviceClass.TrackingReference:
{
var err = ETrackedPropertyError.TrackedProp_Success;
var batteryPercentage = system.GetFloatTrackedDeviceProperty(i, ETrackedDeviceProperty.Prop_DeviceBatteryPercentage_Float, ref err);
if (err != ETrackedPropertyError.TrackedProp_Success)
{
batteryPercentage = 1f;
}
err = ETrackedPropertyError.TrackedProp_Success;
var isCharging = system.GetBoolTrackedDeviceProperty(i, ETrackedDeviceProperty.Prop_DeviceIsCharging_Bool, ref err);
if (err != ETrackedPropertyError.TrackedProp_Success)
{
isCharging = false;
}
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 (_overlayHand == 0 ||
(_overlayHand == 1 && role == ETrackedControllerRole.LeftHand) ||
(_overlayHand == 2 && role == ETrackedControllerRole.RightHand))
{
if (system.GetControllerState(i, ref state, (uint)Marshal.SizeOf(state)) &&
(state.ulButtonPressed & (_menuButton ? 2u : isOculus ? 128u : 4u)) != 0)
{
_nextOverlayUpdate = DateTime.MinValue;
if (role == ETrackedControllerRole.LeftHand)
{
Array.Copy(_translationLeft, _translation, 3);
Array.Copy(_rotationLeft, _rotation, 3);
}
else
{
Array.Copy(_translationRight, _translation, 3);
Array.Copy(_rotationRight, _rotation, 3);
}
overlayIndex = i;
}
}
}
var type = string.Empty;
if (devClass == ETrackedDeviceClass.Controller)
{
if (role == ETrackedControllerRole.LeftHand)
{
type = "leftController";
}
else if (role == ETrackedControllerRole.RightHand)
{
type = "rightController";
}
else
{
type = "controller";
}
}
else if (devClass == ETrackedDeviceClass.GenericTracker)
{
type = "tracker";
}
else if (devClass == ETrackedDeviceClass.TrackingReference)
{
type = "base";
}
var item = new[]
{
type,
system.IsTrackedDeviceConnected(i)
? "connected"
: "disconnected",
isCharging
? "charging"
: "discharging",
(batteryPercentage * 100).ToString(),
poses[i].eTrackingResult.ToString()
};
_deviceListLock.EnterWriteLock();
try
{
_deviceList.Add(item);
}
finally
{
_deviceListLock.ExitWriteLock();
}
break;
}
}
}
}
internal EVROverlayError ProcessDashboard(CVROverlay overlay, ref ulong dashboardHandle, bool dashboardVisible)
{
var err = EVROverlayError.None;
if (dashboardHandle == 0)
{
err = overlay.FindOverlay("VRCX", ref dashboardHandle);
if (err != EVROverlayError.None)
{
if (err != EVROverlayError.UnknownOverlay)
{
return err;
}
ulong thumbnailHandle = 0;
err = overlay.CreateDashboardOverlay("VRCX", "VRCX", ref dashboardHandle, ref thumbnailHandle);
if (err != EVROverlayError.None)
{
return err;
}
var iconPath = Path.Combine(Program.BaseDirectory, "VRCX.png");
err = overlay.SetOverlayFromFile(thumbnailHandle, iconPath);
if (err != EVROverlayError.None)
{
return err;
}
err = overlay.SetOverlayWidthInMeters(dashboardHandle, 1.5f);
if (err != EVROverlayError.None)
{
return err;
}
err = overlay.SetOverlayInputMethod(dashboardHandle, VROverlayInputMethod.Mouse);
if (err != EVROverlayError.None)
{
return err;
}
}
}
var e = new VREvent_t();
while (overlay.PollNextOverlayEvent(dashboardHandle, ref e, (uint)Marshal.SizeOf(e)))
{
var type = (EVREventType)e.eventType;
if (type == EVREventType.VREvent_MouseMove)
{
var m = e.data.mouse;
var s = _wristOverlay.Size;
_wristOverlay.GetBrowserHost().SendMouseMoveEvent((int)(m.x * s.Width), s.Height - (int)(m.y * s.Height), false, CefEventFlags.None);
}
else if (type == EVREventType.VREvent_MouseButtonDown)
{
var m = e.data.mouse;
var s = _wristOverlay.Size;
_wristOverlay.GetBrowserHost().SendMouseClickEvent((int)(m.x * s.Width), s.Height - (int)(m.y * s.Height), MouseButtonType.Left, false, 1, CefEventFlags.LeftMouseButton);
}
else if (type == EVREventType.VREvent_MouseButtonUp)
{
var m = e.data.mouse;
var s = _wristOverlay.Size;
_wristOverlay.GetBrowserHost().SendMouseClickEvent((int)(m.x * s.Width), s.Height - (int)(m.y * s.Height), MouseButtonType.Left, true, 1, CefEventFlags.None);
}
}
if (dashboardVisible)
{
var texture = new Texture_t
{
handle = _texture1.NativePointer
};
err = overlay.SetOverlayTexture(dashboardHandle, ref texture);
if (err != EVROverlayError.None)
{
return err;
}
}
return err;
}
internal EVROverlayError ProcessOverlay1(CVROverlay overlay, ref ulong overlayHandle, ref bool overlayVisible, bool dashboardVisible, uint overlayIndex)
{
var err = EVROverlayError.None;
if (overlayHandle == 0)
{
err = overlay.FindOverlay("VRCX1", ref overlayHandle);
if (err != EVROverlayError.None)
{
if (err != EVROverlayError.UnknownOverlay)
{
return err;
}
overlayVisible = false;
err = overlay.CreateOverlay("VRCX1", "VRCX1", ref overlayHandle);
if (err != EVROverlayError.None)
{
return err;
}
err = overlay.SetOverlayAlpha(overlayHandle, 0.9f);
if (err != EVROverlayError.None)
{
return err;
}
err = overlay.SetOverlayWidthInMeters(overlayHandle, 1f);
if (err != EVROverlayError.None)
{
return err;
}
err = overlay.SetOverlayInputMethod(overlayHandle, VROverlayInputMethod.None);
if (err != EVROverlayError.None)
{
return err;
}
}
}
if (overlayIndex != OpenVR.k_unTrackedDeviceIndexInvalid)
{
// http://www.opengl-tutorial.org/beginners-tutorials/tutorial-3-matrices
// Scaling-Rotation-Translation
var m = Matrix.Scaling(0.25f);
m *= Matrix.RotationX(_rotation[0]);
m *= Matrix.RotationY(_rotation[1]);
m *= Matrix.RotationZ(_rotation[2]);
m *= Matrix.Translation(_translation[0], _translation[1], _translation[2]);
var hm34 = new HmdMatrix34_t
{
m0 = m.M11,
m1 = m.M21,
m2 = m.M31,
m3 = m.M41,
m4 = m.M12,
m5 = m.M22,
m6 = m.M32,
m7 = m.M42,
m8 = m.M13,
m9 = m.M23,
m10 = m.M33,
m11 = m.M43
};
err = overlay.SetOverlayTransformTrackedDeviceRelative(overlayHandle, overlayIndex, ref hm34);
if (err != EVROverlayError.None)
{
return err;
}
}
if (!dashboardVisible &&
DateTime.UtcNow.CompareTo(_nextOverlayUpdate) <= 0)
{
var texture = new Texture_t
{
handle = _texture1.NativePointer
};
err = overlay.SetOverlayTexture(overlayHandle, ref texture);
if (err != EVROverlayError.None)
{
return err;
}
if (!overlayVisible)
{
err = overlay.ShowOverlay(overlayHandle);
if (err != EVROverlayError.None)
{
return err;
}
overlayVisible = true;
}
}
else if (overlayVisible)
{
err = overlay.HideOverlay(overlayHandle);
if (err != EVROverlayError.None)
{
return err;
}
overlayVisible = false;
}
return err;
}
internal EVROverlayError ProcessOverlay2(CVROverlay overlay, ref ulong overlayHandle, ref bool overlayVisible, bool dashboardVisible)
{
var err = EVROverlayError.None;
if (overlayHandle == 0)
{
err = overlay.FindOverlay("VRCX2", ref overlayHandle);
if (err != EVROverlayError.None)
{
if (err != EVROverlayError.UnknownOverlay)
{
return err;
}
overlayVisible = false;
err = overlay.CreateOverlay("VRCX2", "VRCX2", ref overlayHandle);
if (err != EVROverlayError.None)
{
return err;
}
err = overlay.SetOverlayAlpha(overlayHandle, 0.9f);
if (err != EVROverlayError.None)
{
return err;
}
err = overlay.SetOverlayWidthInMeters(overlayHandle, 1f);
if (err != EVROverlayError.None)
{
return err;
}
err = overlay.SetOverlayInputMethod(overlayHandle, VROverlayInputMethod.None);
if (err != EVROverlayError.None)
{
return err;
}
var m = Matrix.Scaling(1f);
m *= Matrix.Translation(0, -0.3f, -1.5f);
var hm34 = new HmdMatrix34_t
{
m0 = m.M11,
m1 = m.M21,
m2 = m.M31,
m3 = m.M41,
m4 = m.M12,
m5 = m.M22,
m6 = m.M32,
m7 = m.M42,
m8 = m.M13,
m9 = m.M23,
m10 = m.M33,
m11 = m.M43
};
err = overlay.SetOverlayTransformTrackedDeviceRelative(overlayHandle, OpenVR.k_unTrackedDeviceIndex_Hmd, ref hm34);
if (err != EVROverlayError.None)
{
return err;
}
}
}
if (!dashboardVisible)
{
var texture = new Texture_t
{
handle = _texture2.NativePointer
};
err = overlay.SetOverlayTexture(overlayHandle, ref texture);
if (err != EVROverlayError.None)
{
return err;
}
if (!overlayVisible)
{
err = overlay.ShowOverlay(overlayHandle);
if (err != EVROverlayError.None)
{
return err;
}
overlayVisible = true;
}
}
else if (overlayVisible)
{
err = overlay.HideOverlay(overlayHandle);
if (err != EVROverlayError.None)
{
return err;
}
overlayVisible = false;
}
return err;
}
public override void ExecuteVrFeedFunction(string function, string json)
{
if (_wristOverlay == null) return;
if (_wristOverlay.IsLoading)
Restart();
_wristOverlay.ExecuteScriptAsync($"$app.{function}", json);
}
public override void ExecuteVrOverlayFunction(string function, string json)
{
if (_hmdOverlay == null) return;
if (_hmdOverlay.IsLoading)
Restart();
_hmdOverlay.ExecuteScriptAsync($"$app.{function}", json);
}
}
}

View File

@@ -56,7 +56,7 @@ namespace VRCX
{
_browser1.ExecuteScriptAsync("location.reload()");
_browser2.ExecuteScriptAsync("location.reload()");
VRCXVR.Instance.Refresh();
Program.VRCXVRInstance.Refresh();
}
private void button_devtools_Click(object sender, System.EventArgs e)

View File

@@ -22,6 +22,7 @@ namespace VRCX
public static string Version { get; private set; }
public static bool LaunchDebug;
private static readonly NLog.Logger logger = NLog.LogManager.GetLogger("VRCX");
public static VRCXVRInterface VRCXVRInstance { get; private set; }
private static void SetProgramDirectories()
{
@@ -187,14 +188,19 @@ namespace VRCX
WebApi.Instance.Init();
LogWatcher.Instance.Init();
AutoAppLaunchManager.Instance.Init();
CefService.Instance.Init();
IPCServer.Instance.Init();
VRCXVR.Instance.Init();
if (VRCXStorage.Instance.Get("VRCX_DisableVrOverlayGpuAcceleration") == "true")
VRCXVRInstance = new VRCXVRLegacy();
else
VRCXVRInstance = new VRCXVR();
VRCXVRInstance.Init();
Application.Run(new MainForm());
logger.Info("{0} Exiting...", Version);
WebApi.Instance.SaveCookies();
VRCXVR.Instance.Exit();
VRCXVRInstance.Exit();
CefService.Instance.Exit();
AutoAppLaunchManager.Instance.Exit();