// Copyright HTC Corporation All Rights Reserved. // Remove FAKE_DATA if editor or windows is supported. #if UNITY_EDITOR #define FAKE_DATA #endif using System; using System.Runtime.InteropServices; using UnityEngine; using UnityEngine.XR.OpenXR; using UnityEngine.XR.OpenXR.Features; using VIVE.OpenXR.Feature; #if UNITY_EDITOR using UnityEditor; using UnityEditor.XR.OpenXR.Features; #endif namespace VIVE.OpenXR.Anchor { #if UNITY_EDITOR [OpenXRFeature(UiName = "VIVE XR Anchor", Desc = "VIVE's implementaion of the XR_HTC_anchor.", Company = "HTC", DocumentationLink = "..\\Documentation", OpenxrExtensionStrings = kOpenxrExtensionString, Version = "1.0.0", BuildTargetGroups = new[] { BuildTargetGroup.Android }, FeatureId = featureId )] #endif public class ViveAnchor : OpenXRFeature { public const string kOpenxrExtensionString = "XR_HTC_anchor"; /// /// The feature id string. This is used to give the feature a well known id for reference. /// public const string featureId = "vive.wave.openxr.feature.htcanchor"; private XrInstance m_XrInstance = 0; private XrSession session = 0; private XrSystemId m_XrSystemId = 0; #region struct, enum, const of this extensions public struct XrSystemAnchorPropertiesHTC { public XrStructureType type; public System.IntPtr next; public XrBool32 supportsAnchor; } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] public struct XrSpatialAnchorNameHTC { [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] public string name; } public struct XrSpatialAnchorCreateInfoHTC { public XrStructureType type; public System.IntPtr next; public XrSpace space; public XrPosef poseInSpace; public XrSpatialAnchorNameHTC name; } #endregion #region delegates and delegate instances delegate XrResult DelegateXrCreateSpatialAnchorHTC(XrSession session, ref XrSpatialAnchorCreateInfoHTC createInfo, ref XrSpace anchor); delegate XrResult DelegateXrGetSpatialAnchorNameHTC(XrSpace anchor, ref XrSpatialAnchorNameHTC name); DelegateXrCreateSpatialAnchorHTC XrCreateSpatialAnchorHTC; DelegateXrGetSpatialAnchorNameHTC XrGetSpatialAnchorNameHTC; #endregion delegates and delegate instances #region override functions /// protected override IntPtr HookGetInstanceProcAddr(IntPtr func) { Debug.Log("ViveAnchor HookGetInstanceProcAddr() "); return ViveInterceptors.Instance.HookGetInstanceProcAddr(func); } /// protected override bool OnInstanceCreate(ulong xrInstance) { //Debug.Log("VIVEAnchor OnInstanceCreate() "); if (!OpenXRRuntime.IsExtensionEnabled(kOpenxrExtensionString)) { Debug.LogWarning("ViveAnchor OnInstanceCreate() " + kOpenxrExtensionString + " is NOT enabled."); return false; } m_XrInstance = xrInstance; //Debug.Log("OnInstanceCreate() " + m_XrInstance); CommonWrapper.Instance.OnInstanceCreate(xrInstance, xrGetInstanceProcAddr); SpaceWrapper.Instance.OnInstanceCreate(xrInstance, CommonWrapper.Instance.GetInstanceProcAddr); return GetXrFunctionDelegates(m_XrInstance); } protected override void OnInstanceDestroy(ulong xrInstance) { CommonWrapper.Instance.OnInstanceDestroy(); SpaceWrapper.Instance.OnInstanceDestroy(); } /// protected override void OnSessionCreate(ulong xrSession) { Debug.Log("ViveAnchor OnSessionCreate() "); // here's one way you can grab the session Debug.Log($"EXT: Got xrSession: {xrSession}"); session = xrSession; } /// protected override void OnSessionBegin(ulong xrSession) { Debug.Log("ViveAnchor OnSessionBegin() "); Debug.Log($"EXT: xrBeginSession: {xrSession}"); } /// protected override void OnSessionEnd(ulong xrSession) { Debug.Log("ViveAnchor OnSessionEnd() "); Debug.Log($"EXT: about to xrEndSession: {xrSession}"); } // XXX Every millisecond the AppSpace switched from one space to another space. I don't know what is going on. //private ulong appSpace; //protected override void OnAppSpaceChange(ulong space) //{ // //Debug.Log($"VIVEAnchor OnAppSpaceChange({appSpace} -> {space})"); // appSpace = space; //} /// protected override void OnSystemChange(ulong xrSystem) { m_XrSystemId = xrSystem; Debug.Log("ViveAnchor OnSystemChange() " + m_XrSystemId); } #endregion override functions private bool GetXrFunctionDelegates(XrInstance xrInstance) { Debug.Log("ViveAnchor GetXrFunctionDelegates() "); bool ret = true; IntPtr funcPtr = IntPtr.Zero; OpenXRHelper.xrGetInstanceProcAddrDelegate GetAddr = CommonWrapper.Instance.GetInstanceProcAddr; // shorter name ret &= OpenXRHelper.GetXrFunctionDelegate(GetAddr, xrInstance, "xrCreateSpatialAnchorHTC", out XrCreateSpatialAnchorHTC); ret &= OpenXRHelper.GetXrFunctionDelegate(GetAddr, xrInstance, "xrGetSpatialAnchorNameHTC", out XrGetSpatialAnchorNameHTC); return ret; } #region functions of extension /// /// Helper function to get this feature' properties. /// See xrGetSystemProperties /// public XrResult GetProperties(out XrSystemAnchorPropertiesHTC anchorProperties) { anchorProperties = new XrSystemAnchorPropertiesHTC(); anchorProperties.type = XrStructureType.XR_TYPE_SYSTEM_ANCHOR_PROPERTIES_HTC; #if FAKE_DATA if (Application.isEditor) { anchorProperties.type = XrStructureType.XR_TYPE_SYSTEM_ANCHOR_PROPERTIES_HTC; anchorProperties.supportsAnchor = true; return XrResult.XR_SUCCESS; } #endif return CommonWrapper.Instance.GetProperties(m_XrInstance, m_XrSystemId, ref anchorProperties); } public XrResult CreateSpatialAnchor(XrSpatialAnchorCreateInfoHTC createInfo, out XrSpace anchor) { anchor = default; #if FAKE_DATA if (Application.isEditor) return XrResult.XR_SUCCESS; #endif var ret = XrCreateSpatialAnchorHTC(session, ref createInfo, ref anchor); Debug.Log("ViveAnchor CreateSpatialAnchor() r=" + ret + ", a=" + anchor + ", bs=" + createInfo.space + ", pos=(" + createInfo.poseInSpace.position.x + "," + createInfo.poseInSpace.position.y + "," + createInfo.poseInSpace.position.z + "), rot=(" + createInfo.poseInSpace.orientation.x + "," + createInfo.poseInSpace.orientation.y + "," + createInfo.poseInSpace.orientation.z + "," + createInfo.poseInSpace.orientation.w + "), n=" + createInfo.name.name); return ret; } public XrResult GetSpatialAnchorName(XrSpace anchor, out XrSpatialAnchorNameHTC name) { name = default; #if FAKE_DATA if (Application.isEditor) { name.name = "fake anchor"; return XrResult.XR_SUCCESS; } #endif return XrGetSpatialAnchorNameHTC(anchor, ref name); } #endregion #region tools for user /// /// According to XRInputSubsystem's tracking origin mode, return the corresponding XrSpace. /// /// public XrSpace GetTrackingSpace() { var s = GetCurrentAppSpace(); Debug.Log("ViveAnchor GetTrackingSpace() s=" + s); return s; } #endregion } }