Last active
March 7, 2024 17:40
-
-
Save mikeskydev/5f52bd25cd40f67a1b753dd6abd95ffe to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//Copyright Icosa Foundation | |
using System; | |
using System.Runtime.InteropServices; | |
using AOT; | |
using UnityEditor; | |
using UnityEngine; | |
using UnityEngine.XR.OpenXR; | |
using UnityEngine.XR.OpenXR.Features; | |
#if UNITY_EDITOR | |
using UnityEditor.XR.OpenXR.Features; | |
#endif | |
namespace IcosaFoundation.OpenXR.Unity.FBPassthrough | |
{ | |
/// <summary> | |
/// Example feature showing how to intercept a single OpenXR function. | |
/// </summary> | |
#if UNITY_EDITOR | |
[OpenXRFeature(UiName = "Facebook Passthrough", | |
BuildTargetGroups = new []{BuildTargetGroup.Standalone, BuildTargetGroup.WSA, BuildTargetGroup.Android}, | |
Company = "Icosa Foundation", | |
Desc = "Implement XR_FB_passthrough without OVR SDK", | |
OpenxrExtensionStrings = "XR_FB_passthrough", | |
Version = "0.0.1", | |
FeatureId = featureId)] | |
#endif | |
public class FBPassthroughFeature : OpenXRFeature | |
{ | |
/// <summary> | |
/// The feature id string. This is used to give the feature a well known id for reference. | |
/// </summary> | |
public const string featureId = "foundation.icosa.openxr-facebook-passthrough"; | |
/// <inheritdoc /> | |
protected override IntPtr HookGetInstanceProcAddr(IntPtr func) | |
{ | |
return func; | |
} | |
private static ulong XrInstance = 0; | |
private XrPassthroughFB activePassthrough = new XrPassthroughFB(); | |
private XrPassthroughLayerFB activeLayer = new XrPassthroughLayerFB(); | |
/// <inheritdoc /> | |
protected override bool OnInstanceCreate(ulong xrInstance) | |
{ | |
// here's one way you can grab the instance | |
XrInstance = xrInstance; | |
var success = LoadBindings(); | |
return true; | |
} | |
/// <inheritdoc /> | |
protected override void OnSessionCreate(ulong xrSession) | |
{ | |
// here's one way you can grab the session | |
Debug.Log($"EXT: Got xrSession: {xrSession}"); | |
// Test activate | |
var createSuccess = xrCreatePassthroughFB( | |
xrSession, | |
new XrPassthroughCreateInfoFB(XrPassthroughFlagsFB.IS_RUNNING_AT_CREATION_BIT_FB), | |
out activePassthrough); | |
var layerSuccess = xrCreatePassthroughLayerFB(xrSession, new XrPassthroughLayerCreateInfoFB(activePassthrough, XrPassthroughFlagsFB.IS_RUNNING_AT_CREATION_BIT_FB, XrPassthroughLayerPurposeFB.RECONSTRUCTION_FB), out activeLayer); | |
XrCompositionLayerPassthroughFB layer = new XrCompositionLayerPassthroughFB( | |
XrCompositionLayerFlags.BLEND_TEXTURE_SOURCE_ALPHA_BIT, activeLayer); | |
// TODO: submit layer somehow | |
} | |
protected override void OnSessionBegin (ulong xrSession) | |
{ | |
Debug.Log($"EXT: xrBeginSession: {xrSession}"); | |
} | |
protected override void OnSessionEnd(ulong xrSession) | |
{ | |
Debug.Log($"EXT: about to xrEndSession: {xrSession}"); | |
} | |
private delegate ulong GetInstanceProcAddrDelegate(ulong instance, string procName, out IntPtr procAddr); | |
private static IntPtr GetFunction(string functionName) | |
{ | |
var getInstanceProcAddr = Marshal.GetDelegateForFunctionPointer<GetInstanceProcAddrDelegate>(xrGetInstanceProcAddr); | |
ulong result = getInstanceProcAddr(XrInstance, functionName, out var returnPtr); | |
if (result < 0) | |
{ | |
Debug.LogWarning($"Failed to find {functionName}"); | |
return IntPtr.Zero; | |
} | |
return returnPtr; | |
} | |
#region OpenXR native bindings and types | |
// https://github.com/StereoKit/StereoKit/blob/master/Examples/StereoKitTest/Tools/PassthroughFBExt.cs | |
enum XrStructureType : UInt64 | |
{ | |
XR_TYPE_PASSTHROUGH_CREATE_INFO_FB = 1000118001, | |
XR_TYPE_PASSTHROUGH_LAYER_CREATE_INFO_FB = 1000118002, | |
XR_TYPE_PASSTHROUGH_STYLE_FB = 1000118020, | |
XR_TYPE_COMPOSITION_LAYER_PASSTHROUGH_FB = 1000118003, | |
} | |
enum XrPassthroughFlagsFB : UInt64 | |
{ | |
None = 0, | |
IS_RUNNING_AT_CREATION_BIT_FB = 0x00000001 | |
} | |
enum XrCompositionLayerFlags : UInt64 | |
{ | |
None = 0, | |
CORRECT_CHROMATIC_ABERRATION_BIT = 0x00000001, | |
BLEND_TEXTURE_SOURCE_ALPHA_BIT = 0x00000002, | |
UNPREMULTIPLIED_ALPHA_BIT = 0x00000004, | |
} | |
enum XrPassthroughLayerPurposeFB : UInt32 | |
{ | |
RECONSTRUCTION_FB = 0, | |
PROJECTED_FB = 1, | |
TRACKED_KEYBOARD_HANDS_FB = 1000203001, | |
MAX_ENUM_FB = 0x7FFFFFFF, | |
} | |
enum XrResult : UInt32 | |
{ | |
Success = 0, | |
} | |
#pragma warning disable 0169 // handle is not "used", but required for interop | |
struct XrPassthroughFB { ulong handle; } | |
struct XrPassthroughLayerFB { ulong handle; } | |
#pragma warning restore 0169 | |
[StructLayout(LayoutKind.Sequential)] | |
struct XrPassthroughCreateInfoFB | |
{ | |
private XrStructureType type; | |
public IntPtr next; | |
public XrPassthroughFlagsFB flags; | |
public XrPassthroughCreateInfoFB(XrPassthroughFlagsFB passthroughFlags) | |
{ | |
type = XrStructureType.XR_TYPE_PASSTHROUGH_CREATE_INFO_FB; | |
next = IntPtr.Zero; | |
flags = passthroughFlags; | |
} | |
} | |
[StructLayout(LayoutKind.Sequential)] | |
struct XrPassthroughLayerCreateInfoFB | |
{ | |
private XrStructureType type; | |
public IntPtr next; | |
public XrPassthroughFB passthrough; | |
public XrPassthroughFlagsFB flags; | |
public XrPassthroughLayerPurposeFB purpose; | |
public XrPassthroughLayerCreateInfoFB(XrPassthroughFB passthrough, XrPassthroughFlagsFB flags, XrPassthroughLayerPurposeFB purpose) | |
{ | |
type = XrStructureType.XR_TYPE_PASSTHROUGH_LAYER_CREATE_INFO_FB; | |
next = IntPtr.Zero; | |
this.passthrough = passthrough; | |
this.flags = flags; | |
this.purpose = purpose; | |
} | |
} | |
[StructLayout(LayoutKind.Sequential)] | |
struct XrPassthroughStyleFB | |
{ | |
public XrStructureType type; | |
public IntPtr next; | |
public float textureOpacityFactor; | |
public Color edgeColor; | |
public XrPassthroughStyleFB(float textureOpacityFactor, Color edgeColor) | |
{ | |
type = XrStructureType.XR_TYPE_PASSTHROUGH_STYLE_FB; | |
next = IntPtr.Zero; | |
this.textureOpacityFactor = textureOpacityFactor; | |
this.edgeColor = edgeColor; | |
} | |
} | |
[StructLayout(LayoutKind.Sequential)] | |
struct XrCompositionLayerPassthroughFB | |
{ | |
public XrStructureType type; | |
public IntPtr next; | |
public XrCompositionLayerFlags flags; | |
public ulong space; | |
public XrPassthroughLayerFB layerHandle; | |
public XrCompositionLayerPassthroughFB(XrCompositionLayerFlags flags, XrPassthroughLayerFB layerHandle) | |
{ | |
type = XrStructureType.XR_TYPE_COMPOSITION_LAYER_PASSTHROUGH_FB; | |
next = IntPtr.Zero; | |
space = 0; | |
this.flags = flags; | |
this.layerHandle = layerHandle; | |
} | |
} | |
delegate XrResult del_xrCreatePassthroughFB (ulong session, [In] XrPassthroughCreateInfoFB createInfo, out XrPassthroughFB outPassthrough); | |
delegate XrResult del_xrDestroyPassthroughFB (XrPassthroughFB passthrough); | |
delegate XrResult del_xrPassthroughStartFB (XrPassthroughFB passthrough); | |
delegate XrResult del_xrPassthroughPauseFB (XrPassthroughFB passthrough); | |
delegate XrResult del_xrCreatePassthroughLayerFB (ulong session, [In] XrPassthroughLayerCreateInfoFB createInfo, out XrPassthroughLayerFB outLayer); | |
delegate XrResult del_xrDestroyPassthroughLayerFB (XrPassthroughLayerFB layer); | |
delegate XrResult del_xrPassthroughLayerPauseFB (XrPassthroughLayerFB layer); | |
delegate XrResult del_xrPassthroughLayerResumeFB (XrPassthroughLayerFB layer); | |
delegate XrResult del_xrPassthroughLayerSetStyleFB(XrPassthroughLayerFB layer, [In] XrPassthroughStyleFB style); | |
del_xrCreatePassthroughFB xrCreatePassthroughFB; | |
del_xrDestroyPassthroughFB xrDestroyPassthroughFB; | |
del_xrPassthroughStartFB xrPassthroughStartFB; | |
del_xrPassthroughPauseFB xrPassthroughPauseFB; | |
del_xrCreatePassthroughLayerFB xrCreatePassthroughLayerFB; | |
del_xrDestroyPassthroughLayerFB xrDestroyPassthroughLayerFB; | |
del_xrPassthroughLayerPauseFB xrPassthroughLayerPauseFB; | |
del_xrPassthroughLayerResumeFB xrPassthroughLayerResumeFB; | |
del_xrPassthroughLayerSetStyleFB xrPassthroughLayerSetStyleFB; | |
bool LoadBindings() | |
{ | |
xrCreatePassthroughFB = Marshal.GetDelegateForFunctionPointer<del_xrCreatePassthroughFB> (GetFunction("xrCreatePassthroughFB")); | |
xrDestroyPassthroughFB = Marshal.GetDelegateForFunctionPointer<del_xrDestroyPassthroughFB> (GetFunction("xrDestroyPassthroughFB")); | |
xrPassthroughStartFB = Marshal.GetDelegateForFunctionPointer<del_xrPassthroughStartFB> (GetFunction("xrPassthroughStartFB")); | |
xrPassthroughPauseFB = Marshal.GetDelegateForFunctionPointer<del_xrPassthroughPauseFB> (GetFunction("xrPassthroughPauseFB")); | |
xrCreatePassthroughLayerFB = Marshal.GetDelegateForFunctionPointer<del_xrCreatePassthroughLayerFB> (GetFunction("xrCreatePassthroughLayerFB")); | |
xrDestroyPassthroughLayerFB = Marshal.GetDelegateForFunctionPointer<del_xrDestroyPassthroughLayerFB> (GetFunction("xrDestroyPassthroughLayerFB")); | |
xrPassthroughLayerPauseFB = Marshal.GetDelegateForFunctionPointer<del_xrPassthroughLayerPauseFB> (GetFunction("xrPassthroughLayerPauseFB")); | |
xrPassthroughLayerResumeFB = Marshal.GetDelegateForFunctionPointer<del_xrPassthroughLayerResumeFB> (GetFunction("xrPassthroughLayerResumeFB")); | |
xrPassthroughLayerSetStyleFB = Marshal.GetDelegateForFunctionPointer<del_xrPassthroughLayerSetStyleFB>(GetFunction("xrPassthroughLayerSetStyleFB")); | |
return | |
xrCreatePassthroughFB != null && | |
xrDestroyPassthroughFB != null && | |
xrPassthroughStartFB != null && | |
xrPassthroughPauseFB != null && | |
xrCreatePassthroughLayerFB != null && | |
xrDestroyPassthroughLayerFB != null && | |
xrPassthroughLayerPauseFB != null && | |
xrPassthroughLayerResumeFB != null && | |
xrPassthroughLayerSetStyleFB != null; | |
} | |
#endregion | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment