// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. using System.Threading.Tasks; using UnityEngine; #if MSFT_OPENXR && (UNITY_STANDALONE_WIN || UNITY_WSA || UNITY_ANDROID) using Microsoft.MixedReality.OpenXR; using Microsoft.MixedReality.Toolkit.Utilities.Gltf.Serialization; using System.Collections.Generic; #endif // MSFT_OPENXR && (UNITY_STANDALONE_WIN || UNITY_WSA || UNITY_ANDROID) namespace Microsoft.MixedReality.Toolkit.XRSDK.OpenXR { /// /// Queries the OpenXR APIs for a renderable controller model. /// internal class OpenXRControllerModelProvider { public OpenXRControllerModelProvider(Utilities.Handedness handedness) { #if MSFT_OPENXR && (UNITY_STANDALONE_WIN || UNITY_WSA || UNITY_ANDROID) controllerModelProvider = handedness == Utilities.Handedness.Left ? ControllerModel.Left : ControllerModel.Right; #endif // MSFT_OPENXR && (UNITY_STANDALONE_WIN || UNITY_WSA || UNITY_ANDROID) } #if MSFT_OPENXR && (UNITY_STANDALONE_WIN || UNITY_WSA || UNITY_ANDROID) private static readonly Dictionary ControllerModelDictionary = new Dictionary(2); private readonly ControllerModel controllerModelProvider; #endif // MSFT_OPENXR && (UNITY_STANDALONE_WIN || UNITY_WSA || UNITY_ANDROID) // Disables "This async method lacks 'await' operators and will run synchronously." when the correct OpenXR package isn't installed #pragma warning disable CS1998 /// /// Attempts to load the glTF controller model from OpenXR. /// /// The controller model as a GameObject or null if it was unobtainable. public async Task TryGenerateControllerModelFromPlatformSDK() { GameObject gltfGameObject = null; #if MSFT_OPENXR && (UNITY_STANDALONE_WIN || UNITY_WSA || UNITY_ANDROID) if (!controllerModelProvider.TryGetControllerModelKey(out ulong modelKey)) { Debug.LogError("Failed to obtain controller model key from platform."); return null; } if (ControllerModelDictionary.TryGetValue(modelKey, out gltfGameObject)) { gltfGameObject.SetActive(true); return gltfGameObject; } byte[] modelStream = await controllerModelProvider.TryGetControllerModel(modelKey); if (modelStream == null || modelStream.Length == 0) { Debug.LogError("Failed to obtain controller model from platform."); return null; } Utilities.Gltf.Schema.GltfObject gltfObject = GltfUtility.GetGltfObjectFromGlb(modelStream); gltfGameObject = await gltfObject.ConstructAsync(); if (gltfGameObject != null) { // After all the awaits, double check that another task didn't finish earlier if (ControllerModelDictionary.TryGetValue(modelKey, out GameObject existingGameObject)) { Object.Destroy(gltfGameObject); return existingGameObject; } else { ControllerModelDictionary.Add(modelKey, gltfGameObject); } } #endif // MSFT_OPENXR && (UNITY_STANDALONE_WIN || UNITY_WSA || UNITY_ANDROID) return gltfGameObject; } #pragma warning restore CS1998 } }