Skip to content

Commit

Permalink
Fix render models not loading properly when using FPFC
Browse files Browse the repository at this point in the history
  • Loading branch information
nicoco007 committed Dec 22, 2024
1 parent 69e2048 commit b7f8daa
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 23 deletions.
10 changes: 7 additions & 3 deletions Source/CustomAvatar/Tracking/OpenVR/OpenVRRenderModelLoader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,9 @@ namespace CustomAvatar.Tracking.OpenVR
internal class OpenVRRenderModelLoader : IDisposable
{
private static readonly uint kRenderModelVertexStructSize = (uint)Marshal.SizeOf(typeof(RenderModel_Vertex_t));
private static readonly string[] kOffsetComponentNames = new[] { "openxr_grip", "grip" };
private static readonly string[] kOffsetComponentNames = ["openxr_grip", "grip"];

private readonly Dictionary<string, RenderModel> _renderModelCache = new();
private readonly Dictionary<string, RenderModel> _renderModelCache = [];
private readonly SemaphoreSlim _renderModelSemaphore = new(1);

private readonly ILogger<OpenVRRenderModelLoader> _logger;
Expand Down Expand Up @@ -78,7 +78,11 @@ internal async Task<RenderModel> GetRenderModelAsync(string renderModelName)
if (!_renderModelCache.TryGetValue(renderModelName, out RenderModel renderModel))
{
renderModel = await LoadRenderModelAsync(renderModelName);
_renderModelCache[renderModelName] = renderModel;

if (renderModel != null)
{
_renderModelCache[renderModelName] = renderModel;
}
}

return renderModel;
Expand Down
53 changes: 34 additions & 19 deletions Source/CustomAvatar/Tracking/OpenVR/OpenVRRenderModelProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,47 +14,41 @@
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.

using System;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using CustomAvatar.Logging;
using Valve.VR;
using Zenject;

namespace CustomAvatar.Tracking.OpenVR
{
#pragma warning disable IDE0065
using OpenVR = Valve.VR.OpenVR;
#pragma warning restore IDE0065

internal class OpenVRRenderModelProvider : IRenderModelProvider, IInitializable
internal class OpenVRRenderModelProvider : IRenderModelProvider
{
private static readonly uint kInputOriginInfoStructSize = (uint)Marshal.SizeOf(typeof(InputOriginInfo_t));

private readonly ILogger<OpenVRRenderModelProvider> _logger;
private readonly OpenVRRenderModelLoader _openVRRenderModelLoader;

private readonly ulong[] _handles = new ulong[6];

public OpenVRRenderModelProvider(ILogger<OpenVRRenderModelProvider> logger, OpenVRRenderModelLoader openVRRenderModelLoader)
{
_logger = logger;
_openVRRenderModelLoader = openVRRenderModelLoader;
}

public void Initialize()
{
_handles[(int)DeviceUse.Head] = GetDeviceHandle(OpenVR.k_pchPathUserHead);
_handles[(int)DeviceUse.LeftHand] = GetDeviceHandle(OpenVR.k_pchPathUserHandLeft);
_handles[(int)DeviceUse.RightHand] = GetDeviceHandle(OpenVR.k_pchPathUserHandRight);
_handles[(int)DeviceUse.Waist] = GetDeviceHandle(OpenVR.k_pchPathUserWaist);
_handles[(int)DeviceUse.LeftFoot] = GetDeviceHandle(OpenVR.k_pchPathUserFootLeft);
_handles[(int)DeviceUse.RightFoot] = GetDeviceHandle(OpenVR.k_pchPathUserFootRight);
}

public Task<RenderModel> GetRenderModelAsync(DeviceUse deviceUse)
{
InputOriginInfo_t originInfo = GetOriginInfo(deviceUse);

if (originInfo.devicePath == default)
{
return Task.FromResult<RenderModel>(null);
}

string renderModelName = GetStringTrackedDeviceProperty(originInfo.trackedDeviceIndex, ETrackedDeviceProperty.Prop_RenderModelName_String);

if (string.IsNullOrEmpty(renderModelName))
Expand All @@ -65,25 +59,46 @@ public Task<RenderModel> GetRenderModelAsync(DeviceUse deviceUse)
return _openVRRenderModelLoader.GetRenderModelAsync(renderModelName);
}

private ulong GetDeviceHandle(string devicePath)
private ulong GetDeviceHandle(DeviceUse deviceUse)
{
if (OpenVR.Input == null)
{
return default;
}

string devicePath = deviceUse switch
{
DeviceUse.Head => OpenVR.k_pchPathUserHead,
DeviceUse.LeftHand => OpenVR.k_pchPathUserHandLeft,
DeviceUse.RightHand => OpenVR.k_pchPathUserHandRight,
DeviceUse.Waist => OpenVR.k_pchPathUserWaist,
DeviceUse.LeftFoot => OpenVR.k_pchPathUserFootLeft,
DeviceUse.RightFoot => OpenVR.k_pchPathUserFootRight,
_ => throw new ArgumentException("Invalid device use", nameof(deviceUse)),
};

ulong handle = 0;
EVRInputError error = OpenVR.Input.GetInputSourceHandle(devicePath, ref handle);

if (error != EVRInputError.None)
{
_logger.LogError($"Failed to get input source handle for '{devicePath}': {error}");
return 0;
return default;
}

return handle;
}

private InputOriginInfo_t GetOriginInfo(DeviceUse deviceUse)
{
ulong handle = _handles[(int)deviceUse];
if (OpenVR.Input == null)
{
return default;
}

ulong handle = GetDeviceHandle(deviceUse);

if (handle == 0)
if (handle == default)
{
return default;
}
Expand All @@ -108,7 +123,7 @@ private static string GetStringTrackedDeviceProperty(uint deviceIndex, ETrackedD
{
if (OpenVR.System == null)
{
throw new System.InvalidOperationException("OpenVR is not running");
throw new InvalidOperationException("OpenVR is not running");
}

ETrackedPropertyError error = ETrackedPropertyError.TrackedProp_Success;
Expand Down
2 changes: 1 addition & 1 deletion Source/CustomAvatar/Zenject/CustomAvatarsInstaller.cs
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ private void BindOpenVR()
if (OpenVRHelper.Initialize())
{
Container.Bind(typeof(OpenVRRenderModelLoader), typeof(IDisposable)).To<OpenVRRenderModelLoader>().AsSingle();
Container.Bind(typeof(IRenderModelProvider), typeof(IInitializable)).To<OpenVRRenderModelProvider>().AsSingle();
Container.Bind(typeof(IRenderModelProvider)).To<OpenVRRenderModelProvider>().AsSingle();
}
}
}
Expand Down

0 comments on commit b7f8daa

Please # to comment.