// Copyright HTC Corporation All Rights Reserved.
using System;
using UnityEngine;
namespace VIVE.OpenXR.Feature
{
///
/// To use this wrapper, you need to call CommonWrapper.Instance.OnInstanceCreate() in your feature's OnInstanceCreate(),
/// and call CommonWrapper.Instance.OnInstanceDestroy() in your feature's OnInstanceDestroy().
///
public class SpaceWrapper : ViveFeatureWrapperBase, IViveFeatureWrapper
{
delegate XrResult DelegateXrLocateSpace(XrSpace space, XrSpace baseSpace, XrTime time, ref XrSpaceLocation location);
delegate XrResult DelegateXrDestroySpace(XrSpace space);
OpenXRHelper.xrCreateReferenceSpaceDelegate XrCreateReferenceSpace;
DelegateXrLocateSpace XrLocateSpace;
DelegateXrDestroySpace XrDestroySpace;
///
/// Features should call ViveSpaceWrapper.Instance.OnInstanceCreate() in their OnInstanceCreate().
///
///
///
///
///
public bool OnInstanceCreate(XrInstance xrInstance, IntPtr GetAddr)
{
if (IsInited) return true;
if (xrInstance == null)
throw new Exception("ViveSpace: xrInstance is null");
SetGetInstanceProcAddrPtr(GetAddr);
Debug.Log("ViveSpace: OnInstanceCreate()");
bool ret = true;
IntPtr funcPtr = IntPtr.Zero;
ret &= OpenXRHelper.GetXrFunctionDelegate(xrGetInstanceProcAddr, xrInstance, "xrCreateReferenceSpace", out XrCreateReferenceSpace);
ret &= OpenXRHelper.GetXrFunctionDelegate(xrGetInstanceProcAddr, xrInstance, "xrLocateSpace", out XrLocateSpace);
ret &= OpenXRHelper.GetXrFunctionDelegate(xrGetInstanceProcAddr, xrInstance, "xrDestroySpace", out XrDestroySpace);
IsInited = ret;
return ret;
}
public void OnInstanceDestroy()
{
IsInited = false;
XrCreateReferenceSpace = null;
XrLocateSpace = null;
XrDestroySpace = null;
}
///
/// Create a reference space without create info.
/// Example:
/// CreateReferenceSpace(session, XrReferenceSpaceType.XR_REFERENCE_SPACE_TYPE_LOCAL, XrPosef.Identity, out space);
/// CreateReferenceSpace(session, XrReferenceSpaceType.XR_REFERENCE_SPACE_TYPE_STAGE, XrPosef.Identity, out space);
///
///
///
///
///
///
public XrResult CreateReferenceSpace(XrSession session, XrReferenceSpaceType referenceSpaceType, XrPosef pose, out XrSpace space)
{
space = 0;
if (!IsInited)
return XrResult.XR_ERROR_HANDLE_INVALID;
var createInfo = new XrReferenceSpaceCreateInfo();
createInfo.type = XrStructureType.XR_TYPE_REFERENCE_SPACE_CREATE_INFO;
createInfo.next = IntPtr.Zero;
createInfo.referenceSpaceType = referenceSpaceType;
createInfo.poseInReferenceSpace = pose;
return XrCreateReferenceSpace(session, ref createInfo, out space);
}
///
/// Create a reference space.
///
///
///
///
///
public XrResult CreateReferenceSpace(XrSession session, XrReferenceSpaceCreateInfo createInfo, out XrSpace space)
{
space = 0;
if (!IsInited)
return XrResult.XR_ERROR_HANDLE_INVALID;
return XrCreateReferenceSpace(session, ref createInfo, out space);
}
public XrResult LocateSpace(XrSpace space, XrSpace baseSpace, XrTime time, ref XrSpaceLocation location)
{
if (!IsInited)
return XrResult.XR_ERROR_HANDLE_INVALID;
//Debug.Log($"LocateSpace(s={space}, bs={baseSpace}, t={time}");
return XrLocateSpace(space, baseSpace, time, ref location);
}
public XrResult DestroySpace(XrSpace space)
{
if (!IsInited)
return XrResult.XR_ERROR_HANDLE_INVALID;
Debug.Log($"DestroySpace({space})");
return XrDestroySpace(space);
}
}
///
/// The XrSpace's Unity wrapper. Input and output are in Unity coordinate system.
/// After use it, you should call Dispose() to release the XrSpace.
///
public class Space : IDisposable
{
protected XrSpace space;
private bool disposed = false;
public Space(XrSpace space)
{
Debug.Log($"Space({space})");
this.space = space;
}
///
/// Get the raw XrSpace. Only use it when class Space instance is alive.
/// You should not try to store this XrSpace, because it may be destroyed.
///
///
public XrSpace GetXrSpace()
{
return space;
}
public bool GetRelatedPose(XrSpace baseSpace, XrTime time, out UnityEngine.Pose pose)
{
// If the xrBaseSpace is changed, the pose will be updated.
pose = default;
XrSpaceLocation location = new XrSpaceLocation();
location.type = XrStructureType.XR_TYPE_SPACE_LOCATION;
location.next = IntPtr.Zero;
var ret = SpaceWrapper.Instance.LocateSpace(space, baseSpace, time, ref location);
if (ret != XrResult.XR_SUCCESS)
{
//Debug.Log("Space: LocateSpace ret=" + ret);
return false;
}
//Debug.Log("Space: baseSpace=" + baseSpace + ", space=" + space + ", time=" + time + ", ret=" + ret);
//Debug.Log("Space: location.locationFlags=" + location.locationFlags);
//Debug.Log("Space: location.pose.position=" + location.pose.position.x + "," + location.pose.position.y + "," + location.pose.position.z);
//Debug.Log("Space: location.pose.orientation=" + location.pose.orientation.x + "," + location.pose.orientation.y + "," + location.pose.orientation.z + "," + location.pose.orientation.w);
if ((location.locationFlags & XrSpaceLocationFlags.XR_SPACE_LOCATION_POSITION_VALID_BIT) > 0 &&
(location.locationFlags & XrSpaceLocationFlags.XR_SPACE_LOCATION_ORIENTATION_VALID_BIT) > 0)
{
pose = new Pose(location.pose.position.ToUnityVector(), location.pose.orientation.ToUnityQuaternion());
return true;
}
return false;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!disposed)
{
if (disposing)
{
// Managered resource
}
// Non managered resource
//Debug.Log($"Space: DestroySpace({space})");
SpaceWrapper.Instance.DestroySpace(space);
space = 0;
disposed = true;
}
}
~Space()
{
Dispose(false);
}
}
}