// Copyright HTC Corporation All Rights Reserved. using System; using System.Collections.Generic; using System.Runtime.InteropServices; using UnityEngine; namespace VIVE.OpenXR.Passthrough { /// /// The forms of passthrough layer. /// public enum PassthroughLayerForm { /// Fullscreen Passthrough Form Planar = 0, /// Projected Passthrough Form Projected = 1 } /// /// The types of passthrough space. /// public enum ProjectedPassthroughSpaceType { /// /// XR_REFERENCE_SPACE_TYPE_VIEW at (0,0,0) with orientation (0,0,0,1) /// Headlock = 0, /// /// When TrackingOriginMode is TrackingOriginModeFlags.Floor: /// XR_REFERENCE_SPACE_TYPE_STAGE at (0,0,0) with orientation (0,0,0,1) /// /// When TrackingOriginMode is TrackingOriginModeFlags.Device: /// XR_REFERENCE_SPACE_TYPE_LOCAL at (0,0,0) with orientation (0,0,0,1) /// /// Worldlock = 1 } // -------------------- 12.88. XR_HTC_passthrough -------------------- #region New Object Types /// /// An application can create an XrPassthroughHTC handle by calling xrCreatePassthroughHTC. The returned passthrough handle can be subsequently used in API calls. /// public struct XrPassthroughHTC : IEquatable { private readonly UInt64 value; public XrPassthroughHTC(UInt64 u) { value = u; } public static implicit operator UInt64(XrPassthroughHTC equatable) { return equatable.value; } public static implicit operator XrPassthroughHTC(UInt64 u) { return new XrPassthroughHTC(u); } public bool Equals(XrPassthroughHTC other) { return value == other.value; } public bool Equals(UInt64 other) { return value == other; } public override bool Equals(object obj) { return obj is XrPassthroughHTC && Equals((XrPassthroughHTC)obj); } public override int GetHashCode() { return value.GetHashCode(); } public override string ToString() { return value.ToString(); } public static bool operator ==(XrPassthroughHTC a, XrPassthroughHTC b) { return a.Equals(b); } public static bool operator !=(XrPassthroughHTC a, XrPassthroughHTC b) { return !a.Equals(b); } public static bool operator >=(XrPassthroughHTC a, XrPassthroughHTC b) { return a.value >= b.value; } public static bool operator <=(XrPassthroughHTC a, XrPassthroughHTC b) { return a.value <= b.value; } public static bool operator >(XrPassthroughHTC a, XrPassthroughHTC b) { return a.value > b.value; } public static bool operator <(XrPassthroughHTC a, XrPassthroughHTC b) { return a.value < b.value; } public static XrPassthroughHTC operator +(XrPassthroughHTC a, XrPassthroughHTC b) { return a.value + b.value; } public static XrPassthroughHTC operator -(XrPassthroughHTC a, XrPassthroughHTC b) { return a.value - b.value; } public static XrPassthroughHTC operator *(XrPassthroughHTC a, XrPassthroughHTC b) { return a.value * b.value; } public static XrPassthroughHTC operator /(XrPassthroughHTC a, XrPassthroughHTC b) { if (b.value == 0) { throw new DivideByZeroException(); } return a.value / b.value; } } #endregion #region New Enums /// /// The XrPassthroughFormHTC enumeration identifies the form of the passthrough, presenting the passthrough fill the full screen or project onto a specified mesh. /// public enum XrPassthroughFormHTC { /// /// Presents the passthrough with full of the entire screen.. /// XR_PASSTHROUGH_FORM_PLANAR_HTC = 0, /// /// Presents the passthrough projecting onto a custom mesh. /// XR_PASSTHROUGH_FORM_PROJECTED_HTC = 1, }; #endregion #region New Structures /// /// The XrPassthroughCreateInfoHTC structure describes the information to create an XrPassthroughCreateInfoHTC handle. /// [StructLayout(LayoutKind.Sequential)] public struct XrPassthroughCreateInfoHTC { /// /// The XrStructureType of this structure. /// public XrStructureType type; /// /// NULL or a pointer to the next structure in a structure chain. No such structures are defined in core OpenXR or this extension. /// public IntPtr next; /// /// The form specifies the form of passthrough. /// public XrPassthroughFormHTC form; /// The XrStructureType of this structure. /// NULL or a pointer to the next structure in a structure chain. No such structures are defined in core OpenXR or this extension. /// An XrFacialTrackingTypeHTC which describes which type of facial tracking should be used for this handle. public XrPassthroughCreateInfoHTC(XrStructureType in_type, IntPtr in_next, XrPassthroughFormHTC in_form) { type = in_type; next = in_next; form = in_form; } }; /// /// The application can specify the XrPassthroughColorHTC to adjust the alpha value of the passthrough. The range is between 0.0f and 1.0f, 1.0f means opaque. /// [StructLayout(LayoutKind.Sequential)] public struct XrPassthroughColorHTC { /// /// The XrStructureType of this structure. /// public XrStructureType type; /// /// Next is NULL or a pointer to the next structure in a structure chain, such as XrPassthroughMeshTransformInfoHTC. /// public IntPtr next; /// /// The alpha value of the passthrough in the range [0, 1]. /// public float alpha; public XrPassthroughColorHTC(float in_alpha) { type = XrStructureType.XR_TYPE_PASSTHROUGH_COLOR_HTC; next = IntPtr.Zero; alpha = in_alpha; } }; /// /// The XrPassthroughMeshTransformInfoHTC structure describes the mesh and transformation. /// [StructLayout(LayoutKind.Sequential)] public struct XrPassthroughMeshTransformInfoHTC { /// /// The XrStructureType of this structure. /// public XrStructureType type; /// /// Next is NULL or a pointer to the next structure in a structure chain. /// public IntPtr next; /// /// The count of vertices array in the mesh. /// public UInt32 vertexCount; /// /// An array of XrVector3f. The size of the array must be equal to vertexCount. /// public IntPtr vertices; // XrVector3f /// /// The count of indices array in the mesh. /// public UInt32 indexCount; /// /// An array of triangle indices. The size of the array must be equal to indexCount. /// public IntPtr indices; // UInt32[] /// /// The XrSpace that defines the projected passthrough's base space for transformations. /// public XrSpace baseSpace; /// /// The XrTime that defines the time at which the transform is applied. /// public XrTime time; /// /// The XrPosef that defines the pose of the mesh /// public XrPosef pose; /// /// The XrVector3f that defines the scale of the mesh /// public XrVector3f scale; }; /// /// A pointer to XrCompositionLayerPassthroughHTC may be submitted in xrEndFrame as a pointer to the base structure XrCompositionLayerBaseHeader, in the desired layer order, to request the runtime to composite a passthrough layer into the final frame output. /// [StructLayout(LayoutKind.Sequential)] public struct XrCompositionLayerPassthroughHTC { /// /// The XrStructureType of this structure. /// public XrStructureType type; /// /// Next is NULL or a pointer to the next structure in a structure chain, such as XrPassthroughMeshTransformInfoHTC. /// public IntPtr next; /// /// A bitmask of XrCompositionLayerFlagBits describing flags to apply to the layer. /// public XrCompositionLayerFlags layerFlags; /// /// The XrSpace that specifies the layerˇ¦s space - must be XR_NULL_HANDLE. /// public XrSpace space; /// /// The XrPassthroughHTC previously created by xrCreatePassthroughHTC. /// public XrPassthroughHTC passthrough; /// /// The XrPassthroughColorHTC describing the color information with the alpha value of the passthrough layer. /// public XrPassthroughColorHTC color; public XrCompositionLayerPassthroughHTC(XrCompositionLayerFlags in_layerFlags, XrSpace in_space, XrPassthroughHTC in_passthrough, XrPassthroughColorHTC in_color) { type = XrStructureType.XR_TYPE_COMPOSITION_LAYER_PASSTHROUGH_HTC; next = IntPtr.Zero; layerFlags = in_layerFlags; space = in_space; passthrough = in_passthrough; color = in_color; } }; [StructLayout(LayoutKind.Sequential)] public struct XrPassthroughConfigurationBaseHeaderHTC { public XrStructureType type; public IntPtr next; }; [StructLayout(LayoutKind.Sequential, Pack = 8)] public struct XrPassthroughConfigurationImageRateHTC { public XrStructureType type; public IntPtr next; public float srcImageRate; public float dstImageRate; }; [StructLayout(LayoutKind.Sequential, Pack = 8)] public struct XrPassthroughConfigurationImageQualityHTC { public XrStructureType type; public IntPtr next; public float scale; }; [StructLayout(LayoutKind.Sequential)] public struct XrEventDataPassthroughConfigurationImageRateChangedHTC { public XrStructureType type; public IntPtr next; public XrPassthroughConfigurationImageRateHTC fromImageRate; public XrPassthroughConfigurationImageRateHTC toImageRate; public XrEventDataPassthroughConfigurationImageRateChangedHTC(XrStructureType in_type, IntPtr in_next, XrPassthroughConfigurationImageRateHTC in_fromImageRate, XrPassthroughConfigurationImageRateHTC in_toImageRate) { type = in_type; next = in_next; fromImageRate = in_fromImageRate; toImageRate = in_toImageRate; } public static XrEventDataPassthroughConfigurationImageRateChangedHTC identity { get { return new XrEventDataPassthroughConfigurationImageRateChangedHTC( XrStructureType.XR_TYPE_EVENT_DATA_PASSTHROUGH_CONFIGURATION_IMAGE_RATE_CHANGED_HTC, IntPtr.Zero, new XrPassthroughConfigurationImageRateHTC { type = XrStructureType.XR_TYPE_PASSTHROUGH_CONFIGURATION_IMAGE_RATE_HTC, next = IntPtr.Zero }, new XrPassthroughConfigurationImageRateHTC { type = XrStructureType.XR_TYPE_PASSTHROUGH_CONFIGURATION_IMAGE_RATE_HTC, next = IntPtr.Zero }); // user is default present } } public static bool Get(XrEventDataBuffer eventDataBuffer, out XrEventDataPassthroughConfigurationImageRateChangedHTC eventDataPassthroughConfigurationImageRate) { eventDataPassthroughConfigurationImageRate = identity; if (eventDataBuffer.type == XrStructureType.XR_TYPE_EVENT_DATA_PASSTHROUGH_CONFIGURATION_IMAGE_RATE_CHANGED_HTC) { eventDataPassthroughConfigurationImageRate.next = eventDataBuffer.next; eventDataPassthroughConfigurationImageRate.fromImageRate.type = (XrStructureType)BitConverter.ToUInt32(eventDataBuffer.varying, 0); eventDataPassthroughConfigurationImageRate.fromImageRate.next = (IntPtr)BitConverter.ToInt64(eventDataBuffer.varying, 8); eventDataPassthroughConfigurationImageRate.fromImageRate.srcImageRate = BitConverter.ToSingle(eventDataBuffer.varying, 16); eventDataPassthroughConfigurationImageRate.fromImageRate.dstImageRate = BitConverter.ToSingle(eventDataBuffer.varying, 20); eventDataPassthroughConfigurationImageRate.toImageRate.type = (XrStructureType)BitConverter.ToUInt32(eventDataBuffer.varying, 24); eventDataPassthroughConfigurationImageRate.toImageRate.next = (IntPtr)BitConverter.ToInt64(eventDataBuffer.varying, 32); eventDataPassthroughConfigurationImageRate.toImageRate.srcImageRate = BitConverter.ToSingle(eventDataBuffer.varying, 40); eventDataPassthroughConfigurationImageRate.toImageRate.dstImageRate = BitConverter.ToSingle(eventDataBuffer.varying, 44); return true; } return false; } }; [StructLayout(LayoutKind.Sequential)] public struct XrEventDataPassthroughConfigurationImageQualityChangedHTC { public XrStructureType type; public IntPtr next; public XrPassthroughConfigurationImageQualityHTC fromImageQuality; public XrPassthroughConfigurationImageQualityHTC toImageQuality; public XrEventDataPassthroughConfigurationImageQualityChangedHTC(XrStructureType in_type, IntPtr in_next, XrPassthroughConfigurationImageQualityHTC in_fromImageQuality, XrPassthroughConfigurationImageQualityHTC in_toImageQuality) { type = in_type; next = in_next; fromImageQuality = in_fromImageQuality; toImageQuality = in_toImageQuality; } public static XrEventDataPassthroughConfigurationImageQualityChangedHTC identity { get { return new XrEventDataPassthroughConfigurationImageQualityChangedHTC( XrStructureType.XR_TYPE_EVENT_DATA_PASSTHROUGH_CONFIGURATION_IMAGE_QUALITY_CHANGED_HTC, IntPtr.Zero, new XrPassthroughConfigurationImageQualityHTC { type = XrStructureType.XR_TYPE_PASSTHROUGH_CONFIGURATION_IMAGE_QUALITY_HTC, next = IntPtr.Zero }, new XrPassthroughConfigurationImageQualityHTC { type = XrStructureType.XR_TYPE_PASSTHROUGH_CONFIGURATION_IMAGE_QUALITY_HTC, next = IntPtr.Zero }); // user is default present } } public static bool Get(XrEventDataBuffer eventDataBuffer, out XrEventDataPassthroughConfigurationImageQualityChangedHTC ventDataPassthroughConfigurationImageQuality) { ventDataPassthroughConfigurationImageQuality = identity; if (eventDataBuffer.type == XrStructureType.XR_TYPE_EVENT_DATA_PASSTHROUGH_CONFIGURATION_IMAGE_QUALITY_CHANGED_HTC) { ventDataPassthroughConfigurationImageQuality.next = eventDataBuffer.next; ventDataPassthroughConfigurationImageQuality.fromImageQuality.type = (XrStructureType)BitConverter.ToUInt32(eventDataBuffer.varying, 0); ventDataPassthroughConfigurationImageQuality.fromImageQuality.next = (IntPtr)BitConverter.ToInt64(eventDataBuffer.varying, 8); ventDataPassthroughConfigurationImageQuality.fromImageQuality.scale = BitConverter.ToSingle(eventDataBuffer.varying, 16); ventDataPassthroughConfigurationImageQuality.toImageQuality.type = (XrStructureType)BitConverter.ToUInt32(eventDataBuffer.varying, 24); ventDataPassthroughConfigurationImageQuality.toImageQuality.next = (IntPtr)BitConverter.ToInt64(eventDataBuffer.varying, 32); ventDataPassthroughConfigurationImageQuality.toImageQuality.scale = BitConverter.ToSingle(eventDataBuffer.varying, 40); return true; } return false; } }; [StructLayout(LayoutKind.Sequential)] public struct XrSystemPassthroughConfigurationPropertiesHTC { public XrStructureType type; public IntPtr next; public XrBool32 supportsImageRate; public XrBool32 supportsImageQuality; }; #endregion #region New Functions public static class VivePassthroughHelper { /// /// The delegate function of xrCreatePassthroughHTC. /// /// An XrSession in which the passthrough will be active. /// createInfo is a pointer to an XrPassthroughCreateInfoHTC structure containing information about how to create the passthrough. /// passthrough is a pointer to a handle in which the created XrPassthroughHTC is returned. /// XR_SUCCESS for success. public delegate XrResult xrCreatePassthroughHTCDelegate( XrSession session, XrPassthroughCreateInfoHTC createInfo, out XrPassthroughHTC passthrough); /// /// The delegate function of xrDestroyFacialTrackerHTC. /// /// passthrough is the XrPassthroughHTC to be destroyed.. /// XR_SUCCESS for success. public delegate XrResult xrDestroyPassthroughHTCDelegate( XrPassthroughHTC passthrough); public delegate XrResult xrEnumeratePassthroughImageRatesHTCDelegate( XrSession session, [In] UInt32 imageRateCapacityInput, ref UInt32 imageRateCountOutput, [In, Out] XrPassthroughConfigurationImageRateHTC[] imageRates); public delegate XrResult xrGetPassthroughConfigurationHTCDelegate( XrSession session, IntPtr/*ref XrPassthroughConfigurationBaseHeaderHTC*/ config); public delegate XrResult xrSetPassthroughConfigurationHTCDelegate( XrSession session, IntPtr/*ref XrPassthroughConfigurationBaseHeaderHTC*/ config); } public static class VivePassthroughImageQualityChanged { public delegate void OnImageQualityChanged(float fromQuality, float toQuality); public static void Listen(OnImageQualityChanged callback) { if (!allEventListeners.Contains(callback)) allEventListeners.Add(callback); } public static void Remove(OnImageQualityChanged callback) { if (allEventListeners.Contains(callback)) allEventListeners.Remove(callback); } public static void Send(float fromQuality, float toQuality) { int N = 0; if (allEventListeners != null) { N = allEventListeners.Count; for (int i = N - 1; i >= 0; i--) { OnImageQualityChanged single = allEventListeners[i]; try { single(fromQuality, toQuality); } catch (Exception e) { Debug.Log("Event : " + e.ToString()); allEventListeners.Remove(single); Debug.Log("Event : A listener is removed due to exception."); } } } } private static List allEventListeners = new List(); } public static class VivePassthroughImageRateChanged { public delegate void OnImageRateChanged(float fromSrcImageRate, float fromDestImageRate, float toSrcImageRate, float toDestImageRate); public static void Listen(OnImageRateChanged callback) { if (!allEventListeners.Contains(callback)) allEventListeners.Add(callback); } public static void Remove(OnImageRateChanged callback) { if (allEventListeners.Contains(callback)) allEventListeners.Remove(callback); } public static void Send(float fromSrcImageRate, float fromDestImageRate, float toSrcImageRate, float toDestImageRate) { int N = 0; if (allEventListeners != null) { N = allEventListeners.Count; for (int i = N - 1; i >= 0; i--) { OnImageRateChanged single = allEventListeners[i]; try { single(fromSrcImageRate, fromDestImageRate, toSrcImageRate, toDestImageRate); } catch (Exception e) { Debug.Log("Event : " + e.ToString()); allEventListeners.Remove(single); Debug.Log("Event : A listener is removed due to exception."); } } } } private static List allEventListeners = new List(); } #endregion }