From 0db31c34d1b05877595ce0521cd9c5002b734836 Mon Sep 17 00:00:00 2001 From: Henri Date: Wed, 29 May 2024 11:53:41 +0300 Subject: [PATCH] Config for building for Quest --- Config/DefaultEngine.ini | 6 +- Plugins/MetaXR/Config/BaseOculusXR.ini | 140 + Plugins/MetaXR/Config/FilterPlugin.ini | 14 + .../LeftMetaQuestTouchPlusMaterial.uasset | 3 + ...estTouchProBatteryIndicatorMaterial.uasset | 3 + .../LeftMetaQuestTouchProMaterial.uasset | 3 + ...estTouchProBatteryIndicatorMaterial.uasset | 3 + .../MetaQuestTouchProMaterial.uasset | 3 + .../Materials/OculusMR_ChromaKey.uasset | 3 + .../OculusMR_OpaqueColoredMaterial.uasset | 3 + .../Materials/OculusMR_WhiteMaterial.uasset | 3 + .../Materials/PokeAHoleMaterial.uasset | 3 + .../RightMetaQuestTouchPlusMaterial.uasset | 3 + ...estTouchProBatteryIndicatorMaterial.uasset | 3 + .../RightMetaQuestTouchProMaterial.uasset | 3 + .../Materials/TouchForQuest2Material.uasset | 3 + ...ouchForQuestRiftSControllerMaterial.uasset | 3 + .../model_pieces_controllerMATphongRT.uasset | 3 + .../Materials/touchController_mat.uasset | 3 + .../Content/Meshes/LeftMetaQuestTouchPlus.fbx | 3 + .../Meshes/LeftMetaQuestTouchPlus.uasset | 3 + ...aQuestTouchPlusBatteryIndicatorQuad.uasset | 3 + .../Meshes/LeftMetaQuestTouchPro.uasset | 3 + ...taQuestTouchProBatteryIndicatorQuad.uasset | 3 + .../Meshes/LeftMetaQuestTouchProNub.uasset | 3 + .../Content/Meshes/LeftTouchForQuest2.uasset | 3 + .../LeftTouchForQuestRiftSController.fbx | 3 + .../LeftTouchForQuestRiftSController.uasset | 3 + .../Meshes/RightMetaQuestTouchPlus.fbx | 3 + .../Meshes/RightMetaQuestTouchPlus.uasset | 3 + ...aQuestTouchPlusBatteryIndicatorQuad.uasset | 3 + .../Meshes/RightMetaQuestTouchPro.uasset | 3 + ...taQuestTouchProBatteryIndicatorQuad.uasset | 3 + .../Meshes/RightMetaQuestTouchProNub.uasset | 3 + .../Content/Meshes/RightTouchForQuest2.uasset | 3 + .../RightTouchForQuestRiftSController.fbx | 3 + .../RightTouchForQuestRiftSController.uasset | 3 + .../MetaXR/Content/MetaXRControllers.uasset | 3 + .../MetaXR/Content/OculusMR_GreenKey.uasset | 3 + Plugins/MetaXR/Content/OculusModels.tps | 13 + .../MetaXR/Content/OculusModels_License.txt | 8 + .../LeftMetaQuestTouchPlus_Color.uasset | 3 + ...ftMetaQuestTouchProBatteryIndicator.uasset | 3 + .../LeftMetaQuestTouchPro_Color.uasset | 3 + .../LeftMetaQuestTouchPro_Normal.uasset | 3 + .../MetaQuestTouchProBatteryIndicator.uasset | 3 + .../RightMetaQuestTouchPlus_Color.uasset | 3 + ...htMetaQuestTouchProBatteryIndicator.uasset | 3 + .../RightMetaQuestTouchPro_Color.uasset | 3 + .../RightMetaQuestTouchPro_Normal.uasset | 3 + .../TouchForQuest2Material_Roughness.uasset | 3 + .../Textures/TouchForQuest2_Color.uasset | 3 + ...TouchForQuestRiftSController_albedo.uasset | 3 + Plugins/MetaXR/OculusXR.uplugin | 150 + Plugins/MetaXR/Resources/ButtonIcon_80x.png | 3 + Plugins/MetaXR/Resources/GreenDot.svg | 5 + Plugins/MetaXR/Resources/GreyDot.svg | 5 + Plugins/MetaXR/Resources/Icon128.png | 3 + Plugins/MetaXR/Resources/MetaLogo.svg | 3 + .../MetaXR/Resources/MetaQuestBackground.png | 3 + Plugins/MetaXR/Resources/PlatformDesktop.svg | 3 + Plugins/MetaXR/Resources/PlatformQuest2.svg | 7 + Plugins/MetaXR/Resources/PlatformQuest3.svg | 10 + Plugins/MetaXR/Resources/RedDot.svg | 5 + Plugins/MetaXR/Resources/WhiteDot.svg | 5 + Plugins/MetaXR/Resources/YellowDot.svg | 5 + .../MetaXR/Shaders/Private/HardOcclusions.usf | 36 + .../Private/ScreenPixelShaderArraySlice.usf | 25 + .../OculusXRAnchors/OculusXRAnchors.Build.cs | 35 + .../OculusXRAnchorBPFunctionLibrary.cpp | 225 + .../Private/OculusXRAnchorComponent.cpp | 208 + .../Private/OculusXRAnchorComponents.cpp | 104 + .../Private/OculusXRAnchorDelegates.cpp | 24 + .../Private/OculusXRAnchorLatentActions.cpp | 581 ++ .../Private/OculusXRAnchorManager.cpp | 816 +++ .../Private/OculusXRAnchorManager.h | 33 + .../Private/OculusXRAnchorTypes.cpp | 96 + .../Private/OculusXRAnchorTypesPrivate.cpp | 79 + .../Private/OculusXRAnchorTypesPrivate.h | 8 + .../Private/OculusXRAnchors.cpp | 732 ++ .../Private/OculusXRAnchorsModule.cpp | 55 + .../Private/OculusXRAnchorsModule.h | 41 + .../Private/OculusXRAnchorsPrivate.h | 5 + .../Private/OculusXRRoomLayoutManager.cpp | 148 + .../Private/OculusXRRoomLayoutManager.h | 21 + .../OculusXRRoomLayoutManagerComponent.cpp | 82 + .../OculusXRSpatialAnchorComponent.cpp | 28 + .../Private/OculusXRSpatialAnchorManager.cpp | 13 + .../Private/OculusXRSpatialAnchorManager.h | 19 + .../Private/OculusXRTelemetryAnchorsEvents.h | 24 + .../Public/IOculusXRAnchorsModule.h | 37 + .../Public/OculusXRAnchorBPFunctionLibrary.h | 56 + .../Public/OculusXRAnchorComponent.h | 56 + .../Public/OculusXRAnchorComponents.h | 149 + .../Public/OculusXRAnchorDelegates.h | 122 + .../Public/OculusXRAnchorLatentActions.h | 298 + .../Public/OculusXRAnchorTypes.h | 293 + .../OculusXRAnchors/Public/OculusXRAnchors.h | 146 + .../OculusXRRoomLayoutManagerComponent.h | 64 + .../Public/OculusXRSpatialAnchorComponent.h | 25 + .../OculusXREditor/OculusXREditor.Build.cs | 55 + .../Private/OculusXRBuildAnalytics.cpp | 325 + .../Private/OculusXRBuildAnalytics.h | 62 + .../Private/OculusXREditorModule.cpp | 598 ++ .../Private/OculusXREditorModule.h | 99 + .../Private/OculusXREditorSettings.cpp | 9 + .../OculusXRMovementAssetsFactories.cpp | 346 + .../Private/OculusXRMovementAssetsFactories.h | 49 + .../OculusXRPassthroughColorLutAsset.cpp | 59 + .../OculusXRPassthroughColorLutAsset.h | 33 + .../Private/OculusXRPlatformToolSettings.cpp | 25 + .../Private/OculusXRPlatformToolWidget.cpp | 1650 +++++ .../Private/OculusXRPlatformToolWidget.h | 222 + .../Private/OculusXRPrivacyNotification.cpp | 82 + .../Private/OculusXRPrivacyNotification.h | 7 + .../Private/OculusXRSettingsToggle.cpp | 202 + .../Private/OculusXRSettingsToggle.h | 27 + .../Private/OculusXRTelemetryEditorEvents.h | 10 + .../Private/OculusXRToolCommands.cpp | 30 + .../Private/OculusXRToolCommands.h | 44 + .../Private/OculusXRToolStyle.cpp | 72 + .../Private/OculusXRToolStyle.h | 30 + .../Public/IOculusXREditorModule.h | 19 + .../Public/OculusXREditorSettings.h | 37 + .../Public/OculusXRPlatformToolSettings.h | 272 + .../OculusXREyeTracker.Build.cs | 42 + .../Private/OculusXREyeTracker.cpp | 214 + .../OculusXRTelemetryEyeTrackerEvents.h | 10 + .../Source/OculusXRHMD/OculusMobile_APL.xml | 549 ++ .../Source/OculusXRHMD/OculusXRHMD.Build.cs | 139 + .../Private/OculusStressTestShader.usf | 65 + .../Private/OculusXRAssetManager.cpp | 294 + .../Private/OculusXRAssetManager.h | 30 + .../OculusXRHMD/Private/OculusXRDelegates.cpp | 8 + .../OculusXRHMD/Private/OculusXRDelegates.h | 19 + .../Private/OculusXREventComponent.cpp | 21 + .../Private/OculusXRFunctionLibrary.cpp | 985 +++ .../OculusXRHMD/Private/OculusXRHMD.cpp | 4876 +++++++++++++ .../Source/OculusXRHMD/Private/OculusXRHMD.h | 637 ++ .../OculusXRHMD/Private/OculusXRHMDModule.cpp | 509 ++ .../OculusXRHMD/Private/OculusXRHMDModule.h | 121 + .../Private/OculusXRHMDPrivate.cpp | 95 + .../OculusXRHMD/Private/OculusXRHMDPrivate.h | 311 + .../Private/OculusXRHMDPrivateRHI.h | 64 + .../Private/OculusXRHMDRuntimeSettings.cpp | 299 + .../Private/OculusXRHMD_ConsoleCommands.cpp | 90 + .../Private/OculusXRHMD_ConsoleCommands.h | 45 + .../Private/OculusXRHMD_CustomPresent.cpp | 657 ++ .../Private/OculusXRHMD_CustomPresent.h | 117 + .../OculusXRHMD_CustomPresent_D3D11.cpp | 118 + .../OculusXRHMD_CustomPresent_D3D12.cpp | 114 + .../OculusXRHMD_CustomPresent_Vulkan.cpp | 171 + .../OculusXRHMD_DeferredDeletionQueue.cpp | 71 + .../OculusXRHMD_DeferredDeletionQueue.h | 45 + .../OculusXRHMD_DynamicResolutionState.cpp | 90 + .../OculusXRHMD_DynamicResolutionState.h | 43 + .../Private/OculusXRHMD_FoveatedRendering.cpp | 53 + .../Private/OculusXRHMD_FoveatedRendering.h | 31 + .../Private/OculusXRHMD_GameFrame.cpp | 33 + .../Private/OculusXRHMD_GameFrame.h | 65 + .../OculusXRHMD/Private/OculusXRHMD_Layer.cpp | 1484 ++++ .../OculusXRHMD/Private/OculusXRHMD_Layer.h | 233 + .../Private/OculusXRHMD_Settings.cpp | 135 + .../Private/OculusXRHMD_Settings.h | 174 + .../OculusXRHMD_SpectatorScreenController.cpp | 121 + .../OculusXRHMD_SpectatorScreenController.h | 53 + .../Private/OculusXRHMD_Splash.cpp | 666 ++ .../OculusXRHMD/Private/OculusXRHMD_Splash.h | 146 + .../Private/OculusXRHMD_StressTester.cpp | 309 + .../Private/OculusXRHMD_StressTester.h | 91 + .../Private/OculusXRHMD_VulkanExtensions.cpp | 120 + .../Private/OculusXRHMD_VulkanExtensions.h | 43 + .../OculusXRPassthroughLayerShapes.cpp | 152 + .../Private/OculusXRPluginWrapper.cpp | 461 ++ .../Private/OculusXRPluginWrapper.h | 414 ++ .../OculusXRHMD/Private/OculusXRQPL.cpp | 106 + .../Private/OculusXRResourceHolder.cpp | 27 + .../Private/OculusXRResourceHolder.h | 22 + .../Private/OculusXRSceneCaptureCubemap.cpp | 193 + .../Private/OculusXRSceneCaptureCubemap.h | 79 + .../OculusXRHMD/Private/OculusXRSimulator.cpp | 66 + .../OculusXRHMD/Private/OculusXRSimulator.h | 21 + .../OculusXRSyntheticEnvironmentServer.cpp | 108 + .../OculusXRSyntheticEnvironmentServer.h | 31 + .../OculusXRHMD/Private/OculusXRTelemetry.cpp | 49 + .../Private/OculusXRTelemetryEvents.h | 12 + .../OculusXRTelemetryPrivacySettings.cpp | 82 + .../OculusXRTelemetryPrivacySettings.h | 39 + .../OculusXRHMD/Public/IOculusXRHMDModule.h | 132 + .../Public/OculusXRAssetDirectory.h | 18 + .../Public/OculusXREventComponent.h | 34 + .../Public/OculusXRFunctionLibrary.h | 436 ++ .../Public/OculusXRHMDRuntimeSettings.h | 212 + .../OculusXRHMD/Public/OculusXRHMDTypes.h | 361 + .../Public/OculusXRPassthroughLayerShapes.h | 164 + .../Public/OculusXRPassthroughMesh.h | 30 + .../Source/OculusXRHMD/Public/OculusXRQPL.h | 75 + .../OculusXRHMD/Public/OculusXRTelemetry.h | 170 + .../OculusXRInput/OculusXRInput.Build.cs | 61 + .../Private/OculusXRControllerComponent.cpp | 161 + .../Private/OculusXRControllerTracking.cpp | 67 + .../Private/OculusXRControllerTracking.h | 43 + .../Private/OculusXRHandComponent.cpp | 221 + .../Private/OculusXRHandTracking.cpp | 687 ++ .../Private/OculusXRHandTracking.h | 58 + .../OculusXRInput/Private/OculusXRInput.cpp | 1875 +++++ .../OculusXRInput/Private/OculusXRInput.h | 145 + .../Private/OculusXRInputFunctionLibrary.cpp | 175 + .../Private/OculusXRInputModule.cpp | 72 + .../Private/OculusXRInputModule.h | 53 + .../Private/OculusXRInputState.h | 544 ++ .../Public/IOculusXRInputModule.h | 54 + .../Public/OculusXRControllerComponent.h | 61 + .../Public/OculusXRHandComponent.h | 100 + .../Public/OculusXRInputFunctionLibrary.h | 350 + .../Source/OculusXRMR/OculusXRMR.Build.cs | 77 + .../Private/OculusXRMRFunctionLibrary.cpp | 180 + .../OculusXRMR/Private/OculusXRMRModule.cpp | 537 ++ .../OculusXRMR/Private/OculusXRMRModule.h | 97 + .../OculusXRMR/Private/OculusXRMRPrivate.h | 12 + .../Private/OculusXRMR_CastingCameraActor.cpp | 869 +++ .../Private/OculusXRMR_CastingCameraActor.h | 131 + .../Private/OculusXRMR_PlaneMeshComponent.cpp | 270 + .../Private/OculusXRMR_PlaneMeshComponent.h | 77 + .../Private/OculusXRMR_Settings.cpp | 142 + .../OculusXRMR/Private/OculusXRMR_State.cpp | 13 + .../OculusXRMR/Private/OculusXRMR_State.h | 117 + .../OculusXRMR/Public/IOculusXRMRModule.h | 38 + .../Public/OculusXRMRFunctionLibrary.h | 59 + .../OculusXRMR/Public/OculusXRMR_Settings.h | 175 + .../OculusXRMovement.Build.cs | 38 + .../LiveLinkOculusXRMovementSourceFactory.cpp | 40 + .../LiveLinkOculusXRMovementSourceFactory.h | 21 + .../Private/OculusXRBodyTrackingComponent.cpp | 263 + .../Private/OculusXREyeTrackingComponent.cpp | 198 + .../Private/OculusXRFaceTrackingComponent.cpp | 315 + .../OculusXRLiveLinkRetargetBodyAsset.cpp | 157 + .../OculusXRLiveLinkRetargetFaceAsset.cpp | 82 + .../OculusXRMorphTargetsController.cpp | 90 + .../Private/OculusXRMovement.cpp | 334 + .../OculusXRMovementFunctionLibrary.cpp | 105 + .../Private/OculusXRMovementLiveLink.cpp | 355 + .../Private/OculusXRMovementLiveLink.h | 112 + .../Private/OculusXRMovementLog.h | 7 + .../Private/OculusXRMovementModule.cpp | 56 + .../Private/OculusXRMovementModule.h | 39 + .../Private/OculusXRMovementTypes.cpp | 53 + .../Private/OculusXRTelemetryMovementEvents.h | 14 + .../Public/IOculusXRMovementModule.h | 59 + .../Public/OculusXRBodyTrackingComponent.h | 69 + .../Public/OculusXREyeTrackingComponent.h | 99 + .../Public/OculusXRFaceTrackingComponent.h | 104 + .../OculusXRLiveLinkRetargetBodyAsset.h | 143 + .../OculusXRLiveLinkRetargetFaceAsset.h | 60 + .../Public/OculusXRMorphTargetsController.h | 36 + .../Public/OculusXRMovement.h | 41 + .../Public/OculusXRMovementFunctionLibrary.h | 71 + .../Public/OculusXRMovementHelpers.h | 24 + .../Public/OculusXRMovementTypes.h | 336 + .../OculusXROpenXRHMD.Build.cs | 131 + .../Private/OculusXROpenXRHMD.cpp | 142 + .../Private/OculusXROpenXRHMD.h | 61 + .../Public/IOculusXROpenXRHMDPlugin.h | 9 + .../OculusXRPassthrough.Build.cs | 38 + .../Private/OculusXRPassthroughColorLut.cpp | 278 + .../OculusXRPassthroughLayerComponent.cpp | 647 ++ .../Private/OculusXRPassthroughModule.cpp | 25 + .../Private/OculusXRPassthroughModule.h | 26 + .../Public/IOculusXRPassthroughModule.h | 35 + .../Public/OculusXRPassthroughColorLut.h | 80 + .../OculusXRPassthroughLayerComponent.h | 259 + .../OculusXRProjectSetupTool.Build.cs | 50 + .../Private/OculusXRPSTEvents.h | 31 + .../Private/OculusXRPSTUtils.h | 139 + .../OculusXRProjectSetupToolModule.cpp | 400 ++ .../Private/OculusXRProjectSetupToolModule.h | 62 + .../OculusXRRuleProcessorSubsystem.cpp | 292 + .../Private/OculusXRSetupRule.cpp | 96 + .../Private/Rules/OculusXRAnchorsRules.cpp | 49 + .../Private/Rules/OculusXRAnchorsRules.h | 49 + .../Rules/OculusXRCompatibilityRules.cpp | 187 + .../Rules/OculusXRCompatibilityRules.h | 176 + .../Private/Rules/OculusXRMovementRules.cpp | 69 + .../Private/Rules/OculusXRMovementRules.h | 67 + .../Rules/OculusXRPassthroughRules.cpp | 50 + .../Private/Rules/OculusXRPassthroughRules.h | 49 + .../Private/Rules/OculusXRPluginRules.cpp | 80 + .../Private/Rules/OculusXRPluginRules.h | 71 + .../Private/Rules/OculusXRRenderingRules.cpp | 246 + .../Private/Rules/OculusXRRenderingRules.h | 293 + .../Tests/OculusXRProjectSetupTool.spec.cpp | 169 + .../Widget/OculusXRProjectSetupToolWidget.cpp | 1026 +++ .../Widget/OculusXRProjectSetupToolWidget.h | 119 + .../Widget/OculusXRProjectTutorialWidget.cpp | 331 + .../Widget/OculusXRProjectTutorialWidget.h | 46 + .../Widget/OculusXRStatusBarWidget.cpp | 77 + .../Private/Widget/OculusXRStatusBarWidget.h | 27 + .../Public/IOculusXRProjectSetupModule.h | 29 + .../Public/OculusXRPSTSettings.h | 52 + .../Public/OculusXRRuleProcessorSubsystem.h | 100 + .../Public/OculusXRSetupRule.h | 145 + .../OculusXRScene/OculusXRScene.Build.cs | 37 + .../OculusXRScene/Private/OculusXRScene.cpp | 17 + .../Private/OculusXRSceneActor.cpp | 757 ++ .../Private/OculusXRSceneAnchorComponent.cpp | 21 + .../Private/OculusXRSceneDelegates.cpp | 5 + .../Private/OculusXRSceneEventHandling.cpp | 38 + .../Private/OculusXRSceneEventHandling.h | 19 + .../Private/OculusXRSceneFunctionLibrary.cpp | 11 + .../OculusXRSceneGlobalMeshComponent.cpp | 67 + .../Private/OculusXRSceneModule.cpp | 44 + .../Private/OculusXRSceneModule.h | 37 + .../Private/OculusXRSceneSubsystem.cpp | 43 + .../Public/IOculusXRSceneModule.h | 37 + .../OculusXRScene/Public/OculusXRScene.h | 14 + .../OculusXRScene/Public/OculusXRSceneActor.h | 178 + .../Public/OculusXRSceneAnchorComponent.h | 24 + .../Public/OculusXRSceneDelegates.h | 13 + .../Public/OculusXRSceneEventDelegates.h | 17 + .../Public/OculusXRSceneFunctionLibrary.h | 16 + .../Public/OculusXRSceneGlobalMeshComponent.h | 49 + .../Public/OculusXRSceneSubsystem.h | 31 + .../OculusXRScene/Public/OculusXRSceneTypes.h | 14 + .../KhronosOpenXRHeaders.build.cs | 14 + .../Source/Thirdparty/KhronosOpenXR/LICENSE | 202 + .../KhronosOpenXR/LICENSES/Apache-2.0.txt | 208 + .../Thirdparty/KhronosOpenXR/LICENSES/MIT.txt | 19 + .../include/khronos/openxr/openxr.h | 6161 +++++++++++++++++ .../include/khronos/openxr/openxr_platform.h | 715 ++ .../khronos/openxr/openxr_platform_defines.h | 114 + .../khronos/openxr/openxr_reflection.h | 4594 ++++++++++++ .../openxr/openxr_reflection_parent_structs.h | 265 + .../openxr/openxr_reflection_structs.h | 502 ++ .../OVRPlugin/OVRPlugin/Include/OVR_Plugin.h | 1205 ++++ .../OVRPlugin/Include/OVR_Plugin_Deprecated.h | 430 ++ .../OVRPlugin/Include/OVR_Plugin_Insight.h | 119 + .../OVRPlugin/Include/OVR_Plugin_Ktx.h | 47 + .../OVRPlugin/Include/OVR_Plugin_Media.h | 112 + .../Include/OVR_Plugin_MixedReality.h | 146 + .../OVR_Plugin_MixedReality_Deprecated.h | 38 + .../OVRPlugin/Include/OVR_Plugin_Types.h | 3619 ++++++++++ .../Include/OVR_Plugin_Types_Deprecated.h | 237 + .../OVRPlugin/OVRPlugin/LICENSE.txt | 17 + .../Thirdparty/OVRPlugin/OVRPluginXR.build.cs | 23 + .../MetaXR/Source/Thirdparty/OpenXR/LICENSE | 202 + .../Thirdparty/OpenXR/LICENSES/Apache-2.0.txt | 208 + .../Source/Thirdparty/OpenXR/LICENSES/MIT.txt | 19 + .../Thirdparty/OpenXR/OpenXRHeaders.build.cs | 15 + .../OpenXR/include/khronos/openxr/openxr.h | 4581 ++++++++++++ .../include/khronos/openxr/openxr_platform.h | 690 ++ .../khronos/openxr/openxr_platform_defines.h | 110 + .../khronos/openxr/openxr_reflection.h | 3158 +++++++++ VRTowerDefense.uproject | 9 + 353 files changed, 74095 insertions(+), 3 deletions(-) create mode 100644 Plugins/MetaXR/Config/BaseOculusXR.ini create mode 100644 Plugins/MetaXR/Config/FilterPlugin.ini create mode 100644 Plugins/MetaXR/Content/Materials/LeftMetaQuestTouchPlusMaterial.uasset create mode 100644 Plugins/MetaXR/Content/Materials/LeftMetaQuestTouchProBatteryIndicatorMaterial.uasset create mode 100644 Plugins/MetaXR/Content/Materials/LeftMetaQuestTouchProMaterial.uasset create mode 100644 Plugins/MetaXR/Content/Materials/MetaQuestTouchProBatteryIndicatorMaterial.uasset create mode 100644 Plugins/MetaXR/Content/Materials/MetaQuestTouchProMaterial.uasset create mode 100644 Plugins/MetaXR/Content/Materials/OculusMR_ChromaKey.uasset create mode 100644 Plugins/MetaXR/Content/Materials/OculusMR_OpaqueColoredMaterial.uasset create mode 100644 Plugins/MetaXR/Content/Materials/OculusMR_WhiteMaterial.uasset create mode 100644 Plugins/MetaXR/Content/Materials/PokeAHoleMaterial.uasset create mode 100644 Plugins/MetaXR/Content/Materials/RightMetaQuestTouchPlusMaterial.uasset create mode 100644 Plugins/MetaXR/Content/Materials/RightMetaQuestTouchProBatteryIndicatorMaterial.uasset create mode 100644 Plugins/MetaXR/Content/Materials/RightMetaQuestTouchProMaterial.uasset create mode 100644 Plugins/MetaXR/Content/Materials/TouchForQuest2Material.uasset create mode 100644 Plugins/MetaXR/Content/Materials/TouchForQuestRiftSControllerMaterial.uasset create mode 100644 Plugins/MetaXR/Content/Materials/model_pieces_controllerMATphongRT.uasset create mode 100644 Plugins/MetaXR/Content/Materials/touchController_mat.uasset create mode 100644 Plugins/MetaXR/Content/Meshes/LeftMetaQuestTouchPlus.fbx create mode 100644 Plugins/MetaXR/Content/Meshes/LeftMetaQuestTouchPlus.uasset create mode 100644 Plugins/MetaXR/Content/Meshes/LeftMetaQuestTouchPlusBatteryIndicatorQuad.uasset create mode 100644 Plugins/MetaXR/Content/Meshes/LeftMetaQuestTouchPro.uasset create mode 100644 Plugins/MetaXR/Content/Meshes/LeftMetaQuestTouchProBatteryIndicatorQuad.uasset create mode 100644 Plugins/MetaXR/Content/Meshes/LeftMetaQuestTouchProNub.uasset create mode 100644 Plugins/MetaXR/Content/Meshes/LeftTouchForQuest2.uasset create mode 100644 Plugins/MetaXR/Content/Meshes/LeftTouchForQuestRiftSController.fbx create mode 100644 Plugins/MetaXR/Content/Meshes/LeftTouchForQuestRiftSController.uasset create mode 100644 Plugins/MetaXR/Content/Meshes/RightMetaQuestTouchPlus.fbx create mode 100644 Plugins/MetaXR/Content/Meshes/RightMetaQuestTouchPlus.uasset create mode 100644 Plugins/MetaXR/Content/Meshes/RightMetaQuestTouchPlusBatteryIndicatorQuad.uasset create mode 100644 Plugins/MetaXR/Content/Meshes/RightMetaQuestTouchPro.uasset create mode 100644 Plugins/MetaXR/Content/Meshes/RightMetaQuestTouchProBatteryIndicatorQuad.uasset create mode 100644 Plugins/MetaXR/Content/Meshes/RightMetaQuestTouchProNub.uasset create mode 100644 Plugins/MetaXR/Content/Meshes/RightTouchForQuest2.uasset create mode 100644 Plugins/MetaXR/Content/Meshes/RightTouchForQuestRiftSController.fbx create mode 100644 Plugins/MetaXR/Content/Meshes/RightTouchForQuestRiftSController.uasset create mode 100644 Plugins/MetaXR/Content/MetaXRControllers.uasset create mode 100644 Plugins/MetaXR/Content/OculusMR_GreenKey.uasset create mode 100644 Plugins/MetaXR/Content/OculusModels.tps create mode 100644 Plugins/MetaXR/Content/OculusModels_License.txt create mode 100644 Plugins/MetaXR/Content/Textures/LeftMetaQuestTouchPlus_Color.uasset create mode 100644 Plugins/MetaXR/Content/Textures/LeftMetaQuestTouchProBatteryIndicator.uasset create mode 100644 Plugins/MetaXR/Content/Textures/LeftMetaQuestTouchPro_Color.uasset create mode 100644 Plugins/MetaXR/Content/Textures/LeftMetaQuestTouchPro_Normal.uasset create mode 100644 Plugins/MetaXR/Content/Textures/MetaQuestTouchProBatteryIndicator.uasset create mode 100644 Plugins/MetaXR/Content/Textures/RightMetaQuestTouchPlus_Color.uasset create mode 100644 Plugins/MetaXR/Content/Textures/RightMetaQuestTouchProBatteryIndicator.uasset create mode 100644 Plugins/MetaXR/Content/Textures/RightMetaQuestTouchPro_Color.uasset create mode 100644 Plugins/MetaXR/Content/Textures/RightMetaQuestTouchPro_Normal.uasset create mode 100644 Plugins/MetaXR/Content/Textures/TouchForQuest2Material_Roughness.uasset create mode 100644 Plugins/MetaXR/Content/Textures/TouchForQuest2_Color.uasset create mode 100644 Plugins/MetaXR/Content/Textures/TouchForQuestRiftSController_albedo.uasset create mode 100644 Plugins/MetaXR/OculusXR.uplugin create mode 100644 Plugins/MetaXR/Resources/ButtonIcon_80x.png create mode 100644 Plugins/MetaXR/Resources/GreenDot.svg create mode 100644 Plugins/MetaXR/Resources/GreyDot.svg create mode 100644 Plugins/MetaXR/Resources/Icon128.png create mode 100644 Plugins/MetaXR/Resources/MetaLogo.svg create mode 100644 Plugins/MetaXR/Resources/MetaQuestBackground.png create mode 100644 Plugins/MetaXR/Resources/PlatformDesktop.svg create mode 100644 Plugins/MetaXR/Resources/PlatformQuest2.svg create mode 100644 Plugins/MetaXR/Resources/PlatformQuest3.svg create mode 100644 Plugins/MetaXR/Resources/RedDot.svg create mode 100644 Plugins/MetaXR/Resources/WhiteDot.svg create mode 100644 Plugins/MetaXR/Resources/YellowDot.svg create mode 100644 Plugins/MetaXR/Shaders/Private/HardOcclusions.usf create mode 100644 Plugins/MetaXR/Shaders/Private/ScreenPixelShaderArraySlice.usf create mode 100644 Plugins/MetaXR/Source/OculusXRAnchors/OculusXRAnchors.Build.cs create mode 100644 Plugins/MetaXR/Source/OculusXRAnchors/Private/OculusXRAnchorBPFunctionLibrary.cpp create mode 100644 Plugins/MetaXR/Source/OculusXRAnchors/Private/OculusXRAnchorComponent.cpp create mode 100644 Plugins/MetaXR/Source/OculusXRAnchors/Private/OculusXRAnchorComponents.cpp create mode 100644 Plugins/MetaXR/Source/OculusXRAnchors/Private/OculusXRAnchorDelegates.cpp create mode 100644 Plugins/MetaXR/Source/OculusXRAnchors/Private/OculusXRAnchorLatentActions.cpp create mode 100644 Plugins/MetaXR/Source/OculusXRAnchors/Private/OculusXRAnchorManager.cpp create mode 100644 Plugins/MetaXR/Source/OculusXRAnchors/Private/OculusXRAnchorManager.h create mode 100644 Plugins/MetaXR/Source/OculusXRAnchors/Private/OculusXRAnchorTypes.cpp create mode 100644 Plugins/MetaXR/Source/OculusXRAnchors/Private/OculusXRAnchorTypesPrivate.cpp create mode 100644 Plugins/MetaXR/Source/OculusXRAnchors/Private/OculusXRAnchorTypesPrivate.h create mode 100644 Plugins/MetaXR/Source/OculusXRAnchors/Private/OculusXRAnchors.cpp create mode 100644 Plugins/MetaXR/Source/OculusXRAnchors/Private/OculusXRAnchorsModule.cpp create mode 100644 Plugins/MetaXR/Source/OculusXRAnchors/Private/OculusXRAnchorsModule.h create mode 100644 Plugins/MetaXR/Source/OculusXRAnchors/Private/OculusXRAnchorsPrivate.h create mode 100644 Plugins/MetaXR/Source/OculusXRAnchors/Private/OculusXRRoomLayoutManager.cpp create mode 100644 Plugins/MetaXR/Source/OculusXRAnchors/Private/OculusXRRoomLayoutManager.h create mode 100644 Plugins/MetaXR/Source/OculusXRAnchors/Private/OculusXRRoomLayoutManagerComponent.cpp create mode 100644 Plugins/MetaXR/Source/OculusXRAnchors/Private/OculusXRSpatialAnchorComponent.cpp create mode 100644 Plugins/MetaXR/Source/OculusXRAnchors/Private/OculusXRSpatialAnchorManager.cpp create mode 100644 Plugins/MetaXR/Source/OculusXRAnchors/Private/OculusXRSpatialAnchorManager.h create mode 100644 Plugins/MetaXR/Source/OculusXRAnchors/Private/OculusXRTelemetryAnchorsEvents.h create mode 100644 Plugins/MetaXR/Source/OculusXRAnchors/Public/IOculusXRAnchorsModule.h create mode 100644 Plugins/MetaXR/Source/OculusXRAnchors/Public/OculusXRAnchorBPFunctionLibrary.h create mode 100644 Plugins/MetaXR/Source/OculusXRAnchors/Public/OculusXRAnchorComponent.h create mode 100644 Plugins/MetaXR/Source/OculusXRAnchors/Public/OculusXRAnchorComponents.h create mode 100644 Plugins/MetaXR/Source/OculusXRAnchors/Public/OculusXRAnchorDelegates.h create mode 100644 Plugins/MetaXR/Source/OculusXRAnchors/Public/OculusXRAnchorLatentActions.h create mode 100644 Plugins/MetaXR/Source/OculusXRAnchors/Public/OculusXRAnchorTypes.h create mode 100644 Plugins/MetaXR/Source/OculusXRAnchors/Public/OculusXRAnchors.h create mode 100644 Plugins/MetaXR/Source/OculusXRAnchors/Public/OculusXRRoomLayoutManagerComponent.h create mode 100644 Plugins/MetaXR/Source/OculusXRAnchors/Public/OculusXRSpatialAnchorComponent.h create mode 100644 Plugins/MetaXR/Source/OculusXREditor/OculusXREditor.Build.cs create mode 100644 Plugins/MetaXR/Source/OculusXREditor/Private/OculusXRBuildAnalytics.cpp create mode 100644 Plugins/MetaXR/Source/OculusXREditor/Private/OculusXRBuildAnalytics.h create mode 100644 Plugins/MetaXR/Source/OculusXREditor/Private/OculusXREditorModule.cpp create mode 100644 Plugins/MetaXR/Source/OculusXREditor/Private/OculusXREditorModule.h create mode 100644 Plugins/MetaXR/Source/OculusXREditor/Private/OculusXREditorSettings.cpp create mode 100644 Plugins/MetaXR/Source/OculusXREditor/Private/OculusXRMovementAssetsFactories.cpp create mode 100644 Plugins/MetaXR/Source/OculusXREditor/Private/OculusXRMovementAssetsFactories.h create mode 100644 Plugins/MetaXR/Source/OculusXREditor/Private/OculusXRPassthroughColorLutAsset.cpp create mode 100644 Plugins/MetaXR/Source/OculusXREditor/Private/OculusXRPassthroughColorLutAsset.h create mode 100644 Plugins/MetaXR/Source/OculusXREditor/Private/OculusXRPlatformToolSettings.cpp create mode 100644 Plugins/MetaXR/Source/OculusXREditor/Private/OculusXRPlatformToolWidget.cpp create mode 100644 Plugins/MetaXR/Source/OculusXREditor/Private/OculusXRPlatformToolWidget.h create mode 100644 Plugins/MetaXR/Source/OculusXREditor/Private/OculusXRPrivacyNotification.cpp create mode 100644 Plugins/MetaXR/Source/OculusXREditor/Private/OculusXRPrivacyNotification.h create mode 100644 Plugins/MetaXR/Source/OculusXREditor/Private/OculusXRSettingsToggle.cpp create mode 100644 Plugins/MetaXR/Source/OculusXREditor/Private/OculusXRSettingsToggle.h create mode 100644 Plugins/MetaXR/Source/OculusXREditor/Private/OculusXRTelemetryEditorEvents.h create mode 100644 Plugins/MetaXR/Source/OculusXREditor/Private/OculusXRToolCommands.cpp create mode 100644 Plugins/MetaXR/Source/OculusXREditor/Private/OculusXRToolCommands.h create mode 100644 Plugins/MetaXR/Source/OculusXREditor/Private/OculusXRToolStyle.cpp create mode 100644 Plugins/MetaXR/Source/OculusXREditor/Private/OculusXRToolStyle.h create mode 100644 Plugins/MetaXR/Source/OculusXREditor/Public/IOculusXREditorModule.h create mode 100644 Plugins/MetaXR/Source/OculusXREditor/Public/OculusXREditorSettings.h create mode 100644 Plugins/MetaXR/Source/OculusXREditor/Public/OculusXRPlatformToolSettings.h create mode 100644 Plugins/MetaXR/Source/OculusXREyeTracker/OculusXREyeTracker.Build.cs create mode 100644 Plugins/MetaXR/Source/OculusXREyeTracker/Private/OculusXREyeTracker.cpp create mode 100644 Plugins/MetaXR/Source/OculusXREyeTracker/Private/OculusXRTelemetryEyeTrackerEvents.h create mode 100644 Plugins/MetaXR/Source/OculusXRHMD/OculusMobile_APL.xml create mode 100644 Plugins/MetaXR/Source/OculusXRHMD/OculusXRHMD.Build.cs create mode 100644 Plugins/MetaXR/Source/OculusXRHMD/Private/OculusStressTestShader.usf create mode 100644 Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRAssetManager.cpp create mode 100644 Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRAssetManager.h create mode 100644 Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRDelegates.cpp create mode 100644 Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRDelegates.h create mode 100644 Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXREventComponent.cpp create mode 100644 Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRFunctionLibrary.cpp create mode 100644 Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD.cpp create mode 100644 Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD.h create mode 100644 Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMDModule.cpp create mode 100644 Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMDModule.h create mode 100644 Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMDPrivate.cpp create mode 100644 Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMDPrivate.h create mode 100644 Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMDPrivateRHI.h create mode 100644 Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMDRuntimeSettings.cpp create mode 100644 Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_ConsoleCommands.cpp create mode 100644 Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_ConsoleCommands.h create mode 100644 Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_CustomPresent.cpp create mode 100644 Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_CustomPresent.h create mode 100644 Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_CustomPresent_D3D11.cpp create mode 100644 Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_CustomPresent_D3D12.cpp create mode 100644 Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_CustomPresent_Vulkan.cpp create mode 100644 Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_DeferredDeletionQueue.cpp create mode 100644 Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_DeferredDeletionQueue.h create mode 100644 Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_DynamicResolutionState.cpp create mode 100644 Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_DynamicResolutionState.h create mode 100644 Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_FoveatedRendering.cpp create mode 100644 Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_FoveatedRendering.h create mode 100644 Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_GameFrame.cpp create mode 100644 Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_GameFrame.h create mode 100644 Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_Layer.cpp create mode 100644 Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_Layer.h create mode 100644 Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_Settings.cpp create mode 100644 Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_Settings.h create mode 100644 Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_SpectatorScreenController.cpp create mode 100644 Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_SpectatorScreenController.h create mode 100644 Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_Splash.cpp create mode 100644 Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_Splash.h create mode 100644 Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_StressTester.cpp create mode 100644 Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_StressTester.h create mode 100644 Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_VulkanExtensions.cpp create mode 100644 Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_VulkanExtensions.h create mode 100644 Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRPassthroughLayerShapes.cpp create mode 100644 Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRPluginWrapper.cpp create mode 100644 Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRPluginWrapper.h create mode 100644 Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRQPL.cpp create mode 100644 Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRResourceHolder.cpp create mode 100644 Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRResourceHolder.h create mode 100644 Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRSceneCaptureCubemap.cpp create mode 100644 Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRSceneCaptureCubemap.h create mode 100644 Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRSimulator.cpp create mode 100644 Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRSimulator.h create mode 100644 Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRSyntheticEnvironmentServer.cpp create mode 100644 Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRSyntheticEnvironmentServer.h create mode 100644 Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRTelemetry.cpp create mode 100644 Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRTelemetryEvents.h create mode 100644 Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRTelemetryPrivacySettings.cpp create mode 100644 Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRTelemetryPrivacySettings.h create mode 100644 Plugins/MetaXR/Source/OculusXRHMD/Public/IOculusXRHMDModule.h create mode 100644 Plugins/MetaXR/Source/OculusXRHMD/Public/OculusXRAssetDirectory.h create mode 100644 Plugins/MetaXR/Source/OculusXRHMD/Public/OculusXREventComponent.h create mode 100644 Plugins/MetaXR/Source/OculusXRHMD/Public/OculusXRFunctionLibrary.h create mode 100644 Plugins/MetaXR/Source/OculusXRHMD/Public/OculusXRHMDRuntimeSettings.h create mode 100644 Plugins/MetaXR/Source/OculusXRHMD/Public/OculusXRHMDTypes.h create mode 100644 Plugins/MetaXR/Source/OculusXRHMD/Public/OculusXRPassthroughLayerShapes.h create mode 100644 Plugins/MetaXR/Source/OculusXRHMD/Public/OculusXRPassthroughMesh.h create mode 100644 Plugins/MetaXR/Source/OculusXRHMD/Public/OculusXRQPL.h create mode 100644 Plugins/MetaXR/Source/OculusXRHMD/Public/OculusXRTelemetry.h create mode 100644 Plugins/MetaXR/Source/OculusXRInput/OculusXRInput.Build.cs create mode 100644 Plugins/MetaXR/Source/OculusXRInput/Private/OculusXRControllerComponent.cpp create mode 100644 Plugins/MetaXR/Source/OculusXRInput/Private/OculusXRControllerTracking.cpp create mode 100644 Plugins/MetaXR/Source/OculusXRInput/Private/OculusXRControllerTracking.h create mode 100644 Plugins/MetaXR/Source/OculusXRInput/Private/OculusXRHandComponent.cpp create mode 100644 Plugins/MetaXR/Source/OculusXRInput/Private/OculusXRHandTracking.cpp create mode 100644 Plugins/MetaXR/Source/OculusXRInput/Private/OculusXRHandTracking.h create mode 100644 Plugins/MetaXR/Source/OculusXRInput/Private/OculusXRInput.cpp create mode 100644 Plugins/MetaXR/Source/OculusXRInput/Private/OculusXRInput.h create mode 100644 Plugins/MetaXR/Source/OculusXRInput/Private/OculusXRInputFunctionLibrary.cpp create mode 100644 Plugins/MetaXR/Source/OculusXRInput/Private/OculusXRInputModule.cpp create mode 100644 Plugins/MetaXR/Source/OculusXRInput/Private/OculusXRInputModule.h create mode 100644 Plugins/MetaXR/Source/OculusXRInput/Private/OculusXRInputState.h create mode 100644 Plugins/MetaXR/Source/OculusXRInput/Public/IOculusXRInputModule.h create mode 100644 Plugins/MetaXR/Source/OculusXRInput/Public/OculusXRControllerComponent.h create mode 100644 Plugins/MetaXR/Source/OculusXRInput/Public/OculusXRHandComponent.h create mode 100644 Plugins/MetaXR/Source/OculusXRInput/Public/OculusXRInputFunctionLibrary.h create mode 100644 Plugins/MetaXR/Source/OculusXRMR/OculusXRMR.Build.cs create mode 100644 Plugins/MetaXR/Source/OculusXRMR/Private/OculusXRMRFunctionLibrary.cpp create mode 100644 Plugins/MetaXR/Source/OculusXRMR/Private/OculusXRMRModule.cpp create mode 100644 Plugins/MetaXR/Source/OculusXRMR/Private/OculusXRMRModule.h create mode 100644 Plugins/MetaXR/Source/OculusXRMR/Private/OculusXRMRPrivate.h create mode 100644 Plugins/MetaXR/Source/OculusXRMR/Private/OculusXRMR_CastingCameraActor.cpp create mode 100644 Plugins/MetaXR/Source/OculusXRMR/Private/OculusXRMR_CastingCameraActor.h create mode 100644 Plugins/MetaXR/Source/OculusXRMR/Private/OculusXRMR_PlaneMeshComponent.cpp create mode 100644 Plugins/MetaXR/Source/OculusXRMR/Private/OculusXRMR_PlaneMeshComponent.h create mode 100644 Plugins/MetaXR/Source/OculusXRMR/Private/OculusXRMR_Settings.cpp create mode 100644 Plugins/MetaXR/Source/OculusXRMR/Private/OculusXRMR_State.cpp create mode 100644 Plugins/MetaXR/Source/OculusXRMR/Private/OculusXRMR_State.h create mode 100644 Plugins/MetaXR/Source/OculusXRMR/Public/IOculusXRMRModule.h create mode 100644 Plugins/MetaXR/Source/OculusXRMR/Public/OculusXRMRFunctionLibrary.h create mode 100644 Plugins/MetaXR/Source/OculusXRMR/Public/OculusXRMR_Settings.h create mode 100644 Plugins/MetaXR/Source/OculusXRMovement/OculusXRMovement.Build.cs create mode 100644 Plugins/MetaXR/Source/OculusXRMovement/Private/LiveLinkOculusXRMovementSourceFactory.cpp create mode 100644 Plugins/MetaXR/Source/OculusXRMovement/Private/LiveLinkOculusXRMovementSourceFactory.h create mode 100644 Plugins/MetaXR/Source/OculusXRMovement/Private/OculusXRBodyTrackingComponent.cpp create mode 100644 Plugins/MetaXR/Source/OculusXRMovement/Private/OculusXREyeTrackingComponent.cpp create mode 100644 Plugins/MetaXR/Source/OculusXRMovement/Private/OculusXRFaceTrackingComponent.cpp create mode 100644 Plugins/MetaXR/Source/OculusXRMovement/Private/OculusXRLiveLinkRetargetBodyAsset.cpp create mode 100644 Plugins/MetaXR/Source/OculusXRMovement/Private/OculusXRLiveLinkRetargetFaceAsset.cpp create mode 100644 Plugins/MetaXR/Source/OculusXRMovement/Private/OculusXRMorphTargetsController.cpp create mode 100644 Plugins/MetaXR/Source/OculusXRMovement/Private/OculusXRMovement.cpp create mode 100644 Plugins/MetaXR/Source/OculusXRMovement/Private/OculusXRMovementFunctionLibrary.cpp create mode 100644 Plugins/MetaXR/Source/OculusXRMovement/Private/OculusXRMovementLiveLink.cpp create mode 100644 Plugins/MetaXR/Source/OculusXRMovement/Private/OculusXRMovementLiveLink.h create mode 100644 Plugins/MetaXR/Source/OculusXRMovement/Private/OculusXRMovementLog.h create mode 100644 Plugins/MetaXR/Source/OculusXRMovement/Private/OculusXRMovementModule.cpp create mode 100644 Plugins/MetaXR/Source/OculusXRMovement/Private/OculusXRMovementModule.h create mode 100644 Plugins/MetaXR/Source/OculusXRMovement/Private/OculusXRMovementTypes.cpp create mode 100644 Plugins/MetaXR/Source/OculusXRMovement/Private/OculusXRTelemetryMovementEvents.h create mode 100644 Plugins/MetaXR/Source/OculusXRMovement/Public/IOculusXRMovementModule.h create mode 100644 Plugins/MetaXR/Source/OculusXRMovement/Public/OculusXRBodyTrackingComponent.h create mode 100644 Plugins/MetaXR/Source/OculusXRMovement/Public/OculusXREyeTrackingComponent.h create mode 100644 Plugins/MetaXR/Source/OculusXRMovement/Public/OculusXRFaceTrackingComponent.h create mode 100644 Plugins/MetaXR/Source/OculusXRMovement/Public/OculusXRLiveLinkRetargetBodyAsset.h create mode 100644 Plugins/MetaXR/Source/OculusXRMovement/Public/OculusXRLiveLinkRetargetFaceAsset.h create mode 100644 Plugins/MetaXR/Source/OculusXRMovement/Public/OculusXRMorphTargetsController.h create mode 100644 Plugins/MetaXR/Source/OculusXRMovement/Public/OculusXRMovement.h create mode 100644 Plugins/MetaXR/Source/OculusXRMovement/Public/OculusXRMovementFunctionLibrary.h create mode 100644 Plugins/MetaXR/Source/OculusXRMovement/Public/OculusXRMovementHelpers.h create mode 100644 Plugins/MetaXR/Source/OculusXRMovement/Public/OculusXRMovementTypes.h create mode 100644 Plugins/MetaXR/Source/OculusXROpenXRHMD/OculusXROpenXRHMD.Build.cs create mode 100644 Plugins/MetaXR/Source/OculusXROpenXRHMD/Private/OculusXROpenXRHMD.cpp create mode 100644 Plugins/MetaXR/Source/OculusXROpenXRHMD/Private/OculusXROpenXRHMD.h create mode 100644 Plugins/MetaXR/Source/OculusXROpenXRHMD/Public/IOculusXROpenXRHMDPlugin.h create mode 100644 Plugins/MetaXR/Source/OculusXRPassthrough/OculusXRPassthrough.Build.cs create mode 100644 Plugins/MetaXR/Source/OculusXRPassthrough/Private/OculusXRPassthroughColorLut.cpp create mode 100644 Plugins/MetaXR/Source/OculusXRPassthrough/Private/OculusXRPassthroughLayerComponent.cpp create mode 100644 Plugins/MetaXR/Source/OculusXRPassthrough/Private/OculusXRPassthroughModule.cpp create mode 100644 Plugins/MetaXR/Source/OculusXRPassthrough/Private/OculusXRPassthroughModule.h create mode 100644 Plugins/MetaXR/Source/OculusXRPassthrough/Public/IOculusXRPassthroughModule.h create mode 100644 Plugins/MetaXR/Source/OculusXRPassthrough/Public/OculusXRPassthroughColorLut.h create mode 100644 Plugins/MetaXR/Source/OculusXRPassthrough/Public/OculusXRPassthroughLayerComponent.h create mode 100644 Plugins/MetaXR/Source/OculusXRProjectSetupTool/OculusXRProjectSetupTool.Build.cs create mode 100644 Plugins/MetaXR/Source/OculusXRProjectSetupTool/Private/OculusXRPSTEvents.h create mode 100644 Plugins/MetaXR/Source/OculusXRProjectSetupTool/Private/OculusXRPSTUtils.h create mode 100644 Plugins/MetaXR/Source/OculusXRProjectSetupTool/Private/OculusXRProjectSetupToolModule.cpp create mode 100644 Plugins/MetaXR/Source/OculusXRProjectSetupTool/Private/OculusXRProjectSetupToolModule.h create mode 100644 Plugins/MetaXR/Source/OculusXRProjectSetupTool/Private/OculusXRRuleProcessorSubsystem.cpp create mode 100644 Plugins/MetaXR/Source/OculusXRProjectSetupTool/Private/OculusXRSetupRule.cpp create mode 100644 Plugins/MetaXR/Source/OculusXRProjectSetupTool/Private/Rules/OculusXRAnchorsRules.cpp create mode 100644 Plugins/MetaXR/Source/OculusXRProjectSetupTool/Private/Rules/OculusXRAnchorsRules.h create mode 100644 Plugins/MetaXR/Source/OculusXRProjectSetupTool/Private/Rules/OculusXRCompatibilityRules.cpp create mode 100644 Plugins/MetaXR/Source/OculusXRProjectSetupTool/Private/Rules/OculusXRCompatibilityRules.h create mode 100644 Plugins/MetaXR/Source/OculusXRProjectSetupTool/Private/Rules/OculusXRMovementRules.cpp create mode 100644 Plugins/MetaXR/Source/OculusXRProjectSetupTool/Private/Rules/OculusXRMovementRules.h create mode 100644 Plugins/MetaXR/Source/OculusXRProjectSetupTool/Private/Rules/OculusXRPassthroughRules.cpp create mode 100644 Plugins/MetaXR/Source/OculusXRProjectSetupTool/Private/Rules/OculusXRPassthroughRules.h create mode 100644 Plugins/MetaXR/Source/OculusXRProjectSetupTool/Private/Rules/OculusXRPluginRules.cpp create mode 100644 Plugins/MetaXR/Source/OculusXRProjectSetupTool/Private/Rules/OculusXRPluginRules.h create mode 100644 Plugins/MetaXR/Source/OculusXRProjectSetupTool/Private/Rules/OculusXRRenderingRules.cpp create mode 100644 Plugins/MetaXR/Source/OculusXRProjectSetupTool/Private/Rules/OculusXRRenderingRules.h create mode 100644 Plugins/MetaXR/Source/OculusXRProjectSetupTool/Private/Tests/OculusXRProjectSetupTool.spec.cpp create mode 100644 Plugins/MetaXR/Source/OculusXRProjectSetupTool/Private/Widget/OculusXRProjectSetupToolWidget.cpp create mode 100644 Plugins/MetaXR/Source/OculusXRProjectSetupTool/Private/Widget/OculusXRProjectSetupToolWidget.h create mode 100644 Plugins/MetaXR/Source/OculusXRProjectSetupTool/Private/Widget/OculusXRProjectTutorialWidget.cpp create mode 100644 Plugins/MetaXR/Source/OculusXRProjectSetupTool/Private/Widget/OculusXRProjectTutorialWidget.h create mode 100644 Plugins/MetaXR/Source/OculusXRProjectSetupTool/Private/Widget/OculusXRStatusBarWidget.cpp create mode 100644 Plugins/MetaXR/Source/OculusXRProjectSetupTool/Private/Widget/OculusXRStatusBarWidget.h create mode 100644 Plugins/MetaXR/Source/OculusXRProjectSetupTool/Public/IOculusXRProjectSetupModule.h create mode 100644 Plugins/MetaXR/Source/OculusXRProjectSetupTool/Public/OculusXRPSTSettings.h create mode 100644 Plugins/MetaXR/Source/OculusXRProjectSetupTool/Public/OculusXRRuleProcessorSubsystem.h create mode 100644 Plugins/MetaXR/Source/OculusXRProjectSetupTool/Public/OculusXRSetupRule.h create mode 100644 Plugins/MetaXR/Source/OculusXRScene/OculusXRScene.Build.cs create mode 100644 Plugins/MetaXR/Source/OculusXRScene/Private/OculusXRScene.cpp create mode 100644 Plugins/MetaXR/Source/OculusXRScene/Private/OculusXRSceneActor.cpp create mode 100644 Plugins/MetaXR/Source/OculusXRScene/Private/OculusXRSceneAnchorComponent.cpp create mode 100644 Plugins/MetaXR/Source/OculusXRScene/Private/OculusXRSceneDelegates.cpp create mode 100644 Plugins/MetaXR/Source/OculusXRScene/Private/OculusXRSceneEventHandling.cpp create mode 100644 Plugins/MetaXR/Source/OculusXRScene/Private/OculusXRSceneEventHandling.h create mode 100644 Plugins/MetaXR/Source/OculusXRScene/Private/OculusXRSceneFunctionLibrary.cpp create mode 100644 Plugins/MetaXR/Source/OculusXRScene/Private/OculusXRSceneGlobalMeshComponent.cpp create mode 100644 Plugins/MetaXR/Source/OculusXRScene/Private/OculusXRSceneModule.cpp create mode 100644 Plugins/MetaXR/Source/OculusXRScene/Private/OculusXRSceneModule.h create mode 100644 Plugins/MetaXR/Source/OculusXRScene/Private/OculusXRSceneSubsystem.cpp create mode 100644 Plugins/MetaXR/Source/OculusXRScene/Public/IOculusXRSceneModule.h create mode 100644 Plugins/MetaXR/Source/OculusXRScene/Public/OculusXRScene.h create mode 100644 Plugins/MetaXR/Source/OculusXRScene/Public/OculusXRSceneActor.h create mode 100644 Plugins/MetaXR/Source/OculusXRScene/Public/OculusXRSceneAnchorComponent.h create mode 100644 Plugins/MetaXR/Source/OculusXRScene/Public/OculusXRSceneDelegates.h create mode 100644 Plugins/MetaXR/Source/OculusXRScene/Public/OculusXRSceneEventDelegates.h create mode 100644 Plugins/MetaXR/Source/OculusXRScene/Public/OculusXRSceneFunctionLibrary.h create mode 100644 Plugins/MetaXR/Source/OculusXRScene/Public/OculusXRSceneGlobalMeshComponent.h create mode 100644 Plugins/MetaXR/Source/OculusXRScene/Public/OculusXRSceneSubsystem.h create mode 100644 Plugins/MetaXR/Source/OculusXRScene/Public/OculusXRSceneTypes.h create mode 100644 Plugins/MetaXR/Source/Thirdparty/KhronosOpenXR/KhronosOpenXRHeaders.build.cs create mode 100644 Plugins/MetaXR/Source/Thirdparty/KhronosOpenXR/LICENSE create mode 100644 Plugins/MetaXR/Source/Thirdparty/KhronosOpenXR/LICENSES/Apache-2.0.txt create mode 100644 Plugins/MetaXR/Source/Thirdparty/KhronosOpenXR/LICENSES/MIT.txt create mode 100644 Plugins/MetaXR/Source/Thirdparty/KhronosOpenXR/include/khronos/openxr/openxr.h create mode 100644 Plugins/MetaXR/Source/Thirdparty/KhronosOpenXR/include/khronos/openxr/openxr_platform.h create mode 100644 Plugins/MetaXR/Source/Thirdparty/KhronosOpenXR/include/khronos/openxr/openxr_platform_defines.h create mode 100644 Plugins/MetaXR/Source/Thirdparty/KhronosOpenXR/include/khronos/openxr/openxr_reflection.h create mode 100644 Plugins/MetaXR/Source/Thirdparty/KhronosOpenXR/include/khronos/openxr/openxr_reflection_parent_structs.h create mode 100644 Plugins/MetaXR/Source/Thirdparty/KhronosOpenXR/include/khronos/openxr/openxr_reflection_structs.h create mode 100644 Plugins/MetaXR/Source/Thirdparty/OVRPlugin/OVRPlugin/Include/OVR_Plugin.h create mode 100644 Plugins/MetaXR/Source/Thirdparty/OVRPlugin/OVRPlugin/Include/OVR_Plugin_Deprecated.h create mode 100644 Plugins/MetaXR/Source/Thirdparty/OVRPlugin/OVRPlugin/Include/OVR_Plugin_Insight.h create mode 100644 Plugins/MetaXR/Source/Thirdparty/OVRPlugin/OVRPlugin/Include/OVR_Plugin_Ktx.h create mode 100644 Plugins/MetaXR/Source/Thirdparty/OVRPlugin/OVRPlugin/Include/OVR_Plugin_Media.h create mode 100644 Plugins/MetaXR/Source/Thirdparty/OVRPlugin/OVRPlugin/Include/OVR_Plugin_MixedReality.h create mode 100644 Plugins/MetaXR/Source/Thirdparty/OVRPlugin/OVRPlugin/Include/OVR_Plugin_MixedReality_Deprecated.h create mode 100644 Plugins/MetaXR/Source/Thirdparty/OVRPlugin/OVRPlugin/Include/OVR_Plugin_Types.h create mode 100644 Plugins/MetaXR/Source/Thirdparty/OVRPlugin/OVRPlugin/Include/OVR_Plugin_Types_Deprecated.h create mode 100644 Plugins/MetaXR/Source/Thirdparty/OVRPlugin/OVRPlugin/LICENSE.txt create mode 100644 Plugins/MetaXR/Source/Thirdparty/OVRPlugin/OVRPluginXR.build.cs create mode 100644 Plugins/MetaXR/Source/Thirdparty/OpenXR/LICENSE create mode 100644 Plugins/MetaXR/Source/Thirdparty/OpenXR/LICENSES/Apache-2.0.txt create mode 100644 Plugins/MetaXR/Source/Thirdparty/OpenXR/LICENSES/MIT.txt create mode 100644 Plugins/MetaXR/Source/Thirdparty/OpenXR/OpenXRHeaders.build.cs create mode 100644 Plugins/MetaXR/Source/Thirdparty/OpenXR/include/khronos/openxr/openxr.h create mode 100644 Plugins/MetaXR/Source/Thirdparty/OpenXR/include/khronos/openxr/openxr_platform.h create mode 100644 Plugins/MetaXR/Source/Thirdparty/OpenXR/include/khronos/openxr/openxr_platform_defines.h create mode 100644 Plugins/MetaXR/Source/Thirdparty/OpenXR/include/khronos/openxr/openxr_reflection.h diff --git a/Config/DefaultEngine.ini b/Config/DefaultEngine.ini index c2d7c6c..6ed0593 100644 --- a/Config/DefaultEngine.ini +++ b/Config/DefaultEngine.ini @@ -112,7 +112,7 @@ VisualizeCalibrationColorMaterialPath=None VisualizeCalibrationCustomMaterialPath=None VisualizeCalibrationGrayscaleMaterialPath=None r.Mobile.AntiAliasing=3 -r.Mobile.FloatPrecisionMode=2 +r.Mobile.FloatPrecisionMode=0 r.OpenGL.ForceDXC=0 r.DynamicGlobalIlluminationMethod=1 @@ -183,8 +183,8 @@ StoreVersionOffsetArm64=0 StoreVersionOffsetX8664=0 ApplicationDisplayName= VersionDisplayName=1.0 -MinSDKVersion=23 -TargetSDKVersion=25 +MinSDKVersion=32 +TargetSDKVersion=32 InstallLocation=InternalOnly bEnableLint=False bPackageDataInsideApk=True diff --git a/Plugins/MetaXR/Config/BaseOculusXR.ini b/Plugins/MetaXR/Config/BaseOculusXR.ini new file mode 100644 index 0000000..cd0a0ca --- /dev/null +++ b/Plugins/MetaXR/Config/BaseOculusXR.ini @@ -0,0 +1,140 @@ +[CoreRedirects] +; ++PackageRedirects=(OldName="/OculusVR/",NewName="/OculusXR/",MatchSubstring=true) +; ++ClassRedirects=(OldName="/Script/OculusHMD.OculusResourceHolder", NewName="/Script/OculusXRHMD.OculusXRResourceHolder") ++ClassRedirects=(OldName="/Script/OculusHMD.OculusPassthroughLayerComponent", NewName="/Script/OculusXRPassthrough.OculusXRPassthroughLayerComponent") ++ClassRedirects=(OldName="/Script/OculusHMD.StereoLayerShapeUserDefined", NewName="/Script/OculusXRPassthrough.OculusXRStereoLayerShapeUserDefined") ++ClassRedirects=(OldName="/Script/OculusHMD.StereoLayerShapeReconstructed", NewName="/Script/OculusXRPassthrough.OculusXRStereoLayerShapeReconstructed") ++ClassRedirects=(OldName="/Script/OculusHMD.OculusHMDRuntimeSettings", NewName="/Script/OculusXRHMD.OculusXRHMDRuntimeSettings") ++ClassRedirects=(OldName="/Script/OculusHMD.OculusEventComponent", NewName="/Script/OculusXRHMD.OculusXREventComponent") ++ClassRedirects=(OldName="/Script/OculusHMD.OculusSceneCaptureCubemap", NewName="/Script/OculusXRHMD.OculusXRSceneCaptureCubemap") ++ClassRedirects=(OldName="/Script/OculusHMD.PassthroughLayerBase", NewName="/Script/OculusXRPassthrough.OculusXRPassthroughLayerBase") ++ClassRedirects=(OldName="/Script/OculusHMD.OculusFunctionLibrary", NewName="/Script/OculusXRHMD.OculusXRFunctionLibrary") +; ++EnumRedirects=(OldName="EOculusXrApi", NewName="/Script/OculusXRHMD.EOculusXRXrApi") ++EnumRedirects=(OldName="EHandTrackingSupport", NewName="/Script/OculusXRHMD.EOculusXRHandTrackingSupport") ++EnumRedirects=(OldName="ETrackedDeviceType", NewName="/Script/OculusXRHMD.EOculusXRTrackedDeviceType") ++EnumRedirects=(OldName="EHandTrackingFrequency", NewName="/Script/OculusXRHMD.EOculusXRHandTrackingFrequency") ++EnumRedirects=(OldName="EColorMapType", NewName="/Script/OculusXRHMD.EOculusXRColorMapType") ++EnumRedirects=(OldName="EPassthroughLayerOrder", NewName="/Script/OculusXRHMD.EOculusXRPassthroughLayerOrder") ++EnumRedirects=(OldName="EOculusDeviceType", NewName="/Script/OculusXRHMD.EOculusXRDeviceType") ++EnumRedirects=(OldName="EColorSpace", NewName="/Script/OculusXRHMD.EOculusXRColorSpace") ++EnumRedirects=(OldName="EBoundaryType", NewName="/Script/OculusXRHMD.EOculusXRBoundaryType") ++EnumRedirects=(OldName="EProcessorPerformanceLevel", NewName="/Script/OculusXRHMD.EOculusXRProcessorPerformanceLevel") +; ++StructRedirects=(OldName="/Script/OculusHMD.GuardianTestResult", NewName="/Script/OculusXRHMD.OculusXRGuardianTestResult") ++StructRedirects=(OldName="/Script/OculusHMD.OculusSplashDesc", NewName="/Script/OculusXRHMD.OculusXRSplashDesc") ++StructRedirects=(OldName="/Script/OculusHMD.HmdUserProfile", NewName="/Script/OculusXRHMD.OculusXRHmdUserProfile") ++StructRedirects=(OldName="/Script/OculusHMD.HmdUserProfileField", NewName="/Script/OculusXRHMD.OculusXRHmdUserProfileField") +; ++ClassRedirects=(OldName="/Script/OculusInput.OculusHandComponent", NewName="/Script/OculusXRInput.OculusXRHandComponent") ++ClassRedirects=(OldName="/Script/OculusInput.OculusMRFunctionLibrary", NewName="/Script/OculusXRInput.OculusXRMRFunctionLibrary") ++ClassRedirects=(OldName="/Script/OculusInput.OculusInputFunctionLibrary", NewName="/Script/OculusXRInput.OculusXRInputFunctionLibrary") +; ++EnumRedirects=(OldName="ETrackingConfidence", NewName="/Script/OculusXRInput.EOculusXRTrackingConfidence") ++EnumRedirects=(OldName="EConfidenceBehavior", NewName="/Script/OculusXRInput.EOculusXRConfidenceBehavior") ++EnumRedirects=(OldName="EOculusHandType", NewName="/Script/OculusXRInput.EOculusXRHandType") ++EnumRedirects=(OldName="EOculusFinger", NewName="/Script/OculusXRInput.EOculusXRFinger") ++EnumRedirects=(OldName="ESystemGestureBehavior", NewName="/Script/OculusXRInput.EOculusXRSystemGestureBehavior") ++EnumRedirects=(OldName="EBone", NewName="/Script/OculusXRInput.EOculusXRBone") +; ++StructRedirects=(OldName="/Script/OculusInput.OculusCapsuleCollider", NewName="/Script/OculusXRInput.OculusXRCapsuleCollider") +; +; +; +; ++ClassRedirects=(OldName="/Script/OculusEditor.OculusHMDRuntimeSettings", NewName="/Script/OculusXREditor.OculusXRHMDRuntimeSettings") ++ClassRedirects=(OldName="/Script/OculusEditor.OculusEditorSettings", NewName="/Script/OculusXREditor.OculusXREditorSettings") ++ClassRedirects=(OldName="/Script/OculusEditor.OculusPlatformToolSettings", NewName="/Script/OculusXREditor.OculusXRPlatformToolSettings") +; ++EnumRedirects=(OldName="EOculusAssetType", NewName="/Script/OculusXREditor.EOculusXRAssetType") ++EnumRedirects=(OldName="EOculusPlatform", NewName="/Script/OculusXREditor.EOculusXRPlatform") ++EnumRedirects=(OldName="EOculusGamepadEmulation", NewName="/Script/OculusXREditor.EOculusXRGamepadEmulation") +; ++StructRedirects=(OldName="/Script/OculusEditor.RedistPackage", NewName="/Script/OculusXREditor.OculusXRRedistPackage") ++StructRedirects=(OldName="/Script/OculusEditor.AssetConfig", NewName="/Script/OculusXREditor.OculusXRAssetConfig") +; ++ClassRedirects=(OldName="/Script/OculusMR.OculusFunctionLibrary", NewName="/Script/OculusMR.OculusXRFunctionLibrary") ++ClassRedirects=(OldName="/Script/OculusMR.OculusMR_Settings", NewName="/Script/OculusMR.OculusXRMR_Settings") ++ClassRedirects=(OldName="/Script/OculusMR.OculusMRFunctionLibrary", NewName="/Script/OculusMR.OculusXRMRFunctionLibrary") +; ++EnumRedirects=(OldName="EOculusMR_CameraDeviceEnum", NewName="/Script/OculusMR.EOculusXRMR_CameraDeviceEnum") ++EnumRedirects=(OldName="EOculusMR_PostProcessEffects", NewName="/Script/OculusMR.EOculusXRMR_PostProcessEffects") ++EnumRedirects=(OldName="EOculusMR_CompositionMethod", NewName="/Script/OculusMR.EOculusXRMR_CompositionMethod") ++EnumRedirects=(OldName="EOculusMR_ClippingReference", NewName="/Script/OculusMR.EOculusXRMR_ClippingReference") +; ++StructRedirects=(OldName="/Script/OculusMR.OculusMR_PlaneMeshTriangle", NewName="/Script/OculusMR.OculusXRMR_PlaneMeshTriangle") ++StructRedirects=(OldName="/Script/OculusMR.TrackedCamera", NewName="/Script/OculusMR.OculusXRTrackedCamera") +; ++EnumRedirects=(OldName="EOculusXRXrApi",ValueChanges=(("LegacyOVRPlugin","OVRPluginOpenXR"))) +; ++EnumRedirects=(OldName="ETiledMultiResLevel",NewName="EOculusXRFoveatedRenderingLevel",ValueChanges=(("ETiledMultiResLevel_Off","Off"),("ETiledMultiResLevel_LMSLow","Low"),("ETiledMultiResLevel_LMSMedium","Medium"),("ETiledMultiResLevel_LMSHigh","High"),("ETiledMultiResLevel_LMSHighTop","HighTop"))) ++FunctionRedirects=(OldName="GetTiledMultiresLevel",NewName="GetFoveatedRenderingLevel") ++FunctionRedirects=(OldName="SetTiledMultiresLevel",NewName="SetFoveatedRenderingLevel") ++EnumRedirects=(OldName="EFixedFoveatedRenderingLevel",NewName="EOculusXRFoveatedRenderingLevel",ValueChanges=(("FFR_Off","Off"),("FFR_Low","Low"),("FFR_Medium","Medium"),("FFR_High","High"),("FFR_HighTop","HighTop"))) ++FunctionRedirects=(OldName="GetFixedFoveatedRenderingLevel",NewName="GetFoveatedRenderingLevel") ++FunctionRedirects=(OldName="SetFixedFoveatedRenderingLevel",NewName="SetFoveatedRenderingLevel") +; ++EnumRedirects=(OldName="/Script/OculusXRHMD.EOculusDeviceType",ValueChanges=(("OculusQuest","OculusQuest_Deprecated"),("Quest_Link","Quest_Link_Deprecated"))) +; +; Anchors and Scene redirects ++StructRedirects=(OldName="/Script/OculusAnchors.OculusSpaceQueryInfo", NewName="/Script/OculusXRAnchors.OculusXRSpaceQueryInfo") ++StructRedirects=(OldName="/Script/OculusAnchors.OculusSpaceQueryResult", NewName="/Script/OculusXRAnchors.OculusXRSpaceQueryResult") ++StructRedirects=(OldName="/Script/OculusAnchors.OculusSpaceQueryFilterValues", NewName="/Script/OculusXRAnchors.OculusXRSpaceQueryFilterValues") ++StructRedirects=(OldName="/Script/OculusAnchors.OculusAnchorManager", NewName="/Script/OculusXRAnchors.OculusXRAnchorManager") ++StructRedirects=(OldName="/Script/OculusAnchors.OculusSpatialAnchorManager", NewName="/Script/OculusXRAnchors.OculusXRSpatialAnchorManager") ++StructRedirects=(OldName="/Script/OculusAnchors.OculusRoomLayoutManager", NewName="/Script/OculusXRAnchors.OculusXRRoomLayoutManager") ++StructRedirects=(OldName="/Script/OculusAnchors.OculusAnchors", NewName="/Script/OculusXRAnchors.OculusXRAnchors") ++StructRedirects=(OldName="/Script/OculusAnchors.OculusRoomLayout", NewName="/Script/OculusXRAnchors.OculusXRRoomLayout") ++StructRedirects=(OldName="/Script/OculusScene.OculusSpawnedSceneAnchorProperties", NewName="/Script/OculusXRScene.OculusXRSpawnedSceneAnchorProperties") ++StructRedirects=(OldName="/Script/OculusAnchors.UUID", NewName="/Script/OculusXRAnchors.OculusXRUUID") ++StructRedirects=(OldName="/Script/OculusAnchors.UInt64", NewName="/Script/OculusXRAnchors.OculusXRUInt64") +; ++EnumRedirects=(OldName="EOculusSpaceQueryFilterType", NewName="/Script/OculusXRAnchors.EOculusXRSpaceQueryFilterType") ++EnumRedirects=(OldName="EOculusSpaceStorageLocation", NewName="/Script/OculusXRAnchors.EOculusXRSpaceStorageLocation") ++EnumRedirects=(OldName="EOculusSpaceStoragePersistenceMode", NewName="/Script/OculusXRAnchors.EOculusXRSpaceStoragePersistenceMode") ++EnumRedirects=(OldName="EOculusSpaceComponentType", NewName="/Script/OculusXRAnchors.EOculusXRSpaceComponentType") ++EnumRedirects=(OldName="EOculusLaunchCaptureFlowWhenMissingScene", NewName="/Script/OculusXRScene.EOculusXRLaunchCaptureFlowWhenMissingScene") +; ++ClassRedirects=(OldName="/Script/OculusAnchors.OculusAnchorComponent", NewName="/Script/OculusXRAnchors.OculusXRAnchorComponent") ++ClassRedirects=(OldName="/Script/OculusAnchors.OculusAnchorBPFuctionLibrary", NewName="/Script/OculusXRAnchors.OculusXRAnchorBPFuctionLibrary") ++ClassRedirects=(OldName="/Script/OculusAnchors.OculusAsyncAction_CreateSpatialAnchor", NewName="/Script/OculusXRAnchors.OculusXRAsyncAction_CreateSpatialAnchor") ++ClassRedirects=(OldName="/Script/OculusAnchors.OculusAsyncAction_EraseAnchor", NewName="/Script/OculusXRAnchors.OculusXRAsyncAction_EraseAnchor") ++ClassRedirects=(OldName="/Script/OculusAnchors.OculusAsyncAction_SaveAnchor", NewName="/Script/OculusXRAnchors.OculusXRAsyncAction_SaveAnchor") ++ClassRedirects=(OldName="/Script/OculusAnchors.OculusAsyncAction_QueryAnchors", NewName="/Script/OculusXRAnchors.OculusXRAsyncAction_QueryAnchors") ++ClassRedirects=(OldName="/Script/OculusAnchors.OculusAsyncAction_SetAnchorComponentStatus", NewName="/Script/OculusXRAnchors.OculusXRAsyncAction_SetAnchorComponentStatus") ++ClassRedirects=(OldName="/Script/OculusAnchors.OculusRoomLayoutManagerComponent", NewName="/Script/OculusXRAnchors.OculusXRRoomLayoutManagerComponent") ++ClassRedirects=(OldName="/Script/OculusAnchors.OculusSpatialAnchorComponent", NewName="/Script/OculusXRAnchors.OculusXRSpatialAnchorComponent") ++ClassRedirects=(OldName="/Script/OculusScene.OculusSceneAnchorComponent", NewName="/Script/OculusXRScene.OculusXRSceneAnchorComponent") ++ClassRedirects=(OldName="/Script/OculusScene.OculusSceneActor", NewName="/Script/OculusXRScene.OculusXRSceneActor") +; ++FunctionRedirects=(OldName="OculusAsyncAction_CreateSpatialAnchor.OculusAsyncCreateSpatialAnchor",NewName="OculusXRAsyncAction_CreateSpatialAnchor.OculusXRAsyncCreateSpatialAnchor") ++FunctionRedirects=(OldName="OculusAsyncAction_EraseAnchor.OculusAsyncEraseAnchor",NewName="OculusXRAsyncAction_EraseAnchor.OculusXRAsyncEraseAnchor") ++FunctionRedirects=(OldName="OculusAsyncAction_SaveAnchor.OculusAsyncSaveAnchor",NewName="OculusXRAsyncAction_SaveAnchor.OculusXRAsyncSaveAnchor") ++FunctionRedirects=(OldName="OculusAsyncAction_QueryAnchors.OculusAsyncQueryAnchors",NewName="OculusXRAsyncAction_QueryAnchors.OculusXRAsyncQueryAnchors") ++FunctionRedirects=(OldName="OculusAsyncAction_QueryAnchors.OculusAsyncQueryAnchorsAdvanced",NewName="OculusXRAsyncAction_QueryAnchors.OculusXRAsyncQueryAnchorsAdvanced") ++FunctionRedirects=(OldName="OculusAsyncAction_SetAnchorComponentStatus.OculusAsyncSetAnchorComponentStatus",NewName="OculusXRAsyncAction_SetAnchorComponentStatus.OculusXRAsyncSetAnchorComponentStatus") +; ++ClassRedirects=(OldName="/Script/OculusXRHMD.OculusXRPassthroughLayerComponent", NewName="/Script/OculusXRPassthrough.OculusXRPassthroughLayerComponent") ++ClassRedirects=(OldName="/Script/OculusXRHMD.OculusXRPassthroughLayerBase", NewName="/Script/OculusXRPassthrough.OculusXRPassthroughLayerBase") ++ClassRedirects=(OldName="/Script/OculusXRHMD.OculusXRStereoLayerShapeUserDefined", NewName="/Script/OculusXRPassthrough.OculusXRStereoLayerShapeUserDefined") ++ClassRedirects=(OldName="/Script/OculusXRHMD.OculusXRStereoLayerShapeReconstructed", NewName="/Script/OculusXRPassthrough.OculusXRStereoLayerShapeReconstructed") + +; Movement ++EnumRedirects=(OldName="EOculusBodyTrackingMode", NewName="/Script/OculusXRMovement.EOculusXRBodyTrackingMode") ++EnumRedirects=(OldName="EOculusBoneID", NewName="/Script/OculusXRMovement.EOculusXRBoneID") ++EnumRedirects=(OldName="EOculusFaceExpression", NewName="/Script/OculusXRMovement.EOculusXRFaceExpression") ++EnumRedirects=(OldName="EOculusFaceConfidence", NewName="/Script/OculusXRMovement.EOculusXRFaceConfidence") ++EnumRedirects=(OldName="EOculusEye", NewName="/Script/OculusXRMovement.EOculusXREye") +; ++StructRedirects=(OldName="/Script/OculusMovement.OculusBodyJoint", NewName="/Script/OculusXRMovement.OculusXRBodyJoint") ++StructRedirects=(OldName="/Script/OculusMovement.OculusBodyState", NewName="/Script/OculusXRMovement.OculusXRBodyState") ++StructRedirects=(OldName="/Script/OculusMovement.OculusFaceState", NewName="/Script/OculusXRMovement.OculusXRFaceState") ++StructRedirects=(OldName="/Script/OculusMovement.OculusEyeGazeState", NewName="/Script/OculusXRMovement.OculusXREyeGazeState") ++StructRedirects=(OldName="/Script/OculusMovement.OculusEyeGazesState", NewName="/Script/OculusXRMovement.OculusXREyeGazesState") +; ++ClassRedirects=(OldName="/Script/OculusMovement.OculusBodyTrackingComponent", NewName="/Script/OculusXRMovement.OculusXRBodyTrackingComponent") ++ClassRedirects=(OldName="/Script/OculusMovement.OculusEyeTrackingComponent", NewName="/Script/OculusXRMovement.OculusXREyeTrackingComponent") ++ClassRedirects=(OldName="/Script/OculusMovement.OculusFaceTrackingComponent", NewName="/Script/OculusXRMovement.OculusXRFaceTrackingComponent") ++ClassRedirects=(OldName="/Script/OculusMovement.OculusMovementFunctionLibrary", NewName="/Script/OculusXRMovement.OculusXRMovementFunctionLibrary") diff --git a/Plugins/MetaXR/Config/FilterPlugin.ini b/Plugins/MetaXR/Config/FilterPlugin.ini new file mode 100644 index 0000000..9d21933 --- /dev/null +++ b/Plugins/MetaXR/Config/FilterPlugin.ini @@ -0,0 +1,14 @@ +[FilterPlugin] +; This section lists additional files which will be packaged along with your plugin. Paths should be listed relative to the root plugin directory, and +; may include "...", "*", and "?" wildcards to match directories, files, and individual characters respectively. +; +; Examples: +; /README.txt +; /Extras/... +; /Binaries/ThirdParty/*.dll +/Config/... +/build.log +/Shaders/... +/Source/Thirdparty/... + + diff --git a/Plugins/MetaXR/Content/Materials/LeftMetaQuestTouchPlusMaterial.uasset b/Plugins/MetaXR/Content/Materials/LeftMetaQuestTouchPlusMaterial.uasset new file mode 100644 index 0000000..91f2538 --- /dev/null +++ b/Plugins/MetaXR/Content/Materials/LeftMetaQuestTouchPlusMaterial.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:18b4cd5b341fdf48d7f3011f2432cbc4c92e12a8dc1ff927b38644752eb36ecb +size 9496 diff --git a/Plugins/MetaXR/Content/Materials/LeftMetaQuestTouchProBatteryIndicatorMaterial.uasset b/Plugins/MetaXR/Content/Materials/LeftMetaQuestTouchProBatteryIndicatorMaterial.uasset new file mode 100644 index 0000000..a0c16d7 --- /dev/null +++ b/Plugins/MetaXR/Content/Materials/LeftMetaQuestTouchProBatteryIndicatorMaterial.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a61acc9ffab64e3b5a61c33e7956b1d6120f9a4ff04478e5c953d2b993c91383 +size 10304 diff --git a/Plugins/MetaXR/Content/Materials/LeftMetaQuestTouchProMaterial.uasset b/Plugins/MetaXR/Content/Materials/LeftMetaQuestTouchProMaterial.uasset new file mode 100644 index 0000000..ecfb794 --- /dev/null +++ b/Plugins/MetaXR/Content/Materials/LeftMetaQuestTouchProMaterial.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a7b09956cc5b47dc73e3d3df164c6729aa60a4c40907d4fc890545d691738f68 +size 10447 diff --git a/Plugins/MetaXR/Content/Materials/MetaQuestTouchProBatteryIndicatorMaterial.uasset b/Plugins/MetaXR/Content/Materials/MetaQuestTouchProBatteryIndicatorMaterial.uasset new file mode 100644 index 0000000..480b235 --- /dev/null +++ b/Plugins/MetaXR/Content/Materials/MetaQuestTouchProBatteryIndicatorMaterial.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:66ea7aed173476c8fffcd897f6ad05578afb0fb4a1c8905fddf8f84a19c3051a +size 86538 diff --git a/Plugins/MetaXR/Content/Materials/MetaQuestTouchProMaterial.uasset b/Plugins/MetaXR/Content/Materials/MetaQuestTouchProMaterial.uasset new file mode 100644 index 0000000..653c1dd --- /dev/null +++ b/Plugins/MetaXR/Content/Materials/MetaQuestTouchProMaterial.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ca52344d9f210e3765146e18b566381198605894dcf484bdbaa4e3f198012bc3 +size 83175 diff --git a/Plugins/MetaXR/Content/Materials/OculusMR_ChromaKey.uasset b/Plugins/MetaXR/Content/Materials/OculusMR_ChromaKey.uasset new file mode 100644 index 0000000..8360b1c --- /dev/null +++ b/Plugins/MetaXR/Content/Materials/OculusMR_ChromaKey.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a08c44e3ac881924182cf152ef04768fa4673124b9fde9dfd3657d687d5fd527 +size 167711 diff --git a/Plugins/MetaXR/Content/Materials/OculusMR_OpaqueColoredMaterial.uasset b/Plugins/MetaXR/Content/Materials/OculusMR_OpaqueColoredMaterial.uasset new file mode 100644 index 0000000..310103e --- /dev/null +++ b/Plugins/MetaXR/Content/Materials/OculusMR_OpaqueColoredMaterial.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:56e4bb5c2b9e5d0765e0fbd36be331f9c2ab0dbc260cc83cf6e97a4d019834eb +size 94122 diff --git a/Plugins/MetaXR/Content/Materials/OculusMR_WhiteMaterial.uasset b/Plugins/MetaXR/Content/Materials/OculusMR_WhiteMaterial.uasset new file mode 100644 index 0000000..501e4c8 --- /dev/null +++ b/Plugins/MetaXR/Content/Materials/OculusMR_WhiteMaterial.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5c3c46ffd291896349c33c643f6a487b9d1dd7397928d31e8e35733af34fbc83 +size 59981 diff --git a/Plugins/MetaXR/Content/Materials/PokeAHoleMaterial.uasset b/Plugins/MetaXR/Content/Materials/PokeAHoleMaterial.uasset new file mode 100644 index 0000000..5862022 --- /dev/null +++ b/Plugins/MetaXR/Content/Materials/PokeAHoleMaterial.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:34b2ede22fa887498b332b44dde4179f376820a3047ae37f7128efa51d79ba95 +size 6499 diff --git a/Plugins/MetaXR/Content/Materials/RightMetaQuestTouchPlusMaterial.uasset b/Plugins/MetaXR/Content/Materials/RightMetaQuestTouchPlusMaterial.uasset new file mode 100644 index 0000000..58d51ea --- /dev/null +++ b/Plugins/MetaXR/Content/Materials/RightMetaQuestTouchPlusMaterial.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8533a56d45e68757df582780a1b53fef2a67dab954eeecf1407bcf2f6c1f0139 +size 9368 diff --git a/Plugins/MetaXR/Content/Materials/RightMetaQuestTouchProBatteryIndicatorMaterial.uasset b/Plugins/MetaXR/Content/Materials/RightMetaQuestTouchProBatteryIndicatorMaterial.uasset new file mode 100644 index 0000000..d063a10 --- /dev/null +++ b/Plugins/MetaXR/Content/Materials/RightMetaQuestTouchProBatteryIndicatorMaterial.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:79ee74d05bf719de83532ac298cba55d07246aae025582d7596ccf3304865948 +size 10312 diff --git a/Plugins/MetaXR/Content/Materials/RightMetaQuestTouchProMaterial.uasset b/Plugins/MetaXR/Content/Materials/RightMetaQuestTouchProMaterial.uasset new file mode 100644 index 0000000..595f768 --- /dev/null +++ b/Plugins/MetaXR/Content/Materials/RightMetaQuestTouchProMaterial.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a2235389523b132b61a9a3181c0da746dc6602bb8a5734d61c9dd50ec3fd6066 +size 9918 diff --git a/Plugins/MetaXR/Content/Materials/TouchForQuest2Material.uasset b/Plugins/MetaXR/Content/Materials/TouchForQuest2Material.uasset new file mode 100644 index 0000000..c36c3ba --- /dev/null +++ b/Plugins/MetaXR/Content/Materials/TouchForQuest2Material.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f7c6b15d5326132ba49af186ca77694380307cb4ada1d4c16e1bafaec77454a7 +size 10829 diff --git a/Plugins/MetaXR/Content/Materials/TouchForQuestRiftSControllerMaterial.uasset b/Plugins/MetaXR/Content/Materials/TouchForQuestRiftSControllerMaterial.uasset new file mode 100644 index 0000000..1958b33 --- /dev/null +++ b/Plugins/MetaXR/Content/Materials/TouchForQuestRiftSControllerMaterial.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:36520d74b4b291d8687afbb60a418e64e7f51652976f3b94d7fcb11f7da6b44f +size 99699 diff --git a/Plugins/MetaXR/Content/Materials/model_pieces_controllerMATphongRT.uasset b/Plugins/MetaXR/Content/Materials/model_pieces_controllerMATphongRT.uasset new file mode 100644 index 0000000..a089fb0 --- /dev/null +++ b/Plugins/MetaXR/Content/Materials/model_pieces_controllerMATphongRT.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:577e3f7b7075af3fd27cdc28634a4f53d99c54075dd7f989732d94037906a826 +size 111033 diff --git a/Plugins/MetaXR/Content/Materials/touchController_mat.uasset b/Plugins/MetaXR/Content/Materials/touchController_mat.uasset new file mode 100644 index 0000000..0e14920 --- /dev/null +++ b/Plugins/MetaXR/Content/Materials/touchController_mat.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3e824230bd07de2ed74be6b8ddbd5f494c548926f4e3c3c46c0e8bcbb663c2e7 +size 95047 diff --git a/Plugins/MetaXR/Content/Meshes/LeftMetaQuestTouchPlus.fbx b/Plugins/MetaXR/Content/Meshes/LeftMetaQuestTouchPlus.fbx new file mode 100644 index 0000000..fabe4d7 --- /dev/null +++ b/Plugins/MetaXR/Content/Meshes/LeftMetaQuestTouchPlus.fbx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4f62b338735c8087992c208663a0dcb6ae8c95928c1edea3c44f8b37d04da04f +size 287792 diff --git a/Plugins/MetaXR/Content/Meshes/LeftMetaQuestTouchPlus.uasset b/Plugins/MetaXR/Content/Meshes/LeftMetaQuestTouchPlus.uasset new file mode 100644 index 0000000..38c6e6c --- /dev/null +++ b/Plugins/MetaXR/Content/Meshes/LeftMetaQuestTouchPlus.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fbbe2060876c117412fbe59652c58ded6d9c6dd394e69db67c322eb13729af10 +size 222375 diff --git a/Plugins/MetaXR/Content/Meshes/LeftMetaQuestTouchPlusBatteryIndicatorQuad.uasset b/Plugins/MetaXR/Content/Meshes/LeftMetaQuestTouchPlusBatteryIndicatorQuad.uasset new file mode 100644 index 0000000..a7e75e1 --- /dev/null +++ b/Plugins/MetaXR/Content/Meshes/LeftMetaQuestTouchPlusBatteryIndicatorQuad.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e39c18f4f4084cc7586d0c1277aafa45ee1e8beb89bc2cffb7d48726b0ccb4b5 +size 16434 diff --git a/Plugins/MetaXR/Content/Meshes/LeftMetaQuestTouchPro.uasset b/Plugins/MetaXR/Content/Meshes/LeftMetaQuestTouchPro.uasset new file mode 100644 index 0000000..c7d211a --- /dev/null +++ b/Plugins/MetaXR/Content/Meshes/LeftMetaQuestTouchPro.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:df4df64c2debebbaee15e9bd593b9be243d7f4734d4fabba30d28d06ca733d0d +size 167905 diff --git a/Plugins/MetaXR/Content/Meshes/LeftMetaQuestTouchProBatteryIndicatorQuad.uasset b/Plugins/MetaXR/Content/Meshes/LeftMetaQuestTouchProBatteryIndicatorQuad.uasset new file mode 100644 index 0000000..a772841 --- /dev/null +++ b/Plugins/MetaXR/Content/Meshes/LeftMetaQuestTouchProBatteryIndicatorQuad.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0f5cff83f8dc2d0684fb65789bea65e341a3e984a784b8ee48e3b14d320416e0 +size 15403 diff --git a/Plugins/MetaXR/Content/Meshes/LeftMetaQuestTouchProNub.uasset b/Plugins/MetaXR/Content/Meshes/LeftMetaQuestTouchProNub.uasset new file mode 100644 index 0000000..d6eb184 --- /dev/null +++ b/Plugins/MetaXR/Content/Meshes/LeftMetaQuestTouchProNub.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d9d27399ac32afd39edb67cdcc20a4068eb95d05abb396532b6112ac6fdcc5c8 +size 26968 diff --git a/Plugins/MetaXR/Content/Meshes/LeftTouchForQuest2.uasset b/Plugins/MetaXR/Content/Meshes/LeftTouchForQuest2.uasset new file mode 100644 index 0000000..35b8960 --- /dev/null +++ b/Plugins/MetaXR/Content/Meshes/LeftTouchForQuest2.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9cadbc5a391b529d73b94e66c99b8a51009a10f263a753718a0498c14a95b9f9 +size 1620506 diff --git a/Plugins/MetaXR/Content/Meshes/LeftTouchForQuestRiftSController.fbx b/Plugins/MetaXR/Content/Meshes/LeftTouchForQuestRiftSController.fbx new file mode 100644 index 0000000..2e4e5b0 --- /dev/null +++ b/Plugins/MetaXR/Content/Meshes/LeftTouchForQuestRiftSController.fbx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:496844537b5ab18ffac4466e4197eee9b021abebefb093cf704d3e0a84f25eda +size 422976 diff --git a/Plugins/MetaXR/Content/Meshes/LeftTouchForQuestRiftSController.uasset b/Plugins/MetaXR/Content/Meshes/LeftTouchForQuestRiftSController.uasset new file mode 100644 index 0000000..e4ec152 --- /dev/null +++ b/Plugins/MetaXR/Content/Meshes/LeftTouchForQuestRiftSController.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c9e972e4a04cc074a073c24a3466bd836af6607017c20655cd8ab925a0611887 +size 334980 diff --git a/Plugins/MetaXR/Content/Meshes/RightMetaQuestTouchPlus.fbx b/Plugins/MetaXR/Content/Meshes/RightMetaQuestTouchPlus.fbx new file mode 100644 index 0000000..8ec73d9 --- /dev/null +++ b/Plugins/MetaXR/Content/Meshes/RightMetaQuestTouchPlus.fbx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3ba211be52ccf6e3e8708ec51777b250ce9ca9d2070e1295fc68231020769558 +size 288704 diff --git a/Plugins/MetaXR/Content/Meshes/RightMetaQuestTouchPlus.uasset b/Plugins/MetaXR/Content/Meshes/RightMetaQuestTouchPlus.uasset new file mode 100644 index 0000000..e0c1c7c --- /dev/null +++ b/Plugins/MetaXR/Content/Meshes/RightMetaQuestTouchPlus.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8bd963c95a8d0c150ec7ad42f95230f4aa8e98f0845c5ee3d2fc743757953ba6 +size 221786 diff --git a/Plugins/MetaXR/Content/Meshes/RightMetaQuestTouchPlusBatteryIndicatorQuad.uasset b/Plugins/MetaXR/Content/Meshes/RightMetaQuestTouchPlusBatteryIndicatorQuad.uasset new file mode 100644 index 0000000..80f8b0d --- /dev/null +++ b/Plugins/MetaXR/Content/Meshes/RightMetaQuestTouchPlusBatteryIndicatorQuad.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:663d20fa26629279e88dbcff73b0c853229980c2f65fdd619ea5e917c392b796 +size 15627 diff --git a/Plugins/MetaXR/Content/Meshes/RightMetaQuestTouchPro.uasset b/Plugins/MetaXR/Content/Meshes/RightMetaQuestTouchPro.uasset new file mode 100644 index 0000000..877b4b5 --- /dev/null +++ b/Plugins/MetaXR/Content/Meshes/RightMetaQuestTouchPro.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9984f8f285005921951e276bb61066cfd147afbd88543ec5c0d3f1b0d1e3d0cc +size 168472 diff --git a/Plugins/MetaXR/Content/Meshes/RightMetaQuestTouchProBatteryIndicatorQuad.uasset b/Plugins/MetaXR/Content/Meshes/RightMetaQuestTouchProBatteryIndicatorQuad.uasset new file mode 100644 index 0000000..afa906a --- /dev/null +++ b/Plugins/MetaXR/Content/Meshes/RightMetaQuestTouchProBatteryIndicatorQuad.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ce6e651a9055315c0bb53b161ef6cced4537c850bd2319341dd453f1f3390b9c +size 15954 diff --git a/Plugins/MetaXR/Content/Meshes/RightMetaQuestTouchProNub.uasset b/Plugins/MetaXR/Content/Meshes/RightMetaQuestTouchProNub.uasset new file mode 100644 index 0000000..228aab7 --- /dev/null +++ b/Plugins/MetaXR/Content/Meshes/RightMetaQuestTouchProNub.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6736591f01a4bedf1aefecb29d6cd50a584c37f8ebdbfdb080fec9b6a0349921 +size 27434 diff --git a/Plugins/MetaXR/Content/Meshes/RightTouchForQuest2.uasset b/Plugins/MetaXR/Content/Meshes/RightTouchForQuest2.uasset new file mode 100644 index 0000000..540f381 --- /dev/null +++ b/Plugins/MetaXR/Content/Meshes/RightTouchForQuest2.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:cdf3cf3027f6b6e5665b2a8b8aa3d36d5cf6e8375ad457fd41eddf45864f4bef +size 1622442 diff --git a/Plugins/MetaXR/Content/Meshes/RightTouchForQuestRiftSController.fbx b/Plugins/MetaXR/Content/Meshes/RightTouchForQuestRiftSController.fbx new file mode 100644 index 0000000..ea282ce --- /dev/null +++ b/Plugins/MetaXR/Content/Meshes/RightTouchForQuestRiftSController.fbx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1da951971570105cff39f7f10122caff22e0655811d9be13730ed2f8de305483 +size 422784 diff --git a/Plugins/MetaXR/Content/Meshes/RightTouchForQuestRiftSController.uasset b/Plugins/MetaXR/Content/Meshes/RightTouchForQuestRiftSController.uasset new file mode 100644 index 0000000..d7b703d --- /dev/null +++ b/Plugins/MetaXR/Content/Meshes/RightTouchForQuestRiftSController.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:816ffcda1ebd0c01fc413d37497888df005782ff14f5a603a049f85a9776298b +size 337188 diff --git a/Plugins/MetaXR/Content/MetaXRControllers.uasset b/Plugins/MetaXR/Content/MetaXRControllers.uasset new file mode 100644 index 0000000..7a67a0f --- /dev/null +++ b/Plugins/MetaXR/Content/MetaXRControllers.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2dfb96c7159d3366f59fcbe277db3086b8e86a04e253748a5f376b85ee95112a +size 19999 diff --git a/Plugins/MetaXR/Content/OculusMR_GreenKey.uasset b/Plugins/MetaXR/Content/OculusMR_GreenKey.uasset new file mode 100644 index 0000000..f85346e --- /dev/null +++ b/Plugins/MetaXR/Content/OculusMR_GreenKey.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d507f10c27952b84435a1fc313452ae514d1f5467f44774ddf64e2c443d34341 +size 109846 diff --git a/Plugins/MetaXR/Content/OculusModels.tps b/Plugins/MetaXR/Content/OculusModels.tps new file mode 100644 index 0000000..0fac4c5 --- /dev/null +++ b/Plugins/MetaXR/Content/OculusModels.tps @@ -0,0 +1,13 @@ + + + Oculus Models + /Engine/Plugins/Runtime/Oculus/OculusVR/Content/ + Provide our licensees with models that match actual physical Oculus devices. + https://developer.oculus.com/licenses/art-1.0/ + + Licensees + Git + P4 + + /Engine/Source/ThirdParty/Licenses/OculusModels_License.txt + \ No newline at end of file diff --git a/Plugins/MetaXR/Content/OculusModels_License.txt b/Plugins/MetaXR/Content/OculusModels_License.txt new file mode 100644 index 0000000..4c170b2 --- /dev/null +++ b/Plugins/MetaXR/Content/OculusModels_License.txt @@ -0,0 +1,8 @@ +Art Attribution License 1.0 +Copyright © Facebook Technologies, LLC and its affiliates. All rights reserved. + +You may use these images solely for referring to the corresponding product in your video game or VR experience (including manuals for users). Otherwise, you may not use these images, or any trademarks, logos or other intellectual property owned by Facebook Technologies, LLC formerly known as Oculus VR, LLC (“Oculus”), including but not limited to use on merchandise or other product such as clothing, hats, or mugs. Do not use the Oculus images in a way that implies a partnership, sponsorship or endorsement; or features Oculus on materials associated with pornography, illegal activities, or other materials that violate Oculus Terms. + +THE IMAGES ARE PROVIDED TO YOU ON AN “AS IS” BASIS AND YOU ARE SOLELY RESPONSIBLE FOR YOUR USE OF THE IMAGES. OCULUS DISCLAIMS ALL WARRANTIES REGARDING THE IMAGES, INCLUDING WARRANTIES OF NON-INFRINGEMENT. OCULUS SHALL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, CONSEQUENTIAL OR PUNITIVE DAMAGES ARISING FROM OR RELATED TO YOUR USE OF THE IMAGES. + +For the avoidance of doubt, this license shall not apply to the Oculus name, trademark or service mark, logo or design. \ No newline at end of file diff --git a/Plugins/MetaXR/Content/Textures/LeftMetaQuestTouchPlus_Color.uasset b/Plugins/MetaXR/Content/Textures/LeftMetaQuestTouchPlus_Color.uasset new file mode 100644 index 0000000..397e139 --- /dev/null +++ b/Plugins/MetaXR/Content/Textures/LeftMetaQuestTouchPlus_Color.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9d32f405dbb75078ca333884200775dc66e5401682479e1c6af9e3bf5aaea59c +size 5144987 diff --git a/Plugins/MetaXR/Content/Textures/LeftMetaQuestTouchProBatteryIndicator.uasset b/Plugins/MetaXR/Content/Textures/LeftMetaQuestTouchProBatteryIndicator.uasset new file mode 100644 index 0000000..9129ae1 --- /dev/null +++ b/Plugins/MetaXR/Content/Textures/LeftMetaQuestTouchProBatteryIndicator.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b899a9f05947db5ec1674afc635d46a9c17f0c34fc99a465eb871d72028fd9ee +size 17617 diff --git a/Plugins/MetaXR/Content/Textures/LeftMetaQuestTouchPro_Color.uasset b/Plugins/MetaXR/Content/Textures/LeftMetaQuestTouchPro_Color.uasset new file mode 100644 index 0000000..75e1d27 --- /dev/null +++ b/Plugins/MetaXR/Content/Textures/LeftMetaQuestTouchPro_Color.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f70c8b8e4ab9205f04cfd7cd9cffbc976232fd8c46e5232405576373abb332bc +size 4620263 diff --git a/Plugins/MetaXR/Content/Textures/LeftMetaQuestTouchPro_Normal.uasset b/Plugins/MetaXR/Content/Textures/LeftMetaQuestTouchPro_Normal.uasset new file mode 100644 index 0000000..b76c109 --- /dev/null +++ b/Plugins/MetaXR/Content/Textures/LeftMetaQuestTouchPro_Normal.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:313a1d6a1cb9f2c6a423f4c92a795039ae4251f0fa3b99b4fa97215bf7753900 +size 2368859 diff --git a/Plugins/MetaXR/Content/Textures/MetaQuestTouchProBatteryIndicator.uasset b/Plugins/MetaXR/Content/Textures/MetaQuestTouchProBatteryIndicator.uasset new file mode 100644 index 0000000..2471569 --- /dev/null +++ b/Plugins/MetaXR/Content/Textures/MetaQuestTouchProBatteryIndicator.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:57efcf04e1ac726e768e4a41835a36eae7a2afbdbdd74c6c48c93ca6da673c01 +size 17449 diff --git a/Plugins/MetaXR/Content/Textures/RightMetaQuestTouchPlus_Color.uasset b/Plugins/MetaXR/Content/Textures/RightMetaQuestTouchPlus_Color.uasset new file mode 100644 index 0000000..2ea3715 --- /dev/null +++ b/Plugins/MetaXR/Content/Textures/RightMetaQuestTouchPlus_Color.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3019e678d58551f5491ff9637781176aa63fc65d5d0fdddbd1f0be6f0cf24958 +size 5110320 diff --git a/Plugins/MetaXR/Content/Textures/RightMetaQuestTouchProBatteryIndicator.uasset b/Plugins/MetaXR/Content/Textures/RightMetaQuestTouchProBatteryIndicator.uasset new file mode 100644 index 0000000..bf66b95 --- /dev/null +++ b/Plugins/MetaXR/Content/Textures/RightMetaQuestTouchProBatteryIndicator.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:93d12f1335d4a208ec3010e1a78f2e3970f48a9d69f84434c5ee6c9f5c648a24 +size 17624 diff --git a/Plugins/MetaXR/Content/Textures/RightMetaQuestTouchPro_Color.uasset b/Plugins/MetaXR/Content/Textures/RightMetaQuestTouchPro_Color.uasset new file mode 100644 index 0000000..5b18886 --- /dev/null +++ b/Plugins/MetaXR/Content/Textures/RightMetaQuestTouchPro_Color.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5f1c75cd9c92d2619bd367e7db3cfc39d920293a42a0ce210070da9410bb58d2 +size 4653519 diff --git a/Plugins/MetaXR/Content/Textures/RightMetaQuestTouchPro_Normal.uasset b/Plugins/MetaXR/Content/Textures/RightMetaQuestTouchPro_Normal.uasset new file mode 100644 index 0000000..fb7d279 --- /dev/null +++ b/Plugins/MetaXR/Content/Textures/RightMetaQuestTouchPro_Normal.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5abf3f6a4991c65e934ab3aa3498b68a8ee89558e3f8262141951e9ee4a78309 +size 2405558 diff --git a/Plugins/MetaXR/Content/Textures/TouchForQuest2Material_Roughness.uasset b/Plugins/MetaXR/Content/Textures/TouchForQuest2Material_Roughness.uasset new file mode 100644 index 0000000..7aa165f --- /dev/null +++ b/Plugins/MetaXR/Content/Textures/TouchForQuest2Material_Roughness.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:41c13554ad2a5d4ebc96841e1427a5696b4533e365c4b2d81881a0f1fde38af6 +size 97016 diff --git a/Plugins/MetaXR/Content/Textures/TouchForQuest2_Color.uasset b/Plugins/MetaXR/Content/Textures/TouchForQuest2_Color.uasset new file mode 100644 index 0000000..c84c3db --- /dev/null +++ b/Plugins/MetaXR/Content/Textures/TouchForQuest2_Color.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c6c2fc5d9188597d6570a93d484781ceddd1ee62625e7a1ea1aba49e4ca4dd03 +size 470761 diff --git a/Plugins/MetaXR/Content/Textures/TouchForQuestRiftSController_albedo.uasset b/Plugins/MetaXR/Content/Textures/TouchForQuestRiftSController_albedo.uasset new file mode 100644 index 0000000..d4211c2 --- /dev/null +++ b/Plugins/MetaXR/Content/Textures/TouchForQuestRiftSController_albedo.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e02ac4d4c3d1ad7fbdbc0132d47b5beee52d8cf4d050480847fda855ff69bd0e +size 2601539 diff --git a/Plugins/MetaXR/OculusXR.uplugin b/Plugins/MetaXR/OculusXR.uplugin new file mode 100644 index 0000000..86d6aea --- /dev/null +++ b/Plugins/MetaXR/OculusXR.uplugin @@ -0,0 +1,150 @@ +{ + "FileVersion": 3, + "Version": 1, + "VersionName": "1.96.0", + "FriendlyName": "Meta XR", + "Description": "Support for Meta Quest headsets and controllers", + "Category": "Virtual Reality", + "CreatedBy": "Meta Platforms, Inc.", + "CreatedByURL": "https://www.meta.com/", + "DocsURL": "https://developer.oculus.com/documentation/unreal/latest/concepts/unreal-engine/", + "MarketplaceURL": "com.epicgames.launcher://ue/marketplace/product/8313d8d7e7cf4e03a33e79eb757bccba", + "SupportURL": "https://forums.oculusvr.com/developer", + "EngineVersion": "5.3.0", + "CanContainContent": true, + "Installed": true, + "SupportedTargetPlatforms": [ + "Win64", + "Android" + ], + "Modules": [ + { + "Name": "OculusXRHMD", + "Type": "Runtime", + "LoadingPhase": "PostConfigInit", + "PlatformAllowList": [ + "Win64", + "Android" + ] + }, + { + "Name": "OculusXRInput", + "Type": "Runtime", + "LoadingPhase": "Default", + "PlatformAllowList": [ + "Win64", + "Android" + ] + }, + { + "Name": "OculusXRMR", + "Type": "Runtime", + "LoadingPhase": "PostEngineInit", + "PlatformAllowList": [ + "Win64", + "Android" + ] + }, + { + "Name": "OculusXROpenXRHMD", + "Type": "Runtime", + "LoadingPhase": "PostConfigInit", + "PlatformAllowList": [ + "Win64", + "Android" + ] + }, + { + "Name": "OculusXRAnchors", + "Type": "Runtime", + "LoadingPhase": "PostEngineInit", + "PlatformAllowList": [ + "Win64", + "Android" + ] + }, + { + "Name": "OculusXRScene", + "Type": "Runtime", + "LoadingPhase": "PostEngineInit", + "PlatformAllowList": [ + "Win64", + "Android" + ] + }, + { + "Name": "OculusXRMovement", + "Type": "Runtime", + "LoadingPhase": "PostEngineInit", + "PlatformAllowList": [ + "Win64", + "Android" + ] + }, + { + "Name": "OculusXREyeTracker", + "Type": "Runtime", + "LoadingPhase": "Default", + "PlatformAllowList": [ + "Win64", + "Android" + ] + }, + { + "Name": "OculusXREditor", + "Type": "Editor", + "LoadingPhase": "Default", + "PlatformAllowList": [ + "Win64" + ] + }, + { + "Name": "OculusXRProjectSetupTool", + "Type": "Editor", + "LoadingPhase": "PostEngineInit", + "PlatformAllowList": [ + "Win64" + ] + }, + { + "Name": "OculusXRPassthrough", + "Type": "Runtime", + "LoadingPhase": "PostEngineInit", + "PlatformAllowList": [ + "Win64", + "Android" + ] + } + ], + "Plugins": [ + { + "Name": "XRBase", + "Enabled": true, + "Optional": true + }, + { + "Name": "EnhancedInput", + "Enabled": true + }, + { + "Name": "ProceduralMeshComponent", + "Enabled": true + }, + { + "Name": "AndroidPermission", + "Enabled": true + }, + { + "Name": "LiveLink", + "Enabled": true + }, + { + "Name": "OpenXR", + "Enabled": false + }, + { + "Name": "PluginBrowser", + "Enabled": true + } + ] +} \ No newline at end of file diff --git a/Plugins/MetaXR/Resources/ButtonIcon_80x.png b/Plugins/MetaXR/Resources/ButtonIcon_80x.png new file mode 100644 index 0000000..352504a --- /dev/null +++ b/Plugins/MetaXR/Resources/ButtonIcon_80x.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:10ec795f2657782e8e52d97f2c63f9ec5f7cdc02ca6236f0f7300068527ca834 +size 2332 diff --git a/Plugins/MetaXR/Resources/GreenDot.svg b/Plugins/MetaXR/Resources/GreenDot.svg new file mode 100644 index 0000000..a62cbc8 --- /dev/null +++ b/Plugins/MetaXR/Resources/GreenDot.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/Plugins/MetaXR/Resources/GreyDot.svg b/Plugins/MetaXR/Resources/GreyDot.svg new file mode 100644 index 0000000..f1e3da4 --- /dev/null +++ b/Plugins/MetaXR/Resources/GreyDot.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/Plugins/MetaXR/Resources/Icon128.png b/Plugins/MetaXR/Resources/Icon128.png new file mode 100644 index 0000000..17bad82 --- /dev/null +++ b/Plugins/MetaXR/Resources/Icon128.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b6d55c2205e75a8f7ef23b37d6dfe0f4314042b56ab297c67676d1342cf705c3 +size 4209 diff --git a/Plugins/MetaXR/Resources/MetaLogo.svg b/Plugins/MetaXR/Resources/MetaLogo.svg new file mode 100644 index 0000000..40b09f3 --- /dev/null +++ b/Plugins/MetaXR/Resources/MetaLogo.svg @@ -0,0 +1,3 @@ + + + diff --git a/Plugins/MetaXR/Resources/MetaQuestBackground.png b/Plugins/MetaXR/Resources/MetaQuestBackground.png new file mode 100644 index 0000000..4633a23 --- /dev/null +++ b/Plugins/MetaXR/Resources/MetaQuestBackground.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:334961564d63bd669cd5a01790fa253f01de10720066acce83e6a2ea8c2682c2 +size 113118 diff --git a/Plugins/MetaXR/Resources/PlatformDesktop.svg b/Plugins/MetaXR/Resources/PlatformDesktop.svg new file mode 100644 index 0000000..f5ef916 --- /dev/null +++ b/Plugins/MetaXR/Resources/PlatformDesktop.svg @@ -0,0 +1,3 @@ + + + diff --git a/Plugins/MetaXR/Resources/PlatformQuest2.svg b/Plugins/MetaXR/Resources/PlatformQuest2.svg new file mode 100644 index 0000000..5ee91e3 --- /dev/null +++ b/Plugins/MetaXR/Resources/PlatformQuest2.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/Plugins/MetaXR/Resources/PlatformQuest3.svg b/Plugins/MetaXR/Resources/PlatformQuest3.svg new file mode 100644 index 0000000..514c730 --- /dev/null +++ b/Plugins/MetaXR/Resources/PlatformQuest3.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/Plugins/MetaXR/Resources/RedDot.svg b/Plugins/MetaXR/Resources/RedDot.svg new file mode 100644 index 0000000..02baaaf --- /dev/null +++ b/Plugins/MetaXR/Resources/RedDot.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/Plugins/MetaXR/Resources/WhiteDot.svg b/Plugins/MetaXR/Resources/WhiteDot.svg new file mode 100644 index 0000000..c179483 --- /dev/null +++ b/Plugins/MetaXR/Resources/WhiteDot.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/Plugins/MetaXR/Resources/YellowDot.svg b/Plugins/MetaXR/Resources/YellowDot.svg new file mode 100644 index 0000000..8b3b5b2 --- /dev/null +++ b/Plugins/MetaXR/Resources/YellowDot.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/Plugins/MetaXR/Shaders/Private/HardOcclusions.usf b/Plugins/MetaXR/Shaders/Private/HardOcclusions.usf new file mode 100644 index 0000000..9eaf21d --- /dev/null +++ b/Plugins/MetaXR/Shaders/Private/HardOcclusions.usf @@ -0,0 +1,36 @@ +// Copyright Epic Games, Inc. All Rights Reserved. + +#include "/Engine/Public/Platform.ush" + +#define NUM_VIEWS 2 + +// PS Textures Parameters +Texture2DArray EnvironmentDepthTexture; +SamplerState EnvironmentDepthSampler; +float2 DepthFactors; +float4x4 ScreenToDepthMatrices[NUM_VIEWS]; +int DepthViewId; + +void HardOcclusionsPS( + noperspective float4 UVAndScreenPos : TEXCOORD0, + float4 SvPosition : SV_POSITION, +#if INSTANCED_STEREO + in uint InstanceId : SV_InstanceID, +#elif MOBILE_MULTI_VIEW + in uint ViewId : SV_ViewID, +#endif + out float4 OutColor : SV_Target0, + out float OutDepth : SV_DEPTH) +{ +#if INSTANCED_STEREO + uint ViewId = InstanceId & 1; +#elif !MOBILE_MULTI_VIEW + uint ViewId = DepthViewId; +#endif + float4 TexCoordH = mul(ScreenToDepthMatrices[ViewId], float4(UVAndScreenPos.x, 1.0f - UVAndScreenPos.y, 0.0, 1.0)); + float3 TexCoord = float3(TexCoordH.x / TexCoordH.w, TexCoordH.y / TexCoordH.w, ViewId); + float InputDepthEye = EnvironmentDepthTexture.Sample(EnvironmentDepthSampler, TexCoord).r; + float DepthEye = InputDepthEye * DepthFactors.x + DepthFactors.y; + OutDepth = DepthEye; + OutColor = float4(0.0, 0.0, 0.0, 1.0); +} diff --git a/Plugins/MetaXR/Shaders/Private/ScreenPixelShaderArraySlice.usf b/Plugins/MetaXR/Shaders/Private/ScreenPixelShaderArraySlice.usf new file mode 100644 index 0000000..9c471cb --- /dev/null +++ b/Plugins/MetaXR/Shaders/Private/ScreenPixelShaderArraySlice.usf @@ -0,0 +1,25 @@ +// Copyright Epic Games, Inc. All Rights Reserved. + +#include "/Engine/Private/Common.ush" + +Texture2DArray InTexture; +SamplerState InTextureSampler; +int MipLevel; +int ArraySlice; + +void MainMipLevel( + FScreenVertexOutput Input, + out float4 OutColor : SV_Target0 + ) +{ + OutColor = InTexture.SampleLevel(InTextureSampler, float3(Input.UV, ArraySlice), MipLevel); +} + +void MainsRGBSourceMipLevel( + FScreenVertexOutput Input, + out float4 OutColor : SV_Target0 + ) +{ + OutColor = InTexture.SampleLevel(InTextureSampler, float3(Input.UV, ArraySlice), MipLevel); + OutColor.rgb = pow( OutColor.rgb, 1.0f / 2.2f ); +} diff --git a/Plugins/MetaXR/Source/OculusXRAnchors/OculusXRAnchors.Build.cs b/Plugins/MetaXR/Source/OculusXRAnchors/OculusXRAnchors.Build.cs new file mode 100644 index 0000000..2ee2aa3 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRAnchors/OculusXRAnchors.Build.cs @@ -0,0 +1,35 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +namespace UnrealBuildTool.Rules +{ + public class OculusXRAnchors : ModuleRules + { + public OculusXRAnchors(ReadOnlyTargetRules Target) : base(Target) + { + bUseUnity = true; + + PrivateDependencyModuleNames.AddRange( + new string[] + { + "Core", + "CoreUObject", + "Engine", + "OculusXRHMD", + "OVRPluginXR", + "ProceduralMeshComponent", + }); + + PrivateIncludePaths.AddRange( + new string[] { + // Relative to Engine\Plugins\Runtime\Oculus\OculusVR\Source + "OculusXRHMD/Private", + }); + + PublicIncludePaths.AddRange( + new string[] { + "Runtime/Engine/Classes/Components", + }); + } + } +} diff --git a/Plugins/MetaXR/Source/OculusXRAnchors/Private/OculusXRAnchorBPFunctionLibrary.cpp b/Plugins/MetaXR/Source/OculusXRAnchors/Private/OculusXRAnchorBPFunctionLibrary.cpp new file mode 100644 index 0000000..2b18bf8 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRAnchors/Private/OculusXRAnchorBPFunctionLibrary.cpp @@ -0,0 +1,225 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#include "OculusXRAnchorBPFunctionLibrary.h" +#include "OculusXRHMD.h" +#include "OculusXRSpatialAnchorComponent.h" +#include "OculusXRAnchorsPrivate.h" +#include "OculusXRRoomLayoutManager.h" +#include "OculusXRAnchorManager.h" +#include "Kismet/BlueprintFunctionLibrary.h" + +AActor* UOculusXRAnchorBPFunctionLibrary::SpawnActorWithAnchorHandle(UObject* WorldContextObject, FOculusXRUInt64 Handle, FOculusXRUUID UUID, EOculusXRSpaceStorageLocation Location, UClass* ActorClass, + AActor* Owner, APawn* Instigator, ESpawnActorCollisionHandlingMethod CollisionHandlingMethod) +{ + FActorSpawnParameters SpawnInfo; + SpawnInfo.Owner = Owner; + SpawnInfo.Instigator = Instigator; + SpawnInfo.ObjectFlags |= RF_Transient; + SpawnInfo.SpawnCollisionHandlingOverride = CollisionHandlingMethod; + + UWorld* World = GEngine->GetWorldFromContextObject(WorldContextObject, EGetWorldErrorMode::LogAndReturnNull); + if (World == nullptr) + { + UE_LOG(LogOculusXRAnchors, Warning, TEXT("Invalid WorldContext Object for SpawnActorWithAnchorHandle.")); + return nullptr; + } + + AActor* NewSpatialAnchorActor = World->SpawnActor(ActorClass, nullptr, nullptr, SpawnInfo); + if (NewSpatialAnchorActor == nullptr) + { + UE_LOG(LogOculusXRAnchors, Warning, TEXT("Failed to spawn Actor in SpawnActorWithAnchorHandle")); + return nullptr; + } + + UOculusXRSpatialAnchorComponent* SpatialAnchorComponent = NewSpatialAnchorActor->FindComponentByClass(); + if (SpatialAnchorComponent == nullptr) + { + SpatialAnchorComponent = Cast(NewSpatialAnchorActor->AddComponentByClass(UOculusXRSpatialAnchorComponent::StaticClass(), false, FTransform::Identity, false)); + } + + if (!IsValid(SpatialAnchorComponent)) + { + UE_LOG(LogOculusXRAnchors, Warning, TEXT("Failed to find or spawn Spatial Anchor component in SpawnActorWithAnchorHandle")); + return nullptr; + } + + SpatialAnchorComponent->SetHandle(Handle); + SpatialAnchorComponent->SetUUID(UUID); + SpatialAnchorComponent->SetStoredLocation(Location, true); + return NewSpatialAnchorActor; +} + +AActor* UOculusXRAnchorBPFunctionLibrary::SpawnActorWithAnchorQueryResults(UObject* WorldContextObject, const FOculusXRSpaceQueryResult& QueryResult, UClass* ActorClass, AActor* Owner, APawn* Instigator, ESpawnActorCollisionHandlingMethod CollisionHandlingMethod) +{ + return SpawnActorWithAnchorHandle(WorldContextObject, QueryResult.Space, QueryResult.UUID, QueryResult.Location, ActorClass, Owner, Instigator, CollisionHandlingMethod); +} + +bool UOculusXRAnchorBPFunctionLibrary::GetAnchorComponentStatus(AActor* TargetActor, EOculusXRSpaceComponentType ComponentType, bool& bIsEnabled) +{ + UOculusXRAnchorComponent* AnchorComponent = Cast(TargetActor->GetComponentByClass(UOculusXRAnchorComponent::StaticClass())); + + if (!IsValid(AnchorComponent)) + { + UE_LOG(LogOculusXRAnchors, Warning, TEXT("Invalid Anchor Component provided to GetAnchorComponentStatus")); + bIsEnabled = false; + return false; + } + + bool bOutIsEnabled = false; + bool bIsChangePending = false; + + EOculusXRAnchorResult::Type AnchorResult; + bool bDidCallStart = OculusXRAnchors::FOculusXRAnchors::GetAnchorComponentStatus(AnchorComponent, ComponentType, bOutIsEnabled, bIsChangePending, AnchorResult); + if (!bDidCallStart) + { + UE_LOG(LogOculusXRAnchors, Warning, TEXT("Failed to start call to internal GetAnchorComponentStatus")); + bIsEnabled = false; + return false; + } + + bIsEnabled = bOutIsEnabled; + return bIsEnabled; +} + +bool UOculusXRAnchorBPFunctionLibrary::GetAnchorTransformByHandle(const FOculusXRUInt64& Handle, FTransform& OutTransform) +{ + FOculusXRAnchorLocationFlags AnchorFlags(0); + return TryGetAnchorTransformByHandle(Handle, OutTransform, AnchorFlags); +} + +bool UOculusXRAnchorBPFunctionLibrary::TryGetAnchorTransformByHandle(const FOculusXRUInt64& Handle, FTransform& OutTransform, FOculusXRAnchorLocationFlags& OutLocationFlags) +{ + OculusXRHMD::FOculusXRHMD* OutHMD = OculusXRHMD::FOculusXRHMD::GetOculusXRHMD(); + if (!OutHMD) + { + UE_LOG(LogOculusXRAnchors, Warning, TEXT("Unable to retrieve OculusXRHMD, cannot calculate anchor transform.")); + return false; + } + + ovrpTrackingOrigin ovrpOrigin = ovrpTrackingOrigin_EyeLevel; + const bool bTrackingOriginSuccess = FOculusXRHMDModule::GetPluginWrapper().GetInitialized() && OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetTrackingOriginType2(&ovrpOrigin)); + if (!bTrackingOriginSuccess) + { + UE_LOG(LogOculusXRAnchors, Warning, TEXT("Unable to get tracking origin, cannot calculate anchor transform.")); + return false; + } + + OutTransform = FTransform::Identity; + OutLocationFlags = FOculusXRAnchorLocationFlags(0); + + const ovrpUInt64 ovrpSpace = Handle.GetValue(); + ovrpSpaceLocationf ovrpSpaceLocation; + + const bool bSuccess = FOculusXRHMDModule::GetPluginWrapper().GetInitialized() && OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().LocateSpace2(&ovrpSpaceLocation, &ovrpSpace, ovrpOrigin)); + if (bSuccess) + { + OutLocationFlags = FOculusXRAnchorLocationFlags(ovrpSpaceLocation.locationFlags); + if (OutLocationFlags.IsValid()) + { + OculusXRHMD::FPose Pose; + OutHMD->ConvertPose(ovrpSpaceLocation.pose, Pose); + const FTransform trackingToWorld = OutHMD->GetLastTrackingToWorld(); + + OutTransform.SetLocation(trackingToWorld.TransformPosition(Pose.Position)); + OutTransform.SetRotation(FRotator(trackingToWorld.TransformRotation(FQuat(Pose.Orientation))).Quaternion()); + } + else + { + return false; + } + } + + return bSuccess; +} + +FString UOculusXRAnchorBPFunctionLibrary::AnchorHandleToString(const FOculusXRUInt64 Value) +{ + return FString::Printf(TEXT("%llu"), Value.Value); +} + +FString UOculusXRAnchorBPFunctionLibrary::AnchorUUIDToString(const FOculusXRUUID& Value) +{ + return Value.ToString(); +} + +FOculusXRUUID UOculusXRAnchorBPFunctionLibrary::StringToAnchorUUID(const FString& Value) +{ + // Static size for the max length of the string, two chars per hex digit, 16 digits. + checkf(Value.Len() == 32, TEXT("'%s' is not a valid UUID"), *Value); + + ovrpUuid newID; + HexToBytes(Value, newID.data); + + return FOculusXRUUID(newID.data); +} +bool UOculusXRAnchorBPFunctionLibrary::IsAnchorResultSuccess(EOculusXRAnchorResult::Type result) +{ +#if OCULUS_HMD_SUPPORTED_PLATFORMS + return OVRP_SUCCESS(result); +#endif + return false; +} + +const UOculusXRBaseAnchorComponent* UOculusXRAnchorBPFunctionLibrary::GetAnchorComponent(const FOculusXRSpaceQueryResult& QueryResult, EOculusXRSpaceComponentType ComponentType, UObject* Outer) +{ + switch (ComponentType) + { + case EOculusXRSpaceComponentType::Locatable: + return UOculusXRBaseAnchorComponent::FromSpace(QueryResult.Space.Value, Outer); + case EOculusXRSpaceComponentType::ScenePlane: + return UOculusXRBaseAnchorComponent::FromSpace(QueryResult.Space.Value, Outer); + case EOculusXRSpaceComponentType::SceneVolume: + return UOculusXRBaseAnchorComponent::FromSpace(QueryResult.Space.Value, Outer); + case EOculusXRSpaceComponentType::SemanticClassification: + return UOculusXRBaseAnchorComponent::FromSpace(QueryResult.Space.Value, Outer); + case EOculusXRSpaceComponentType::RoomLayout: + return UOculusXRBaseAnchorComponent::FromSpace(QueryResult.Space.Value, Outer); + case EOculusXRSpaceComponentType::SpaceContainer: + return UOculusXRBaseAnchorComponent::FromSpace(QueryResult.Space.Value, Outer); + case EOculusXRSpaceComponentType::Sharable: + return UOculusXRBaseAnchorComponent::FromSpace(QueryResult.Space.Value, Outer); + case EOculusXRSpaceComponentType::Storable: + return UOculusXRBaseAnchorComponent::FromSpace(QueryResult.Space.Value, Outer); + case EOculusXRSpaceComponentType::TriangleMesh: + return UOculusXRBaseAnchorComponent::FromSpace(QueryResult.Space.Value, Outer); + default: + return nullptr; + } +} + +bool UOculusXRAnchorBPFunctionLibrary::GetRoomLayout(FOculusXRUInt64 Space, FOculusXRRoomLayout& RoomLayoutOut, int32 MaxWallsCapacity) +{ + if (MaxWallsCapacity <= 0) + { + return false; + } + + FOculusXRUUID OutCeilingUuid; + FOculusXRUUID OutFloorUuid; + TArray OutWallsUuid; + + const bool bSuccess = OculusXRAnchors::FOculusXRRoomLayoutManager::GetSpaceRoomLayout(Space.Value, static_cast(MaxWallsCapacity), OutCeilingUuid, OutFloorUuid, OutWallsUuid); + + if (bSuccess) + { + RoomLayoutOut.CeilingUuid = OutCeilingUuid; + RoomLayoutOut.FloorUuid = OutFloorUuid; + RoomLayoutOut.WallsUuid.InsertZeroed(0, OutWallsUuid.Num()); + + for (int32 i = 0; i < OutWallsUuid.Num(); ++i) + { + RoomLayoutOut.WallsUuid[i] = OutWallsUuid[i]; + } + + TArray spaceUUIDs; + EOculusXRAnchorResult::Type result = OculusXRAnchors::FOculusXRAnchorManager::GetSpaceContainerUUIDs(Space, spaceUUIDs); + + if (UOculusXRAnchorBPFunctionLibrary::IsAnchorResultSuccess(result)) + { + RoomLayoutOut.RoomObjectUUIDs = spaceUUIDs; + } + } + + return bSuccess; +} + diff --git a/Plugins/MetaXR/Source/OculusXRAnchors/Private/OculusXRAnchorComponent.cpp b/Plugins/MetaXR/Source/OculusXRAnchors/Private/OculusXRAnchorComponent.cpp new file mode 100644 index 0000000..d81ee3c --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRAnchors/Private/OculusXRAnchorComponent.cpp @@ -0,0 +1,208 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#include "OculusXRAnchorComponent.h" +#include "OculusXRAnchors.h" +#include "OculusXRHMD.h" +#include "OculusXRAnchorBPFunctionLibrary.h" +#include "OculusXRAnchorsPrivate.h" +#include "GameFramework/PlayerController.h" + +#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST) +static TAutoConsoleVariable CVarOculusXRVerboseAnchorDebugXR( + TEXT("ovr.OculusXRVerboseAnchorDebug"), + 0, + TEXT("Enables or disables verbose logging for Oculus anchors.\n") + TEXT("<=0: disabled (no printing)\n") + TEXT(" 1: enabled (verbose logging)\n")); +#endif + +UOculusXRAnchorComponent::UOculusXRAnchorComponent(const FObjectInitializer& ObjectInitializer) + : Super(ObjectInitializer) + , bUpdateHeadSpaceTransform(true) + , AnchorHandle(0) + , StorageLocations(0) +{ + AnchorHandle = 0; + PrimaryComponentTick.bCanEverTick = true; + PrimaryComponentTick.bStartWithTickEnabled = true; + PrimaryComponentTick.TickGroup = TG_PostUpdateWork; +} + +void UOculusXRAnchorComponent::BeginPlay() +{ + Super::BeginPlay(); + + UWorld* World = GetWorld(); + if (IsValid(World)) + { + APlayerController* PlayerController = World->GetFirstPlayerController(); + if (IsValid(PlayerController)) + { + PlayerCameraManager = PlayerController->PlayerCameraManager; + } + } +} + +void UOculusXRAnchorComponent::TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) +{ + Super::TickComponent(DeltaTime, TickType, ThisTickFunction); + UpdateAnchorTransform(); +} + +void UOculusXRAnchorComponent::EndPlay(const EEndPlayReason::Type EndPlayReason) +{ + Super::EndPlay(EndPlayReason); + + if (HasValidHandle()) + { + EOculusXRAnchorResult::Type AnchorResult; + OculusXRAnchors::FOculusXRAnchors::DestroyAnchor(AnchorHandle.GetValue(), AnchorResult); + } +} + +FOculusXRUInt64 UOculusXRAnchorComponent::GetHandle() const +{ + return AnchorHandle; +} + +void UOculusXRAnchorComponent::SetHandle(FOculusXRUInt64 Handle) +{ + AnchorHandle = Handle; +} + +bool UOculusXRAnchorComponent::HasValidHandle() const +{ + return AnchorHandle != FOculusXRUInt64(0); +} + +FOculusXRUUID UOculusXRAnchorComponent::GetUUID() const +{ + return AnchorUUID; +} + +void UOculusXRAnchorComponent::SetUUID(FOculusXRUUID NewUUID) +{ + if (AnchorUUID.IsValidUUID()) + { + UE_LOG(LogOculusXRAnchors, Warning, TEXT("Anchor component already has valid UUID, cannot re-assign a new UUID. Component: %s -- Space: %llu -- UUID: %s"), + *GetName(), AnchorHandle, *AnchorUUID.ToString()); + return; + } + + if (!NewUUID.IsValidUUID()) + { + UE_LOG(LogOculusXRAnchors, Warning, TEXT("New UUID provided to component is invalid, cannot assign. Component: %s -- Space: %llu"), *GetName(), AnchorHandle); + return; + } + + UE_LOG(LogOculusXRAnchors, Verbose, TEXT("Assigned new Oculus UUID: %s"), *NewUUID.ToString()); + + AnchorUUID = NewUUID; +} + +bool UOculusXRAnchorComponent::IsStoredAtLocation(EOculusXRSpaceStorageLocation Location) const +{ + UE_LOG(LogOculusXRAnchors, Verbose, TEXT("Anchor UUID: %s - Saved Local: %d - Saved Cloud: %d"), + *GetUUID().ToString(), + StorageLocations & static_cast(EOculusXRSpaceStorageLocation::Local), + StorageLocations & static_cast(EOculusXRSpaceStorageLocation::Cloud)); + + return (StorageLocations & static_cast(Location)) > 0; +} + +void UOculusXRAnchorComponent::SetStoredLocation(EOculusXRSpaceStorageLocation Location, bool Stored) +{ + if (Stored) + { + StorageLocations |= static_cast(Location); + } + else + { + StorageLocations = StorageLocations & ~static_cast(Location); + } + + UE_LOG(LogOculusXRAnchors, Verbose, TEXT("Anchor UUID: %s - Saved Local: %d - Saved Cloud: %d"), + *GetUUID().ToString(), + StorageLocations & static_cast(EOculusXRSpaceStorageLocation::Local), + StorageLocations & static_cast(EOculusXRSpaceStorageLocation::Cloud)); +} + +bool UOculusXRAnchorComponent::IsSaved() const +{ + return StorageLocations > 0; +} + +void UOculusXRAnchorComponent::UpdateAnchorTransform() const +{ + if (GetWorld() == nullptr) + { + UE_LOG(LogOculusXRAnchors, Warning, TEXT("Unable to retrieve World Context")); + return; + } + + AActor* Parent = GetOwner(); + if (Parent) + { + if (AnchorHandle.Value) + { + FTransform OutTransform; + if (UOculusXRAnchorBPFunctionLibrary::GetAnchorTransformByHandle(AnchorHandle, OutTransform)) + { +#if WITH_EDITOR + // Link only head-space transform update + if (bUpdateHeadSpaceTransform && PlayerCameraManager != nullptr) + { + FTransform MainCameraTransform; + MainCameraTransform.SetLocation(PlayerCameraManager->GetCameraLocation()); + MainCameraTransform.SetRotation(FQuat(PlayerCameraManager->GetCameraRotation())); + + if (!ToWorldSpacePose(MainCameraTransform, OutTransform)) + { + UE_LOG(LogOculusXRAnchors, Display, TEXT("Was not able to transform anchor to world space pose")); + } + } +#endif + +#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST) + if (CVarOculusXRVerboseAnchorDebugXR.GetValueOnGameThread() > 0) + { + UE_LOG(LogOculusXRAnchors, Display, TEXT("UpdateAnchor Pos %s"), *OutTransform.GetLocation().ToString()); + UE_LOG(LogOculusXRAnchors, Display, TEXT("UpdateAnchor Rot %s"), *OutTransform.GetRotation().ToString()); + } +#endif + Parent->SetActorLocationAndRotation(OutTransform.GetLocation(), OutTransform.GetRotation(), false, 0, ETeleportType::ResetPhysics); + } + } + } +} + +bool UOculusXRAnchorComponent::ToWorldSpacePose(FTransform CameraTransform, FTransform& OutTrackingSpaceTransform) const +{ + OculusXRHMD::FOculusXRHMD* OculusXRHMD = OculusXRHMD::FOculusXRHMD::GetOculusXRHMD(); + if (!OculusXRHMD) + { + UE_LOG(LogOculusXRAnchors, Warning, TEXT("Unable to retrieve OculusXRHMD, cannot calculate anchor world space pose.")); + return false; + } + + OculusXRHMD::FPose MainCameraPose(CameraTransform.GetRotation(), CameraTransform.GetLocation()); + OculusXRHMD::FPose TrackingSpacePose(OutTrackingSpaceTransform.GetRotation(), OutTrackingSpaceTransform.GetLocation()); + + FVector OutHeadPosition; + FQuat OutHeadOrientation; + const bool bGetPose = OculusXRHMD->GetCurrentPose(OculusXRHMD->HMDDeviceId, OutHeadOrientation, OutHeadPosition); + if (!bGetPose) + return false; + + OculusXRHMD::FPose HeadPose(OutHeadOrientation, OutHeadPosition); + + OculusXRHMD::FPose poseInHeadSpace = HeadPose.Inverse() * TrackingSpacePose; + + // To world space pose + const OculusXRHMD::FPose WorldTrackingSpacePose = MainCameraPose * poseInHeadSpace; + + OutTrackingSpaceTransform.SetLocation(WorldTrackingSpacePose.Position); + OutTrackingSpaceTransform.SetRotation(WorldTrackingSpacePose.Orientation); + + return true; +} diff --git a/Plugins/MetaXR/Source/OculusXRAnchors/Private/OculusXRAnchorComponents.cpp b/Plugins/MetaXR/Source/OculusXRAnchors/Private/OculusXRAnchorComponents.cpp new file mode 100644 index 0000000..b54fe47 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRAnchors/Private/OculusXRAnchorComponents.cpp @@ -0,0 +1,104 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#include "OculusXRAnchorComponents.h" + +#include "OculusXRAnchorBPFunctionLibrary.h" +#include "OculusXRAnchorManager.h" +#include "OculusXRRoomLayoutManager.h" +#include "OculusXRSpatialAnchorComponent.h" + +bool UOculusXRBaseAnchorComponent::IsComponentEnabled() const +{ + bool OutEnabled; + bool OutChangePending; + + auto OutResult = OculusXRAnchors::FOculusXRAnchorManager::GetSpaceComponentStatus(Space, Type, OutEnabled, OutChangePending); + return UOculusXRAnchorBPFunctionLibrary::IsAnchorResultSuccess(OutResult) && OutEnabled; +} + +EOculusXRSpaceComponentType UOculusXRBaseAnchorComponent::GetType() const +{ + return Type; +} + +uint64 UOculusXRBaseAnchorComponent::GetSpace() const +{ + return Space; +} + +bool UOculusXRLocatableAnchorComponent::GetTransform(FTransform& outTransform) const +{ + ensure(IsComponentEnabled()); + + if (!UOculusXRAnchorBPFunctionLibrary::GetAnchorTransformByHandle(Space, outTransform)) + { + UE_LOG(LogOculusSpatialAnchor, Warning, TEXT("Fetching transform failed.")); + return false; + } + return true; +} + +bool UOculusXRPlaneAnchorComponent::GetPositionAndSize(FVector& outPosition, FVector& outSize) const +{ + ensure(IsComponentEnabled()); + + if (!UOculusXRAnchorBPFunctionLibrary::IsAnchorResultSuccess(OculusXRAnchors::FOculusXRAnchorManager::GetSpaceScenePlane(Space, outPosition, outSize))) + { + UE_LOG(LogOculusSpatialAnchor, Warning, TEXT("Fetching scene plane failed.")); + return false; + } + + return true; +} + +bool UOculusXRVolumeAnchorComponent::GetPositionAndSize(FVector& outPosition, FVector& outSize) const +{ + ensure(IsComponentEnabled()); + + if (!UOculusXRAnchorBPFunctionLibrary::IsAnchorResultSuccess(OculusXRAnchors::FOculusXRAnchorManager::GetSpaceSceneVolume(Space, outPosition, outSize))) + { + UE_LOG(LogOculusSpatialAnchor, Warning, TEXT("Fetching scene plane failed.")); + return false; + } + + return true; +} + +bool UOculusXRSemanticClassificationAnchorComponent::GetSemanticClassifications(TArray& outClassifications) const +{ + ensure(IsComponentEnabled()); + + if (!UOculusXRAnchorBPFunctionLibrary::IsAnchorResultSuccess(OculusXRAnchors::FOculusXRAnchorManager::GetSpaceSemanticClassification(Space, outClassifications))) + { + UE_LOG(LogOculusSpatialAnchor, Warning, TEXT("Fetching scene volume failed.")); + return false; + } + + return true; +} + +bool UOculusXRRoomLayoutAnchorComponent::GetRoomLayout(FOculusXRUUID& outFloorUUID, FOculusXRUUID& outCeilingUUID, TArray& outWallsUUIDs) const +{ + ensure(IsComponentEnabled()); + + if (!OculusXRAnchors::FOculusXRRoomLayoutManager::GetSpaceRoomLayout(Space, 64, outCeilingUUID, outFloorUUID, outWallsUUIDs)) + { + UE_LOG(LogOculusSpatialAnchor, Warning, TEXT("Fetching room layout failed.")); + return false; + } + + return true; +} + +bool UOculusXRSpaceContainerAnchorComponent::GetUUIDs(TArray& outUUIDs) const +{ + ensure(IsComponentEnabled()); + + if (!OculusXRAnchors::FOculusXRAnchorManager::GetSpaceContainer(Space, outUUIDs)) + { + UE_LOG(LogOculusSpatialAnchor, Warning, TEXT("Fetching container uuids failed.")); + return false; + } + + return true; +} diff --git a/Plugins/MetaXR/Source/OculusXRAnchors/Private/OculusXRAnchorDelegates.cpp b/Plugins/MetaXR/Source/OculusXRAnchors/Private/OculusXRAnchorDelegates.cpp new file mode 100644 index 0000000..f264457 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRAnchors/Private/OculusXRAnchorDelegates.cpp @@ -0,0 +1,24 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#include "OculusXRAnchorDelegates.h" + +FOculusXRAnchorEventDelegates::FOculusXRSpatialAnchorCreateCompleteDelegate FOculusXRAnchorEventDelegates::OculusSpatialAnchorCreateComplete; + +FOculusXRAnchorEventDelegates::FOculusXRSpaceSetComponentStatusCompleteDelegate FOculusXRAnchorEventDelegates::OculusSpaceSetComponentStatusComplete; + +FOculusXRAnchorEventDelegates::FOculusXRSpaceQueryResultsDelegate FOculusXRAnchorEventDelegates::OculusSpaceQueryResults; + +FOculusXRAnchorEventDelegates::FOculusXRSpaceQueryResultDelegate FOculusXRAnchorEventDelegates::OculusSpaceQueryResult; + +FOculusXRAnchorEventDelegates::FOculusXRSpaceQueryCompleteDelegate FOculusXRAnchorEventDelegates::OculusSpaceQueryComplete; + +FOculusXRAnchorEventDelegates::FOculusXRSpaceSaveCompleteDelegate FOculusXRAnchorEventDelegates::OculusSpaceSaveComplete; + +FOculusXRAnchorEventDelegates::FOculusXRSpaceListSaveCompleteDelegate FOculusXRAnchorEventDelegates::OculusSpaceListSaveComplete; + +FOculusXRAnchorEventDelegates::FOculusXRSpaceEraseCompleteDelegate FOculusXRAnchorEventDelegates::OculusSpaceEraseComplete; + +FOculusXRAnchorEventDelegates::FOculusXRSpaceShareCompleteDelegate FOculusXRAnchorEventDelegates::OculusSpaceShareComplete; + +FOculusXRAnchorEventDelegates::FOculusXRSceneCaptureCompleteDelegate FOculusXRAnchorEventDelegates::OculusSceneCaptureComplete; + diff --git a/Plugins/MetaXR/Source/OculusXRAnchors/Private/OculusXRAnchorLatentActions.cpp b/Plugins/MetaXR/Source/OculusXRAnchors/Private/OculusXRAnchorLatentActions.cpp new file mode 100644 index 0000000..940e5be --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRAnchors/Private/OculusXRAnchorLatentActions.cpp @@ -0,0 +1,581 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#include "OculusXRAnchorLatentActions.h" +#include "OculusXRAnchorsPrivate.h" +#include "OculusXRHMD.h" +#include "OculusXRAnchorBPFunctionLibrary.h" +#include "OculusXRRoomLayoutManager.h" +#include "OculusXRAnchorDelegates.h" + +// +// Create Spatial Anchor +// +void UOculusXRAsyncAction_CreateSpatialAnchor::Activate() +{ + if (!IsValid(TargetActor)) + { + UE_LOG(LogOculusXRAnchors, Warning, TEXT("Invalid Target Actor passed to CreateSpatialAnchor latent action.")); + + Failure.Broadcast(EOculusXRAnchorResult::Failure); + return; + } + + EOculusXRAnchorResult::Type Result; + bool bStartedAsync = OculusXRAnchors::FOculusXRAnchors::CreateSpatialAnchor( + AnchorTransform, + TargetActor, + FOculusXRSpatialAnchorCreateDelegate::CreateUObject(this, &UOculusXRAsyncAction_CreateSpatialAnchor::HandleCreateComplete), + Result); + + if (!bStartedAsync) + { + UE_LOG(LogOculusXRAnchors, Warning, TEXT("Failed to start async OVR Plugin call for CreateSpatialAnchor latent action.")); + Failure.Broadcast(Result); + } +} + +UOculusXRAsyncAction_CreateSpatialAnchor* UOculusXRAsyncAction_CreateSpatialAnchor::OculusXRAsyncCreateSpatialAnchor(AActor* TargetActor, const FTransform& AnchorTransform) +{ + UOculusXRAsyncAction_CreateSpatialAnchor* Action = NewObject(); + Action->TargetActor = TargetActor; + Action->AnchorTransform = AnchorTransform; + + if (IsValid(TargetActor)) + { + Action->RegisterWithGameInstance(TargetActor->GetWorld()); + } + else + { + Action->RegisterWithGameInstance(GWorld); + } + + return Action; +} + +void UOculusXRAsyncAction_CreateSpatialAnchor::HandleCreateComplete(EOculusXRAnchorResult::Type CreateResult, UOculusXRAnchorComponent* Anchor) +{ + if (UOculusXRAnchorBPFunctionLibrary::IsAnchorResultSuccess(CreateResult)) + { + Success.Broadcast(Anchor, CreateResult); + } + else + { + Failure.Broadcast(CreateResult); + } + + SetReadyToDestroy(); +} + +// +// Erase Space +// +void UOculusXRAsyncAction_EraseAnchor::Activate() +{ + if (!IsValid(TargetActor)) + { + UE_LOG(LogOculusXRAnchors, Warning, TEXT("Invalid Target Actor passed to EraseSpace latent action.")); + + Failure.Broadcast(EOculusXRAnchorResult::Failure); + return; + } + + UOculusXRAnchorComponent* AnchorComponent = TargetActor->FindComponentByClass(); + if (AnchorComponent == nullptr) + { + UE_LOG(LogOculusXRAnchors, Warning, TEXT("No anchor on actor in EraseSpace latent action.")); + + Failure.Broadcast(EOculusXRAnchorResult::Failure); + return; + } + + EOculusXRAnchorResult::Type Result; + bool bStartedAsync = OculusXRAnchors::FOculusXRAnchors::EraseAnchor( + AnchorComponent, + FOculusXRAnchorEraseDelegate::CreateUObject(this, &UOculusXRAsyncAction_EraseAnchor::HandleEraseAnchorComplete), + Result); + + if (!bStartedAsync) + { + UE_LOG(LogOculusXRAnchors, Warning, TEXT("Failed to start async OVR Plugin call for EraseSpace latent action.")); + + Failure.Broadcast(Result); + } +} + +UOculusXRAsyncAction_EraseAnchor* UOculusXRAsyncAction_EraseAnchor::OculusXRAsyncEraseAnchor(AActor* TargetActor) +{ + UOculusXRAsyncAction_EraseAnchor* Action = NewObject(); + Action->TargetActor = TargetActor; + + if (IsValid(TargetActor)) + { + Action->RegisterWithGameInstance(TargetActor->GetWorld()); + } + else + { + Action->RegisterWithGameInstance(GWorld); + } + + return Action; +} + +void UOculusXRAsyncAction_EraseAnchor::HandleEraseAnchorComplete(EOculusXRAnchorResult::Type EraseResult, FOculusXRUUID UUID) +{ + if (UOculusXRAnchorBPFunctionLibrary::IsAnchorResultSuccess(EraseResult)) + { + Success.Broadcast(TargetActor, UUID, EraseResult); + } + else + { + Failure.Broadcast(EraseResult); + } + + SetReadyToDestroy(); +} + +// +// Save Space +// +void UOculusXRAsyncAction_SaveAnchor::Activate() +{ + if (!IsValid(TargetActor)) + { + UE_LOG(LogOculusXRAnchors, Warning, TEXT("Invalid Target Actor passed to SaveSpace latent action.")); + + Failure.Broadcast(EOculusXRAnchorResult::Failure); + return; + } + + UOculusXRAnchorComponent* AnchorComponent = TargetActor->FindComponentByClass(); + if (AnchorComponent == nullptr) + { + Failure.Broadcast(EOculusXRAnchorResult::Failure); + return; + } + + UE_LOG(LogOculusXRAnchors, Log, TEXT("Attempting to save anchor: %s to location %s"), IsValid(AnchorComponent) ? *AnchorComponent->GetName() : TEXT("INVALID ANCHOR"), *UEnum::GetValueAsString(StorageLocation)); + + EOculusXRAnchorResult::Type Result; + bool bStartedAsync = OculusXRAnchors::FOculusXRAnchors::SaveAnchor( + AnchorComponent, + StorageLocation, + FOculusXRAnchorSaveDelegate::CreateUObject(this, &UOculusXRAsyncAction_SaveAnchor::HandleSaveAnchorComplete), + Result); + + if (!bStartedAsync) + { + UE_LOG(LogOculusXRAnchors, Warning, TEXT("Failed to start async OVR Plugin call for SaveSpace latent action.")); + Failure.Broadcast(Result); + } +} + +UOculusXRAsyncAction_SaveAnchor* UOculusXRAsyncAction_SaveAnchor::OculusXRAsyncSaveAnchor(AActor* TargetActor, EOculusXRSpaceStorageLocation StorageLocation) +{ + UOculusXRAsyncAction_SaveAnchor* Action = NewObject(); + Action->TargetActor = TargetActor; + Action->StorageLocation = StorageLocation; + + if (IsValid(TargetActor)) + { + Action->RegisterWithGameInstance(TargetActor->GetWorld()); + } + else + { + Action->RegisterWithGameInstance(GWorld); + } + + return Action; +} + +void UOculusXRAsyncAction_SaveAnchor::HandleSaveAnchorComplete(EOculusXRAnchorResult::Type SaveResult, UOculusXRAnchorComponent* Anchor) +{ + if (UOculusXRAnchorBPFunctionLibrary::IsAnchorResultSuccess(SaveResult)) + { + Success.Broadcast(Anchor, SaveResult); + } + else + { + Failure.Broadcast(SaveResult); + } + + SetReadyToDestroy(); +} + +// +// Save Anchor List +// +void UOculusXRAsyncAction_SaveAnchorList::Activate() +{ + if (TargetAnchors.Num() == 0) + { + UE_LOG(LogOculusXRAnchors, Warning, TEXT("Empty Target Actor array passed to SaveSpaces latent action.")); + + Failure.Broadcast(EOculusXRAnchorResult::Failure); + return; + } + + EOculusXRAnchorResult::Type Result; + bool bStartedAsync = OculusXRAnchors::FOculusXRAnchors::SaveAnchorList( + TargetAnchors, + StorageLocation, + FOculusXRAnchorSaveListDelegate::CreateUObject(this, &UOculusXRAsyncAction_SaveAnchorList::HandleSaveAnchorListComplete), + Result); + + if (!bStartedAsync) + { + UE_LOG(LogOculusXRAnchors, Warning, TEXT("Failed to start async OVR Plugin call for SaveSpaceList latent action.")); + + Failure.Broadcast(Result); + } +} + +UOculusXRAsyncAction_SaveAnchorList* UOculusXRAsyncAction_SaveAnchorList::OculusXRAsyncSaveAnchorList(const TArray& TargetActors, EOculusXRSpaceStorageLocation StorageLocation) +{ + UOculusXRAsyncAction_SaveAnchorList* Action = NewObject(); + + auto ValidActorPtr = TargetActors.FindByPredicate([](AActor* Actor) { return IsValid(Actor); }); + + for (auto& it : TargetActors) + { + if (!IsValid(it)) + { + continue; + } + + UOculusXRAnchorComponent* AnchorComponent = it->FindComponentByClass(); + Action->TargetAnchors.Add(AnchorComponent); + } + + Action->StorageLocation = StorageLocation; + + if (ValidActorPtr != nullptr) + { + Action->RegisterWithGameInstance(*ValidActorPtr); + } + + return Action; +} + +void UOculusXRAsyncAction_SaveAnchorList::HandleSaveAnchorListComplete(EOculusXRAnchorResult::Type SaveResult, const TArray& SavedSpaces) +{ + if (UOculusXRAnchorBPFunctionLibrary::IsAnchorResultSuccess(SaveResult)) + { + Success.Broadcast(SavedSpaces, SaveResult); + } + else + { + Failure.Broadcast(SaveResult); + } + + SetReadyToDestroy(); +} + +// +// Query Spaces +// +void UOculusXRAsyncAction_QueryAnchors::Activate() +{ + EOculusXRAnchorResult::Type Result; + bool bStartedAsync = OculusXRAnchors::FOculusXRAnchors::QueryAnchorsAdvanced( + QueryInfo, + FOculusXRAnchorQueryDelegate::CreateUObject(this, &UOculusXRAsyncAction_QueryAnchors::HandleQueryAnchorsResults), + Result); + + if (!bStartedAsync) + { + UE_LOG(LogOculusXRAnchors, Warning, TEXT("Failed to start async OVR Plugin call for QuerySpaces latent action.")); + + Failure.Broadcast(Result); + } +} + +UOculusXRAsyncAction_QueryAnchors* UOculusXRAsyncAction_QueryAnchors::OculusXRAsyncQueryAnchors(EOculusXRSpaceStorageLocation Location, const TArray& UUIDs) +{ + FOculusXRSpaceQueryInfo QueryInfo; + QueryInfo.FilterType = EOculusXRSpaceQueryFilterType::FilterByIds; + QueryInfo.IDFilter = UUIDs; + QueryInfo.Location = Location; + QueryInfo.MaxQuerySpaces = UUIDs.Num(); + + UOculusXRAsyncAction_QueryAnchors* Action = NewObject(); + Action->QueryInfo = QueryInfo; + + return Action; +} + +UOculusXRAsyncAction_QueryAnchors* UOculusXRAsyncAction_QueryAnchors::OculusXRAsyncQueryAnchorsAdvanced(const FOculusXRSpaceQueryInfo& QueryInfo) +{ + UOculusXRAsyncAction_QueryAnchors* Action = NewObject(); + Action->QueryInfo = QueryInfo; + + return Action; +} + +void UOculusXRAsyncAction_QueryAnchors::HandleQueryAnchorsResults(EOculusXRAnchorResult::Type QueryResult, const TArray& Results) +{ + QueryResults = Results; + + if (UOculusXRAnchorBPFunctionLibrary::IsAnchorResultSuccess(QueryResult)) + { + Success.Broadcast(QueryResults, QueryResult); + } + else + { + Failure.Broadcast(QueryResult); + } + + SetReadyToDestroy(); +} + +// +// Set Component Status with Anchor Actor +// +void UOculusXRAsyncAction_SetAnchorComponentStatus::Activate() +{ + if (!IsValid(TargetActor)) + { + UE_LOG(LogOculusXRAnchors, Warning, TEXT("Invalid Target Actor passed to SetComponentStatus latent action.")); + + Failure.Broadcast(EOculusXRAnchorResult::Failure); + return; + } + + TargetAnchorComponent = TargetActor->FindComponentByClass(); + if (TargetAnchorComponent == nullptr) + { + Failure.Broadcast(EOculusXRAnchorResult::Failure); + return; + } + + EOculusXRAnchorResult::Type Result; + bool bStartedAsync = OculusXRAnchors::FOculusXRAnchors::SetAnchorComponentStatus( + TargetAnchorComponent, + ComponentType, + bEnabled, + 0, + FOculusXRAnchorSetComponentStatusDelegate::CreateUObject(this, &UOculusXRAsyncAction_SetAnchorComponentStatus::HandleSetComponentStatusComplete), + Result); + + if (!bStartedAsync) + { + UE_LOG(LogOculusXRAnchors, Warning, TEXT("Failed to start async OVR Plugin call for SetComponentStatus latent action.")); + + Failure.Broadcast(Result); + } +} + +UOculusXRAsyncAction_SetAnchorComponentStatus* UOculusXRAsyncAction_SetAnchorComponentStatus::OculusXRAsyncSetAnchorComponentStatus(AActor* TargetActor, EOculusXRSpaceComponentType ComponentType, bool bEnabled) +{ + UOculusXRAsyncAction_SetAnchorComponentStatus* Action = NewObject(); + Action->TargetActor = TargetActor; + Action->ComponentType = ComponentType; + Action->bEnabled = bEnabled; + + if (IsValid(TargetActor)) + { + Action->RegisterWithGameInstance(TargetActor->GetWorld()); + } + else + { + Action->RegisterWithGameInstance(GWorld); + } + + return Action; +} + +void UOculusXRAsyncAction_SetAnchorComponentStatus::HandleSetComponentStatusComplete(EOculusXRAnchorResult::Type SetStatusResult, uint64 AnchorHandle, EOculusXRSpaceComponentType SpaceComponentType, bool bResultEnabled) +{ + if (UOculusXRAnchorBPFunctionLibrary::IsAnchorResultSuccess(SetStatusResult)) + { + Success.Broadcast(TargetAnchorComponent, SpaceComponentType, bResultEnabled, SetStatusResult); + } + else + { + Failure.Broadcast(SetStatusResult); + } + + SetReadyToDestroy(); +} + +// +// Set Component Status +// +void UOculusXRAsyncAction_SetComponentStatus::Activate() +{ + EOculusXRAnchorResult::Type Result; + bool bStartedAsync = OculusXRAnchors::FOculusXRAnchors::SetComponentStatus( + Component->GetSpace(), + Component->GetType(), + bEnabled, + 0, + FOculusXRAnchorSetComponentStatusDelegate::CreateUObject(this, &UOculusXRAsyncAction_SetComponentStatus::HandleSetComponentStatusComplete), + Result); + + if (!bStartedAsync) + { + UE_LOG(LogOculusXRAnchors, Warning, TEXT("Failed to start async OVR Plugin call for SetComponentStatus latent action.")); + + Failure.Broadcast(Result); + } +} + +UOculusXRAsyncAction_SetComponentStatus* UOculusXRAsyncAction_SetComponentStatus::OculusXRAsyncSetComponentStatus(UOculusXRBaseAnchorComponent* Component, bool bEnabled) +{ + UOculusXRAsyncAction_SetComponentStatus* Action = NewObject(); + Action->Component = Component; + Action->bEnabled = bEnabled; + + Action->RegisterWithGameInstance(GWorld); + + return Action; +} + +void UOculusXRAsyncAction_SetComponentStatus::HandleSetComponentStatusComplete(EOculusXRAnchorResult::Type SetStatusResult, uint64 AnchorHandle, EOculusXRSpaceComponentType SpaceComponentType, bool bResultEnabled) +{ + if (UOculusXRAnchorBPFunctionLibrary::IsAnchorResultSuccess(SetStatusResult)) + { + Success.Broadcast(Component, SetStatusResult); + } + else + { + Failure.Broadcast(SetStatusResult); + } + + SetReadyToDestroy(); +} + +// +// Share Spaces +// +void UOculusXRAsyncAction_ShareAnchors::Activate() +{ + if (TargetAnchors.Num() == 0) + { + UE_LOG(LogOculusXRAnchors, Warning, TEXT("Empty Target Actors array passed to ShareSpaces latent action.")); + + Failure.Broadcast(EOculusXRAnchorResult::Failure); + return; + } + + if (ToShareWithIds.Num() == 0) + { + UE_LOG(LogOculusXRAnchors, Warning, TEXT("Empty Target Player IDs array passed to ShareSpaces latent action.")); + + Failure.Broadcast(EOculusXRAnchorResult::Failure); + return; + } + + EOculusXRAnchorResult::Type Result; + bool bStartedAsync = OculusXRAnchors::FOculusXRAnchors::ShareAnchors( + TargetAnchors, + ToShareWithIds, + FOculusXRAnchorShareDelegate::CreateUObject(this, &UOculusXRAsyncAction_ShareAnchors::HandleShareAnchorsComplete), + Result); + + if (!bStartedAsync) + { + UE_LOG(LogOculusXRAnchors, Warning, TEXT("Failed to start async OVR Plugin call for ShareSpaces latent action.")); + + Failure.Broadcast(Result); + } +} + +UOculusXRAsyncAction_ShareAnchors* UOculusXRAsyncAction_ShareAnchors::OculusXRAsyncShareAnchors(const TArray& TargetActors, const TArray& ToShareWithIds) +{ + UOculusXRAsyncAction_ShareAnchors* Action = NewObject(); + + for (const auto& UserIDString : ToShareWithIds) + { + uint64 UserId = FCString::Strtoui64(*UserIDString, nullptr, 10); + if (UserId == 0) + { + UE_LOG(LogOculusXRAnchors, Warning, TEXT("UserID provided to share anchors was invalid or unconvertable: %s"), *UserIDString); + } + + Action->ToShareWithIds.Add(UserId); + } + + for (auto& it : TargetActors) + { + if (!IsValid(it)) + { + continue; + } + + UOculusXRAnchorComponent* AnchorComponent = it->FindComponentByClass(); + Action->TargetAnchors.Add(AnchorComponent); + } + + auto ValidActorPtr = TargetActors.FindByPredicate([](AActor* Actor) { return IsValid(Actor); }); + if (ValidActorPtr != nullptr) + { + Action->RegisterWithGameInstance(*ValidActorPtr); + } + else + { + Action->RegisterWithGameInstance(GWorld); + } + + return Action; +} + +void UOculusXRAsyncAction_ShareAnchors::HandleShareAnchorsComplete(EOculusXRAnchorResult::Type ShareResult, const TArray& SharedAnchors, const TArray& OculusUserIDs) +{ + TArray OculusUserIDStrings; + for (const auto& it : OculusUserIDs) + { + OculusUserIDStrings.Add(FString::Printf(TEXT("%llu"), it)); + } + + if (UOculusXRAnchorBPFunctionLibrary::IsAnchorResultSuccess(ShareResult)) + { + Success.Broadcast(SharedAnchors, OculusUserIDStrings, ShareResult); + } + else + { + Failure.Broadcast(ShareResult); + } + + // Unbind and mark for destruction + SetReadyToDestroy(); +} + + +UOculusXRAnchorLaunchCaptureFlow* UOculusXRAnchorLaunchCaptureFlow::LaunchCaptureFlowAsync(const UObject* WorldContext) +{ + UWorld* World = GEngine->GetWorldFromContextObject(WorldContext, EGetWorldErrorMode::ReturnNull); + if (!ensureAlwaysMsgf(IsValid(WorldContext), TEXT("World Context was not valid."))) + { + return nullptr; + } + + // Create a new UMyDelayAsyncAction, and store function arguments in it. + auto NewAction = NewObject(); + NewAction->RegisterWithGameInstance(World->GetGameInstance()); + return NewAction; +} + +void UOculusXRAnchorLaunchCaptureFlow::Activate() +{ + Request = 0; + FOculusXRAnchorEventDelegates::OculusSceneCaptureComplete.AddUObject(this, &UOculusXRAnchorLaunchCaptureFlow::OnCaptureFinish); + bool CaptureStarted = OculusXRAnchors::FOculusXRRoomLayoutManager::RequestSceneCapture(Request); + if (!CaptureStarted) + { + FOculusXRAnchorEventDelegates::OculusSceneCaptureComplete.RemoveAll(this); + Failure.Broadcast(); + } +} + +void UOculusXRAnchorLaunchCaptureFlow::OnCaptureFinish(FOculusXRUInt64 RequestId, bool bSuccess) +{ + if (Request != RequestId.GetValue()) + { + UE_LOG(LogOculusXRAnchors, Warning, TEXT("%llu request id doesn't match %llu. Ignoring request."), RequestId, Request); + return; + } + + FOculusXRAnchorEventDelegates::OculusSceneCaptureComplete.RemoveAll(this); + Success.Broadcast(); + SetReadyToDestroy(); +} diff --git a/Plugins/MetaXR/Source/OculusXRAnchors/Private/OculusXRAnchorManager.cpp b/Plugins/MetaXR/Source/OculusXRAnchors/Private/OculusXRAnchorManager.cpp new file mode 100644 index 0000000..94d8e41 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRAnchors/Private/OculusXRAnchorManager.cpp @@ -0,0 +1,816 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#include "OculusXRAnchorManager.h" + +#include + +#include "OculusXRHMD.h" +#include "OculusXRAnchorsModule.h" +#include "OculusXRAnchorDelegates.h" +#include "OculusXRAnchorBPFunctionLibrary.h" +#include "OculusXRAnchorTypesPrivate.h" + +namespace OculusXRAnchors +{ + OculusXRHMD::FOculusXRHMD* GetHMD(bool& OutSuccessful) + { + OculusXRHMD::FOculusXRHMD* OutHMD = OculusXRHMD::FOculusXRHMD::GetOculusXRHMD(); + if (!OutHMD) + { + UE_LOG(LogOculusXRAnchors, Warning, TEXT("Unable to retrieve OculusXRHMD")); + OutSuccessful = false; + } + + OutSuccessful = true; + + return OutHMD; + } + + ovrpUuid ConvertFOculusXRUUIDtoOvrpUuid(const FOculusXRUUID& UUID) + { + ovrpUuid Result; + FMemory::Memcpy(Result.data, UUID.UUIDBytes); + + return Result; + } + + ovrpSpaceQueryInfo ConvertToOVRPSpaceQueryInfo(const FOculusXRSpaceQueryInfo& UEQueryInfo) + { + static const int32 MaxIdsInFilter = 1024; + static const int32 MaxComponentTypesInFilter = 16; + + ovrpSpaceQueryInfo Result; + + Result.queryType = ovrpSpaceQueryType_Action; + Result.actionType = ovrpSpaceQueryActionType_Load; + + Result.maxQuerySpaces = UEQueryInfo.MaxQuerySpaces; + Result.timeout = static_cast(UEQueryInfo.Timeout); // Prevent compiler warnings, though there is a possible loss of data here. + + switch (UEQueryInfo.Location) + { + case EOculusXRSpaceStorageLocation::Invalid: + Result.location = ovrpSpaceStorageLocation_Invalid; + break; + case EOculusXRSpaceStorageLocation::Local: + Result.location = ovrpSpaceStorageLocation_Local; + break; + case EOculusXRSpaceStorageLocation::Cloud: + Result.location = ovrpSpaceStorageLocation_Cloud; + break; + } + + switch (UEQueryInfo.FilterType) + { + case EOculusXRSpaceQueryFilterType::None: + Result.filterType = ovrpSpaceQueryFilterType_None; + break; + case EOculusXRSpaceQueryFilterType::FilterByIds: + Result.filterType = ovrpSpaceQueryFilterType_Ids; + break; + case EOculusXRSpaceQueryFilterType::FilterByComponentType: + Result.filterType = ovrpSpaceQueryFilterType_Components; + break; + } + + + Result.IdInfo.numIds = FMath::Min(MaxIdsInFilter, UEQueryInfo.IDFilter.Num()); + for (int i = 0; i < Result.IdInfo.numIds; ++i) + { + ovrpUuid OvrUuid = ConvertFOculusXRUUIDtoOvrpUuid(UEQueryInfo.IDFilter[i]); + Result.IdInfo.ids[i] = OvrUuid; + } + + Result.componentsInfo.numComponents = FMath::Min(MaxComponentTypesInFilter, UEQueryInfo.ComponentFilter.Num()); + for (int i = 0; i < Result.componentsInfo.numComponents; ++i) + { + Result.componentsInfo.components[i] = ConvertToOvrpComponentType(UEQueryInfo.ComponentFilter[i]); + } + + return Result; + } + + template + void GetEventData(ovrpEventDataBuffer& Buffer, T& OutEventData) + { + unsigned char* BufData = Buffer.EventData; + BufData -= sizeof(uint64); //correct offset + + memcpy(&OutEventData, BufData, sizeof(T)); + } + + void FOculusXRAnchorManager::OnPollEvent(ovrpEventDataBuffer* EventDataBuffer, bool& EventPollResult) + { + ovrpEventDataBuffer& buf = *EventDataBuffer; + EventPollResult = true; + + switch (buf.EventType) + { + case ovrpEventType_SpatialAnchorCreateComplete: + { + ovrpEventDataSpatialAnchorCreateComplete AnchorCreateEvent; + GetEventData(buf, AnchorCreateEvent); + + const FOculusXRUInt64 RequestId(AnchorCreateEvent.requestId); + const FOculusXRUInt64 Space(AnchorCreateEvent.space); + const FOculusXRUUID BPUUID(AnchorCreateEvent.uuid.data); + + FOculusXRAnchorEventDelegates::OculusSpatialAnchorCreateComplete.Broadcast(RequestId, AnchorCreateEvent.result, Space, BPUUID); + + UE_LOG(LogOculusXRAnchors, Verbose, TEXT("ovrpEventType_SpatialAnchorCreateComplete Request ID: %llu -- Space: %llu -- UUID: %s -- Result: %d"), + RequestId.GetValue(), + Space.GetValue(), + *BPUUID.ToString(), + AnchorCreateEvent.result); + + break; + } + case ovrpEventType_SpaceSetComponentStatusComplete: + { + ovrpEventDataSpaceSetStatusComplete SetStatusEvent; + GetEventData(buf, SetStatusEvent); + + //translate to BP types + const FOculusXRUInt64 RequestId(SetStatusEvent.requestId); + const FOculusXRUInt64 Space(SetStatusEvent.space); + EOculusXRSpaceComponentType BPSpaceComponentType = ConvertToUEComponentType(SetStatusEvent.componentType); + const FOculusXRUUID BPUUID(SetStatusEvent.uuid.data); + const bool bEnabled = (SetStatusEvent.enabled == ovrpBool_True); + + FOculusXRAnchorEventDelegates::OculusSpaceSetComponentStatusComplete.Broadcast( + RequestId, + SetStatusEvent.result, + Space, + BPUUID, + BPSpaceComponentType, + bEnabled); + + UE_LOG(LogOculusXRAnchors, Verbose, TEXT("ovrpEventType_SpaceSetComponentStatusComplete Request ID: %llu -- Type: %d -- Enabled: %d -- Space: %llu -- Result: %d"), + SetStatusEvent.requestId, + SetStatusEvent.componentType, + SetStatusEvent.enabled, + SetStatusEvent.space, + SetStatusEvent.result); + + break; + } + case ovrpEventType_SpaceQueryResults: + { + ovrpEventSpaceQueryResults QueryEvent; + GetEventData(buf, QueryEvent); + + const FOculusXRUInt64 RequestId(QueryEvent.requestId); + + FOculusXRAnchorEventDelegates::OculusSpaceQueryResults.Broadcast(RequestId); + + ovrpUInt32 ovrpOutCapacity = 0; + + // First get capacity + const bool bGetCapacityResult = FOculusXRHMDModule::GetPluginWrapper().GetInitialized() && OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().RetrieveSpaceQueryResults(&QueryEvent.requestId, 0, &ovrpOutCapacity, nullptr)); + + UE_LOG(LogOculusXRAnchors, Log, TEXT("ovrpEventType_SpaceQueryResults Request ID: %llu -- Capacity: %d -- Result: %d"), QueryEvent.requestId, ovrpOutCapacity, bGetCapacityResult); + + std::vector ovrpResults(ovrpOutCapacity); + + // Get Query Data + const bool bGetQueryDataResult = FOculusXRHMDModule::GetPluginWrapper().GetInitialized() && OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().RetrieveSpaceQueryResults(&QueryEvent.requestId, ovrpResults.size(), &ovrpOutCapacity, ovrpResults.data())); + + for (auto queryResultElement : ovrpResults) + { + UE_LOG(LogOculusXRAnchors, Verbose, TEXT("ovrpEventType_SpaceQueryResult Space: %llu -- Result: %d"), queryResultElement.space, bGetQueryDataResult); + + //translate types + FOculusXRUInt64 Space(queryResultElement.space); + FOculusXRUUID BPUUID(queryResultElement.uuid.data); + FOculusXRAnchorEventDelegates::OculusSpaceQueryResult.Broadcast(RequestId, Space, BPUUID); + } + + break; + } + case ovrpEventType_SpaceQueryComplete: + { + ovrpEventSpaceQueryComplete QueryCompleteEvent; + GetEventData(buf, QueryCompleteEvent); + + //translate to BP types + const FOculusXRUInt64 RequestId(QueryCompleteEvent.requestId); + const bool bSucceeded = QueryCompleteEvent.result >= 0; + + FOculusXRAnchorEventDelegates::OculusSpaceQueryComplete.Broadcast(RequestId, QueryCompleteEvent.result); + + UE_LOG(LogOculusXRAnchors, Verbose, TEXT("ovrpEventType_SpaceQueryComplete Request ID: %llu -- Result: %d"), QueryCompleteEvent.requestId, QueryCompleteEvent.result); + + break; + } + case ovrpEventType_SpaceSaveComplete: + { + ovrpEventSpaceStorageSaveResult StorageResult; + GetEventData(buf, StorageResult); + + //translate to BP types + const FOculusXRUUID uuid(StorageResult.uuid.data); + const FOculusXRUInt64 FSpace(StorageResult.space); + const FOculusXRUInt64 FRequest(StorageResult.requestId); + const bool bResult = StorageResult.result >= 0; + + FOculusXRAnchorEventDelegates::OculusSpaceSaveComplete.Broadcast(FRequest, FSpace, bResult, StorageResult.result, uuid); + + UE_LOG(LogOculusXRAnchors, Verbose, TEXT("ovrpEventType_SpaceSaveComplete Request ID: %llu -- Space: %llu -- Result: %d"), StorageResult.requestId, StorageResult.space, StorageResult.result); + + break; + } + case ovrpEventType_SpaceListSaveResult: + { + ovrpEventSpaceListSaveResult SpaceListSaveResult; + GetEventData(buf, SpaceListSaveResult); + + FOculusXRUInt64 RequestId(SpaceListSaveResult.requestId); + + UE_LOG(LogOculusXRAnchors, Verbose, TEXT("ovrpEventType_SpaceListSaveResult Request ID: %llu -- Result: %d"), SpaceListSaveResult.requestId, SpaceListSaveResult.result); + FOculusXRAnchorEventDelegates::OculusSpaceListSaveComplete.Broadcast(RequestId, SpaceListSaveResult.result); + + break; + } + case ovrpEventType_SpaceEraseComplete: + { + ovrpEventSpaceStorageEraseResult SpaceEraseEvent; + GetEventData(buf, SpaceEraseEvent); + + //translate to BP types + const FOculusXRUUID uuid(SpaceEraseEvent.uuid.data); + const FOculusXRUInt64 FRequestId(SpaceEraseEvent.requestId); + const FOculusXRUInt64 FResult(SpaceEraseEvent.result); + const EOculusXRSpaceStorageLocation BPLocation = (SpaceEraseEvent.location == ovrpSpaceStorageLocation_Local) ? EOculusXRSpaceStorageLocation::Local : EOculusXRSpaceStorageLocation::Invalid; + + UE_LOG(LogOculusXRAnchors, Verbose, TEXT("ovrpEventType_SpaceEraseComplete Request ID: %llu -- Result: %d -- UUID: %s"), SpaceEraseEvent.requestId, SpaceEraseEvent.result, *UOculusXRAnchorBPFunctionLibrary::AnchorUUIDToString(SpaceEraseEvent.uuid.data)); + + FOculusXRAnchorEventDelegates::OculusSpaceEraseComplete.Broadcast(FRequestId, FResult.Value, uuid, BPLocation); + break; + } + case ovrpEventType_SpaceShareResult: + { + unsigned char* BufData = buf.EventData; + ovrpUInt64 OvrpRequestId = 0; + memcpy(&OvrpRequestId, BufData, sizeof(OvrpRequestId)); + + ovrpEventSpaceShareResult SpaceShareSpaceResult; + GetEventData(buf, SpaceShareSpaceResult); + + FOculusXRUInt64 RequestId(SpaceShareSpaceResult.requestId); + + UE_LOG(LogOculusXRAnchors, Verbose, TEXT("ovrpEventType_SpaceShareSpaceResult Request ID: %llu -- Result: %d"), + SpaceShareSpaceResult.requestId, + SpaceShareSpaceResult.result); + + FOculusXRAnchorEventDelegates::OculusSpaceShareComplete.Broadcast(RequestId, SpaceShareSpaceResult.result); + + break; + } + case ovrpEventType_None: + default: + { + EventPollResult = false; + break; + } + } + } + + EOculusXRAnchorResult::Type FOculusXRAnchorManager::CreateAnchor(const FTransform& InTransform, uint64& OutRequestId, const FTransform& CameraTransform) + { + bool bValidHMD; + OculusXRHMD::FOculusXRHMD* HMD = GetHMD(bValidHMD); + if (!bValidHMD) + { + UE_LOG(LogOculusXRAnchors, Warning, TEXT("FOculusAnchorManager::CreateAnchor failed to retrieve HMD.")); + return EOculusXRAnchorResult::Failure; + } + + ovrpTrackingOrigin TrackingOriginType; + ovrpPosef Posef; + double Time = 0; + + const FTransform TrackingToWorld = HMD->GetLastTrackingToWorld(); + + // convert to tracking space + const FQuat TrackingSpaceOrientation = TrackingToWorld.Inverse().TransformRotation(InTransform.Rotator().Quaternion()); + const FVector TrackingSpacePosition = TrackingToWorld.Inverse().TransformPosition(InTransform.GetLocation()); + + const OculusXRHMD::FPose TrackingSpacePose(TrackingSpaceOrientation, TrackingSpacePosition); + +#if WITH_EDITOR + // Link only head space position update + FVector OutHeadPosition; + FQuat OutHeadOrientation; + const bool bGetPose = HMD->GetCurrentPose(HMD->HMDDeviceId, OutHeadOrientation, OutHeadPosition); + if (!bGetPose) + { + UE_LOG(LogOculusXRAnchors, Warning, TEXT("FOculusAnchorManager::CreateAnchor failed to get current headset pose.")); + return EOculusXRAnchorResult::Failure; + } + + OculusXRHMD::FPose HeadPose(OutHeadOrientation, OutHeadPosition); + + OculusXRHMD::FPose MainCameraPose(CameraTransform.GetRotation(), CameraTransform.GetLocation()); + OculusXRHMD::FPose PoseInHeadSpace = MainCameraPose.Inverse() * TrackingSpacePose; + + // To world space pose + OculusXRHMD::FPose WorldPose = HeadPose * PoseInHeadSpace; + + const bool bConverted = HMD->ConvertPose(WorldPose, Posef); +#else + const bool bConverted = HMD->ConvertPose(TrackingSpacePose, Posef); +#endif + + if (!bConverted) + { + UE_LOG(LogOculusXRAnchors, Warning, TEXT("FOculusAnchorManager::CreateAnchor failed to convert pose.")); + return EOculusXRAnchorResult::Failure; + } + + FOculusXRHMDModule::GetPluginWrapper().GetTrackingOriginType2(&TrackingOriginType); + FOculusXRHMDModule::GetPluginWrapper().GetTimeInSeconds(&Time); + + const ovrpSpatialAnchorCreateInfo SpatialAnchorCreateInfo = { + TrackingOriginType, + Posef, + Time + }; + + const ovrpResult Result = FOculusXRHMDModule::GetPluginWrapper().CreateSpatialAnchor(&SpatialAnchorCreateInfo, &OutRequestId); + UE_LOG(LogOculusXRAnchors, Verbose, TEXT("CreateAnchor Request ID: %llu"), OutRequestId); + + if (OVRP_FAILURE(Result)) + { + UE_LOG(LogOculusXRAnchors, Error, TEXT("FOculusAnchorManager::CreateAnchor failed. Result: %d"), Result); + } + + return static_cast(Result); + } + + EOculusXRAnchorResult::Type FOculusXRAnchorManager::DestroySpace(uint64 Space) + { + const ovrpResult Result = FOculusXRHMDModule::GetPluginWrapper().DestroySpace(static_cast(&Space)); + + UE_LOG(LogOculusXRAnchors, Verbose, TEXT("DestroySpace Space ID: %llu"), Space); + + return static_cast(Result); + } + + EOculusXRAnchorResult::Type FOculusXRAnchorManager::SetSpaceComponentStatus(uint64 Space, EOculusXRSpaceComponentType SpaceComponentType, bool Enable, float Timeout, uint64& OutRequestId) + { + ovrpSpaceComponentType ovrpType = ConvertToOvrpComponentType(SpaceComponentType); + ovrpUInt64 OvrpOutRequestId = 0; + + const ovrpUInt64 OVRPSpace = Space; + + // validate existing status + ovrpBool isEnabled = false; + ovrpBool changePending = false; + const ovrpResult getComponentStatusResult = FOculusXRHMDModule::GetPluginWrapper().GetSpaceComponentStatus(&OVRPSpace, ovrpType, &isEnabled, &changePending); + + bool isStatusChangingOrSame = (static_cast(isEnabled) == Enable && !changePending) || (static_cast(isEnabled) != Enable && changePending); + if (OVRP_SUCCESS(getComponentStatusResult) && isStatusChangingOrSame) + { + return EOculusXRAnchorResult::Success; + } + + // set status + const ovrpResult Result = FOculusXRHMDModule::GetPluginWrapper().SetSpaceComponentStatus( + &OVRPSpace, + ovrpType, + Enable, + Timeout, + &OvrpOutRequestId); + + memcpy(&OutRequestId, &OvrpOutRequestId, sizeof(uint64)); + + UE_LOG(LogOculusXRAnchors, Verbose, TEXT("SetSpaceComponentStatus Request ID: %llu"), OutRequestId); + + return static_cast(Result); + } + + EOculusXRAnchorResult::Type FOculusXRAnchorManager::GetSpaceComponentStatus(uint64 Space, EOculusXRSpaceComponentType SpaceComponentType, bool& OutEnabled, bool& OutChangePending) + { + const ovrpUInt64 OVRPSpace = Space; + ovrpBool OutOvrpEnabled = ovrpBool_False; + ovrpBool OutOvrpChangePending = ovrpBool_False; + + ovrpSpaceComponentType ovrpType = ConvertToOvrpComponentType(SpaceComponentType); + + const ovrpResult Result = FOculusXRHMDModule::GetPluginWrapper().GetSpaceComponentStatus( + &OVRPSpace, + ovrpType, + &OutOvrpEnabled, + &OutOvrpChangePending); + + OutEnabled = (OutOvrpEnabled == ovrpBool_True); + OutChangePending = (OutOvrpChangePending == ovrpBool_True); + + return static_cast(Result); + } + + EOculusXRAnchorResult::Type FOculusXRAnchorManager::GetSupportedAnchorComponents(uint64 Handle, TArray& OutSupportedTypes) + { + if (!FOculusXRHMDModule::GetPluginWrapper().GetInitialized()) + { + return EOculusXRAnchorResult::Failure; + } + + ovrpSpace ovrSpace = Handle; + TArray ovrComponentTypes; + ovrpUInt32 input = 0; + ovrpUInt32 output = 0; + + ovrpResult enumerateResult = FOculusXRHMDModule::GetPluginWrapper().EnumerateSpaceSupportedComponents(&ovrSpace, input, &output, nullptr); + if (!OVRP_SUCCESS(enumerateResult)) + { + return static_cast(enumerateResult); + } + + input = output; + ovrComponentTypes.SetNumZeroed(output); + + enumerateResult = FOculusXRHMDModule::GetPluginWrapper().EnumerateSpaceSupportedComponents(&ovrSpace, input, &output, ovrComponentTypes.GetData()); + if (!OVRP_SUCCESS(enumerateResult)) + { + return static_cast(enumerateResult); + } + + OutSupportedTypes.SetNumZeroed(ovrComponentTypes.Num()); + for (int i = 0; i < ovrComponentTypes.Num(); ++i) + { + OutSupportedTypes[i] = ConvertToUEComponentType(ovrComponentTypes[i]); + } + + return static_cast(enumerateResult); + } + + EOculusXRAnchorResult::Type FOculusXRAnchorManager::SaveAnchor(uint64 Space, + EOculusXRSpaceStorageLocation StorageLocation, + EOculusXRSpaceStoragePersistenceMode StoragePersistenceMode, uint64& OutRequestId) + { + ovrpSpaceStorageLocation OvrpStorageLocation = ovrpSpaceStorageLocation_Local; + switch (StorageLocation) + { + case EOculusXRSpaceStorageLocation::Invalid: + OvrpStorageLocation = ovrpSpaceStorageLocation_Invalid; + break; + case EOculusXRSpaceStorageLocation::Local: + OvrpStorageLocation = ovrpSpaceStorageLocation_Local; + break; + case EOculusXRSpaceStorageLocation::Cloud: + OvrpStorageLocation = ovrpSpaceStorageLocation_Cloud; + break; + default: + break; + } + + ovrpSpaceStoragePersistenceMode OvrpStoragePersistenceMode = ovrpSpaceStoragePersistenceMode_Invalid; + switch (StoragePersistenceMode) + { + case EOculusXRSpaceStoragePersistenceMode::Invalid: + OvrpStoragePersistenceMode = ovrpSpaceStoragePersistenceMode_Invalid; + break; + case EOculusXRSpaceStoragePersistenceMode::Indefinite: + OvrpStoragePersistenceMode = ovrpSpaceStoragePersistenceMode_Indefinite; + break; + default: + break; + } + + ovrpUInt64 OvrpOutRequestId = 0; + const ovrpResult Result = FOculusXRHMDModule::GetPluginWrapper().SaveSpace(&Space, OvrpStorageLocation, OvrpStoragePersistenceMode, &OvrpOutRequestId); + + UE_LOG(LogOculusXRAnchors, Verbose, TEXT("Saving space with: SpaceID: %llu -- Location: %d -- Persistence: %d -- OutID: %llu"), Space, OvrpStorageLocation, OvrpStoragePersistenceMode, OvrpOutRequestId); + + memcpy(&OutRequestId, &OvrpOutRequestId, sizeof(uint64)); + + if (OVRP_FAILURE(Result)) + { + UE_LOG(LogOculusXRAnchors, Warning, TEXT("FOculusXRHMD::SaveAnchor failed with: SpaceID: %llu -- Location: %d -- Persistence: %d"), Space, OvrpStorageLocation, OvrpStoragePersistenceMode); + } + + return static_cast(Result); + } + + EOculusXRAnchorResult::Type FOculusXRAnchorManager::SaveAnchorList(const TArray& Spaces, EOculusXRSpaceStorageLocation StorageLocation, uint64& OutRequestId) + { + ovrpSpaceStorageLocation OvrpStorageLocation = ovrpSpaceStorageLocation_Local; + switch (StorageLocation) + { + case EOculusXRSpaceStorageLocation::Invalid: + OvrpStorageLocation = ovrpSpaceStorageLocation_Invalid; + break; + case EOculusXRSpaceStorageLocation::Local: + OvrpStorageLocation = ovrpSpaceStorageLocation_Local; + break; + case EOculusXRSpaceStorageLocation::Cloud: + OvrpStorageLocation = ovrpSpaceStorageLocation_Cloud; + break; + default: + break; + } + + ovrpUInt64 OvrpOutRequestId = 0; + const ovrpResult Result = FOculusXRHMDModule::GetPluginWrapper().SaveSpaceList(Spaces.GetData(), Spaces.Num(), OvrpStorageLocation, &OvrpOutRequestId); + + UE_LOG(LogOculusXRAnchors, Verbose, TEXT("Saving space list: Location: %d -- OutID: %llu"), OvrpStorageLocation, OvrpOutRequestId); + for (auto& it : Spaces) + { + UE_LOG(LogOculusXRAnchors, Verbose, TEXT("\tSpaceID: %llu"), it); + } + + memcpy(&OutRequestId, &OvrpOutRequestId, sizeof(uint64)); + + if (OVRP_FAILURE(Result)) + { + UE_LOG(LogOculusXRAnchors, Warning, TEXT("SaveSpaceList failed -- Result: %d"), Result); + } + + return static_cast(Result); + } + + EOculusXRAnchorResult::Type FOculusXRAnchorManager::EraseAnchor(uint64 AnchorHandle, + EOculusXRSpaceStorageLocation StorageLocation, uint64& OutRequestId) + { + ovrpSpaceStorageLocation ovrpStorageLocation = ovrpSpaceStorageLocation_Local; + switch (StorageLocation) + { + case EOculusXRSpaceStorageLocation::Invalid: + ovrpStorageLocation = ovrpSpaceStorageLocation_Invalid; + break; + case EOculusXRSpaceStorageLocation::Local: + ovrpStorageLocation = ovrpSpaceStorageLocation_Local; + break; + default:; + } + + ovrpUInt64 OvrpOutRequestId = 0; + const ovrpResult Result = FOculusXRHMDModule::GetPluginWrapper().EraseSpace(&AnchorHandle, ovrpStorageLocation, &OvrpOutRequestId); + memcpy(&OutRequestId, &OvrpOutRequestId, sizeof(uint64)); + + UE_LOG(LogOculusXRAnchors, Log, TEXT("Erasing anchor -- Handle: %llu -- Location: %d -- OutID: %llu"), AnchorHandle, ovrpStorageLocation, OvrpOutRequestId); + + return static_cast(Result); + } + + EOculusXRAnchorResult::Type FOculusXRAnchorManager::QuerySpaces(const FOculusXRSpaceQueryInfo& QueryInfo, uint64& OutRequestId) + { + ovrpUInt64 OvrpOutRequestId = 0; + ovrpResult QuerySpacesResult = ovrpFailure; + ovrpSpaceQueryInfo ovrQueryInfo = ConvertToOVRPSpaceQueryInfo(QueryInfo); + QuerySpacesResult = FOculusXRHMDModule::GetPluginWrapper().QuerySpaces(&ovrQueryInfo, &OvrpOutRequestId); + + memcpy(&OutRequestId, &OvrpOutRequestId, sizeof(uint64)); + + UE_LOG(LogOculusXRAnchors, Verbose, TEXT("Query Spaces\n ovrpSpaceQueryInfo:\n\tQueryType: %d\n\tMaxQuerySpaces: %d\n\tTimeout: %f\n\tLocation: %d\n\tActionType: %d\n\tFilterType: %d\n\n\tRequest ID: %llu"), + ovrQueryInfo.queryType, ovrQueryInfo.maxQuerySpaces, (float)ovrQueryInfo.timeout, ovrQueryInfo.location, ovrQueryInfo.actionType, ovrQueryInfo.filterType, OutRequestId); + + if (QueryInfo.FilterType == EOculusXRSpaceQueryFilterType::FilterByIds) + { + UE_LOG(LogOculusXRAnchors, Verbose, TEXT("Query contains %d UUIDs"), QueryInfo.IDFilter.Num()); + for (auto& it : QueryInfo.IDFilter) + { + UE_LOG(LogOculusXRAnchors, Verbose, TEXT("UUID: %s"), *it.ToString()); + } + } + else if (QueryInfo.FilterType == EOculusXRSpaceQueryFilterType::FilterByComponentType) + { + UE_LOG(LogOculusXRAnchors, Verbose, TEXT("Query contains %d Component Types"), QueryInfo.ComponentFilter.Num()); + for (auto& it : QueryInfo.ComponentFilter) + { + UE_LOG(LogOculusXRAnchors, Verbose, TEXT("ComponentType: %s"), *UEnum::GetValueAsString(it)); + } + } + + return static_cast(QuerySpacesResult); + } + + EOculusXRAnchorResult::Type FOculusXRAnchorManager::ShareSpaces(const TArray& Spaces, const TArray& UserIds, uint64& OutRequestId) + { + TArray stringStorage; + TArray OvrpUsers; + for (const auto& UserId : UserIds) + { + ovrpUser OvrUser; + ovrpResult Result = FOculusXRHMDModule::GetPluginWrapper().CreateSpaceUser(&UserId, &OvrUser); + if (OVRP_FAILURE(Result)) + { + UE_LOG(LogOculusXRAnchors, Warning, TEXT("Failed to create space user from ID - %llu"), UserId); + continue; + } + + OvrpUsers.Add(OvrUser); + } + + ovrpUInt64 OvrpOutRequestId = 0; + const ovrpResult ShareSpacesResult = FOculusXRHMDModule::GetPluginWrapper().ShareSpaces(Spaces.GetData(), Spaces.Num(), OvrpUsers.GetData(), OvrpUsers.Num(), &OvrpOutRequestId); + + UE_LOG(LogOculusXRAnchors, Verbose, TEXT("Sharing space list -- OutID: %llu"), OvrpOutRequestId); + for (auto& User : OvrpUsers) + { + UE_LOG(LogOculusXRAnchors, Verbose, TEXT("\tOvrpUser: %llu"), User); + ovrpResult Result = FOculusXRHMDModule::GetPluginWrapper().DestroySpaceUser(&User); + if (OVRP_FAILURE(Result)) + { + UE_LOG(LogOculusXRAnchors, Verbose, TEXT("Failed to destroy space user: %llu"), User); + continue; + } + } + + for (auto& it : Spaces) + { + UE_LOG(LogOculusXRAnchors, Verbose, TEXT("\tSpaceID: %llu"), it); + } + + memcpy(&OutRequestId, &OvrpOutRequestId, sizeof(uint64)); + + return static_cast(ShareSpacesResult); + } + + EOculusXRAnchorResult::Type FOculusXRAnchorManager::GetSpaceContainerUUIDs(uint64 Space, TArray& OutUUIDs) + { + TArray ovrUuidArray; + + // Get the number of elements in the container + ovrpSpaceContainer ovrSpaceContainer; + ovrSpaceContainer.uuidCapacityInput = 0; + ovrSpaceContainer.uuidCountOutput = 0; + ovrSpaceContainer.uuids = nullptr; + ovrpResult result = FOculusXRHMDModule::GetPluginWrapper().GetSpaceContainer(&Space, &ovrSpaceContainer); + if (OVRP_FAILURE(result)) + { + UE_LOG(LogOculusXRAnchors, Warning, TEXT("Failed to get space container %d"), result); + return static_cast(result); + } + + // Retrieve the actual array of UUIDs + ovrUuidArray.SetNum(ovrSpaceContainer.uuidCountOutput); + ovrSpaceContainer.uuidCapacityInput = ovrSpaceContainer.uuidCountOutput; + ovrSpaceContainer.uuids = ovrUuidArray.GetData(); + + result = FOculusXRHMDModule::GetPluginWrapper().GetSpaceContainer(&Space, &ovrSpaceContainer); + if (OVRP_FAILURE(result)) + { + UE_LOG(LogOculusXRAnchors, Warning, TEXT("Failed to get space container %d"), result); + return static_cast(result); + } + + // Write out the remaining UUIDs + OutUUIDs.Reserve(ovrUuidArray.Num()); + for (auto& it : ovrUuidArray) + { + OutUUIDs.Add(FOculusXRUUID(it.data)); + } + + return EOculusXRAnchorResult::Success; + } + + EOculusXRAnchorResult::Type FOculusXRAnchorManager::GetSpaceScenePlane(uint64 Space, FVector& OutPos, FVector& OutSize) + { + OutPos.X = OutPos.Y = OutPos.Z = 0.f; + OutSize.X = OutSize.Y = OutSize.Z = 0.f; + + ovrpRectf rect; + const ovrpResult Result = FOculusXRHMDModule::GetPluginWrapper().GetSpaceBoundingBox2D(&Space, &rect); + + if (OVRP_SUCCESS(Result)) + { + // Convert to UE4's coordinates system + OutPos.Y = rect.Pos.x; + OutPos.Z = rect.Pos.y; + OutSize.Y = rect.Size.w; + OutSize.Z = rect.Size.h; + } + + return static_cast(Result); + } + + EOculusXRAnchorResult::Type FOculusXRAnchorManager::GetSpaceSceneVolume(uint64 Space, FVector& OutPos, FVector& OutSize) + { + OutPos.X = OutPos.Y = OutPos.Z = 0.f; + OutSize.X = OutSize.Y = OutSize.Z = 0.f; + + ovrpBoundsf bounds; + const ovrpResult Result = FOculusXRHMDModule::GetPluginWrapper().GetSpaceBoundingBox3D(&Space, &bounds); + + if (OVRP_SUCCESS(Result)) + { + // Convert from OpenXR's right-handed to Unreal's left-handed coordinate system. + // OpenXR Unreal + // | y | z + // | | + //z <----+ +----> x + // / / + // x/ y/ + // + OutPos.X = -bounds.Pos.z; + OutPos.Y = bounds.Pos.x; + OutPos.Z = bounds.Pos.y; + + // The position represents the corner of the volume which has the lowest value + // of each axis. Since we flipped the sign of one of the axes we need to adjust + // the position to the other side of the volume + OutPos.X -= bounds.Size.d; + + // We keep the size positive for all dimensions + OutSize.X = bounds.Size.d; + OutSize.Y = bounds.Size.w; + OutSize.Z = bounds.Size.h; + } + + return static_cast(Result); + } + + EOculusXRAnchorResult::Type FOculusXRAnchorManager::GetSpaceSemanticClassification(uint64 Space, TArray& OutSemanticClassifications) + { + OutSemanticClassifications.Empty(); + + const int32 maxByteSize = 1024; + char labelsChars[maxByteSize]; + + ovrpSemanticLabels labels; + labels.byteCapacityInput = maxByteSize; + labels.labels = labelsChars; + + const ovrpResult Result = FOculusXRHMDModule::GetPluginWrapper().GetSpaceSemanticLabels(&Space, &labels); + + if (OVRP_SUCCESS(Result)) + { + FString labelsStr(labels.byteCountOutput, labels.labels); + labelsStr.ParseIntoArray(OutSemanticClassifications, TEXT(",")); + } + + return static_cast(Result); + } + + EOculusXRAnchorResult::Type FOculusXRAnchorManager::GetSpaceContainer(uint64 Space, TArray& OutContainerUuids) + { + OutContainerUuids.Empty(); + + ovrpSpaceContainer container; + + ovrpResult Result = FOculusXRHMDModule::GetPluginWrapper().GetSpaceContainer(&Space, &container); + + if (OVRP_SUCCESS(Result)) + { + TArray uuids; + size_t size = container.uuidCountOutput; + uuids.InsertZeroed(0, size); + container.uuidCapacityInput = size; + container.uuids = uuids.GetData(); + Result = FOculusXRHMDModule::GetPluginWrapper().GetSpaceContainer(&Space, &container); + if (OVRP_SUCCESS(Result)) + { + OutContainerUuids.InsertZeroed(0, size); + for (size_t i = 0; i < size; i++) + { + OutContainerUuids[i] = FOculusXRUUID(uuids[i].data); + } + } + } + + return static_cast(Result); + } + + EOculusXRAnchorResult::Type FOculusXRAnchorManager::GetSpaceBoundary2D(uint64 Space, TArray& OutVertices) + { + TArray vertices; + + // Get the number of elements in the container + ovrpBoundary2D boundary; + boundary.vertexCapacityInput = 0; + boundary.vertexCountOutput = 0; + boundary.vertices = nullptr; + + ovrpResult result = FOculusXRHMDModule::GetPluginWrapper().GetSpaceBoundary2D(&Space, &boundary); + if (OVRP_FAILURE(result)) + { + UE_LOG(LogOculusXRAnchors, Warning, TEXT("Failed to get space boundary 2d %d"), result); + return static_cast(result); + } + + // Retrieve the actual array of vertices + vertices.SetNum(boundary.vertexCountOutput); + boundary.vertexCapacityInput = boundary.vertexCountOutput; + boundary.vertices = vertices.GetData(); + + result = FOculusXRHMDModule::GetPluginWrapper().GetSpaceBoundary2D(&Space, &boundary); + if (OVRP_FAILURE(result)) + { + UE_LOG(LogOculusXRAnchors, Warning, TEXT("Failed to get space boundary 2d %d"), result); + return static_cast(result); + } + + // Write out the vertices + OutVertices.Reserve(vertices.Num()); + for (const auto& it : vertices) + { + OutVertices.Add(FVector2f(it.x, it.y)); + } + + return EOculusXRAnchorResult::Success; + } + + +} // namespace OculusXRAnchors diff --git a/Plugins/MetaXR/Source/OculusXRAnchors/Private/OculusXRAnchorManager.h b/Plugins/MetaXR/Source/OculusXRAnchors/Private/OculusXRAnchorManager.h new file mode 100644 index 0000000..701cbab --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRAnchors/Private/OculusXRAnchorManager.h @@ -0,0 +1,33 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#pragma once + +#include "CoreMinimal.h" +#include "OculusXRAnchorComponent.h" +#include "OculusXRHMDPrivate.h" + +namespace OculusXRAnchors +{ + struct OCULUSXRANCHORS_API FOculusXRAnchorManager + { + static EOculusXRAnchorResult::Type CreateAnchor(const FTransform& InTransform, uint64& OutRequestId, const FTransform& CameraTransform); + static EOculusXRAnchorResult::Type DestroySpace(uint64 Space); + static EOculusXRAnchorResult::Type SetSpaceComponentStatus(uint64 Space, EOculusXRSpaceComponentType SpaceComponentType, bool Enable, float Timeout, uint64& OutRequestId); + static EOculusXRAnchorResult::Type GetSpaceComponentStatus(uint64 Space, EOculusXRSpaceComponentType SpaceComponentType, bool& OutEnabled, bool& OutChangePending); + static EOculusXRAnchorResult::Type GetSupportedAnchorComponents(uint64 Handle, TArray& OutSupportedTypes); + static EOculusXRAnchorResult::Type SaveAnchor(uint64 Space, EOculusXRSpaceStorageLocation StorageLocation, EOculusXRSpaceStoragePersistenceMode StoragePersistenceMode, uint64& OutRequestId); + static EOculusXRAnchorResult::Type SaveAnchorList(const TArray& Spaces, EOculusXRSpaceStorageLocation StorageLocation, uint64& OutRequestId); + static EOculusXRAnchorResult::Type EraseAnchor(uint64 AnchorHandle, EOculusXRSpaceStorageLocation StorageLocation, uint64& OutRequestId); + static EOculusXRAnchorResult::Type QuerySpaces(const FOculusXRSpaceQueryInfo& QueryInfo, uint64& OutRequestId); + static EOculusXRAnchorResult::Type ShareSpaces(const TArray& Spaces, const TArray& UserIds, uint64& OutRequestId); + static EOculusXRAnchorResult::Type GetSpaceContainerUUIDs(uint64 Space, TArray& OutUUIDs); + static EOculusXRAnchorResult::Type GetSpaceScenePlane(uint64 Space, FVector& OutPos, FVector& OutSize); + static EOculusXRAnchorResult::Type GetSpaceSceneVolume(uint64 Space, FVector& OutPos, FVector& OutSize); + static EOculusXRAnchorResult::Type GetSpaceSemanticClassification(uint64 Space, TArray& OutSemanticClassification); + static EOculusXRAnchorResult::Type GetSpaceContainer(uint64 Space, TArray& OutContainerUuids); + static EOculusXRAnchorResult::Type GetSpaceBoundary2D(uint64 Space, TArray& OutVertices); + + + static void OnPollEvent(ovrpEventDataBuffer* EventDataBuffer, bool& EventPollResult); + }; +} // namespace OculusXRAnchors diff --git a/Plugins/MetaXR/Source/OculusXRAnchors/Private/OculusXRAnchorTypes.cpp b/Plugins/MetaXR/Source/OculusXRAnchors/Private/OculusXRAnchorTypes.cpp new file mode 100644 index 0000000..d191a98 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRAnchors/Private/OculusXRAnchorTypes.cpp @@ -0,0 +1,96 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#include "OculusXRAnchorTypes.h" +#include "OculusXRHMDPrivate.h" +#include "OculusXRAnchorsModule.h" +#include "OculusXRAnchorTypesPrivate.h" + +bool FOculusXRUInt64::operator==(const FOculusXRUInt64& Right) const +{ + return IsEqual(Right); +} +bool FOculusXRUInt64::operator!=(const FOculusXRUInt64& Right) const +{ + return !IsEqual(Right); +} + +FOculusXRUUID::FOculusXRUUID() +{ + FMemory::Memzero(&UUIDBytes, OCULUSXR_UUID_SIZE); +} + +FOculusXRUUID::FOculusXRUUID(const ovrpXRUuidArray& UuidArray) +{ + FMemory::Memcpy(UUIDBytes, UuidArray); +} + +bool FOculusXRUUID::operator==(const FOculusXRUUID& Right) const +{ + return IsEqual(Right); +} + +bool FOculusXRUUID::operator!=(const FOculusXRUUID& Right) const +{ + return !IsEqual(Right); +} + +bool FOculusXRUUID::IsValidUUID() const +{ + static uint8 InvalidUUID[OCULUSXR_UUID_SIZE] = { 0 }; + + return FMemory::Memcmp(UUIDBytes, InvalidUUID, OCULUSXR_UUID_SIZE) != 0; +} + +bool FOculusXRUUID::IsEqual(const FOculusXRUUID& Other) const +{ + return FMemory::Memcmp(UUIDBytes, Other.UUIDBytes, OCULUSXR_UUID_SIZE) == 0; +} + +uint32 GetTypeHash(const FOculusXRUUID& Other) +{ + return FCrc::MemCrc32(&Other.UUIDBytes, sizeof(Other.UUIDBytes)); +} + +bool FOculusXRUUID::NetSerialize(FArchive& Ar, class UPackageMap* Map, bool& bOutSuccess) +{ + uint8 data[16] = { 0 }; + + for (uint8 i = 0; i < OCULUSXR_UUID_SIZE; ++i) + { + data[i] = UUIDBytes[i]; + }; + + for (uint8 i = 0; i < OCULUSXR_UUID_SIZE; ++i) + { + Ar << data[i]; + }; + + for (uint8 i = 0; i < OCULUSXR_UUID_SIZE; ++i) + { + UUIDBytes[i] = data[i]; + }; + + bOutSuccess = true; + + return true; +} + +FArchive& operator<<(FArchive& Ar, FOculusXRUUID& UUID) +{ + bool bOutSuccess = false; + UUID.NetSerialize(Ar, nullptr, bOutSuccess); + + return Ar; +} + +bool FOculusXRUUID::Serialize(FArchive& Ar) +{ + Ar << *this; + return true; +} + +FString FOculusXRUUID::ToString() const +{ + return BytesToHex(UUIDBytes, OCULUSXR_UUID_SIZE); +} + diff --git a/Plugins/MetaXR/Source/OculusXRAnchors/Private/OculusXRAnchorTypesPrivate.cpp b/Plugins/MetaXR/Source/OculusXRAnchors/Private/OculusXRAnchorTypesPrivate.cpp new file mode 100644 index 0000000..4f0142b --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRAnchors/Private/OculusXRAnchorTypesPrivate.cpp @@ -0,0 +1,79 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#include "OculusXRAnchorTypesPrivate.h" + +ovrpSpaceComponentType ConvertToOvrpComponentType(const EOculusXRSpaceComponentType ComponentType) +{ + ovrpSpaceComponentType ovrpType = ovrpSpaceComponentType_Max; + switch (ComponentType) + { + case EOculusXRSpaceComponentType::Locatable: + ovrpType = ovrpSpaceComponentType_Locatable; + break; + case EOculusXRSpaceComponentType::Sharable: + ovrpType = ovrpSpaceComponentType_Sharable; + break; + case EOculusXRSpaceComponentType::Storable: + ovrpType = ovrpSpaceComponentType_Storable; + break; + case EOculusXRSpaceComponentType::ScenePlane: + ovrpType = ovrpSpaceComponentType_Bounded2D; + break; + case EOculusXRSpaceComponentType::SceneVolume: + ovrpType = ovrpSpaceComponentType_Bounded3D; + break; + case EOculusXRSpaceComponentType::SemanticClassification: + ovrpType = ovrpSpaceComponentType_SemanticLabels; + break; + case EOculusXRSpaceComponentType::RoomLayout: + ovrpType = ovrpSpaceComponentType_RoomLayout; + break; + case EOculusXRSpaceComponentType::SpaceContainer: + ovrpType = ovrpSpaceComponentType_SpaceContainer; + break; + case EOculusXRSpaceComponentType::TriangleMesh: + ovrpType = ovrpSpaceComponentType_TriangleMesh; + break; + default:; + } + + return ovrpType; +} + +EOculusXRSpaceComponentType ConvertToUEComponentType(const ovrpSpaceComponentType ComponentType) +{ + EOculusXRSpaceComponentType ueComponentType = EOculusXRSpaceComponentType::Undefined; + switch (ComponentType) + { + case ovrpSpaceComponentType_Locatable: + ueComponentType = EOculusXRSpaceComponentType::Locatable; + break; + case ovrpSpaceComponentType_Sharable: + ueComponentType = EOculusXRSpaceComponentType::Sharable; + break; + case ovrpSpaceComponentType_Storable: + ueComponentType = EOculusXRSpaceComponentType::Storable; + break; + case ovrpSpaceComponentType_Bounded2D: + ueComponentType = EOculusXRSpaceComponentType::ScenePlane; + break; + case ovrpSpaceComponentType_Bounded3D: + ueComponentType = EOculusXRSpaceComponentType::SceneVolume; + break; + case ovrpSpaceComponentType_SemanticLabels: + ueComponentType = EOculusXRSpaceComponentType::SemanticClassification; + break; + case ovrpSpaceComponentType_RoomLayout: + ueComponentType = EOculusXRSpaceComponentType::RoomLayout; + break; + case ovrpSpaceComponentType_SpaceContainer: + ueComponentType = EOculusXRSpaceComponentType::SpaceContainer; + break; + case ovrpSpaceComponentType_TriangleMesh: + ueComponentType = EOculusXRSpaceComponentType::TriangleMesh; + break; + default:; + } + + return ueComponentType; +} diff --git a/Plugins/MetaXR/Source/OculusXRAnchors/Private/OculusXRAnchorTypesPrivate.h b/Plugins/MetaXR/Source/OculusXRAnchors/Private/OculusXRAnchorTypesPrivate.h new file mode 100644 index 0000000..c350068 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRAnchors/Private/OculusXRAnchorTypesPrivate.h @@ -0,0 +1,8 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#pragma once +#include "OculusXRAnchorTypes.h" +#include "OVR_Plugin_Types.h" + +ovrpSpaceComponentType ConvertToOvrpComponentType(const EOculusXRSpaceComponentType ComponentType); +EOculusXRSpaceComponentType ConvertToUEComponentType(const ovrpSpaceComponentType ComponentType); diff --git a/Plugins/MetaXR/Source/OculusXRAnchors/Private/OculusXRAnchors.cpp b/Plugins/MetaXR/Source/OculusXRAnchors/Private/OculusXRAnchors.cpp new file mode 100644 index 0000000..ecb2e2d --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRAnchors/Private/OculusXRAnchors.cpp @@ -0,0 +1,732 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#include "OculusXRAnchors.h" +#include "CoreMinimal.h" +#include "Camera/PlayerCameraManager.h" +#include "GameFramework/PlayerController.h" +#include "OculusXRAnchorsModule.h" +#include "OculusXRAnchorDelegates.h" +#include "OculusXRHMDModule.h" +#include "OculusXRAnchorManager.h" +#include "OculusXRSpatialAnchorComponent.h" +#include "OculusXRAnchorBPFunctionLibrary.h" +#include "OculusXRTelemetryAnchorsEvents.h" + +namespace OculusXRAnchors +{ + + void FOculusXRAnchors::Initialize() + { + DelegateHandleAnchorCreate = FOculusXRAnchorEventDelegates::OculusSpatialAnchorCreateComplete.AddRaw(this, &FOculusXRAnchors::HandleSpatialAnchorCreateComplete); + DelegateHandleAnchorErase = FOculusXRAnchorEventDelegates::OculusSpaceEraseComplete.AddRaw(this, &FOculusXRAnchors::HandleAnchorEraseComplete); + DelegateHandleSetComponentStatus = FOculusXRAnchorEventDelegates::OculusSpaceSetComponentStatusComplete.AddRaw(this, &FOculusXRAnchors::HandleSetComponentStatusComplete); + DelegateHandleAnchorSave = FOculusXRAnchorEventDelegates::OculusSpaceSaveComplete.AddRaw(this, &FOculusXRAnchors::HandleAnchorSaveComplete); + DelegateHandleAnchorSaveList = FOculusXRAnchorEventDelegates::OculusSpaceListSaveComplete.AddRaw(this, &FOculusXRAnchors::HandleAnchorSaveListComplete); + DelegateHandleQueryResultsBegin = FOculusXRAnchorEventDelegates::OculusSpaceQueryResults.AddRaw(this, &FOculusXRAnchors::HandleAnchorQueryResultsBegin); + DelegateHandleQueryResultElement = FOculusXRAnchorEventDelegates::OculusSpaceQueryResult.AddRaw(this, &FOculusXRAnchors::HandleAnchorQueryResultElement); + DelegateHandleQueryComplete = FOculusXRAnchorEventDelegates::OculusSpaceQueryComplete.AddRaw(this, &FOculusXRAnchors::HandleAnchorQueryComplete); + DelegateHandleAnchorShare = FOculusXRAnchorEventDelegates::OculusSpaceShareComplete.AddRaw(this, &FOculusXRAnchors::HandleAnchorSharingComplete); + } + + void FOculusXRAnchors::Teardown() + { + FOculusXRAnchorEventDelegates::OculusSpatialAnchorCreateComplete.Remove(DelegateHandleAnchorCreate); + FOculusXRAnchorEventDelegates::OculusSpaceEraseComplete.Remove(DelegateHandleAnchorErase); + FOculusXRAnchorEventDelegates::OculusSpaceSetComponentStatusComplete.Remove(DelegateHandleSetComponentStatus); + FOculusXRAnchorEventDelegates::OculusSpaceSaveComplete.Remove(DelegateHandleAnchorSave); + FOculusXRAnchorEventDelegates::OculusSpaceListSaveComplete.Remove(DelegateHandleAnchorSaveList); + FOculusXRAnchorEventDelegates::OculusSpaceQueryResults.Remove(DelegateHandleQueryResultsBegin); + FOculusXRAnchorEventDelegates::OculusSpaceQueryResult.Remove(DelegateHandleQueryResultElement); + FOculusXRAnchorEventDelegates::OculusSpaceQueryComplete.Remove(DelegateHandleQueryComplete); + FOculusXRAnchorEventDelegates::OculusSpaceShareComplete.Remove(DelegateHandleAnchorShare); + } + + FOculusXRAnchors* FOculusXRAnchors::GetInstance() + { + return FOculusXRAnchorsModule::GetOculusAnchors(); + } + + bool FOculusXRAnchors::CreateSpatialAnchor(const FTransform& InTransform, AActor* TargetActor, const FOculusXRSpatialAnchorCreateDelegate& ResultCallback, EOculusXRAnchorResult::Type& OutResult) + { + if (!IsValid(TargetActor)) + { + UE_LOG(LogOculusXRAnchors, Warning, TEXT("Invalid actor provided when attempting to create a spatial anchor.")); + OutResult = EOculusXRAnchorResult::Failure; + ResultCallback.ExecuteIfBound(EOculusXRAnchorResult::Failure, nullptr); + return false; + } + + UWorld* World = TargetActor->GetWorld(); + if (!IsValid(World)) + { + UE_LOG(LogOculusXRAnchors, Warning, TEXT("Unable to retrieve World Context while creating spatial anchor.")); + OutResult = EOculusXRAnchorResult::Failure; + ResultCallback.ExecuteIfBound(EOculusXRAnchorResult::Failure, nullptr); + return false; + } + + APlayerController* PlayerController = World->GetFirstPlayerController(); + if (!IsValid(PlayerController)) + { + UE_LOG(LogOculusXRAnchors, Warning, TEXT("Unable to retrieve Player Controller while creating spatial anchor")); + OutResult = EOculusXRAnchorResult::Failure; + ResultCallback.ExecuteIfBound(EOculusXRAnchorResult::Failure, nullptr); + return false; + } + + APlayerCameraManager* PlayerCameraManager = PlayerController->PlayerCameraManager; + FTransform MainCameraTransform = FTransform::Identity; + if (IsValid(PlayerCameraManager)) + { + MainCameraTransform.SetLocation(PlayerCameraManager->GetCameraLocation()); + MainCameraTransform.SetRotation(FQuat(PlayerCameraManager->GetCameraRotation())); + } + + UOculusXRAnchorComponent* Anchor = Cast(TargetActor->GetComponentByClass(UOculusXRAnchorComponent::StaticClass())); + if (IsValid(Anchor) && Anchor->HasValidHandle()) + { + UE_LOG(LogOculusXRAnchors, Warning, TEXT("Actor targeted to create anchor already has an anchor component with a valid handle.")); + OutResult = EOculusXRAnchorResult::Failure; + ResultCallback.ExecuteIfBound(EOculusXRAnchorResult::Failure, nullptr); + return false; + } + + uint64 RequestId = 0; + OutResult = FOculusXRAnchorManager::CreateAnchor(InTransform, RequestId, MainCameraTransform); + bool bAsyncStartSuccess = UOculusXRAnchorBPFunctionLibrary::IsAnchorResultSuccess(OutResult); + + OculusXRTelemetry::Events::FAnchorsCreateRequest Trace(static_cast(GetTypeHash(RequestId))); + if (bAsyncStartSuccess) + { + CreateAnchorBinding AnchorData; + AnchorData.RequestId = RequestId; + AnchorData.Actor = TargetActor; + AnchorData.Binding = ResultCallback; + + FOculusXRAnchors* SDKInstance = GetInstance(); + SDKInstance->CreateSpatialAnchorBindings.Add(RequestId, AnchorData); + } + else + { + UE_LOG(LogOculusXRAnchors, Warning, TEXT("Failed to start async create spatial anchor.")); + ResultCallback.ExecuteIfBound(EOculusXRAnchorResult::Failure, nullptr); + Trace.SetResult(OculusXRTelemetry::EAction::Cancel).End(); + } + + return bAsyncStartSuccess; + } + + bool FOculusXRAnchors::EraseAnchor(UOculusXRAnchorComponent* Anchor, const FOculusXRAnchorEraseDelegate& ResultCallback, EOculusXRAnchorResult::Type& OutResult) + { + if (!IsValid(Anchor)) + { + UE_LOG(LogOculusXRAnchors, Warning, TEXT("Invalid anchor provided when attempting to erase an anchor.")); + OutResult = EOculusXRAnchorResult::Failure; + ResultCallback.ExecuteIfBound(EOculusXRAnchorResult::Failure, FOculusXRUUID()); + return false; + } + + if (!Anchor->HasValidHandle()) + { + UE_LOG(LogOculusXRAnchors, Warning, TEXT("Cannot erase anchor with invalid handle.")); + OutResult = EOculusXRAnchorResult::Failure; + ResultCallback.ExecuteIfBound(EOculusXRAnchorResult::Failure, FOculusXRUUID()); + return false; + } + + if (!Anchor->IsStoredAtLocation(EOculusXRSpaceStorageLocation::Local)) + { + UE_LOG(LogOculusXRAnchors, Warning, TEXT("Only local anchors can be erased.")); + OutResult = EOculusXRAnchorResult::Failure; + ResultCallback.ExecuteIfBound(EOculusXRAnchorResult::Failure, FOculusXRUUID()); + return false; + } + + uint64 RequestId = 0; + + // Erase only supports local anchors + EOculusXRAnchorResult::Type Result = FOculusXRAnchorManager::EraseAnchor(Anchor->GetHandle(), EOculusXRSpaceStorageLocation::Local, RequestId); + bool bAsyncStartSuccess = UOculusXRAnchorBPFunctionLibrary::IsAnchorResultSuccess(Result); + + OculusXRTelemetry::Events::FAnchorsEraseRequest Trace(static_cast(GetTypeHash(RequestId))); + if (bAsyncStartSuccess) + { + EraseAnchorBinding EraseData; + EraseData.RequestId = RequestId; + EraseData.Binding = ResultCallback; + EraseData.Anchor = Anchor; + + FOculusXRAnchors* SDKInstance = GetInstance(); + SDKInstance->EraseAnchorBindings.Add(RequestId, EraseData); + } + else + { + UE_LOG(LogOculusXRAnchors, Warning, TEXT("Failed to start async erase spatial anchor.")); + ResultCallback.ExecuteIfBound(EOculusXRAnchorResult::Failure, FOculusXRUUID()); + Trace.SetResult(OculusXRTelemetry::EAction::Cancel).End(); + } + + return bAsyncStartSuccess; + } + + bool FOculusXRAnchors::DestroyAnchor(uint64 AnchorHandle, EOculusXRAnchorResult::Type& OutResult) + { + OutResult = FOculusXRAnchorManager::DestroySpace(AnchorHandle); + + return UOculusXRAnchorBPFunctionLibrary::IsAnchorResultSuccess(OutResult); + } + + bool FOculusXRAnchors::SetAnchorComponentStatus(UOculusXRAnchorComponent* Anchor, EOculusXRSpaceComponentType SpaceComponentType, bool Enable, float Timeout, const FOculusXRAnchorSetComponentStatusDelegate& ResultCallback, EOculusXRAnchorResult::Type& OutResult) + { + if (!IsValid(Anchor)) + { + UE_LOG(LogOculusXRAnchors, Warning, TEXT("Invalid anchor provided when attempting to set anchor component status.")); + OutResult = EOculusXRAnchorResult::Failure; + ResultCallback.ExecuteIfBound(EOculusXRAnchorResult::Failure, FOculusXRUInt64(), EOculusXRSpaceComponentType::Undefined, false); + return false; + } + + if (!Anchor->HasValidHandle()) + { + UE_LOG(LogOculusXRAnchors, Warning, TEXT("Anchor provided to set anchor component status has invalid handle.")); + OutResult = EOculusXRAnchorResult::Failure; + ResultCallback.ExecuteIfBound(EOculusXRAnchorResult::Failure, FOculusXRUInt64(), EOculusXRSpaceComponentType::Undefined, false); + return false; + } + + uint64 RequestId = 0; + OutResult = FOculusXRAnchorManager::SetSpaceComponentStatus(Anchor->GetHandle(), SpaceComponentType, Enable, Timeout, RequestId); + bool bAsyncStartSuccess = UOculusXRAnchorBPFunctionLibrary::IsAnchorResultSuccess(OutResult); + + OculusXRTelemetry::Events::FAnchorsSetComponentStatusRequest Trace(static_cast(GetTypeHash(RequestId))); + if (bAsyncStartSuccess) + { + SetComponentStatusBinding SetComponentStatusData; + SetComponentStatusData.RequestId = RequestId; + SetComponentStatusData.Binding = ResultCallback; + SetComponentStatusData.AnchorHandle = Anchor->GetHandle(); + + FOculusXRAnchors* SDKInstance = GetInstance(); + SDKInstance->SetComponentStatusBindings.Add(RequestId, SetComponentStatusData); + } + else + { + UE_LOG(LogOculusXRAnchors, Warning, TEXT("Failed to start async call to set anchor component status.")); + ResultCallback.ExecuteIfBound(EOculusXRAnchorResult::Failure, FOculusXRUInt64(), EOculusXRSpaceComponentType::Undefined, false); + Trace.SetResult(OculusXRTelemetry::EAction::Cancel).End(); + } + + return true; + } + + bool FOculusXRAnchors::GetAnchorComponentStatus(UOculusXRAnchorComponent* Anchor, EOculusXRSpaceComponentType SpaceComponentType, bool& OutEnabled, bool& OutChangePending, EOculusXRAnchorResult::Type& OutResult) + { + if (!IsValid(Anchor)) + { + UE_LOG(LogOculusXRAnchors, Warning, TEXT("Invalid anchor provided when attempting to get space component status.")); + OutResult = EOculusXRAnchorResult::Failure; + return false; + } + + if (!Anchor->HasValidHandle()) + { + UE_LOG(LogOculusXRAnchors, Warning, TEXT("Anchor provided to get space component status has invalid handle.")); + OutResult = EOculusXRAnchorResult::Failure; + return false; + } + + return GetComponentStatus(Anchor->GetHandle(), SpaceComponentType, OutEnabled, OutChangePending, OutResult); + } + + bool FOculusXRAnchors::GetAnchorSupportedComponents(UOculusXRAnchorComponent* Anchor, TArray& OutSupportedComponents, EOculusXRAnchorResult::Type& OutResult) + { + if (!IsValid(Anchor)) + { + UE_LOG(LogOculusXRAnchors, Warning, TEXT("Invalid anchor provided when attempting to get space component status.")); + OutResult = EOculusXRAnchorResult::Failure; + return false; + } + + if (!Anchor->HasValidHandle()) + { + UE_LOG(LogOculusXRAnchors, Warning, TEXT("Anchor provided to get space component status has invalid handle.")); + OutResult = EOculusXRAnchorResult::Failure; + return false; + } + + return GetSupportedComponents(Anchor->GetHandle(), OutSupportedComponents, OutResult); + } + + bool FOculusXRAnchors::SetComponentStatus(uint64 Space, EOculusXRSpaceComponentType SpaceComponentType, bool Enable, float Timeout, const FOculusXRAnchorSetComponentStatusDelegate& ResultCallback, EOculusXRAnchorResult::Type& OutResult) + { + uint64 RequestId = 0; + OutResult = FOculusXRAnchorManager::SetSpaceComponentStatus(Space, SpaceComponentType, Enable, Timeout, RequestId); + bool bAsyncStartSuccess = UOculusXRAnchorBPFunctionLibrary::IsAnchorResultSuccess(OutResult); + + if (bAsyncStartSuccess) + { + SetComponentStatusBinding SetComponentStatusData; + SetComponentStatusData.RequestId = RequestId; + SetComponentStatusData.Binding = ResultCallback; + SetComponentStatusData.AnchorHandle = Space; + + FOculusXRAnchors* SDKInstance = GetInstance(); + SDKInstance->SetComponentStatusBindings.Add(RequestId, SetComponentStatusData); + } + else + { + UE_LOG(LogOculusXRAnchors, Warning, TEXT("Failed to start async call to set anchor component status.")); + ResultCallback.ExecuteIfBound(EOculusXRAnchorResult::Failure, Space, SpaceComponentType, Enable); + } + + return true; + } + + bool FOculusXRAnchors::GetComponentStatus(uint64 AnchorHandle, EOculusXRSpaceComponentType SpaceComponentType, bool& OutEnabled, bool& OutChangePending, EOculusXRAnchorResult::Type& OutResult) + { + OutResult = FOculusXRAnchorManager::GetSpaceComponentStatus(AnchorHandle, SpaceComponentType, OutEnabled, OutChangePending); + return UOculusXRAnchorBPFunctionLibrary::IsAnchorResultSuccess(OutResult); + } + + bool FOculusXRAnchors::GetSupportedComponents(uint64 AnchorHandle, TArray& OutSupportedComponents, EOculusXRAnchorResult::Type& OutResult) + { + OutResult = FOculusXRAnchorManager::GetSupportedAnchorComponents(AnchorHandle, OutSupportedComponents); + return UOculusXRAnchorBPFunctionLibrary::IsAnchorResultSuccess(OutResult); + } + + bool FOculusXRAnchors::SaveAnchor(UOculusXRAnchorComponent* Anchor, EOculusXRSpaceStorageLocation StorageLocation, const FOculusXRAnchorSaveDelegate& ResultCallback, EOculusXRAnchorResult::Type& OutResult) + { + if (!IsValid(Anchor)) + { + UE_LOG(LogOculusXRAnchors, Warning, TEXT("Invalid anchor provided when attempting to save anchor.")); + OutResult = EOculusXRAnchorResult::Failure; + ResultCallback.ExecuteIfBound(EOculusXRAnchorResult::Failure, nullptr); + return false; + } + + if (!Anchor->HasValidHandle()) + { + UE_LOG(LogOculusXRAnchors, Warning, TEXT("Anchor provided to save anchor has invalid handle.")); + OutResult = EOculusXRAnchorResult::Failure; + ResultCallback.ExecuteIfBound(EOculusXRAnchorResult::Failure, nullptr); + return false; + } + + uint64 RequestId = 0; + OutResult = FOculusXRAnchorManager::SaveAnchor(Anchor->GetHandle(), StorageLocation, EOculusXRSpaceStoragePersistenceMode::Indefinite, RequestId); + bool bAsyncStartSuccess = UOculusXRAnchorBPFunctionLibrary::IsAnchorResultSuccess(OutResult); + + OculusXRTelemetry::Events::FAnchorsSaveRequest Trace(static_cast(GetTypeHash(RequestId))); + if (bAsyncStartSuccess) + { + SaveAnchorBinding SaveAnchorData; + SaveAnchorData.RequestId = RequestId; + SaveAnchorData.Binding = ResultCallback; + SaveAnchorData.Location = StorageLocation; + SaveAnchorData.Anchor = Anchor; + + FOculusXRAnchors* SDKInstance = GetInstance(); + SDKInstance->AnchorSaveBindings.Add(RequestId, SaveAnchorData); + } + else + { + UE_LOG(LogOculusXRAnchors, Warning, TEXT("Failed to start async call to save anchor.")); + ResultCallback.ExecuteIfBound(EOculusXRAnchorResult::Failure, nullptr); + Trace.SetResult(OculusXRTelemetry::EAction::Cancel).End(); + } + + return bAsyncStartSuccess; + } + + void AnchorComponentsToReferences(const TArray& Anchors, TArray& Handles, TArray>& AnchorPtrs) + { + Handles.Empty(); + AnchorPtrs.Empty(); + + for (auto& AnchorInstance : Anchors) + { + if (!IsValid(AnchorInstance)) + { + UE_LOG(LogOculusXRAnchors, Warning, TEXT("Invalid anchor provided when attempting to process anchor list.")); + continue; + } + + if (!AnchorInstance->HasValidHandle()) + { + UE_LOG(LogOculusXRAnchors, Warning, TEXT("Anchor provided to anchor list has invalid handle.")); + continue; + } + + Handles.Add(AnchorInstance->GetHandle().GetValue()); + AnchorPtrs.Add(AnchorInstance); + } + } + + bool FOculusXRAnchors::SaveAnchorList(const TArray& Anchors, EOculusXRSpaceStorageLocation StorageLocation, const FOculusXRAnchorSaveListDelegate& ResultCallback, EOculusXRAnchorResult::Type& OutResult) + { + TArray Handles; + TArray> SavedAnchors; + + AnchorComponentsToReferences(Anchors, Handles, SavedAnchors); + + uint64 RequestId = 0; + OutResult = FOculusXRAnchorManager::SaveAnchorList(Handles, StorageLocation, RequestId); + bool bAsyncStartSuccess = UOculusXRAnchorBPFunctionLibrary::IsAnchorResultSuccess(OutResult); + + if (bAsyncStartSuccess) + { + SaveAnchorListBinding SaveAnchorListData; + SaveAnchorListData.RequestId = RequestId; + SaveAnchorListData.Binding = ResultCallback; + SaveAnchorListData.Location = StorageLocation; + SaveAnchorListData.SavedAnchors = SavedAnchors; + + FOculusXRAnchors* SDKInstance = GetInstance(); + SDKInstance->AnchorSaveListBindings.Add(RequestId, SaveAnchorListData); + } + else + { + UE_LOG(LogOculusXRAnchors, Warning, TEXT("Failed to start async call to save anchor list.")); + ResultCallback.ExecuteIfBound(OutResult, TArray()); + } + + return bAsyncStartSuccess; + } + + bool FOculusXRAnchors::QueryAnchors(const TArray& AnchorUUIDs, EOculusXRSpaceStorageLocation Location, const FOculusXRAnchorQueryDelegate& ResultCallback, EOculusXRAnchorResult::Type& OutResult) + { + FOculusXRSpaceQueryInfo QueryInfo; + QueryInfo.FilterType = EOculusXRSpaceQueryFilterType::FilterByIds; + QueryInfo.IDFilter = AnchorUUIDs; + QueryInfo.Location = Location; + QueryInfo.MaxQuerySpaces = AnchorUUIDs.Num(); + + return QueryAnchorsAdvanced(QueryInfo, ResultCallback, OutResult); + } + + bool FOculusXRAnchors::QueryAnchorsAdvanced(const FOculusXRSpaceQueryInfo& QueryInfo, const FOculusXRAnchorQueryDelegate& ResultCallback, EOculusXRAnchorResult::Type& OutResult) + { + uint64 RequestId = 0; + OutResult = FOculusXRAnchorManager::QuerySpaces(QueryInfo, RequestId); + bool bAsyncStartSuccess = UOculusXRAnchorBPFunctionLibrary::IsAnchorResultSuccess(OutResult); + + OculusXRTelemetry::Events::FAnchorsQueryRequest Trace(static_cast(GetTypeHash(RequestId))); + if (bAsyncStartSuccess) + { + AnchorQueryBinding QueryResults; + QueryResults.RequestId = RequestId; + QueryResults.Binding = ResultCallback; + QueryResults.Location = QueryInfo.Location; + + FOculusXRAnchors* SDKInstance = GetInstance(); + SDKInstance->AnchorQueryBindings.Add(RequestId, QueryResults); + } + else + { + UE_LOG(LogOculusXRAnchors, Warning, TEXT("Failed to start async call to query anchors.")); + ResultCallback.ExecuteIfBound(EOculusXRAnchorResult::Failure, TArray()); + Trace.SetResult(OculusXRTelemetry::EAction::Cancel).End(); + } + + return bAsyncStartSuccess; + } + + bool FOculusXRAnchors::ShareAnchors(const TArray& Anchors, const TArray& OculusUserIDs, const FOculusXRAnchorShareDelegate& ResultCallback, EOculusXRAnchorResult::Type& OutResult) + { + TArray Handles; + TArray> SharedAnchors; + + AnchorComponentsToReferences(Anchors, Handles, SharedAnchors); + + uint64 RequestId = 0; + OutResult = FOculusXRAnchorManager::ShareSpaces(Handles, OculusUserIDs, RequestId); + bool bAsyncStartSuccess = UOculusXRAnchorBPFunctionLibrary::IsAnchorResultSuccess(OutResult); + + if (bAsyncStartSuccess) + { + ShareAnchorsBinding ShareAnchorsData; + ShareAnchorsData.RequestId = RequestId; + ShareAnchorsData.Binding = ResultCallback; + ShareAnchorsData.SharedAnchors = SharedAnchors; + ShareAnchorsData.OculusUserIds = OculusUserIDs; + + FOculusXRAnchors* SDKInstance = GetInstance(); + SDKInstance->ShareAnchorsBindings.Add(RequestId, ShareAnchorsData); + } + else + { + UE_LOG(LogOculusXRAnchors, Warning, TEXT("Failed to start async call to share anchor.")); + ResultCallback.ExecuteIfBound(EOculusXRAnchorResult::Failure, TArray(), TArray()); + } + + return bAsyncStartSuccess; + } + + + bool FOculusXRAnchors::GetSpaceContainerUUIDs(uint64 Space, TArray& OutUUIDs, EOculusXRAnchorResult::Type& OutResult) + { + OutResult = FOculusXRAnchorManager::GetSpaceContainerUUIDs(Space, OutUUIDs); + return UOculusXRAnchorBPFunctionLibrary::IsAnchorResultSuccess(OutResult); + } + + bool FOculusXRAnchors::GetSpaceScenePlane(uint64 Space, FVector& OutPos, FVector& OutSize, EOculusXRAnchorResult::Type& OutResult) + { + OutResult = FOculusXRAnchorManager::GetSpaceScenePlane(Space, OutPos, OutSize); + return UOculusXRAnchorBPFunctionLibrary::IsAnchorResultSuccess(OutResult); + } + + bool FOculusXRAnchors::GetSpaceSceneVolume(uint64 Space, FVector& OutPos, FVector& OutSize, EOculusXRAnchorResult::Type& OutResult) + { + OutResult = FOculusXRAnchorManager::GetSpaceSceneVolume(Space, OutPos, OutSize); + return UOculusXRAnchorBPFunctionLibrary::IsAnchorResultSuccess(OutResult); + } + + bool FOculusXRAnchors::GetSpaceSemanticClassification(uint64 Space, TArray& OutSemanticClassifications, EOculusXRAnchorResult::Type& OutResult) + { + OutResult = FOculusXRAnchorManager::GetSpaceSemanticClassification(Space, OutSemanticClassifications); + return UOculusXRAnchorBPFunctionLibrary::IsAnchorResultSuccess(OutResult); + } + + bool FOculusXRAnchors::GetSpaceBoundary2D(uint64 Space, TArray& OutVertices, EOculusXRAnchorResult::Type& OutResult) + { + OutResult = FOculusXRAnchorManager::GetSpaceBoundary2D(Space, OutVertices); + return UOculusXRAnchorBPFunctionLibrary::IsAnchorResultSuccess(OutResult); + } + + + void FOculusXRAnchors::HandleSpatialAnchorCreateComplete(FOculusXRUInt64 RequestId, int Result, FOculusXRUInt64 Space, FOculusXRUUID UUID) + { + OculusXRTelemetry::Events::FAnchorsCreateResponse(static_cast(GetTypeHash(RequestId))) + .SetResult(OVRP_SUCCESS(Result) ? OculusXRTelemetry::EAction::Success : OculusXRTelemetry::EAction::Fail); + CreateAnchorBinding* AnchorDataPtr = CreateSpatialAnchorBindings.Find(RequestId.GetValue()); + if (AnchorDataPtr == nullptr) + { + UE_LOG(LogOculusXRAnchors, Error, TEXT("Couldn't find anchor data binding for create spatial anchor! Request: %llu"), RequestId.GetValue()); + return; + } + + if (OVRP_FAILURE(Result)) + { + UE_LOG(LogOculusXRAnchors, Warning, TEXT("Failed to create Spatial Anchor. Request: %llu -- Result: %d"), RequestId.GetValue(), Result); + AnchorDataPtr->Binding.ExecuteIfBound(static_cast(Result), nullptr); + CreateSpatialAnchorBindings.Remove(RequestId.GetValue()); + return; + } + + if (!AnchorDataPtr->Actor.IsValid()) + { + UE_LOG(LogOculusXRAnchors, Warning, TEXT("Actor has been invalidated while creating actor. Request: %llu"), RequestId.GetValue()); + + // Clean up the orphaned space + EOculusXRAnchorResult::Type AnchorResult; + FOculusXRAnchors::DestroyAnchor(Space, AnchorResult); + + AnchorDataPtr->Binding.ExecuteIfBound(static_cast(Result), nullptr); + CreateSpatialAnchorBindings.Remove(RequestId.GetValue()); + return; + } + + AActor* TargetActor = AnchorDataPtr->Actor.Get(); + + UOculusXRSpatialAnchorComponent* SpatialAnchorComponent = TargetActor->FindComponentByClass(); + if (SpatialAnchorComponent == nullptr) + { + SpatialAnchorComponent = Cast(TargetActor->AddComponentByClass(UOculusXRSpatialAnchorComponent::StaticClass(), false, FTransform::Identity, false)); + } + + SpatialAnchorComponent->SetHandle(Space); + SpatialAnchorComponent->SetUUID(UUID); + + uint64 tempOut; + FOculusXRAnchorManager::SetSpaceComponentStatus(Space, EOculusXRSpaceComponentType::Locatable, true, 0.0f, tempOut); + FOculusXRAnchorManager::SetSpaceComponentStatus(Space, EOculusXRSpaceComponentType::Sharable, true, 0.0f, tempOut); + FOculusXRAnchorManager::SetSpaceComponentStatus(Space, EOculusXRSpaceComponentType::Storable, true, 0.0f, tempOut); + + AnchorDataPtr->Binding.ExecuteIfBound(static_cast(Result), SpatialAnchorComponent); + CreateSpatialAnchorBindings.Remove(RequestId.GetValue()); + } + + void FOculusXRAnchors::HandleAnchorEraseComplete(FOculusXRUInt64 RequestId, int Result, FOculusXRUUID UUID, EOculusXRSpaceStorageLocation Location) + { + OculusXRTelemetry::Events::FAnchorsEraseResponse(static_cast(GetTypeHash(RequestId))) + .SetResult(OVRP_SUCCESS(Result) ? OculusXRTelemetry::EAction::Success : OculusXRTelemetry::EAction::Fail); + EraseAnchorBinding* EraseDataPtr = EraseAnchorBindings.Find(RequestId.GetValue()); + if (EraseDataPtr == nullptr) + { + UE_LOG(LogOculusXRAnchors, Error, TEXT("Couldn't find binding for space erase! Request: %llu"), RequestId.GetValue()); + return; + } + + if (OVRP_FAILURE(Result)) + { + UE_LOG(LogOculusXRAnchors, Warning, TEXT("Failed to erase Spatial Anchor. Request: %llu -- Result: %d"), RequestId.GetValue(), Result); + EraseDataPtr->Binding.ExecuteIfBound(static_cast(Result), UUID); + EraseAnchorBindings.Remove(RequestId.GetValue()); + return; + } + + if (EraseDataPtr->Anchor.IsValid()) + { + // Since you can only erase local anchors, just unset local anchor storage + EraseDataPtr->Anchor->SetStoredLocation(EOculusXRSpaceStorageLocation::Local, false); + } + + EraseDataPtr->Binding.ExecuteIfBound(static_cast(Result), UUID); + EraseAnchorBindings.Remove(RequestId.GetValue()); + } + + void FOculusXRAnchors::HandleSetComponentStatusComplete(FOculusXRUInt64 RequestId, int Result, FOculusXRUInt64 Space, FOculusXRUUID UUID, EOculusXRSpaceComponentType ComponentType, bool Enabled) + { + OculusXRTelemetry::Events::FAnchorsSetComponentStatusResponse(static_cast(GetTypeHash(RequestId))) + .SetResult(OVRP_SUCCESS(Result) ? OculusXRTelemetry::EAction::Success : OculusXRTelemetry::EAction::Fail); + SetComponentStatusBinding* SetStatusBinding = SetComponentStatusBindings.Find(RequestId.GetValue()); + + if (SetStatusBinding == nullptr) + { + UE_LOG(LogOculusXRAnchors, Verbose, TEXT("Couldn't find binding for set component status! Request: %llu"), RequestId.GetValue()); + return; + } + + if (SetStatusBinding != nullptr) + { + SetStatusBinding->Binding.ExecuteIfBound(static_cast(Result), SetStatusBinding->AnchorHandle, ComponentType, Enabled); + SetComponentStatusBindings.Remove(RequestId.GetValue()); + return; + } + + SetStatusBinding->Binding.ExecuteIfBound(static_cast(Result), SetStatusBinding->AnchorHandle, ComponentType, Enabled); + SetComponentStatusBindings.Remove(RequestId.GetValue()); + } + + void FOculusXRAnchors::HandleAnchorSaveComplete(FOculusXRUInt64 RequestId, FOculusXRUInt64 Space, bool Success, int Result, FOculusXRUUID UUID) + { + OculusXRTelemetry::Events::FAnchorsSaveResponse(static_cast(GetTypeHash(RequestId))) + .SetResult(OVRP_SUCCESS(Result) ? OculusXRTelemetry::EAction::Success : OculusXRTelemetry::EAction::Fail); + SaveAnchorBinding* SaveAnchorData = AnchorSaveBindings.Find(RequestId.GetValue()); + if (SaveAnchorData == nullptr) + { + UE_LOG(LogOculusXRAnchors, Error, TEXT("Couldn't find binding for save anchor! Request: %llu"), RequestId.GetValue()); + return; + } + + if (OVRP_FAILURE(Result)) + { + UE_LOG(LogOculusXRAnchors, Warning, TEXT("Failed to save Spatial Anchor. Request: %llu -- Result: %d -- Space: %llu"), RequestId.GetValue(), Result, Space.GetValue()); + SaveAnchorData->Binding.ExecuteIfBound(static_cast(Result), SaveAnchorData->Anchor.Get()); + AnchorSaveBindings.Remove(RequestId.GetValue()); + return; + } + + if (SaveAnchorData->Anchor.IsValid()) + { + SaveAnchorData->Anchor->SetStoredLocation(SaveAnchorData->Location, true); + } + + SaveAnchorData->Binding.ExecuteIfBound(static_cast(Result), SaveAnchorData->Anchor.Get()); + AnchorSaveBindings.Remove(RequestId.GetValue()); + } + + void FOculusXRAnchors::HandleAnchorSaveListComplete(FOculusXRUInt64 RequestId, int Result) + { + SaveAnchorListBinding* SaveListData = AnchorSaveListBindings.Find(RequestId.GetValue()); + if (SaveListData == nullptr) + { + UE_LOG(LogOculusXRAnchors, Error, TEXT("Couldn't find binding for save anchor list! Request: %llu"), RequestId.GetValue()); + return; + } + + // Get all anchors + TArray SavedAnchors; + for (auto& WeakAnchor : SaveListData->SavedAnchors) + { + if (WeakAnchor.IsValid()) + { + SavedAnchors.Add(WeakAnchor.Get()); + } + } + + // Failed to save + if (OVRP_FAILURE(Result)) + { + UE_LOG(LogOculusXRAnchors, Warning, TEXT("Failed to save Spatial Anchors. Request: %llu -- Result: %d"), RequestId.GetValue(), Result); + SaveListData->Binding.ExecuteIfBound(static_cast(Result), SavedAnchors); + AnchorSaveListBindings.Remove(RequestId.GetValue()); + return; + } + + // Set new storage location + for (auto& SavedAnchor : SavedAnchors) + { + SavedAnchor->SetStoredLocation(SaveListData->Location, true); + } + + SaveListData->Binding.ExecuteIfBound(static_cast(Result), SavedAnchors); + AnchorSaveListBindings.Remove(RequestId.GetValue()); + } + + void FOculusXRAnchors::HandleAnchorQueryResultsBegin(FOculusXRUInt64 RequestId) + { + // no op + } + + void FOculusXRAnchors::HandleAnchorQueryResultElement(FOculusXRUInt64 RequestId, FOculusXRUInt64 Space, FOculusXRUUID UUID) + { + AnchorQueryBinding* ResultPtr = AnchorQueryBindings.Find(RequestId.GetValue()); + if (ResultPtr) + { + uint64 tempOut; + TArray supportedTypes; + FOculusXRAnchorManager::GetSupportedAnchorComponents(Space, supportedTypes); + + if (supportedTypes.Contains(EOculusXRSpaceComponentType::Locatable)) + { + FOculusXRAnchorManager::SetSpaceComponentStatus(Space, EOculusXRSpaceComponentType::Locatable, true, 0.0f, tempOut); + } + + if (supportedTypes.Contains(EOculusXRSpaceComponentType::Sharable)) + { + FOculusXRAnchorManager::SetSpaceComponentStatus(Space, EOculusXRSpaceComponentType::Sharable, true, 0.0f, tempOut); + } + + if (supportedTypes.Contains(EOculusXRSpaceComponentType::Storable)) + { + FOculusXRAnchorManager::SetSpaceComponentStatus(Space, EOculusXRSpaceComponentType::Storable, true, 0.0f, tempOut); + } + + ResultPtr->Results.Add(FOculusXRSpaceQueryResult(Space, UUID, ResultPtr->Location)); + } + } + + void FOculusXRAnchors::HandleAnchorQueryComplete(FOculusXRUInt64 RequestId, int Result) + { + OculusXRTelemetry::Events::FAnchorsQueryResponse(static_cast(GetTypeHash(RequestId))) + .SetResult(OVRP_SUCCESS(Result) ? OculusXRTelemetry::EAction::Success : OculusXRTelemetry::EAction::Fail); + AnchorQueryBinding* ResultPtr = AnchorQueryBindings.Find(RequestId.GetValue()); + if (ResultPtr) + { + ResultPtr->Binding.ExecuteIfBound(static_cast(Result), ResultPtr->Results); + AnchorQueryBindings.Remove(RequestId.GetValue()); + } + } + + void FOculusXRAnchors::HandleAnchorSharingComplete(FOculusXRUInt64 RequestId, int Result) + { + ShareAnchorsBinding* ShareAnchorsData = ShareAnchorsBindings.Find(RequestId); + if (ShareAnchorsData == nullptr) + { + UE_LOG(LogOculusXRAnchors, Error, TEXT("Couldn't find binding for share anchors! Request: %llu"), RequestId.GetValue()); + return; + } + + TArray SharedAnchors; + for (auto& WeakAnchor : ShareAnchorsData->SharedAnchors) + { + SharedAnchors.Add(WeakAnchor.Get()); + } + + ShareAnchorsData->Binding.ExecuteIfBound(static_cast(Result), SharedAnchors, ShareAnchorsData->OculusUserIds); + ShareAnchorsBindings.Remove(RequestId.GetValue()); + } + + +} // namespace OculusXRAnchors diff --git a/Plugins/MetaXR/Source/OculusXRAnchors/Private/OculusXRAnchorsModule.cpp b/Plugins/MetaXR/Source/OculusXRAnchors/Private/OculusXRAnchorsModule.cpp new file mode 100644 index 0000000..3e1b59a --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRAnchors/Private/OculusXRAnchorsModule.cpp @@ -0,0 +1,55 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +#include "OculusXRAnchorsModule.h" + +#if OCULUS_ANCHORS_SUPPORTED_PLATFORMS +#include "OculusXRHMDModule.h" +#include "OculusXRHMD.h" +#include "OculusXRAnchors.h" +#include "OculusXRAnchorManager.h" +#include "OculusXRRoomLayoutManager.h" + +DEFINE_LOG_CATEGORY(LogOculusXRAnchors); + +#define LOCTEXT_NAMESPACE "OculusXRAnchors" + +//------------------------------------------------------------------------------------------------- +// FOculusXRAnchorsModule +//------------------------------------------------------------------------------------------------- +void FOculusXRAnchorsModule::StartupModule() +{ + if (!GEngine) + { + return; + } + + OculusXRHMD::FOculusXRHMD* HMD = OculusXRHMD::FOculusXRHMD::GetOculusXRHMD(); + if (!HMD) + { + UE_LOG(LogOculusXRAnchors, Warning, TEXT("Unable to retrieve OculusXRHMD, cannot add event polling delegates.")); + return; + } + + HMD->AddEventPollingDelegate(OculusXRHMD::FOculusXRHMDEventPollingDelegate::CreateStatic(&OculusXRAnchors::FOculusXRAnchorManager::OnPollEvent)); + HMD->AddEventPollingDelegate(OculusXRHMD::FOculusXRHMDEventPollingDelegate::CreateStatic(&OculusXRAnchors::FOculusXRRoomLayoutManager::OnPollEvent)); + + Anchors.Initialize(); +} + +void FOculusXRAnchorsModule::ShutdownModule() +{ + Anchors.Teardown(); +} + +OculusXRAnchors::FOculusXRAnchors* FOculusXRAnchorsModule::GetOculusAnchors() +{ + FOculusXRAnchorsModule& Module = FModuleManager::LoadModuleChecked(TEXT("OculusXRAnchors")); + return &Module.Anchors; +} + +#endif // OCULUS_ANCHORS_SUPPORTED_PLATFORMS + +IMPLEMENT_MODULE(FOculusXRAnchorsModule, OculusXRAnchors) + +#undef LOCTEXT_NAMESPACE diff --git a/Plugins/MetaXR/Source/OculusXRAnchors/Private/OculusXRAnchorsModule.h b/Plugins/MetaXR/Source/OculusXRAnchors/Private/OculusXRAnchorsModule.h new file mode 100644 index 0000000..bb5ea9d --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRAnchors/Private/OculusXRAnchorsModule.h @@ -0,0 +1,41 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +#pragma once +#include "IOculusXRAnchorsModule.h" +#include "OculusXRAnchors.h" + +#define LOCTEXT_NAMESPACE "OculusAnchors" + +//------------------------------------------------------------------------------------------------- +// FOculusXRAnchorsModule +//------------------------------------------------------------------------------------------------- + +#if OCULUS_ANCHORS_SUPPORTED_PLATFORMS + +DECLARE_LOG_CATEGORY_EXTERN(LogOculusXRAnchors, Log, All); + +class FOculusXRAnchorsModule : public IOculusXRAnchorsModule +{ +public: + virtual ~FOculusXRAnchorsModule() = default; + + // IModuleInterface interface + virtual void StartupModule() override; + virtual void ShutdownModule() override; + + static OculusXRAnchors::FOculusXRAnchors* GetOculusAnchors(); + +private: + OculusXRAnchors::FOculusXRAnchors Anchors; +}; + +#else // OCULUS_ANCHORS_SUPPORTED_PLATFORMS + +class FOculusXRAnchorsModule : public FDefaultModuleImpl +{ +}; + +#endif // OCULUS_ANCHORS_SUPPORTED_PLATFORMS + +#undef LOCTEXT_NAMESPACE diff --git a/Plugins/MetaXR/Source/OculusXRAnchors/Private/OculusXRAnchorsPrivate.h b/Plugins/MetaXR/Source/OculusXRAnchors/Private/OculusXRAnchorsPrivate.h new file mode 100644 index 0000000..0f410f5 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRAnchors/Private/OculusXRAnchorsPrivate.h @@ -0,0 +1,5 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#pragma once + +#include "OculusXRAnchorsModule.h" diff --git a/Plugins/MetaXR/Source/OculusXRAnchors/Private/OculusXRRoomLayoutManager.cpp b/Plugins/MetaXR/Source/OculusXRAnchors/Private/OculusXRRoomLayoutManager.cpp new file mode 100644 index 0000000..01f5987 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRAnchors/Private/OculusXRRoomLayoutManager.cpp @@ -0,0 +1,148 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#include "OculusXRRoomLayoutManager.h" +#include "OculusXRHMD.h" +#include "OculusXRAnchorDelegates.h" +#include "OculusXRAnchorsModule.h" + +namespace OculusXRAnchors +{ + void FOculusXRRoomLayoutManager::OnPollEvent(ovrpEventDataBuffer* EventDataBuffer, bool& EventPollResult) + { + ovrpEventDataBuffer& buf = *EventDataBuffer; + + switch (buf.EventType) + { + case ovrpEventType_None: + break; + case ovrpEventType_SceneCaptureComplete: + { + ovrpEventSceneCaptureComplete sceneCaptureComplete; + unsigned char* bufData = buf.EventData; + + memcpy(&sceneCaptureComplete.requestId, bufData, sizeof(sceneCaptureComplete.requestId)); + bufData += sizeof(ovrpUInt64); //move forward + memcpy(&sceneCaptureComplete.result, bufData, sizeof(sceneCaptureComplete.result)); + + FOculusXRAnchorEventDelegates::OculusSceneCaptureComplete.Broadcast(FOculusXRUInt64(sceneCaptureComplete.requestId), sceneCaptureComplete.result >= 0); + break; + } + + default: + { + EventPollResult = false; + break; + } + } + + EventPollResult = true; + } + + /** + * @brief Requests the launch of Capture Flow + * @param OutRequestID The requestId returned by the system + * @return returns true if sucessfull + */ + bool FOculusXRRoomLayoutManager::RequestSceneCapture(uint64& OutRequestID) + { + OutRequestID = 0; + + ovrpSceneCaptureRequest sceneCaptureRequest; + sceneCaptureRequest.request = nullptr; + sceneCaptureRequest.requestByteCount = 0; + + const ovrpResult Result = FOculusXRHMDModule::GetPluginWrapper().RequestSceneCapture(&sceneCaptureRequest, &OutRequestID); + if (OVRP_FAILURE(Result)) + { + return false; + } + + return true; + } + + /** + * @brief Gets the room layout for a specific space + * @param Space The space to get the room layout for + * @param MaxWallsCapacity Maximum number of walls to query + * @param OutCeilingUuid The ceiling entity's uuid + * @param OutFloorUuid The floor entity's uuid + * @param OutWallsUuid Array of uuids belonging to the walls in the room layout + * @return returns true if successful + */ + bool FOculusXRRoomLayoutManager::GetSpaceRoomLayout(const uint64 Space, const uint32 MaxWallsCapacity, + FOculusXRUUID& OutCeilingUuid, FOculusXRUUID& OutFloorUuid, TArray& OutWallsUuid) + { + ovrpRoomLayout roomLayout; + roomLayout.wallUuidCapacityInput = 0; + roomLayout.wallUuidCountOutput = 0; + + // First call to get output size + const ovrpResult firstCallResult = FOculusXRHMDModule::GetPluginWrapper().GetSpaceRoomLayout(&Space, &roomLayout); + if (OVRP_FAILURE(firstCallResult)) + { + return false; + } + + // Set the input size and pointer to the uuid array + TArray uuids; + uuids.InsertZeroed(0, roomLayout.wallUuidCountOutput); + + roomLayout.wallUuidCapacityInput = roomLayout.wallUuidCountOutput; + roomLayout.wallUuids = uuids.GetData(); + + const ovrpResult secondCallResult = FOculusXRHMDModule::GetPluginWrapper().GetSpaceRoomLayout(&Space, &roomLayout); + if (OVRP_FAILURE(secondCallResult)) + { + return false; + } + + OutCeilingUuid = FOculusXRUUID(roomLayout.ceilingUuid.data); + OutFloorUuid = FOculusXRUUID(roomLayout.floorUuid.data); + + OutWallsUuid.Empty(); + OutWallsUuid.InsertZeroed(0, uuids.Num()); + + for (int32 i = 0; i < uuids.Num(); ++i) + { + OutWallsUuid[i] = FOculusXRUUID(roomLayout.wallUuids[i].data); + } + + return true; + } + + bool FOculusXRRoomLayoutManager::GetSpaceTriangleMesh(uint64 Space, TArray& Vertices, TArray& Triangles) + { + ovrpTriangleMesh OVRPMesh = { 0, 0, nullptr, 0, 0, nullptr }; + + ovrpResult CountResult = FOculusXRHMDModule::GetPluginWrapper().GetSpaceTriangleMesh(&Space, &OVRPMesh); + if (OVRP_FAILURE(CountResult)) + { + UE_LOG(LogOculusXRAnchors, Warning, TEXT("Failed to load TriangleMesh info - Space: %llu - Result: %d"), Space, CountResult); + return false; + } + OVRPMesh.indexCapacityInput = OVRPMesh.indexCountOutput; + OVRPMesh.vertexCapacityInput = OVRPMesh.vertexCountOutput; + + TArray OVRPVertices; + OVRPVertices.SetNum(OVRPMesh.vertexCapacityInput); + OVRPMesh.vertices = OVRPVertices.GetData(); + Triangles.SetNum(OVRPMesh.indexCapacityInput); + check(sizeof(TRemoveReference::Type::ElementType) == sizeof(TRemovePointer::Type)); + OVRPMesh.indices = Triangles.GetData(); + + const ovrpResult MeshResult = FOculusXRHMDModule::GetPluginWrapper().GetSpaceTriangleMesh(&Space, &OVRPMesh); + if (OVRP_FAILURE(MeshResult)) + { + UE_LOG(LogOculusXRAnchors, Warning, TEXT("Failed to load TriangleMesh data - Space: %llu - Result: %d"), Space, MeshResult); + return false; + } + + UE_LOG(LogOculusXRAnchors, Verbose, TEXT("Loaded TriangleMesh data - Space: %llu - Vertices: %d - Faces: %d"), + Space, OVRPMesh.vertexCapacityInput, OVRPMesh.indexCapacityInput); + + Vertices.Empty(OVRPVertices.Num()); + Algo::Transform(OVRPVertices, Vertices, [](const auto& Vertex) { return OculusXRHMD::ToFVector(Vertex); }); + return true; + return false; + } +} // namespace OculusXRAnchors diff --git a/Plugins/MetaXR/Source/OculusXRAnchors/Private/OculusXRRoomLayoutManager.h b/Plugins/MetaXR/Source/OculusXRAnchors/Private/OculusXRRoomLayoutManager.h new file mode 100644 index 0000000..f764b4c --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRAnchors/Private/OculusXRRoomLayoutManager.h @@ -0,0 +1,21 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#pragma once + +#include "CoreMinimal.h" +#include "OculusXRAnchorComponent.h" +#include "OculusXRHMDPrivate.h" + +namespace OculusXRAnchors +{ + struct FOculusXRRoomLayoutManager + { + static bool RequestSceneCapture(uint64& OutRequestID); + static bool GetSpaceRoomLayout(const uint64 Space, const uint32 MaxWallsCapacity, + FOculusXRUUID& OutCeilingUuid, FOculusXRUUID& OutFloorUuid, TArray& OutWallsUuid); + + static bool GetSpaceTriangleMesh(uint64 Space, TArray& Vertices, TArray& Triangles); + + static void OnPollEvent(ovrpEventDataBuffer* EventDataBuffer, bool& EventPollResult); + }; +} // namespace OculusXRAnchors diff --git a/Plugins/MetaXR/Source/OculusXRAnchors/Private/OculusXRRoomLayoutManagerComponent.cpp b/Plugins/MetaXR/Source/OculusXRAnchors/Private/OculusXRRoomLayoutManagerComponent.cpp new file mode 100644 index 0000000..67505e8 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRAnchors/Private/OculusXRRoomLayoutManagerComponent.cpp @@ -0,0 +1,82 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#include "OculusXRRoomLayoutManagerComponent.h" +#include "OculusXRHMD.h" +#include "OculusXRRoomLayoutManager.h" +#include "OculusXRAnchorDelegates.h" +#include "OculusXRAnchorManager.h" +#include "OculusXRAnchorBPFunctionLibrary.h" +#include "ProceduralMeshComponent.h" +#include "OculusXRAnchorsModule.h" + +UOculusXRRoomLayoutManagerComponent::UOculusXRRoomLayoutManagerComponent(const FObjectInitializer& ObjectInitializer) +{ + bWantsInitializeComponent = true; // so that InitializeComponent() gets called +} + +void UOculusXRRoomLayoutManagerComponent::OnRegister() +{ + Super::OnRegister(); + + FOculusXRAnchorEventDelegates::OculusSceneCaptureComplete.AddUObject(this, &UOculusXRRoomLayoutManagerComponent::OculusRoomLayoutSceneCaptureComplete_Handler); +} + +void UOculusXRRoomLayoutManagerComponent::OnUnregister() +{ + Super::OnUnregister(); + + FOculusXRAnchorEventDelegates::OculusSceneCaptureComplete.RemoveAll(this); +} + +void UOculusXRRoomLayoutManagerComponent::InitializeComponent() +{ + Super::InitializeComponent(); +} + +void UOculusXRRoomLayoutManagerComponent::UninitializeComponent() +{ + Super::UninitializeComponent(); +} + +bool UOculusXRRoomLayoutManagerComponent::LaunchCaptureFlow() +{ + UE_LOG(LogOculusXRAnchors, Verbose, TEXT("Launch capture flow -- UOculusXRRoomLayoutManagerComponent")); + + uint64 OutRequest = 0; + const bool bSuccess = OculusXRAnchors::FOculusXRRoomLayoutManager::RequestSceneCapture(OutRequest); + if (bSuccess) + { + EntityRequestList.Add(OutRequest); + } + + UE_LOG(LogOculusXRAnchors, Verbose, TEXT("Launch capture flow -- RequestSceneCapture -- %d"), bSuccess); + + return bSuccess; +} + +bool UOculusXRRoomLayoutManagerComponent::GetRoomLayout(FOculusXRUInt64 Space, FOculusXRRoomLayout& RoomLayoutOut, int32 MaxWallsCapacity) +{ + return UOculusXRAnchorBPFunctionLibrary::GetRoomLayout(Space, RoomLayoutOut, MaxWallsCapacity); +} + +bool UOculusXRRoomLayoutManagerComponent::LoadTriangleMesh(FOculusXRUInt64 Space, UProceduralMeshComponent* Mesh, bool CreateCollision) const +{ + ensure(Mesh); + TArray Vertices; + TArray Triangles; + + bool Success = OculusXRAnchors::FOculusXRRoomLayoutManager::GetSpaceTriangleMesh(Space, Vertices, Triangles); + if (!Success) + { + return false; + } + + // Mesh->bUseAsyncCooking = true; + TArray EmptyNormals; + TArray EmptyUV; + TArray EmptyVertexColors; + TArray EmptyTangents; + Mesh->CreateMeshSection(0, Vertices, Triangles, EmptyNormals, EmptyUV, EmptyVertexColors, EmptyTangents, CreateCollision); + + return true; +} diff --git a/Plugins/MetaXR/Source/OculusXRAnchors/Private/OculusXRSpatialAnchorComponent.cpp b/Plugins/MetaXR/Source/OculusXRAnchors/Private/OculusXRSpatialAnchorComponent.cpp new file mode 100644 index 0000000..5982856 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRAnchors/Private/OculusXRSpatialAnchorComponent.cpp @@ -0,0 +1,28 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#include "OculusXRSpatialAnchorComponent.h" + +DEFINE_LOG_CATEGORY(LogOculusSpatialAnchor); + +UOculusXRSpatialAnchorComponent::UOculusXRSpatialAnchorComponent(const FObjectInitializer& ObjectInitializer) + : Super(ObjectInitializer) +{ +} + +bool UOculusXRSpatialAnchorComponent::Create(const FTransform& NewAnchorTransform, AActor* OwningActor, const FOculusXRSpatialAnchorCreateDelegate& Callback) +{ + EOculusXRAnchorResult::Type AnchorResult; + return OculusXRAnchors::FOculusXRAnchors::CreateSpatialAnchor(NewAnchorTransform, OwningActor, Callback, AnchorResult); +} + +bool UOculusXRSpatialAnchorComponent::Erase(const FOculusXRAnchorEraseDelegate& Callback) +{ + EOculusXRAnchorResult::Type AnchorResult; + return OculusXRAnchors::FOculusXRAnchors::EraseAnchor(this, Callback, AnchorResult); +} + +bool UOculusXRSpatialAnchorComponent::Save(EOculusXRSpaceStorageLocation Location, const FOculusXRAnchorSaveDelegate& Callback) +{ + EOculusXRAnchorResult::Type AnchorResult; + return OculusXRAnchors::FOculusXRAnchors::SaveAnchor(this, Location, Callback, AnchorResult); +} diff --git a/Plugins/MetaXR/Source/OculusXRAnchors/Private/OculusXRSpatialAnchorManager.cpp b/Plugins/MetaXR/Source/OculusXRAnchors/Private/OculusXRSpatialAnchorManager.cpp new file mode 100644 index 0000000..2fd78b7 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRAnchors/Private/OculusXRSpatialAnchorManager.cpp @@ -0,0 +1,13 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#include "OculusXRSpatialAnchorManager.h" +#include "OculusXRAnchorBPFunctionLibrary.h" + +namespace OculusXRAnchors +{ + bool FOculusXRSpatialAnchorManager::CreateSpatialAnchor(const FTransform& InTransform, uint64& OutRequestId) + { + EOculusXRAnchorResult::Type Result = CreateAnchor(InTransform, OutRequestId, FTransform::Identity); + return UOculusXRAnchorBPFunctionLibrary::IsAnchorResultSuccess(Result); + } +} // namespace OculusXRAnchors diff --git a/Plugins/MetaXR/Source/OculusXRAnchors/Private/OculusXRSpatialAnchorManager.h b/Plugins/MetaXR/Source/OculusXRAnchors/Private/OculusXRSpatialAnchorManager.h new file mode 100644 index 0000000..5f7e9dd --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRAnchors/Private/OculusXRSpatialAnchorManager.h @@ -0,0 +1,19 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#pragma once + +#include "CoreMinimal.h" +#include "OculusXRAnchorManager.h" + +namespace OculusXRAnchors +{ + struct FOculusXRSpatialAnchorManager : FOculusXRAnchorManager + { + FOculusXRSpatialAnchorManager() + : FOculusXRAnchorManager() + { + } + + static bool CreateSpatialAnchor(const FTransform& InTransform, uint64& OutRequestId); + }; +} // namespace OculusXRAnchors diff --git a/Plugins/MetaXR/Source/OculusXRAnchors/Private/OculusXRTelemetryAnchorsEvents.h b/Plugins/MetaXR/Source/OculusXRAnchors/Private/OculusXRTelemetryAnchorsEvents.h new file mode 100644 index 0000000..a7c8402 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRAnchors/Private/OculusXRTelemetryAnchorsEvents.h @@ -0,0 +1,24 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#pragma once + +#include "OculusXRTelemetry.h" + +namespace OculusXRTelemetry::Events +{ + using FAnchorsCreate = TMarker<191967648>; + using FAnchorsCreateRequest = TScopedMarker; + using FAnchorsCreateResponse = TScopedMarker; + using FAnchorsSetComponentStatus = TMarker<191962330>; + using FAnchorsSetComponentStatusRequest = TScopedMarker; + using FAnchorsSetComponentStatusResponse = TScopedMarker; + using FAnchorsSave = TMarker<191961984>; + using FAnchorsSaveRequest = TScopedMarker; + using FAnchorsSaveResponse = TScopedMarker; + using FAnchorsQuery = TMarker<191959258>; + using FAnchorsQueryRequest = TScopedMarker; + using FAnchorsQueryResponse = TScopedMarker; + using FAnchorsErase = TMarker<191960591>; + using FAnchorsEraseRequest = TScopedMarker; + using FAnchorsEraseResponse = TScopedMarker; +} // namespace OculusXRTelemetry::Events diff --git a/Plugins/MetaXR/Source/OculusXRAnchors/Public/IOculusXRAnchorsModule.h b/Plugins/MetaXR/Source/OculusXRAnchors/Public/IOculusXRAnchorsModule.h new file mode 100644 index 0000000..3a1129e --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRAnchors/Public/IOculusXRAnchorsModule.h @@ -0,0 +1,37 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +#pragma once +#include "Modules/ModuleManager.h" + +#define OCULUS_ANCHORS_SUPPORTED_PLATFORMS (PLATFORM_WINDOWS && WINVER > 0x0502) || (PLATFORM_ANDROID_ARM || PLATFORM_ANDROID_ARM64) + +/** + * The public interface to this module. In most cases, this interface is only public to sibling modules + * within this plugin. + */ +class IOculusXRAnchorsModule : public IModuleInterface +{ + +public: + /** + * Singleton-like access to this module's interface. This is just for convenience! + * Beware of calling this during the shutdown phase, though. Your module might have been unloaded already. + * + * @return Returns singleton instance, loading the module on demand if needed + */ + static inline IOculusXRAnchorsModule& Get() + { + return FModuleManager::LoadModuleChecked("OculusXRAnchors"); + } + + /** + * Checks to see if this module is loaded and ready. It is only valid to call Get() if IsAvailable() returns true. + * + * @return True if the module is loaded and ready to use + */ + static inline bool IsAvailable() + { + return FModuleManager::Get().IsModuleLoaded("OculusXRAnchors"); + } +}; diff --git a/Plugins/MetaXR/Source/OculusXRAnchors/Public/OculusXRAnchorBPFunctionLibrary.h b/Plugins/MetaXR/Source/OculusXRAnchors/Public/OculusXRAnchorBPFunctionLibrary.h new file mode 100644 index 0000000..838828b --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRAnchors/Public/OculusXRAnchorBPFunctionLibrary.h @@ -0,0 +1,56 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#pragma once + +#include "Kismet/BlueprintFunctionLibrary.h" +#include "Kismet/BlueprintAsyncActionBase.h" +#include "OculusXRAnchorTypes.h" +#include "OculusXRAnchorComponents.h" +#include "OculusXRAnchorBPFunctionLibrary.generated.h" + +//Helper +UCLASS() +class OCULUSXRANCHORS_API UOculusXRAnchorBPFunctionLibrary : public UBlueprintFunctionLibrary +{ + GENERATED_BODY() +public: + UFUNCTION(BlueprintCallable, meta = (DisplayName = "Spawn Oculus Anchor Actor", WorldContext = "WorldContextObject", UnsafeDuringActorConstruction = "true"), Category = "OculusXR|SpatialAnchor") + static AActor* SpawnActorWithAnchorHandle(UObject* WorldContextObject, FOculusXRUInt64 Handle, FOculusXRUUID UUID, EOculusXRSpaceStorageLocation AnchorLocation, UClass* ActorClass, AActor* Owner, APawn* Instigator, ESpawnActorCollisionHandlingMethod CollisionHandlingMethod); + + UFUNCTION(BlueprintCallable, meta = (DisplayName = "Spawn Oculus Anchor Actor From Query", WorldContext = "WorldContextObject", UnsafeDuringActorConstruction = "true"), Category = "OculusXR|SpatialAnchor") + static AActor* SpawnActorWithAnchorQueryResults(UObject* WorldContextObject, const FOculusXRSpaceQueryResult& QueryResult, UClass* ActorClass, AActor* Owner, APawn* Instigator, ESpawnActorCollisionHandlingMethod CollisionHandlingMethod); + + UFUNCTION(BlueprintCallable, Category = "OculusXR|SpatialAnchor") + static bool GetAnchorComponentStatus(AActor* TargetActor, EOculusXRSpaceComponentType ComponentType, bool& bIsEnabled); + + UFUNCTION(BlueprintCallable, Category = "OculusXR|SpatialAnchor") + static bool GetAnchorTransformByHandle(const FOculusXRUInt64& Handle, FTransform& OutTransform); + + UFUNCTION(BlueprintCallable, Category = "OculusXR|SpatialAnchor") + static bool TryGetAnchorTransformByHandle(const FOculusXRUInt64& Handle, FTransform& OutTransform, FOculusXRAnchorLocationFlags& OutLocationFlags); + + UFUNCTION(BlueprintPure, meta = (DisplayName = "FOculusXRUInt64 To String", CompactNodeTitle = "->", BlueprintAutocast), Category = "OculusXR|SpatialAnchor") + static FString AnchorHandleToString(const FOculusXRUInt64 Value); + + UFUNCTION(BlueprintPure, meta = (DisplayName = "FOculusXRUUID To String", CompactNodeTitle = "->", BlueprintAutocast), Category = "OculusXR|SpatialAnchor") + static FString AnchorUUIDToString(const FOculusXRUUID& Value); + + UFUNCTION(BlueprintCallable, Category = "OculusXR|SpatialAnchor") + static FOculusXRUUID StringToAnchorUUID(const FString& Value); + + UFUNCTION(BlueprintPure, meta = (DisplayName = "FOculusXRUInt64 equal", CompactNodeTitle = "==", Keywords = "equal", BlueprintAutocast), Category = "OculusXR|SpatialAnchor") + static bool IsEqual_FOculusXRUInt64(const FOculusXRUInt64 Left, const FOculusXRUInt64 Right) { return Left == Right; }; + + UFUNCTION(BlueprintPure, meta = (DisplayName = "FOculusXRUUID equal", CompactNodeTitle = "==", Keywords = "equal", BlueprintAutocast), Category = "OculusXR|SpatialAnchor") + static bool IsEqual_FOculusXRUUID(const FOculusXRUUID& Left, const FOculusXRUUID& Right) { return Left.IsEqual(Right); }; + + UFUNCTION(BlueprintCallable, Category = "OculusXR|SpatialAnchor") + static bool IsAnchorResultSuccess(EOculusXRAnchorResult::Type result); + + UFUNCTION(BlueprintCallable, Category = "OculusXR|SpatialAnchor") + static const UOculusXRBaseAnchorComponent* GetAnchorComponent(const FOculusXRSpaceQueryResult& QueryResult, EOculusXRSpaceComponentType ComponentType, UObject* Outer); + + UFUNCTION(BlueprintCallable, Category = "OculusXR|SpatialAnchor") + static bool GetRoomLayout(FOculusXRUInt64 Space, FOculusXRRoomLayout& RoomLayoutOut, int32 MaxWallsCapacity = 64); + +}; diff --git a/Plugins/MetaXR/Source/OculusXRAnchors/Public/OculusXRAnchorComponent.h b/Plugins/MetaXR/Source/OculusXRAnchors/Public/OculusXRAnchorComponent.h new file mode 100644 index 0000000..d71e502 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRAnchors/Public/OculusXRAnchorComponent.h @@ -0,0 +1,56 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#pragma once + +#include "OculusXRAnchorTypes.h" +#include "Components/ActorComponent.h" +#include "OculusXRAnchorComponent.generated.h" + +UCLASS(meta = (DisplayName = "Oculus Anchor Component")) +class OCULUSXRANCHORS_API UOculusXRAnchorComponent : public UActorComponent +{ + GENERATED_BODY() +public: + UOculusXRAnchorComponent(const FObjectInitializer& ObjectInitializer); + + virtual void BeginPlay() override; + virtual void TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override; + virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override; + + UFUNCTION(BlueprintPure, Category = "OculusXR|Anchor", meta = (DefaultToSelf = Target)) + FOculusXRUInt64 GetHandle() const; + + UFUNCTION(BlueprintCallable, Category = "OculusXR|Anchor", meta = (DefaultToSelf = Target)) + void SetHandle(FOculusXRUInt64 Handle); + + UFUNCTION(BlueprintPure, Category = "OculusXR|Anchor", meta = (DefaultToSelf = Target)) + bool HasValidHandle() const; + + UFUNCTION(BlueprintPure, Category = "OculusXR|Anchor", meta = (DefaultToSelf = Target)) + FOculusXRUUID GetUUID() const; + + void SetUUID(FOculusXRUUID NewUUID); + + UFUNCTION(BlueprintPure, Category = "OculusXR|Anchor", meta = (DefaultToSelf = Target)) + bool IsStoredAtLocation(EOculusXRSpaceStorageLocation Location) const; + + // Not exposed to BP because this is managed in code + void SetStoredLocation(EOculusXRSpaceStorageLocation Location, bool Stored); + + UFUNCTION(BlueprintPure, Category = "OculusXR|Anchor", meta = (DefaultToSelf = Target)) + bool IsSaved() const; + +protected: + bool bUpdateHeadSpaceTransform; + +private: + FOculusXRUInt64 AnchorHandle; + FOculusXRUUID AnchorUUID; + int32 StorageLocations; + + UPROPERTY() + class APlayerCameraManager* PlayerCameraManager; + + void UpdateAnchorTransform() const; + bool ToWorldSpacePose(FTransform CameraTransform, FTransform& OutTrackingSpaceTransform) const; +}; diff --git a/Plugins/MetaXR/Source/OculusXRAnchors/Public/OculusXRAnchorComponents.h b/Plugins/MetaXR/Source/OculusXRAnchors/Public/OculusXRAnchorComponents.h new file mode 100644 index 0000000..f2b1a65 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRAnchors/Public/OculusXRAnchorComponents.h @@ -0,0 +1,149 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#pragma once +#include "UObject/Class.h" +#include "OculusXRAnchorTypes.h" +#include "OculusXRAnchorComponents.generated.h" + +UCLASS(Blueprintable) +class OCULUSXRANCHORS_API UOculusXRBaseAnchorComponent : public UObject +{ + GENERATED_BODY() +public: + template + static T* FromSpace(uint64 space, UObject* Outer) + { + T* Component = NewObject(Outer); + Component->Space = space; + return Component; + } + + UFUNCTION(BlueprintCallable, Category = "OculusXR|SpatialAnchor") + bool IsComponentEnabled() const; + + UFUNCTION(BlueprintCallable, Category = "OculusXR|SpatialAnchor") + EOculusXRSpaceComponentType GetType() const; + + uint64 GetSpace() const; + +protected: + uint64 Space; + EOculusXRSpaceComponentType Type = EOculusXRSpaceComponentType::Undefined; +}; + +UCLASS(Blueprintable) +class OCULUSXRANCHORS_API UOculusXRLocatableAnchorComponent : public UOculusXRBaseAnchorComponent +{ + GENERATED_BODY() +public: + UOculusXRLocatableAnchorComponent() + { + Type = EOculusXRSpaceComponentType::Locatable; + } + + UFUNCTION(BlueprintCallable, Category = "OculusXR|SpatialAnchor") + bool GetTransform(FTransform& outTransform) const; +}; + +UCLASS(Blueprintable) +class OCULUSXRANCHORS_API UOculusXRPlaneAnchorComponent : public UOculusXRBaseAnchorComponent +{ + GENERATED_BODY() +public: + UOculusXRPlaneAnchorComponent() + { + Type = EOculusXRSpaceComponentType::ScenePlane; + } + + UFUNCTION(BlueprintCallable, Category = "OculusXR|SpatialAnchor") + bool GetPositionAndSize(FVector& outPosition, FVector& outSize) const; +}; + +UCLASS(Blueprintable) +class OCULUSXRANCHORS_API UOculusXRVolumeAnchorComponent : public UOculusXRBaseAnchorComponent +{ + GENERATED_BODY() +public: + UOculusXRVolumeAnchorComponent() + { + Type = EOculusXRSpaceComponentType::SceneVolume; + } + + UFUNCTION(BlueprintCallable, Category = "OculusXR|SpatialAnchor") + bool GetPositionAndSize(FVector& outPosition, FVector& outSize) const; +}; + +UCLASS(Blueprintable) +class OCULUSXRANCHORS_API UOculusXRSemanticClassificationAnchorComponent : public UOculusXRBaseAnchorComponent +{ + GENERATED_BODY() +public: + UOculusXRSemanticClassificationAnchorComponent() + { + Type = EOculusXRSpaceComponentType::SemanticClassification; + } + + UFUNCTION(BlueprintCallable, Category = "OculusXR|SpatialAnchor") + bool GetSemanticClassifications(TArray& outClassifications) const; +}; + +UCLASS(Blueprintable) +class OCULUSXRANCHORS_API UOculusXRRoomLayoutAnchorComponent : public UOculusXRBaseAnchorComponent +{ + GENERATED_BODY() +public: + UOculusXRRoomLayoutAnchorComponent() + { + Type = EOculusXRSpaceComponentType::RoomLayout; + } + + UFUNCTION(BlueprintCallable, Category = "OculusXR|SpatialAnchor") + bool GetRoomLayout(FOculusXRUUID& outFloorUUID, FOculusXRUUID& outCeilingUUID, TArray& outWallsUUIDs) const; +}; + +UCLASS(Blueprintable) +class OCULUSXRANCHORS_API UOculusXRSpaceContainerAnchorComponent : public UOculusXRBaseAnchorComponent +{ + GENERATED_BODY() +public: + UOculusXRSpaceContainerAnchorComponent() + { + Type = EOculusXRSpaceComponentType::SpaceContainer; + } + + UFUNCTION(BlueprintCallable, Category = "OculusXR|SpatialAnchor") + bool GetUUIDs(TArray& outUUIDs) const; +}; + +UCLASS(Blueprintable) +class OCULUSXRANCHORS_API UOculusXRSharableAnchorComponent : public UOculusXRBaseAnchorComponent +{ + GENERATED_BODY() +public: + UOculusXRSharableAnchorComponent() + { + Type = EOculusXRSpaceComponentType::Sharable; + } +}; + +UCLASS(Blueprintable) +class OCULUSXRANCHORS_API UOculusXRStorableAnchorComponent : public UOculusXRBaseAnchorComponent +{ + GENERATED_BODY() +public: + UOculusXRStorableAnchorComponent() + { + Type = EOculusXRSpaceComponentType::Storable; + } +}; + +UCLASS(Blueprintable) +class OCULUSXRANCHORS_API UOculusXRTriangleMeshAnchorComponent : public UOculusXRBaseAnchorComponent +{ + GENERATED_BODY() +public: + UOculusXRTriangleMeshAnchorComponent() + { + Type = EOculusXRSpaceComponentType::TriangleMesh; + } +}; diff --git a/Plugins/MetaXR/Source/OculusXRAnchors/Public/OculusXRAnchorDelegates.h b/Plugins/MetaXR/Source/OculusXRAnchors/Public/OculusXRAnchorDelegates.h new file mode 100644 index 0000000..b66795c --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRAnchors/Public/OculusXRAnchorDelegates.h @@ -0,0 +1,122 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#pragma once + +#include "CoreTypes.h" +#include "OculusXRAnchorTypes.h" +#include "Delegates/Delegate.h" + +class FOculusXRAnchorEventDelegates +{ +public: + /* ovrpEventType_SpatialAnchorCreateComplete + * + * SpatialAnchorCreateComplete + * Prefix: + * FOculusXRSpatialAnchorCreateComplete + * Suffix: + * FOculusXRSpatialAnchorCreateCompleteDelegate + */ + DECLARE_MULTICAST_DELEGATE_FourParams(FOculusXRSpatialAnchorCreateCompleteDelegate, FOculusXRUInt64 /*requestId*/, int /*result*/, FOculusXRUInt64 /*space*/, FOculusXRUUID /*uuid*/); + static OCULUSXRANCHORS_API FOculusXRSpatialAnchorCreateCompleteDelegate OculusSpatialAnchorCreateComplete; + + /* ovrpEventType_SpaceSetComponentStatusComplete + * + * SpaceSetComponentStatusComplete + * Prefix: + * FOculusXRSpaceSetComponentStatusComplete + * Suffix: + * FOculusXRSpaceSetComponentStatusCompleteDelegate + */ + DECLARE_MULTICAST_DELEGATE_SixParams(FOculusXRSpaceSetComponentStatusCompleteDelegate, FOculusXRUInt64 /*requestId*/, int /*result*/, FOculusXRUInt64 /*space*/, FOculusXRUUID /*uuid*/, EOculusXRSpaceComponentType /*componenttype */, bool /*enabled*/); + static OCULUSXRANCHORS_API FOculusXRSpaceSetComponentStatusCompleteDelegate OculusSpaceSetComponentStatusComplete; + + /* ovrpEventType_SpaceQueryResults + * + * SpaceQueryResults + * Prefix: + * FOculusXRSpaceQueryResults + * Suffix: + * FOculusXRSpaceQueryResultsDelegate + */ + DECLARE_MULTICAST_DELEGATE_OneParam(FOculusXRSpaceQueryResultsDelegate, FOculusXRUInt64 /*requestId*/); + static OCULUSXRANCHORS_API FOculusXRSpaceQueryResultsDelegate OculusSpaceQueryResults; + + /* SpaceQueryResult (no ovrp event type) + * + * SpaceQueryResult + * Prefix: + * FOculusXRSpaceQueryResult + * Suffix: + * FOculusXRSpaceQueryResultDelegate + */ + DECLARE_MULTICAST_DELEGATE_ThreeParams(FOculusXRSpaceQueryResultDelegate, FOculusXRUInt64 /*requestId*/, FOculusXRUInt64 /* space*/, FOculusXRUUID /*uuid*/); + static OCULUSXRANCHORS_API FOculusXRSpaceQueryResultDelegate OculusSpaceQueryResult; + + /* ovrpEventType_SpaceQueryComplete + * + * SpaceQueryComplete + * Prefix: + * FOculusXRSpaceQueryComplete + * Suffix: + * FOculusXRSpaceQueryCompleteDelegate + */ + DECLARE_MULTICAST_DELEGATE_TwoParams(FOculusXRSpaceQueryCompleteDelegate, FOculusXRUInt64 /*requestId*/, int /*result*/); + static OCULUSXRANCHORS_API FOculusXRSpaceQueryCompleteDelegate OculusSpaceQueryComplete; + + /* ovrpEventType_SpaceSaveComplete + * + * SpaceSaveComplete + * Prefix: + * FOculusXRSpaceSaveComplete + * Suffix: + * FOculusXRSpaceSaveCompleteDelegate + */ + DECLARE_MULTICAST_DELEGATE_FiveParams(FOculusXRSpaceSaveCompleteDelegate, FOculusXRUInt64 /*requestId*/, FOculusXRUInt64 /* space*/, bool /* sucess*/, int /*result*/, FOculusXRUUID /*uuid*/); + static OCULUSXRANCHORS_API FOculusXRSpaceSaveCompleteDelegate OculusSpaceSaveComplete; + + /* ovrpEventType_SpaceListSaveResult + * + * SpaceListSaveComplete + * Prefix: + * FOculusSpaceListSaveComplete + * Suffix: + * FOculusSpaceListSaveCompleteDelegate + */ + DECLARE_MULTICAST_DELEGATE_TwoParams(FOculusXRSpaceListSaveCompleteDelegate, FOculusXRUInt64 /*requestId*/, int /*result*/); + static OCULUSXRANCHORS_API FOculusXRSpaceListSaveCompleteDelegate OculusSpaceListSaveComplete; + + /* ovrpEventType_SpaceEraseComplete + * + * SpaceEraseComplete + * Prefix: + * FOculusXRSpaceEraseComplete + * Suffix: + * FOculusXRSpaceEraseCompleteDelegate + */ + DECLARE_MULTICAST_DELEGATE_FourParams(FOculusXRSpaceEraseCompleteDelegate, FOculusXRUInt64 /*requestId*/, int /* result*/, FOculusXRUUID /*uuid*/, EOculusXRSpaceStorageLocation /*location*/); + static OCULUSXRANCHORS_API FOculusXRSpaceEraseCompleteDelegate OculusSpaceEraseComplete; + + /* ovrpEventType_SpaceShareSpaceResult + * + * SpaceShareComplete + * Prefix: + * FOculusSpaceShareSpacesComplete + * Suffix: + * FOculusSpaceShareSpacesCompleteDelegate + */ + DECLARE_MULTICAST_DELEGATE_TwoParams(FOculusXRSpaceShareCompleteDelegate, FOculusXRUInt64 /*requestId*/, int /*result*/); + static OCULUSXRANCHORS_API FOculusXRSpaceShareCompleteDelegate OculusSpaceShareComplete; + + /* ovrpEventType_SceneCaptureComplete + * + * SceneCaptureComplete + * Prefix: + * FOculusXRSceneCaptureComplete + * Suffix: + * FOculusXRSceneCaptureCompleteDelegate + */ + DECLARE_MULTICAST_DELEGATE_TwoParams(FOculusXRSceneCaptureCompleteDelegate, FOculusXRUInt64 /*requestId*/, bool /*success*/); + static OCULUSXRANCHORS_API FOculusXRSceneCaptureCompleteDelegate OculusSceneCaptureComplete; + +}; diff --git a/Plugins/MetaXR/Source/OculusXRAnchors/Public/OculusXRAnchorLatentActions.h b/Plugins/MetaXR/Source/OculusXRAnchors/Public/OculusXRAnchorLatentActions.h new file mode 100644 index 0000000..224cc41 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRAnchors/Public/OculusXRAnchorLatentActions.h @@ -0,0 +1,298 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#pragma once + +#include "Kismet/BlueprintAsyncActionBase.h" +#include "Templates/SharedPointer.h" +#include "OculusXRAnchorTypes.h" +#include "OculusXRAnchorComponent.h" +#include "OculusXRAnchorComponents.h" +#include "OculusXRAnchorLatentActions.generated.h" + +DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOculusXR_LatentAction_CreateSpatialAnchor_Success, UOculusXRAnchorComponent*, Anchor, EOculusXRAnchorResult::Type, Result); +DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOculusXR_LatentAction_CreateSpatialAnchor_Failure, EOculusXRAnchorResult::Type, Result); + +DECLARE_DYNAMIC_MULTICAST_DELEGATE_ThreeParams(FOculusXR_LatentAction_EraseAnchor_Success, AActor*, Actor, FOculusXRUUID, UUID, EOculusXRAnchorResult::Type, Result); +DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOculusXR_LatentAction_EraseAnchor_Failure, EOculusXRAnchorResult::Type, Result); + +DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOculusXR_LatentAction_SaveAnchor_Success, UOculusXRAnchorComponent*, Anchor, EOculusXRAnchorResult::Type, Result); +DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOculusXR_LatentAction_SaveAnchor_Failure, EOculusXRAnchorResult::Type, Result); + +DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOculusXR_LatentAction_SaveAnchorList_Success, const TArray&, Anchors, EOculusXRAnchorResult::Type, Result); +DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOculusXR_LatentAction_SaveAnchorList_Failure, EOculusXRAnchorResult::Type, Result); + +DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOculusXR_LatentAction_QueryAnchors_Success, const TArray&, QueryResults, EOculusXRAnchorResult::Type, Result); +DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOculusXR_LatentAction_QueryAnchors_Failure, EOculusXRAnchorResult::Type, Result); + +DECLARE_DYNAMIC_MULTICAST_DELEGATE_FourParams(FOculusXR_LatentAction_SetComponentStatus_Success, UOculusXRAnchorComponent*, Anchor, EOculusXRSpaceComponentType, ComponentType, bool, Enabled, EOculusXRAnchorResult::Type, Result); +DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOculusXR_LatentAction_SetComponentStatus_Failure, EOculusXRAnchorResult::Type, Result); + +DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOculusXR_LatentAction_SetAnchorComponentStatus_Success, UOculusXRBaseAnchorComponent*, Component, EOculusXRAnchorResult::Type, Result); +DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOculusXR_LatentAction_SetAnchorComponentStatus_Failure, EOculusXRAnchorResult::Type, Result); + +DECLARE_DYNAMIC_MULTICAST_DELEGATE_ThreeParams(FOculusXR_LatentAction_ShareAnchors_Success, const TArray&, SharedAnchors, const TArray&, UserIds, EOculusXRAnchorResult::Type, Result); +DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOculusXR_LatentAction_ShareAnchors_Failure, EOculusXRAnchorResult::Type, Result); + + +// +// Create Anchor +// +UCLASS() +class OCULUSXRANCHORS_API UOculusXRAsyncAction_CreateSpatialAnchor : public UBlueprintAsyncActionBase +{ + GENERATED_BODY() +public: + virtual void Activate() override; + + UFUNCTION(BlueprintCallable, meta = (BlueprintInternalUseOnly = "true")) + static UOculusXRAsyncAction_CreateSpatialAnchor* OculusXRAsyncCreateSpatialAnchor(AActor* TargetActor, const FTransform& AnchorTransform); + + UPROPERTY(BlueprintAssignable) + FOculusXR_LatentAction_CreateSpatialAnchor_Success Success; + + UPROPERTY(BlueprintAssignable) + FOculusXR_LatentAction_CreateSpatialAnchor_Failure Failure; + + // Target actor + UPROPERTY(Transient) + AActor* TargetActor; + + FTransform AnchorTransform; + +private: + void HandleCreateComplete(EOculusXRAnchorResult::Type CreateResult, UOculusXRAnchorComponent* Anchor); +}; + +// +// Erase Anchor +// +UCLASS() +class OCULUSXRANCHORS_API UOculusXRAsyncAction_EraseAnchor : public UBlueprintAsyncActionBase +{ + GENERATED_BODY() +public: + virtual void Activate() override; + + UFUNCTION(BlueprintCallable, meta = (BlueprintInternalUseOnly = "true")) + static UOculusXRAsyncAction_EraseAnchor* OculusXRAsyncEraseAnchor(AActor* TargetActor); + + UPROPERTY(BlueprintAssignable) + FOculusXR_LatentAction_EraseAnchor_Success Success; + + UPROPERTY(BlueprintAssignable) + FOculusXR_LatentAction_EraseAnchor_Failure Failure; + + // Target actor + UPROPERTY(Transient) + AActor* TargetActor; + + FOculusXRUInt64 DeleteRequestId; + +private: + void HandleEraseAnchorComplete(EOculusXRAnchorResult::Type EraseResult, FOculusXRUUID UUID); +}; + +// +// Save Anchor +// +UCLASS() +class OCULUSXRANCHORS_API UOculusXRAsyncAction_SaveAnchor : public UBlueprintAsyncActionBase +{ + GENERATED_BODY() +public: + virtual void Activate() override; + + UFUNCTION(BlueprintCallable, meta = (BlueprintInternalUseOnly = "true")) + static UOculusXRAsyncAction_SaveAnchor* OculusXRAsyncSaveAnchor(AActor* TargetActor, EOculusXRSpaceStorageLocation StorageLocation); + + UPROPERTY(BlueprintAssignable) + FOculusXR_LatentAction_SaveAnchor_Success Success; + + UPROPERTY(BlueprintAssignable) + FOculusXR_LatentAction_SaveAnchor_Failure Failure; + + // Target actor + UPROPERTY(Transient) + AActor* TargetActor; + + EOculusXRSpaceStorageLocation StorageLocation; + +private: + void HandleSaveAnchorComplete(EOculusXRAnchorResult::Type SaveResult, UOculusXRAnchorComponent* Anchor); +}; + +// +// Save Anchor List +// +UCLASS() +class OCULUSXRANCHORS_API UOculusXRAsyncAction_SaveAnchorList : public UBlueprintAsyncActionBase +{ + GENERATED_BODY() +public: + virtual void Activate() override; + + UFUNCTION(BlueprintCallable, meta = (BlueprintInternalUseOnly = "true")) + static UOculusXRAsyncAction_SaveAnchorList* OculusXRAsyncSaveAnchorList(const TArray& TargetActors, EOculusXRSpaceStorageLocation StorageLocation); + + UPROPERTY(BlueprintAssignable) + FOculusXR_LatentAction_SaveAnchorList_Success Success; + + UPROPERTY(BlueprintAssignable) + FOculusXR_LatentAction_SaveAnchorList_Failure Failure; + + UPROPERTY(Transient) + TArray TargetAnchors; + + EOculusXRSpaceStorageLocation StorageLocation; + +private: + void HandleSaveAnchorListComplete(EOculusXRAnchorResult::Type SaveResult, const TArray& SavedSpaces); +}; + +// +// Query Anchors +// +UCLASS() +class OCULUSXRANCHORS_API UOculusXRAsyncAction_QueryAnchors : public UBlueprintAsyncActionBase +{ + GENERATED_BODY() +public: + virtual void Activate() override; + + UFUNCTION(BlueprintCallable, meta = (BlueprintInternalUseOnly = "true")) + static UOculusXRAsyncAction_QueryAnchors* OculusXRAsyncQueryAnchors(EOculusXRSpaceStorageLocation Location, const TArray& UUIDs); + + UFUNCTION(BlueprintCallable, meta = (BlueprintInternalUseOnly = "true")) + static UOculusXRAsyncAction_QueryAnchors* OculusXRAsyncQueryAnchorsAdvanced(const FOculusXRSpaceQueryInfo& QueryInfo); + + UPROPERTY(BlueprintAssignable) + FOculusXR_LatentAction_QueryAnchors_Success Success; + + UPROPERTY(BlueprintAssignable) + FOculusXR_LatentAction_QueryAnchors_Failure Failure; + + FOculusXRSpaceQueryInfo QueryInfo; + TArray QueryResults; + +private: + void HandleQueryAnchorsResults(EOculusXRAnchorResult::Type QueryResult, const TArray& Results); +}; + +// +// Set Component Status +// +UCLASS() +class OCULUSXRANCHORS_API UOculusXRAsyncAction_SetAnchorComponentStatus : public UBlueprintAsyncActionBase +{ + GENERATED_BODY() +public: + virtual void Activate() override; + + UFUNCTION(BlueprintCallable, meta = (BlueprintInternalUseOnly = "true")) + static UOculusXRAsyncAction_SetAnchorComponentStatus* OculusXRAsyncSetAnchorComponentStatus(AActor* TargetActor, EOculusXRSpaceComponentType ComponentType, bool bEnabled); + + UPROPERTY(BlueprintAssignable) + FOculusXR_LatentAction_SetComponentStatus_Success Success; + + UPROPERTY(BlueprintAssignable) + FOculusXR_LatentAction_SetComponentStatus_Failure Failure; + + // Target actor + UPROPERTY(Transient) + AActor* TargetActor; + + UPROPERTY(Transient) + UOculusXRAnchorComponent* TargetAnchorComponent; + + EOculusXRSpaceComponentType ComponentType; + bool bEnabled; + +private: + void HandleSetComponentStatusComplete(EOculusXRAnchorResult::Type SetStatusResult, uint64 AnchorHandle, EOculusXRSpaceComponentType SpaceComponentType, bool bResultEnabled); +}; + +// +// Set Anchor Component Status +// +UCLASS() +class OCULUSXRANCHORS_API UOculusXRAsyncAction_SetComponentStatus : public UBlueprintAsyncActionBase +{ + GENERATED_BODY() +public: + virtual void Activate() override; + + UFUNCTION(BlueprintCallable, meta = (BlueprintInternalUseOnly = "true")) + static UOculusXRAsyncAction_SetComponentStatus* OculusXRAsyncSetComponentStatus(UOculusXRBaseAnchorComponent* Component, bool bEnabled); + + UPROPERTY(BlueprintAssignable) + FOculusXR_LatentAction_SetAnchorComponentStatus_Success Success; + + UPROPERTY(BlueprintAssignable) + FOculusXR_LatentAction_SetAnchorComponentStatus_Failure Failure; + + // Target actor + UPROPERTY(Transient) + UOculusXRBaseAnchorComponent* Component; + bool bEnabled; + +private: + void HandleSetComponentStatusComplete(EOculusXRAnchorResult::Type SetStatusResult, uint64 AnchorHandle, EOculusXRSpaceComponentType SpaceComponentType, bool bResultEnabled); +}; + +// +// Share Anchors +// +UCLASS() +class OCULUSXRANCHORS_API UOculusXRAsyncAction_ShareAnchors : public UBlueprintAsyncActionBase +{ + GENERATED_BODY() +public: + virtual void Activate() override; + + UFUNCTION(BlueprintCallable, meta = (BlueprintInternalUseOnly = "true")) + static UOculusXRAsyncAction_ShareAnchors* OculusXRAsyncShareAnchors(const TArray& TargetActors, const TArray& ToShareWithIds); + + UPROPERTY(BlueprintAssignable) + FOculusXR_LatentAction_ShareAnchors_Success Success; + + UPROPERTY(BlueprintAssignable) + FOculusXR_LatentAction_ShareAnchors_Failure Failure; + + // Target Spaces + UPROPERTY(Transient) + TArray TargetAnchors; + + // Users to share with + TArray ToShareWithIds; + + FOculusXRUInt64 ShareSpacesRequestId; + +private: + void HandleShareAnchorsComplete(EOculusXRAnchorResult::Type ShareResult, const TArray& TargetAnchors, const TArray& OculusUserIds); +}; + + +UCLASS() +class OCULUSXRANCHORS_API UOculusXRAnchorLaunchCaptureFlow : public UBlueprintAsyncActionBase +{ + GENERATED_BODY() +public: + DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOculusXRAnchorCaptureFlowFinished); + + UFUNCTION(BlueprintCallable, Category = "OculusXR|SpatialAnchor", meta = (WorldContext = "WorldContext", BlueprintInternalUseOnly = "true")) + static UOculusXRAnchorLaunchCaptureFlow* LaunchCaptureFlowAsync(const UObject* WorldContext); + + void Activate() override; + + UPROPERTY(BlueprintAssignable) + FOculusXRAnchorCaptureFlowFinished Success; + + UPROPERTY(BlueprintAssignable) + FOculusXRAnchorCaptureFlowFinished Failure; + +private: + uint64 Request = 0; + + UFUNCTION(CallInEditor) + void OnCaptureFinish(FOculusXRUInt64 RequestId, bool bSuccess); +}; diff --git a/Plugins/MetaXR/Source/OculusXRAnchors/Public/OculusXRAnchorTypes.h b/Plugins/MetaXR/Source/OculusXRAnchors/Public/OculusXRAnchorTypes.h new file mode 100644 index 0000000..d19edc0 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRAnchors/Public/OculusXRAnchorTypes.h @@ -0,0 +1,293 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#pragma once +#include +#include "OculusXRAnchorTypes.generated.h" + +#define OCULUSXR_UUID_SIZE 16 + +typedef uint8 ovrpXRUuidArray[OCULUSXR_UUID_SIZE]; + +UENUM(BlueprintType) +namespace EOculusXRAnchorResult +{ + enum Type + { + Success = 0, + Success_EventUnavailable = 1, + Success_Pending = 2, + + /// Failure + Failure = -1000, + Failure_InvalidParameter = -1001, + Failure_NotInitialized = -1002, + Failure_InvalidOperation = -1003, + Failure_Unsupported = -1004, + Failure_NotYetImplemented = -1005, + Failure_OperationFailed = -1006, + Failure_InsufficientSize = -1007, + Failure_DataIsInvalid = -1008, + Failure_DeprecatedOperation = -1009, + Failure_ErrorLimitReached = -1010, + Failure_ErrorInitializationFailed = -1011, + + /// Space error cases + Failure_SpaceCloudStorageDisabled = -2000, + Failure_SpaceMappingInsufficient = -2001, + Failure_SpaceLocalizationFailed = -2002, + Failure_SpaceNetworkTimeout = -2003, + Failure_SpaceNetworkRequestFailed = -2004, + + + + }; +} // namespace EOculusXRAnchorResult + +UENUM(BlueprintType, meta = (Bitflags)) +enum class EOculusLocationFlags : uint8 +{ + None = 0, // required for the metadata generation + OrientationValid = (1 << 0), + PositionValid = (1 << 1), + OrientationTracked = (1 << 2), + PositionTracked = (1 << 3) +}; + +USTRUCT(BlueprintType) +struct OCULUSXRANCHORS_API FOculusXRAnchorLocationFlags +{ + GENERATED_BODY() +public: + FOculusXRAnchorLocationFlags(uint32 InFlags = 0) + : Flags(InFlags) {} + + bool OrientationValid() const + { + return Flags & static_cast(EOculusLocationFlags::OrientationValid); + } + + bool PositionValid() const + { + return Flags & static_cast(EOculusLocationFlags::PositionValid); + } + + bool OrientationTracked() const + { + return Flags & static_cast(EOculusLocationFlags::OrientationTracked); + } + + bool PositionTracked() const + { + return Flags & static_cast(EOculusLocationFlags::PositionTracked); + } + + bool IsValid() const + { + return OrientationValid() && PositionValid(); + } + +private: + UPROPERTY(BlueprintReadOnly, Category = "OculusXR|SpatialAnchor", meta = (AllowPrivateAccess = "true", Bitmask, BitmaskEnum = "EOculusLocationFlags")) + int32 Flags; +}; + +USTRUCT(BlueprintType) +struct OCULUSXRANCHORS_API FOculusXRUUID +{ + GENERATED_BODY() + + FOculusXRUUID(); + FOculusXRUUID(const ovrpXRUuidArray& UuidArray); + + bool operator==(const FOculusXRUUID& Other) const; + bool operator!=(const FOculusXRUUID& Other) const; + + bool IsValidUUID() const; + + bool IsEqual(const FOculusXRUUID& Other) const; + friend uint32 GetTypeHash(const FOculusXRUUID& Other); + bool NetSerialize(FArchive& Ar, class UPackageMap* Map, bool& bOutSuccess); + + OCULUSXRANCHORS_API friend FArchive& operator<<(FArchive& Ar, FOculusXRUUID& UUID); + bool Serialize(FArchive& Ar); + + FString ToString() const; + + uint8 UUIDBytes[OCULUSXR_UUID_SIZE]; +}; + +template <> +struct TStructOpsTypeTraits : public TStructOpsTypeTraitsBase2 +{ + enum + { + WithIdenticalViaEquality = true, + WithNetSerializer = true, + WithSerializer = true + }; +}; + +USTRUCT(BlueprintType) +struct OCULUSXRANCHORS_API FOculusXRUInt64 +{ + GENERATED_BODY() + + FOculusXRUInt64() + : FOculusXRUInt64(0) {} + FOculusXRUInt64(const uint64& Value) { this->Value = Value; } + + operator uint64() const { return Value; } + bool operator==(const FOculusXRUInt64& Right) const; + bool operator!=(const FOculusXRUInt64& Right) const; + + UPROPERTY() + uint64 Value; + + bool IsEqual(const FOculusXRUInt64& Other) const + { + return Other.Value == Value; + } + + friend uint32 GetTypeHash(const FOculusXRUInt64& Other) + { + return FCrc::MemCrc_DEPRECATED(&Other.Value, sizeof(Other.Value)); + } + + uint64 GetValue() const { return Value; }; + + void SetValue(const uint64 Val) { Value = Val; }; +}; + +template <> +struct TStructOpsTypeTraits : public TStructOpsTypeTraitsBase2 +{ + enum + { + WithIdenticalViaEquality = true, + }; +}; + +UENUM(BlueprintType) +enum class EOculusXRSpaceQueryFilterType : uint8 +{ + None = 0 UMETA(DisplayName = "No Filter"), + FilterByIds = 1 UMETA(DisplayName = "Filter queries by UUIDs"), + FilterByComponentType = 2 UMETA(DisplayName = "Filter queries by component type"), +}; + +// This is used as a bit-mask +UENUM(BlueprintType) +enum class EOculusXRSpaceStorageLocation : uint8 +{ + Invalid = 0 UMETA(DisplayName = "Invalid"), + Local = 1 << 0 UMETA(DisplayName = "Local"), + Cloud = 1 << 1 UMETA(DisplayName = "Cloud") +}; + +UENUM(BlueprintType) +enum class EOculusXRSpaceStoragePersistenceMode : uint8 +{ + Invalid = 0 UMETA(Hidden), + Indefinite = 1 UMETA(DisplayName = "Indefinite"), +}; + +UENUM(BlueprintType) +enum class EOculusXRSpaceComponentType : uint8 +{ + Locatable = 0 UMETA(DisplayName = "Locatable"), + Storable = 1 UMETA(DisplayName = "Storable"), + Sharable = 2 UMETA(DisplayName = "Sharable"), + ScenePlane = 3 UMETA(DisplayName = "ScenePlane"), + SceneVolume = 4 UMETA(DisplayName = "SceneVolume"), + SemanticClassification = 5 UMETA(DisplayName = "SemanticClassification"), + RoomLayout = 6 UMETA(DisplayName = "RoomLayout"), + SpaceContainer = 7 UMETA(DisplayName = "SpaceContainer"), + Undefined = 8 UMETA(DisplayName = "Not defined"), + TriangleMesh = 9 UMETA(DisplayName = "TriangleMesh"), + +}; + +USTRUCT(BlueprintType) +struct OCULUSXRANCHORS_API FOculusXRSpaceQueryInfo +{ + GENERATED_BODY() +public: + FOculusXRSpaceQueryInfo() + : MaxQuerySpaces(1024), Timeout(0), Location(EOculusXRSpaceStorageLocation::Local), FilterType(EOculusXRSpaceQueryFilterType::None) + { + } + + UPROPERTY(BlueprintReadWrite, Category = "OculusXR|SpatialAnchor") + int MaxQuerySpaces; + + UPROPERTY(BlueprintReadWrite, Category = "OculusXR|SpatialAnchor") + float Timeout; + + UPROPERTY(BlueprintReadWrite, Category = "OculusXR|SpatialAnchor") + EOculusXRSpaceStorageLocation Location; + + UPROPERTY(BlueprintReadWrite, Category = "OculusXR|SpatialAnchor") + EOculusXRSpaceQueryFilterType FilterType; + + UPROPERTY(BlueprintReadWrite, Category = "OculusXR|SpatialAnchor") + TArray IDFilter; + + UPROPERTY(BlueprintReadWrite, Category = "OculusXR|SpatialAnchor") + TArray ComponentFilter; +}; + +USTRUCT(BlueprintType) +struct OCULUSXRANCHORS_API FOculusXRSpaceQueryResult +{ + GENERATED_BODY() +public: + FOculusXRSpaceQueryResult() + : Space(0), UUID(), Location(EOculusXRSpaceStorageLocation::Invalid) {} + FOculusXRSpaceQueryResult(FOculusXRUInt64 SpaceHandle, FOculusXRUUID ID, EOculusXRSpaceStorageLocation SpaceLocation) + : Space(SpaceHandle), UUID(ID), Location(SpaceLocation) {} + + UPROPERTY(BlueprintReadWrite, Category = "OculusXR|SpatialAnchor") + FOculusXRUInt64 Space; + + UPROPERTY(BlueprintReadWrite, Category = "OculusXR|SpatialAnchor") + FOculusXRUUID UUID; + + UPROPERTY(BlueprintReadWrite, Category = "OculusXR|SpatialAnchor") + EOculusXRSpaceStorageLocation Location; +}; + +USTRUCT(BlueprintType) +struct OCULUSXRANCHORS_API FOculusXRSpaceQueryFilterValues +{ + GENERATED_BODY() +public: + TArray Uuids; // used if filtering by UUIDs + TArray ComponentTypes; // used if filtering by component types +}; + + +// Represents a room layout within a specific space +USTRUCT(BlueprintType) +struct OCULUSXRANCHORS_API FOculusXRRoomLayout +{ + GENERATED_BODY() +public: + UPROPERTY(BlueprintReadOnly, Category = "OculusXR|Anchors") + FOculusXRUInt64 RoomAnchorHandle; + + UPROPERTY(BlueprintReadOnly, Category = "OculusXR|Anchors") + FOculusXRUUID RoomUuid; + + + UPROPERTY(BlueprintReadOnly, Category = "OculusXR|Anchors") + FOculusXRUUID FloorUuid; + + UPROPERTY(BlueprintReadOnly, Category = "OculusXR|Anchors") + FOculusXRUUID CeilingUuid; + + UPROPERTY(BlueprintReadOnly, Category = "OculusXR|Anchors") + TArray WallsUuid; + + UPROPERTY(BlueprintReadOnly, Category = "OculusXR|Anchors") + TArray RoomObjectUUIDs; +}; diff --git a/Plugins/MetaXR/Source/OculusXRAnchors/Public/OculusXRAnchors.h b/Plugins/MetaXR/Source/OculusXRAnchors/Public/OculusXRAnchors.h new file mode 100644 index 0000000..345dbc9 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRAnchors/Public/OculusXRAnchors.h @@ -0,0 +1,146 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#pragma once + +#include "CoreMinimal.h" +#include "OculusXRAnchorComponent.h" +#include "OculusXRAnchorTypes.h" + +DECLARE_DELEGATE_TwoParams(FOculusXRSpatialAnchorCreateDelegate, EOculusXRAnchorResult::Type /*Result*/, UOculusXRAnchorComponent* /*Anchor*/); +DECLARE_DELEGATE_TwoParams(FOculusXRAnchorEraseDelegate, EOculusXRAnchorResult::Type /*Result*/, FOculusXRUUID /*AnchorUUID*/); +DECLARE_DELEGATE_FourParams(FOculusXRAnchorSetComponentStatusDelegate, EOculusXRAnchorResult::Type /*Result*/, uint64 /*AnchorHandle*/, EOculusXRSpaceComponentType /*ComponentType*/, bool /*Enabled*/); +DECLARE_DELEGATE_TwoParams(FOculusXRAnchorSaveDelegate, EOculusXRAnchorResult::Type /*Result*/, UOculusXRAnchorComponent* /*Anchor*/); +DECLARE_DELEGATE_TwoParams(FOculusXRAnchorSaveListDelegate, EOculusXRAnchorResult::Type /*Result*/, const TArray& /*SavedAnchors*/); +DECLARE_DELEGATE_TwoParams(FOculusXRAnchorQueryDelegate, EOculusXRAnchorResult::Type /*Result*/, const TArray& /*Results*/); +DECLARE_DELEGATE_ThreeParams(FOculusXRAnchorShareDelegate, EOculusXRAnchorResult::Type /*Result*/, const TArray& /*Anchors*/, const TArray& /*Users*/); + +namespace OculusXRAnchors +{ + + struct OCULUSXRANCHORS_API FOculusXRAnchors + { + void Initialize(); + void Teardown(); + + static FOculusXRAnchors* GetInstance(); + + static bool CreateSpatialAnchor(const FTransform& InTransform, AActor* TargetActor, const FOculusXRSpatialAnchorCreateDelegate& ResultCallback, EOculusXRAnchorResult::Type& OutResult); + static bool EraseAnchor(UOculusXRAnchorComponent* Anchor, const FOculusXRAnchorEraseDelegate& ResultCallback, EOculusXRAnchorResult::Type& OutResult); + static bool DestroyAnchor(uint64 AnchorHandle, EOculusXRAnchorResult::Type& OutResult); + + static bool SetAnchorComponentStatus(UOculusXRAnchorComponent* Anchor, EOculusXRSpaceComponentType SpaceComponentType, bool Enable, float Timeout, const FOculusXRAnchorSetComponentStatusDelegate& ResultCallback, EOculusXRAnchorResult::Type& OutResult); + static bool GetAnchorComponentStatus(UOculusXRAnchorComponent* Anchor, EOculusXRSpaceComponentType SpaceComponentType, bool& OutEnabled, bool& OutChangePending, EOculusXRAnchorResult::Type& OutResult); + static bool GetAnchorSupportedComponents(UOculusXRAnchorComponent* Anchor, TArray& OutSupportedComponents, EOculusXRAnchorResult::Type& OutResult); + + static bool SetComponentStatus(uint64 Space, EOculusXRSpaceComponentType SpaceComponentType, bool Enable, float Timeout, const FOculusXRAnchorSetComponentStatusDelegate& ResultCallback, EOculusXRAnchorResult::Type& OutResult); + static bool GetComponentStatus(uint64 AnchorHandle, EOculusXRSpaceComponentType SpaceComponentType, bool& OutEnabled, bool& OutChangePending, EOculusXRAnchorResult::Type& OutResult); + static bool GetSupportedComponents(uint64 AnchorHandle, TArray& OutSupportedComponents, EOculusXRAnchorResult::Type& OutResult); + + static bool SaveAnchor(UOculusXRAnchorComponent* Anchor, EOculusXRSpaceStorageLocation StorageLocation, const FOculusXRAnchorSaveDelegate& ResultCallback, EOculusXRAnchorResult::Type& OutResult); + static bool SaveAnchorList(const TArray& Anchors, EOculusXRSpaceStorageLocation StorageLocation, const FOculusXRAnchorSaveListDelegate& ResultCallback, EOculusXRAnchorResult::Type& OutResult); + + static bool QueryAnchors(const TArray& AnchorUUIDs, EOculusXRSpaceStorageLocation Location, const FOculusXRAnchorQueryDelegate& ResultCallback, EOculusXRAnchorResult::Type& OutResult); + static bool QueryAnchorsAdvanced(const FOculusXRSpaceQueryInfo& QueryInfo, const FOculusXRAnchorQueryDelegate& ResultCallback, EOculusXRAnchorResult::Type& OutResult); + + static bool ShareAnchors(const TArray& Anchors, const TArray& OculusUserIDs, const FOculusXRAnchorShareDelegate& ResultCallback, EOculusXRAnchorResult::Type& OutResult); + + static bool GetSpaceContainerUUIDs(uint64 Space, TArray& OutUUIDs, EOculusXRAnchorResult::Type& OutResult); + static bool GetSpaceScenePlane(uint64 Space, FVector& OutPos, FVector& OutSize, EOculusXRAnchorResult::Type& OutResult); + static bool GetSpaceSceneVolume(uint64 Space, FVector& OutPos, FVector& OutSize, EOculusXRAnchorResult::Type& OutResult); + static bool GetSpaceSemanticClassification(uint64 Space, TArray& OutSemanticClassifications, EOculusXRAnchorResult::Type& OutResult); + static bool GetSpaceBoundary2D(uint64 Space, TArray& OutVertices, EOculusXRAnchorResult::Type& OutResult); + + + + private: + void HandleSpatialAnchorCreateComplete(FOculusXRUInt64 RequestId, int Result, FOculusXRUInt64 Space, FOculusXRUUID UUID); + void HandleAnchorEraseComplete(FOculusXRUInt64 RequestId, int Result, FOculusXRUUID UUID, EOculusXRSpaceStorageLocation Location); + + void HandleSetComponentStatusComplete(FOculusXRUInt64 RequestId, int Result, FOculusXRUInt64 Space, FOculusXRUUID UUID, EOculusXRSpaceComponentType ComponentType, bool Enabled); + + void HandleAnchorSaveComplete(FOculusXRUInt64 RequestId, FOculusXRUInt64 Space, bool Success, int Result, FOculusXRUUID UUID); + void HandleAnchorSaveListComplete(FOculusXRUInt64 RequestId, int Result); + + void HandleAnchorQueryResultsBegin(FOculusXRUInt64 RequestId); + void HandleAnchorQueryResultElement(FOculusXRUInt64 RequestId, FOculusXRUInt64 Space, FOculusXRUUID UUID); + void HandleAnchorQueryComplete(FOculusXRUInt64 RequestId, int Result); + + void HandleAnchorSharingComplete(FOculusXRUInt64 RequestId, int Result); + + + struct EraseAnchorBinding + { + FOculusXRUInt64 RequestId; + FOculusXRAnchorEraseDelegate Binding; + TWeakObjectPtr Anchor; + }; + + struct SetComponentStatusBinding + { + FOculusXRUInt64 RequestId; + FOculusXRAnchorSetComponentStatusDelegate Binding; + uint64 AnchorHandle; + }; + + struct CreateAnchorBinding + { + FOculusXRUInt64 RequestId; + FOculusXRSpatialAnchorCreateDelegate Binding; + TWeakObjectPtr Actor; + }; + + struct SaveAnchorBinding + { + FOculusXRUInt64 RequestId; + FOculusXRAnchorSaveDelegate Binding; + EOculusXRSpaceStorageLocation Location; + TWeakObjectPtr Anchor; + }; + + struct SaveAnchorListBinding + { + FOculusXRUInt64 RequestId; + FOculusXRAnchorSaveListDelegate Binding; + EOculusXRSpaceStorageLocation Location; + TArray> SavedAnchors; + }; + + struct AnchorQueryBinding + { + FOculusXRUInt64 RequestId; + FOculusXRAnchorQueryDelegate Binding; + EOculusXRSpaceStorageLocation Location; + TArray Results; + }; + + struct ShareAnchorsBinding + { + FOculusXRUInt64 RequestId; + FOculusXRAnchorShareDelegate Binding; + TArray> SharedAnchors; + TArray OculusUserIds; + }; + + + // Delegate bindings + TMap CreateSpatialAnchorBindings; + TMap EraseAnchorBindings; + TMap SetComponentStatusBindings; + TMap AnchorSaveBindings; + TMap AnchorSaveListBindings; + TMap AnchorQueryBindings; + TMap ShareAnchorsBindings; + + // Delegate handles + FDelegateHandle DelegateHandleAnchorCreate; + FDelegateHandle DelegateHandleAnchorErase; + FDelegateHandle DelegateHandleSetComponentStatus; + FDelegateHandle DelegateHandleAnchorSave; + FDelegateHandle DelegateHandleAnchorSaveList; + FDelegateHandle DelegateHandleQueryResultsBegin; + FDelegateHandle DelegateHandleQueryResultElement; + FDelegateHandle DelegateHandleQueryComplete; + FDelegateHandle DelegateHandleAnchorShare; + }; + +} // namespace OculusXRAnchors diff --git a/Plugins/MetaXR/Source/OculusXRAnchors/Public/OculusXRRoomLayoutManagerComponent.h b/Plugins/MetaXR/Source/OculusXRAnchors/Public/OculusXRRoomLayoutManagerComponent.h new file mode 100644 index 0000000..28827d2 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRAnchors/Public/OculusXRRoomLayoutManagerComponent.h @@ -0,0 +1,64 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#pragma once + +#include "CoreMinimal.h" +#include "OculusXRSpatialAnchorComponent.h" +#include "OculusXRAnchorBPFunctionLibrary.h" +#include "OculusXRRoomLayoutManagerComponent.generated.h" + +UCLASS(meta = (DisplayName = "OculusXR Room Layout Manager Component", BlueprintSpawnableComponent)) +class OCULUSXRANCHORS_API UOculusXRRoomLayoutManagerComponent : public UActorComponent +{ + GENERATED_BODY() + +public: + UOculusXRRoomLayoutManagerComponent(const FObjectInitializer& ObjectInitializer); + + virtual void InitializeComponent() override; + virtual void UninitializeComponent() override; + + virtual void OnRegister() override; + virtual void OnUnregister() override; + + DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOculusXRRoomLayoutSceneCaptureCompleteDelegate, + FOculusXRUInt64, requestId, + bool, result); + + DECLARE_MULTICAST_DELEGATE_TwoParams(FOculusXRRoomLayoutSceneCompleteNativeDelegate, FOculusXRUInt64 /*requestId*/, bool /*success*/); + FOculusXRRoomLayoutSceneCompleteNativeDelegate OculusXRRoomLayoutSceneCaptureCompleteNative; + + UPROPERTY(BlueprintAssignable, Category = "OculusXR|Room Layout Manager") + FOculusXRRoomLayoutSceneCaptureCompleteDelegate OculusXRRoomLayoutSceneCaptureComplete; + + // Requests to launch Capture Flow + UFUNCTION(BlueprintCallable, Category = "OculusXR|Room Layout Manager") + bool LaunchCaptureFlow(); + + // Gets room layout for a specific space + UFUNCTION(BlueprintCallable, Category = "OculusXR|Room Layout Manager") + bool GetRoomLayout(FOculusXRUInt64 Space, UPARAM(ref) FOculusXRRoomLayout& RoomLayoutOut, int32 MaxWallsCapacity = 64); + + // Loads mesh data (vertices, indeces) associated with the space into UProceduralMeshComponent + UFUNCTION(BlueprintCallable, Category = "OculusXR|Room Layout Manager") + bool LoadTriangleMesh(FOculusXRUInt64 Space, class UProceduralMeshComponent* Mesh, bool CreateCollision) const; + +protected: + UPROPERTY(Transient) + TSet EntityRequestList; + + UPROPERTY(Transient) + TMap RoomLayouts; + +private: + UFUNCTION() + void OculusRoomLayoutSceneCaptureComplete_Handler(FOculusXRUInt64 RequestId, bool bSuccess) + { + if (EntityRequestList.Find(RequestId.Value) != nullptr) + { + OculusXRRoomLayoutSceneCaptureComplete.Broadcast(RequestId, bSuccess); + OculusXRRoomLayoutSceneCaptureCompleteNative.Broadcast(RequestId, bSuccess); + EntityRequestList.Remove(RequestId.Value); + } + } +}; diff --git a/Plugins/MetaXR/Source/OculusXRAnchors/Public/OculusXRSpatialAnchorComponent.h b/Plugins/MetaXR/Source/OculusXRAnchors/Public/OculusXRSpatialAnchorComponent.h new file mode 100644 index 0000000..15a63fb --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRAnchors/Public/OculusXRSpatialAnchorComponent.h @@ -0,0 +1,25 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#pragma once + +#include "CoreMinimal.h" +#include "OculusXRAnchorComponent.h" +#include "OculusXRAnchors.h" +#include "OculusXRSpatialAnchorComponent.generated.h" + +DECLARE_LOG_CATEGORY_EXTERN(LogOculusSpatialAnchor, Log, All); + +UCLASS(meta = (DisplayName = "Oculus Spatial Anchor Component", BlueprintSpawnableComponent)) +class OCULUSXRANCHORS_API UOculusXRSpatialAnchorComponent : public UOculusXRAnchorComponent +{ + GENERATED_BODY() +public: + UOculusXRSpatialAnchorComponent(const FObjectInitializer& ObjectInitializer); + + static bool Create(const FTransform& NewAnchorTransform, AActor* OwningActor, const FOculusXRSpatialAnchorCreateDelegate& Callback); + + bool Erase(const FOculusXRAnchorEraseDelegate& Callback); + bool Save(EOculusXRSpaceStorageLocation Location, const FOculusXRAnchorSaveDelegate& Callback); + +private: +}; diff --git a/Plugins/MetaXR/Source/OculusXREditor/OculusXREditor.Build.cs b/Plugins/MetaXR/Source/OculusXREditor/OculusXREditor.Build.cs new file mode 100644 index 0000000..e850681 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXREditor/OculusXREditor.Build.cs @@ -0,0 +1,55 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +using UnrealBuildTool; + +public class OculusXREditor : ModuleRules +{ + public OculusXREditor(ReadOnlyTargetRules Target) : base(Target) + { + bUseUnity = true; + + PrivateDependencyModuleNames.AddRange( + new string[] { + "Projects", + "InputCore", + "UnrealEd", + "LevelEditor", + "CoreUObject", + "Engine", + "EngineSettings", + "AndroidRuntimeSettings", + "Slate", + "SlateCore", + "EditorStyle", + "Core", + "OculusXRHMD", + "OculusXRMovement", + "OculusXRPassthrough", + "OVRPluginXR", + "OculusXRProjectSetupTool", + "HTTP", + "DesktopPlatform", + "LauncherServices", + "GameProjectGeneration", + "SharedSettingsWidgets", + "RHI", + "SourceControl", + } + ); + + PrivateIncludePaths.AddRange( + new string[] { + // Relative to Engine\Plugins\Runtime\Oculus\OculusVR\Source + "OculusXREditor/Private", + "OculusXRHMD/Private" + }); + + PrivateIncludePathModuleNames.AddRange( + new string[] { + "Settings", + "OculusXRProjectSetupTool" + } + ); + } +} diff --git a/Plugins/MetaXR/Source/OculusXREditor/Private/OculusXRBuildAnalytics.cpp b/Plugins/MetaXR/Source/OculusXREditor/Private/OculusXRBuildAnalytics.cpp new file mode 100644 index 0000000..8d868e4 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXREditor/Private/OculusXRBuildAnalytics.cpp @@ -0,0 +1,325 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +#include "OculusXRBuildAnalytics.h" +#include "GameProjectGenerationModule.h" +#include "OculusXRHMDModule.h" +#include "Runtime/Core/Public/HAL/FileManager.h" + +FOculusBuildAnalytics* FOculusBuildAnalytics::instance = 0; + +FOculusBuildAnalytics* FOculusBuildAnalytics::GetInstance() +{ + if (IOculusXRHMDModule::IsAvailable()) + { + if (instance == nullptr) + { + instance = new FOculusBuildAnalytics(); + } + } + + return instance; +} + +bool FOculusBuildAnalytics::IsOculusXRHMDAvailable() +{ + return IOculusXRHMDModule::IsAvailable() && FOculusXRHMDModule::Get().PreInit(); +} + +void FOculusBuildAnalytics::Shutdown() +{ +} + +FOculusBuildAnalytics::FOculusBuildAnalytics() +{ + bool TelemetryEnabled = false; + if (!GConfig->GetBool(TEXT("/Script/OculusXREditor.OculusXREditorSettings"), TEXT("bEnableOculusBuildTelemetry"), TelemetryEnabled, GEditorIni)) + { + GConfig->SetBool(TEXT("/Script/OculusXREditor.OculusXREditorSettings"), TEXT("bEnableOculusBuildTelemetry"), TelemetryEnabled, GEditorIni); + GConfig->Flush(0); + } + + if (TelemetryEnabled) + { + RegisterLauncherCallback(); + } +} + +void FOculusBuildAnalytics::OnTelemetryToggled(bool Enabled) +{ + if (Enabled) + { + RegisterLauncherCallback(); + } + else + { + if (LauncherCallbackHandle.IsValid()) + { + ILauncherServicesModule& ProjectLauncherServicesModule = FModuleManager::LoadModuleChecked("LauncherServices"); + ProjectLauncherServicesModule.OnCreateLauncherDelegate.Remove(LauncherCallbackHandle); + } + } +} + +void FOculusBuildAnalytics::RegisterLauncherCallback() +{ + ILauncherServicesModule& ProjectLauncherServicesModule = FModuleManager::LoadModuleChecked("LauncherServices"); + LauncherCallbackHandle = ProjectLauncherServicesModule.OnCreateLauncherDelegate.AddRaw(this, &FOculusBuildAnalytics::OnLauncherCreated); +} + +void FOculusBuildAnalytics::OnLauncherCreated(ILauncherRef Launcher) +{ + // Add callback for when launcher worker is started + Launcher->FLauncherWorkerStartedDelegate.AddRaw(this, &FOculusBuildAnalytics::OnLauncherWorkerStarted); +} + +void FOculusBuildAnalytics::OnLauncherWorkerStarted(ILauncherWorkerPtr LauncherWorker, ILauncherProfileRef Profile) +{ + TArray Platforms = Profile.Get().GetCookedPlatforms(); + if (Platforms.Num() == 1) + { + if (Platforms[0].Equals("Android_ASTC") || Platforms[0].Contains("Windows")) + { + CurrentBuildStage = UNDEFINED_STAGE; + AndroidPackageTime = 0; + UATLaunched = false; + BuildCompleted = false; + CurrentBuildPlatform = Platforms[0]; + TotalBuildTime = 0; + BuildStepCount = 0; + + FOculusXRHMDModule::GetPluginWrapper().SetDeveloperMode(true); + + OutputDirectory = Profile.Get().GetPackageDirectory(); + + // Assign callbacks for stages + LauncherWorker.Get()->OnStageCompleted().AddRaw(this, &FOculusBuildAnalytics::OnStageCompleted); + LauncherWorker.Get()->OnOutputReceived().AddRaw(this, &FOculusBuildAnalytics::OnBuildOutputReceived); + LauncherWorker.Get()->OnStageStarted().AddRaw(this, &FOculusBuildAnalytics::OnStageStarted); + LauncherWorker.Get()->OnCompleted().AddRaw(this, &FOculusBuildAnalytics::OnCompleted); + + // Get information on what oculus platform we are building for and also the OS platform + FString OculusPlatform; + if (CurrentBuildPlatform.Equals("Android_ASTC")) + { + UEnum* OculusMobileDevices = StaticEnum(); + UAndroidRuntimeSettings* Settings = GetMutableDefault(); + TArray> TargetOculusDevices = Settings->PackageForOculusMobile; + TArray Devices; + + if (TargetOculusDevices.Contains(EOculusMobileDevice::Quest2)) + { + Devices.Add("quest2"); + } + OculusPlatform = FString::Join(Devices, TEXT("_")); + } + else if (CurrentBuildPlatform.Contains("Windows")) + { + CurrentBuildPlatform = "Windows"; + OculusPlatform = "rift"; + } + + // Count user asset files + UserAssetCount = 0; + TArray FileNames; + IFileManager::Get().FindFilesRecursive(FileNames, *FPaths::ProjectContentDir(), TEXT("*.*"), true, false, false); + UserAssetCount = FileNames.Num(); + + // Count user script files + FGameProjectGenerationModule& GameProjectModule = FModuleManager::LoadModuleChecked(TEXT("GameProjectGeneration")); + SourceFileCount = 0; + SourceFileDirectorySize = 0; + GameProjectModule.Get().GetProjectSourceDirectoryInfo(SourceFileCount, SourceFileDirectorySize); + + // Generate build GUID + FGuid guid = FGuid::NewGuid(); + FOculusXRHMDModule::GetPluginWrapper().AddCustomMetadata("build_guid", TCHAR_TO_ANSI(*guid.ToString())); + + // Send build start event with corresponding metadata + FOculusXRHMDModule::GetPluginWrapper().AddCustomMetadata("asset_count", TCHAR_TO_ANSI(*FString::FromInt(UserAssetCount))); + FOculusXRHMDModule::GetPluginWrapper().AddCustomMetadata("script_count", TCHAR_TO_ANSI(*FString::FromInt(SourceFileCount))); + + FOculusXRHMDModule::GetPluginWrapper().AddCustomMetadata("target_platform", TCHAR_TO_ANSI(*CurrentBuildPlatform)); + FOculusXRHMDModule::GetPluginWrapper().AddCustomMetadata("target_oculus_platform", TCHAR_TO_ANSI(*OculusPlatform)); + + TArray TaskList; + LauncherWorker->GetTasks(TaskList); + BuildStepCount = TaskList.Num(); + } + } +} + +void FOculusBuildAnalytics::OnCompleted(bool Succeeded, double TotalTime, int32 ErrorCode) +{ + if (!BuildCompleted && Succeeded) + { + SendBuildCompleteEvent(TotalTime); + } +} + +void FOculusBuildAnalytics::OnStageCompleted(const FString& StageName, double Time) +{ + if (CurrentBuildStage != UNDEFINED_STAGE) + { + FString TaskName; + switch (CurrentBuildStage) + { + case COOK_IN_EDITOR_STAGE: + TaskName = "build_step_editor_cook"; + break; + case LAUNCH_UAT_STAGE: + TaskName = "build_step_launch_uat"; + break; + case COMPILE_STAGE: + TaskName = "build_step_compile"; + break; + case COOK_STAGE: + TaskName = "build_step_cook"; + break; + case DEPLOY_STAGE: + TaskName = "build_step_deploy"; + break; + case PACKAGE_STAGE: + TaskName = "build_step_package"; + break; + case RUN_STAGE: + return; + default: + TaskName = "build_step_undefined"; + break; + } + + if (AndroidPackageTime > 0) + { + Time -= AndroidPackageTime; + } + + TotalBuildTime += Time; + FOculusXRHMDModule::GetPluginWrapper().SendEvent2(TCHAR_TO_ANSI(*TaskName), TCHAR_TO_ANSI(*FString::SanitizeFloat(Time)), "ovrbuild"); + } +} + +void FOculusBuildAnalytics::OnStageStarted(const FString& StageName) +{ + if (StageName.Equals("Cooking in the editor")) + { + CurrentBuildStage = COOK_IN_EDITOR_STAGE; + } + else if (StageName.Equals("Build Task") && CurrentBuildStage == LAUNCH_UAT_STAGE) + { + CurrentBuildStage = COMPILE_STAGE; + } + else if (StageName.Equals("Build Task")) + { + CurrentBuildStage = LAUNCH_UAT_STAGE; + } + else if (StageName.Equals("Cook Task")) + { + CurrentBuildStage = COOK_STAGE; + } + else if (StageName.Equals("Package Task")) + { + CurrentBuildStage = PACKAGE_STAGE; + } + else if (StageName.Equals("Deploy Task")) + { + CurrentBuildStage = DEPLOY_STAGE; + } + else if (StageName.Equals("Run Task")) + { + CurrentBuildStage = RUN_STAGE; + SendBuildCompleteEvent(TotalBuildTime); + BuildCompleted = true; + } + else + { + CurrentBuildStage = UNDEFINED_STAGE; + } +} + +void FOculusBuildAnalytics::OnBuildOutputReceived(const FString& Message) +{ + if (CurrentBuildPlatform.Equals("Android_ASTC") && (CurrentBuildStage == DEPLOY_STAGE || CurrentBuildStage == PACKAGE_STAGE)) + { + if (Message.Contains("BUILD SUCCESSFUL")) + { + FString Text, Time; + Message.Split("in", &Text, &Time); + + if (!Time.IsEmpty()) + { + FString SMinutes, SSeconds; + if (Time.Contains("m")) + { + Time.Split("m", &SMinutes, &SSeconds); + } + else + { + SSeconds = Time; + } + + int Minutes = FCString::Atoi(*SMinutes); + int Seconds = FCString::Atoi(*SSeconds); + + AndroidPackageTime = Minutes * 60 + Seconds; + + FOculusXRHMDModule::GetPluginWrapper().SendEvent2("build_step_gradle_build", TCHAR_TO_ANSI(*FString::SanitizeFloat(AndroidPackageTime)), "ovrbuild"); + } + } + } +} + +void FOculusBuildAnalytics::SendBuildCompleteEvent(float TotalTime) +{ + if (CurrentBuildPlatform.Equals("Android_ASTC")) + { + int64 APKTotalSize = 0; + TArray FoundAPKs; + OutputDirectory = FPaths::ProjectDir() + "Binaries/Android"; + OutputDirectory = FPaths::ConvertRelativePathToFull(OutputDirectory); + IFileManager::Get().FindFiles(FoundAPKs, *FPaths::Combine(OutputDirectory, TEXT("*.apk")), true, false); + + FDateTime LatestTime = FDateTime(0); + FString LatestAPK; + for (int i = 0; i < FoundAPKs.Num(); i++) + { + FDateTime APKCreationTime = IFileManager::Get().GetTimeStamp(*FPaths::Combine(OutputDirectory, FoundAPKs[i])); + if (APKCreationTime > LatestTime) + { + LatestTime = APKCreationTime; + LatestAPK = FoundAPKs[i]; + } + } + + TArray FoundOBBs; + LatestTime = FDateTime(0); + FString LatestOBB; + IFileManager::Get().FindFiles(FoundOBBs, *FPaths::Combine(OutputDirectory, TEXT("*.obb")), true, false); + for (int i = 0; i < FoundOBBs.Num(); i++) + { + FDateTime OBBCreationTime = IFileManager::Get().GetTimeStamp(*FPaths::Combine(OutputDirectory, FoundOBBs[i])); + if (OBBCreationTime > LatestTime) + { + LatestTime = OBBCreationTime; + LatestOBB = FoundOBBs[i]; + } + } + + if (!LatestAPK.IsEmpty()) + { + APKTotalSize += IFileManager::Get().FileSize(*FPaths::Combine(OutputDirectory, LatestAPK)); + } + if (!LatestOBB.IsEmpty()) + { + APKTotalSize += IFileManager::Get().FileSize(*FPaths::Combine(OutputDirectory, LatestOBB)); + } + + if (APKTotalSize > 0) + { + FOculusXRHMDModule::GetPluginWrapper().AddCustomMetadata("build_output_size", TCHAR_TO_ANSI(*FString::FromInt(APKTotalSize))); + } + } + + FOculusXRHMDModule::GetPluginWrapper().AddCustomMetadata("build_step_count", TCHAR_TO_ANSI(*FString::FromInt(BuildStepCount))); + FOculusXRHMDModule::GetPluginWrapper().SendEvent2("build_complete", TCHAR_TO_ANSI(*FString::SanitizeFloat(TotalTime)), "ovrbuild"); +} diff --git a/Plugins/MetaXR/Source/OculusXREditor/Private/OculusXRBuildAnalytics.h b/Plugins/MetaXR/Source/OculusXREditor/Private/OculusXRBuildAnalytics.h new file mode 100644 index 0000000..06198c6 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXREditor/Private/OculusXRBuildAnalytics.h @@ -0,0 +1,62 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "ILauncherServicesModule.h" +#include "ILauncher.h" +#include "Modules/ModuleManager.h" +#include "UObject/Class.h" +#include "AndroidRuntimeSettings.h" +#include "OculusXRPluginWrapper.h" + +enum EBuildStage +{ + UNDEFINED_STAGE, + COOK_IN_EDITOR_STAGE, + COOK_STAGE, + LAUNCH_UAT_STAGE, + COMPILE_STAGE, + PACKAGE_STAGE, + DEPLOY_STAGE, + RUN_STAGE, +}; + +class FOculusBuildAnalytics +{ +public: + static FOculusBuildAnalytics* GetInstance(); + static void Shutdown(); + static bool IsOculusXRHMDAvailable(); + + void RegisterLauncherCallback(); + void OnTelemetryToggled(bool Enabled); + + void OnLauncherCreated(ILauncherRef Launcher); + void OnLauncherWorkerStarted(ILauncherWorkerPtr LauncherWorker, ILauncherProfileRef Profile); + void OnStageCompleted(const FString& StageName, double Time); + void OnStageStarted(const FString& StageName); + void OnBuildOutputReceived(const FString& Message); + void OnCompleted(bool Succeeded, double TotalTime, int32 ErrorCode); + void SendBuildCompleteEvent(float TotalTime); + +private: + FOculusBuildAnalytics(); + + static FOculusBuildAnalytics* instance; + + FDelegateHandle LauncherCallbackHandle; + + float TotalBuildTime; + float AndroidPackageTime; + bool BuildCompleted; + bool UATLaunched; + int UserAssetCount; + int BuildStepCount; + int32 SourceFileCount; + int64 SourceFileDirectorySize; + + EBuildStage CurrentBuildStage; + FString CurrentBuildPlatform; + FString OutputDirectory; +}; diff --git a/Plugins/MetaXR/Source/OculusXREditor/Private/OculusXREditorModule.cpp b/Plugins/MetaXR/Source/OculusXREditor/Private/OculusXREditorModule.cpp new file mode 100644 index 0000000..3c076b1 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXREditor/Private/OculusXREditorModule.cpp @@ -0,0 +1,598 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#include "OculusXREditorModule.h" + +#include "AssetToolsModule.h" +#include "OculusXRToolStyle.h" +#include "OculusXRToolCommands.h" +#include "OculusXRPlatformToolWidget.h" +#include "OculusXRAssetDirectory.h" +#include "OculusXRHMDRuntimeSettings.h" +#include "IOculusXRProjectSetupModule.h" +#include "OculusXRHMDTypes.h" +#include "LevelEditor.h" +#include "Modules/ModuleManager.h" +#include "Widgets/Docking/SDockTab.h" +#include "Widgets/Input/SButton.h" +#include "PropertyEditorModule.h" +#include "DetailLayoutBuilder.h" +#include "DetailCategoryBuilder.h" +#include "DetailWidgetRow.h" +#include "GeneralProjectSettings.h" +#include "IAssetTools.h" +#include "Framework/MultiBox/MultiBoxBuilder.h" +#include "ISettingsModule.h" +#include "OculusXRPassthroughColorLutAsset.h" +#include "OculusXRHMDModule.h" +#include "OculusXRPrivacyNotification.h" +#include "OculusXRSettingsToggle.h" +#include "OculusXRTelemetryPrivacySettings.h" +#include "OculusXRTelemetry.h" +#include "OculusXRTelemetryEditorEvents.h" +#include "SExternalImageReference.h" +#include "AndroidRuntimeSettings.h" +#include "SourceControlHelpers.h" +#include "Framework/Notifications/NotificationManager.h" +#include "Widgets/Notifications/SNotificationList.h" +#include "Editor/EditorPerformanceSettings.h" + +#define LOCTEXT_NAMESPACE "OculusXREditor" + +const FName FOculusXREditorModule::OculusPlatToolTabName = FName("OculusXRPlaformTool"); + +void FOculusXREditorModule::PostLoadCallback() +{ + FLevelEditorModule& LevelEditorModule = FModuleManager::LoadModuleChecked("LevelEditor"); +} + +void FOculusXREditorModule::StartupModule() +{ + bModuleValid = true; + RegisterSettings(); + FOculusAssetDirectory::LoadForCook(); + + if (!IsRunningCommandlet()) + { + FOculusToolStyle::Initialize(); + FOculusToolStyle::ReloadTextures(); + + FOculusToolCommands::Register(); + + PluginCommands = MakeShareable(new FUICommandList); + + PluginCommands->MapAction( + FOculusToolCommands::Get().OpenProjectSetupTool, + FExecuteAction::CreateRaw(this, &FOculusXREditorModule::PluginOpenSetupToolWindow), + FCanExecuteAction()); + PluginCommands->MapAction( + FOculusToolCommands::Get().OpenPlatWindow, + FExecuteAction::CreateRaw(this, &FOculusXREditorModule::PluginOpenPlatWindow), + FCanExecuteAction()); + PluginCommands->MapAction( + FOculusToolCommands::Get().ToggleDeploySo, + FExecuteAction::CreateLambda([=]() { + UOculusXRHMDRuntimeSettings* settings = GetMutableDefault(); + settings->bDeploySoToDevice = !settings->bDeploySoToDevice; + settings->Modify(true); + settings->UpdateSinglePropertyInConfigFile(settings->GetClass()->FindPropertyByName(GET_MEMBER_NAME_CHECKED(UOculusXRHMDRuntimeSettings, bDeploySoToDevice)), settings->GetDefaultConfigFilename()); + }), + FCanExecuteAction(), + FIsActionChecked::CreateLambda([=]() { + return GetMutableDefault()->bDeploySoToDevice; + })); + PluginCommands->MapAction( + FOculusToolCommands::Get().ToggleMetaXRSim, + FExecuteAction::CreateRaw(this, &FOculusXREditorModule::ToggleOpenXRRuntime), + FCanExecuteAction(), + FIsActionChecked::CreateLambda([=]() { + return FOculusXRHMDModule::IsSimulatorActivated(); + })); + PluginCommands->MapAction( + FOculusToolCommands::Get().LaunchGameRoom, + FExecuteAction::CreateRaw(this, &FOculusXREditorModule::LaunchSESGameRoom), + FCanExecuteAction()); + PluginCommands->MapAction( + FOculusToolCommands::Get().LaunchLivingRoom, + FExecuteAction::CreateRaw(this, &FOculusXREditorModule::LaunchSESLivingRoom), + FCanExecuteAction()); + PluginCommands->MapAction( + FOculusToolCommands::Get().LaunchBedroom, + FExecuteAction::CreateRaw(this, &FOculusXREditorModule::LaunchSESBedroom), + FCanExecuteAction()); + PluginCommands->MapAction( + FOculusToolCommands::Get().StopServer, + FExecuteAction::CreateRaw(this, &FOculusXREditorModule::StopSESServer), + FCanExecuteAction()); + + FLevelEditorModule& LevelEditorModule = FModuleManager::LoadModuleChecked("LevelEditor"); + + // Adds an option to launch the tool to Window->Developer Tools. + TSharedPtr MenuExtender = MakeShareable(new FExtender()); + MenuExtender->AddMenuExtension("Miscellaneous", EExtensionHook::After, PluginCommands, FMenuExtensionDelegate::CreateRaw(this, &FOculusXREditorModule::AddMenuExtension)); + LevelEditorModule.GetMenuExtensibilityManager()->AddExtender(MenuExtender); + + // We add the Oculus menu on the toolbar + TSharedPtr ToolbarExtender = MakeShareable(new FExtender); + ToolbarExtender->AddToolBarExtension("Play", EExtensionHook::After, PluginCommands, FToolBarExtensionDelegate::CreateRaw(this, &FOculusXREditorModule::AddToolbarExtension)); + LevelEditorModule.GetToolBarExtensibilityManager()->AddExtender(ToolbarExtender); + + FGlobalTabmanager::Get()->RegisterNomadTabSpawner(OculusPlatToolTabName, FOnSpawnTab::CreateRaw(this, &FOculusXREditorModule::OnSpawnPlatToolTab)).SetDisplayName(LOCTEXT("FOculusPlatfToolTabTitle", "Meta XR Platform Tool")).SetMenuType(ETabSpawnerMenuType::Hidden); + + // Register asset types + IAssetTools& AssetTools = FModuleManager::LoadModuleChecked("AssetTools").Get(); + AssetTools.RegisterAssetTypeActions(MakeShareable(new FAssetTypeActions_OculusXRPassthroughColorLut)); + + OculusXRTelemetry::PropagateTelemetryConsent(); + + // If needed, open a notification here. + OculusXRTelemetry::SpawnNotification(); + + const UGeneralProjectSettings& ProjectSettings = *GetDefault(); + const FString ProjectIdString = ProjectSettings.ProjectID.ToString(); + const OculusXRTelemetry::TScopedMarker StartEvent; + const auto& Annotated = StartEvent.AddAnnotation("project_hash", StringCast(*ProjectIdString).Get()); + + UEditorPerformanceSettings* EditorPerformanceSettings = GetMutableDefault(); + if (EditorPerformanceSettings->bOverrideMaxViewportRenderingResolution) + { + UE_LOG(LogTemp, Warning, TEXT("Existing value for UEditorPerformanceSettings::MaxViewportRenderingResolution will be overriden.")); + } + + UE_LOG(LogTemp, Log, TEXT("MetaXR ignores max viewport resolution in editor to support full HMD resolutions.")); + EditorPerformanceSettings->bOverrideMaxViewportRenderingResolution = true; + EditorPerformanceSettings->MaxViewportRenderingResolution = 0; + + FPropertyChangedEvent DisabledMaxResolutionEvent(EditorPerformanceSettings->GetClass()->FindPropertyByName(GET_MEMBER_NAME_CHECKED(UEditorPerformanceSettings, MaxViewportRenderingResolution)), EPropertyChangeType::ValueSet); + EditorPerformanceSettings->PostEditChangeProperty(DisabledMaxResolutionEvent); + } +} + +void FOculusXREditorModule::ShutdownModule() +{ + if (!bModuleValid) + { + return; + } + + if (!IsRunningCommandlet()) + { + FOculusToolStyle::Shutdown(); + FOculusToolCommands::Unregister(); + FGlobalTabmanager::Get()->UnregisterNomadTabSpawner(OculusPlatToolTabName); + } + + FOculusAssetDirectory::ReleaseAll(); + if (UObjectInitialized()) + { + UnregisterSettings(); + } +} + +TSharedRef FOculusXREditorModule::OnSpawnPlatToolTab(const FSpawnTabArgs& SpawnTabArgs) +{ + /* clang-format off */ + auto myTab = SNew(SDockTab) + .TabRole(ETabRole::NomadTab) + [ + SNew(SOculusPlatformToolWidget) + ]; + /* clang-format on */ + + return myTab; +} + +void FOculusXREditorModule::RegisterSettings() +{ + if (ISettingsModule* SettingsModule = FModuleManager::GetModulePtr("Settings")) + { + SettingsModule->RegisterSettings("Project", "Plugins", "OculusXR", + LOCTEXT("RuntimeSettingsName", "Meta XR"), + LOCTEXT("RuntimeSettingsDescription", "Configure the Meta XR plugin"), + GetMutableDefault()); + + FPropertyEditorModule& PropertyModule = FModuleManager::GetModuleChecked("PropertyEditor"); + PropertyModule.RegisterCustomClassLayout(UOculusXRHMDRuntimeSettings::StaticClass()->GetFName(), FOnGetDetailCustomizationInstance::CreateStatic(&FOculusXRHMDSettingsDetailsCustomization::MakeInstance)); + + SettingsModule->RegisterSettings("Editor", "Privacy", "OculusXR", + LOCTEXT("PrivacyTelemetrySettingsName", "MetaXR Usage Data"), + LOCTEXT("PrivacyTelemetrySettingsDescription", "Configure the way MetaXR usage information is handled."), + GetMutableDefault()); + PropertyModule.RegisterCustomClassLayout(UOculusXRTelemetryPrivacySettings::StaticClass()->GetFName(), FOnGetDetailCustomizationInstance::CreateStatic(&FOculusXRSettingsToggle::MakeInstance)); + } +} + +void FOculusXREditorModule::UnregisterSettings() +{ + if (ISettingsModule* SettingsModule = FModuleManager::GetModulePtr("Settings")) + { + SettingsModule->UnregisterSettings("Project", "Plugins", "OculusXR"); + SettingsModule->UnregisterSettings("Editor", "Privacy", "OculusXR"); + } +} + +FReply FOculusXREditorModule::PluginClickFn(bool text) +{ + PluginOpenSetupToolWindow(); + return FReply::Handled(); +} + +void FOculusXREditorModule::PluginOpenSetupToolWindow() +{ + IOculusXRProjectSetupToolModule::Get().ShowProjectSetupTool("Meta Menu"); +} + +void FOculusXREditorModule::PluginOpenPlatWindow() +{ + FGlobalTabmanager::Get()->TryInvokeTab(OculusPlatToolTabName); +} + +void FOculusXREditorModule::ToggleOpenXRRuntime() +{ + FOculusXRHMDModule::ToggleOpenXRRuntime(); +} + +void FOculusXREditorModule::LaunchSESGameRoom() +{ + FOculusXRHMDModule::LaunchEnvironment("GameRoom"); +} + +void FOculusXREditorModule::LaunchSESLivingRoom() +{ + FOculusXRHMDModule::LaunchEnvironment("LivingRoom"); +} + +void FOculusXREditorModule::LaunchSESBedroom() +{ + FOculusXRHMDModule::LaunchEnvironment("Bedroom"); +} + +void FOculusXREditorModule::StopSESServer() +{ + FOculusXRHMDModule::StopServer(); +} + +void FOculusXREditorModule::AddMenuExtension(FMenuBuilder& Builder) +{ + bool v = false; + GConfig->GetBool(TEXT("/Script/OculusXREditor.OculusXREditorSettings"), TEXT("bAddMenuOption"), v, GEditorIni); + if (v) + { + Builder.AddMenuEntry(FOculusToolCommands::Get().OpenProjectSetupTool); + } +} + +void FOculusXREditorModule::AddToolbarExtension(FToolBarBuilder& Builder) +{ + Builder.SetLabelVisibility(EVisibility::All); + Builder.AddComboButton( + FUIAction(), + FOnGetContent::CreateRaw(this, &FOculusXREditorModule::CreateToolbarEntryMenu, PluginCommands), + LOCTEXT("OculusToolsToolBarCombo", "Meta XR Tools"), + LOCTEXT("OculusToolsToolBarComboTooltip", "Meta XR tools"), + TAttribute::CreateLambda([]() { + return FSlateIcon(FOculusToolStyle::GetStyleSetName(), "OculusTool.MenuButton"); + }), + false); + + Builder.AddComboButton( + FUIAction(), + FOnGetContent::CreateRaw(this, &FOculusXREditorModule::CreateXrSimToolbarEntryMenu, PluginCommands), + LOCTEXT("MetaXRSimulatorCombo", "Meta XR Simulator"), + LOCTEXT("MetaXRSimulatorComboTooltip", "Meta XR Simulator"), + TAttribute::CreateLambda([]() { + return FSlateIcon(FOculusToolStyle::GetStyleSetName(), "OculusTool.MenuButton"); + }), + false); +} + +// Add the entries to the OculusXR Tools toolbar menu button +TSharedRef FOculusXREditorModule::CreateToolbarEntryMenu(TSharedPtr Commands) +{ + FMenuBuilder MenuBuilder(true, Commands); + MenuBuilder.BeginSection("OculusXRBuilds", LOCTEXT("OculusXRBuilds", "Builds")); + MenuBuilder.AddMenuEntry(FOculusToolCommands::Get().ToggleDeploySo); + MenuBuilder.EndSection(); + + MenuBuilder.BeginSection("OculusXRTools", LOCTEXT("OculusXRTools", "Tools")); + MenuBuilder.AddMenuEntry(FOculusToolCommands::Get().OpenProjectSetupTool); + MenuBuilder.AddMenuEntry(FOculusToolCommands::Get().OpenPlatWindow); + MenuBuilder.EndSection(); + + return MenuBuilder.MakeWidget(); +} + +TSharedRef FOculusXREditorModule::CreateXrSimToolbarEntryMenu(TSharedPtr Commands) +{ + FMenuBuilder MenuBuilder(true, Commands); + + MenuBuilder.BeginSection("MetaXRSimulator", LOCTEXT("MetaXRSimulator", "Toggle")); + MenuBuilder.AddMenuEntry(FOculusToolCommands::Get().ToggleMetaXRSim); + MenuBuilder.EndSection(); + + MenuBuilder.BeginSection("SES", LOCTEXT("SES", "SES")); + MenuBuilder.AddSubMenu( + LOCTEXT("Synthetic Environment Server", "Synthetic Environment Server"), + LOCTEXT("Synthetic Environment Server", "Synthetic Environment Server"), + FNewMenuDelegate::CreateRaw(this, &FOculusXREditorModule::CreateSESSubMenus)); + MenuBuilder.EndSection(); + + return MenuBuilder.MakeWidget(); +} + +void FOculusXREditorModule::CreateSESSubMenus(FMenuBuilder& MenuBuilder) +{ + MenuBuilder.BeginSection("Synthetic Environment Server", LOCTEXT("Synthetic Environment Server", "Synthetic Environment Server")); + MenuBuilder.AddMenuEntry(FOculusToolCommands::Get().LaunchGameRoom); + MenuBuilder.AddMenuEntry(FOculusToolCommands::Get().LaunchLivingRoom); + MenuBuilder.AddMenuEntry(FOculusToolCommands::Get().LaunchBedroom); + MenuBuilder.AddMenuEntry(FOculusToolCommands::Get().StopServer); + MenuBuilder.EndSection(); +} + +FOculusXRHMDSettingsDetailsCustomization::FOculusXRHMDSettingsDetailsCustomization() + : EngineAndroidPath(FPaths::EngineDir() + TEXT("Build/Android/Java")) + , GameAndroidPath(FPaths::ProjectDir() + TEXT("Build/Android")) + , LaunchImageLandscape(FPlatformIconInfo(TEXT("res/drawable/splashscreen_landscape.png"), LOCTEXT("SystemSplashImage", "System Splash Image"), FText::GetEmpty(), 640, 360, FPlatformIconInfo::Required)) + , VRSplashPath(FPaths::ProjectDir() + TEXT("Build/Android/assets/vr_splash.png")) + +{ +} + +TSharedRef FOculusXRHMDSettingsDetailsCustomization::MakeInstance() +{ + return MakeShareable(new FOculusXRHMDSettingsDetailsCustomization); +} + +FReply FOculusXRHMDSettingsDetailsCustomization::PluginClickPerfFn(bool text) +{ + IOculusXRProjectSetupToolModule::Get().ShowProjectSetupTool("Settings"); + return FReply::Handled(); +} + +FReply FOculusXRHMDSettingsDetailsCustomization::PluginClickPlatFn(bool text) +{ + FGlobalTabmanager::Get()->TryInvokeTab(FOculusXREditorModule::OculusPlatToolTabName); + return FReply::Handled(); +} + +FReply FOculusXRHMDSettingsDetailsCustomization::DisableEngineSplash(bool text) +{ + UOculusXRHMDRuntimeSettings* Settings = GetMutableDefault(); + Settings->bAutoEnabled = false; + Settings->SplashDescs.Empty(); + Settings->TryUpdateDefaultConfigFile(); + return FReply::Handled(); +} + +FReply FOculusXRHMDSettingsDetailsCustomization::AddSplashImage(bool text) +{ + const FString AutomaticImagePath = EngineAndroidPath / LaunchImageLandscape.IconPath; + FText FailReason; + if (!SourceControlHelpers::CopyFileUnderSourceControl(VRSplashPath, AutomaticImagePath, LOCTEXT("ImageDescription", "image"), FailReason)) + { + FNotificationInfo Info(FailReason); + Info.ExpireDuration = 3.0f; + FSlateNotificationManager::Get().AddNotification(Info); + return FReply::Unhandled(); + } + + return FReply::Handled(); +} + +void FOculusXRHMDSettingsDetailsCustomization::CustomizeDetails(IDetailLayoutBuilder& DetailLayout) +{ + SavedLayoutBuilder = &DetailLayout; + + // Labeled "General OculusXR" instead of "General" to enable searchability. The button "Launch Oculus Utilities Window" doesn't show up if you search for "Oculus" + IDetailCategoryBuilder& CategoryBuilder = DetailLayout.EditCategory("General Meta XR", FText::GetEmpty(), ECategoryPriority::Important); + /* clang-format off */ + CategoryBuilder.AddCustomRow(LOCTEXT("General", "General")) + .WholeRowContent() + [ + SNew(SVerticalBox) + + SVerticalBox::Slot().AutoHeight().Padding(2) + [ + SNew(SHorizontalBox) + + SHorizontalBox::Slot().AutoWidth() + [ + SNew(SButton) + .Text(LOCTEXT("LaunchTool", "Launch Meta XR Project Setup Tool")) + .OnClicked(this, &FOculusXRHMDSettingsDetailsCustomization::PluginClickPerfFn, true) + ] + + SHorizontalBox::Slot().FillWidth(8) + ] + + SVerticalBox::Slot().AutoHeight().Padding(2) + [ + SNew(SHorizontalBox) + + SHorizontalBox::Slot().AutoWidth() + [ + SNew(SButton) + .Text(LOCTEXT("LaunchPlatTool", "Launch Meta XR Platform Window")) + .OnClicked(this, &FOculusXRHMDSettingsDetailsCustomization::PluginClickPlatFn, true) + ] + + SHorizontalBox::Slot().FillWidth(8) + ] + ]; + + IDetailCategoryBuilder& CTXPTCategoryBuilder = DetailLayout.EditCategory("System SplashScreen", FText::GetEmpty(), ECategoryPriority::Important); + + static const FName WarningColorStyle("Colors.AccentYellow"); + + CTXPTCategoryBuilder.AddCustomRow(LOCTEXT("CTXPTWarning", "Contextual Passthrough Warning")) + .Visibility(TAttribute(this, &FOculusXRHMDSettingsDetailsCustomization::GetContextualPassthroughWarningVisibility)) + [ + SNew(SVerticalBox) + + SVerticalBox::Slot().FillHeight(1.f) + [ + SNew(SHorizontalBox) + + SHorizontalBox::Slot().FillWidth(1.f).VAlign(EVerticalAlignment::VAlign_Center) + [ + SNew(STextBlock) + .Font(IDetailLayoutBuilder::GetDetailFont()) + .AutoWrapText(true) + .Justification(ETextJustify::Center) + .Text(LOCTEXT("CTXPT_EngineSplashWarning", "Engine Splash Screen is enabled, this will result in an inconsistent experience.")) + .ColorAndOpacity(FAppStyle::Get().GetSlateColor(WarningColorStyle)) + ] + + SHorizontalBox::Slot().FillWidth(1.f).HAlign(EHorizontalAlignment::HAlign_Left) + [ + SNew(SButton) + .VAlign(EVerticalAlignment::VAlign_Center) + .Text(LOCTEXT("DisableEngineSplashScreen", "Disable Engine Splash Screen")) + .OnClicked(this, &FOculusXRHMDSettingsDetailsCustomization::DisableEngineSplash, true) + ] + ] + ]; + + + // Duplicate "Show Launch Image" and "Launch Landscape" properties from Android Settings + + CTXPTCategoryBuilder.AddCustomRow(LOCTEXT("ShowSystemSplashImageRow", "Show System Splash Image Row")) + .NameContent() + [ + SNew(SHorizontalBox) + + SHorizontalBox::Slot() + .Padding(FMargin(0, 1, 0, 1)) + .FillWidth(1.0f) + [ + SNew(STextBlock) + .Text(LOCTEXT("ShowSystemSplashImage", "Show System Splash Image")) + .Font(DetailLayout.GetDetailFont()) + .ToolTipText(LOCTEXT("ShowSystemSplashImageToolTip", "Same as \"Show Launch Image\" setting in the \"Platform > Android > Launch Images\" section. If set, the image will be presented by the Operating System at launch time")) + ] + ] + .ValueContent() + .MaxDesiredWidth(400.0f) + .MinDesiredWidth(100.0f) + [ + SNew(SHorizontalBox) + + SHorizontalBox::Slot() + .FillWidth(1.0f) + .VAlign(VAlign_Center) + [ + SNew(SCheckBox) + .IsChecked(TAttribute(this, &FOculusXRHMDSettingsDetailsCustomization::GetShowLaunchImageCheckBoxState)) + .OnCheckStateChanged(this, &FOculusXRHMDSettingsDetailsCustomization::OnShowLaunchImageCheckStateChanged) + ] + ]; + + + const FString AutomaticImagePath = EngineAndroidPath / LaunchImageLandscape.IconPath; + const FString TargetImagePath = GameAndroidPath / LaunchImageLandscape.IconPath; + const FVector2D LaunchImageMaxSize(150.0f, 150.0f); + + CTXPTCategoryBuilder.AddCustomRow(LaunchImageLandscape.IconName) + .IsEnabled(TAttribute(this, &FOculusXRHMDSettingsDetailsCustomization::IsLaunchImageEnabled)) + .NameContent() + [ + SNew(SHorizontalBox) + + SHorizontalBox::Slot() + .Padding(FMargin(0, 1, 0, 1)) + .FillWidth(1.0f) + [ + SNew(STextBlock) + .Text(LaunchImageLandscape.IconName) + .Font(DetailLayout.GetDetailFont()) + .ToolTipText(LOCTEXT("SystemSplashImageToolTip", "Same as \"Launch Landscape\" setting in the \"Platform > Android > Launch Images\" section. This is the image that will be presented by the Operating System at launch time")) + ] + ] + .ValueContent() + .MaxDesiredWidth(400.0f) + .MinDesiredWidth(100.0f) + [ + SNew(SHorizontalBox) + + SHorizontalBox::Slot() + .FillWidth(1.0f) + .VAlign(VAlign_Center) + [ + SNew(SExternalImageReference, AutomaticImagePath, TargetImagePath) + .FileDescription(LaunchImageLandscape.IconDescription) + .MaxDisplaySize(LaunchImageMaxSize) + .OnPostExternalImageCopy(FOnPostExternalImageCopy::CreateSP(this, &FOculusXRHMDSettingsDetailsCustomization::OnLaunchImageChanged)) + ] + ]; + + CTXPTCategoryBuilder.AddCustomRow(LOCTEXT("SystemSplashImageWarning", "System Splash Image warning")) + .Visibility(TAttribute(this, &FOculusXRHMDSettingsDetailsCustomization::GetSystemSplashImageWarningVisibility)) + [ + SNew(SVerticalBox) + + SVerticalBox::Slot().FillHeight(1.f) + [ + SNew(SHorizontalBox) + + SHorizontalBox::Slot().FillWidth(1.f).VAlign(EVerticalAlignment::VAlign_Center) + [ + SNew(STextBlock) + .Font(IDetailLayoutBuilder::GetDetailFont()) + .AutoWrapText(true) + .Justification(ETextJustify::Center) + .Text(LOCTEXT("SystemSplashWarningText", "Splash Image is currently missing from project. Click button to add it.")) + .ColorAndOpacity(FAppStyle::Get().GetSlateColor(WarningColorStyle)) + ] + + SHorizontalBox::Slot().FillWidth(1.f).HAlign(EHorizontalAlignment::HAlign_Left) + [ + SNew(SButton) + .VAlign(EVerticalAlignment::VAlign_Center) + .Text(LOCTEXT("DisableEngineSplashScreen", "Add Splash Image file to project")) + .OnClicked(this, &FOculusXRHMDSettingsDetailsCustomization::AddSplashImage, true) + ] + ] + ]; + /* clang-format on */ +} + +EVisibility FOculusXRHMDSettingsDetailsCustomization::GetContextualPassthroughWarningVisibility() const +{ + UOculusXRHMDRuntimeSettings* OculusSettings = GetMutableDefault(); + return OculusSettings->SystemSplashBackground == ESystemSplashBackgroundType::Contextual && (OculusSettings->bAutoEnabled || !OculusSettings->SplashDescs.IsEmpty()) ? EVisibility::Visible : EVisibility::Collapsed; +} + +ECheckBoxState FOculusXRHMDSettingsDetailsCustomization::GetShowLaunchImageCheckBoxState() const +{ + UAndroidRuntimeSettings* AndroidSettings = GetMutableDefault(); + return AndroidSettings->bShowLaunchImage ? ECheckBoxState::Checked : ECheckBoxState::Unchecked; +} + +bool FOculusXRHMDSettingsDetailsCustomization::IsLaunchImageEnabled() const +{ + UAndroidRuntimeSettings* AndroidSettings = GetMutableDefault(); + return AndroidSettings->bShowLaunchImage; +} + +void FOculusXRHMDSettingsDetailsCustomization::OnShowLaunchImageCheckStateChanged(const ECheckBoxState NewState) +{ + UAndroidRuntimeSettings* AndroidSettings = GetMutableDefault(); + AndroidSettings->bShowLaunchImage = NewState == ECheckBoxState::Checked; + AndroidSettings->TryUpdateDefaultConfigFile(); +} + +bool FOculusXRHMDSettingsDetailsCustomization::OnLaunchImageChanged(const FString& InChosenImage) +{ + // This will refresh the launch image located in android settings as well + SavedLayoutBuilder->ForceRefreshDetails(); + + FText FailReason; + if (!SourceControlHelpers::CopyFileUnderSourceControl(VRSplashPath, InChosenImage, LOCTEXT("ImageDescription", "image"), FailReason)) + { + FNotificationInfo Info(FailReason); + Info.ExpireDuration = 3.0f; + FSlateNotificationManager::Get().AddNotification(Info); + return false; + } + + return true; +} + +EVisibility FOculusXRHMDSettingsDetailsCustomization::GetSystemSplashImageWarningVisibility() const +{ + IFileManager& FileManager = IFileManager::Get(); + + return !FileManager.FileExists(*VRSplashPath) ? EVisibility::Visible : EVisibility::Collapsed; +} + +////////////////////////////////////////////////////////////////////////// + +IMPLEMENT_MODULE(FOculusXREditorModule, OculusXREditor); + +////////////////////////////////////////////////////////////////////////// + +#undef LOCTEXT_NAMESPACE diff --git a/Plugins/MetaXR/Source/OculusXREditor/Private/OculusXREditorModule.h b/Plugins/MetaXR/Source/OculusXREditor/Private/OculusXREditorModule.h new file mode 100644 index 0000000..e5b91da --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXREditor/Private/OculusXREditorModule.h @@ -0,0 +1,99 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#pragma once + +#include "CoreMinimal.h" +#include "IOculusXREditorModule.h" +#include "Modules/ModuleInterface.h" +#include "IDetailCustomization.h" +#include "PlatformIconInfo.h" +#include "Input/Reply.h" +#include "Layout/Visibility.h" + +class FToolBarBuilder; +class FMenuBuilder; + +#define OCULUS_EDITOR_MODULE_NAME "OculusXREditor" + +enum class ECheckBoxState : uint8; + +class FOculusXREditorModule : public IOculusXREditorModule +{ +public: + FOculusXREditorModule() + : bModuleValid(false){}; + + /** IModuleInterface implementation */ + virtual void StartupModule() override; + virtual void ShutdownModule() override; + virtual void PostLoadCallback() override; + + void RegisterSettings(); + void UnregisterSettings(); + + void PluginOpenSetupToolWindow(); + FReply PluginClickFn(bool text); + + void PluginOpenPlatWindow(); + + void ToggleOpenXRRuntime(); + + void CreateSESSubMenus(FMenuBuilder& MenuBuilder); + void LaunchSESGameRoom(); + void LaunchSESLivingRoom(); + void LaunchSESBedroom(); + void StopSESServer(); + +public: + static const FName OculusPlatToolTabName; + +private: + void AddToolbarExtension(FToolBarBuilder& Builder); + TSharedRef CreateToolbarEntryMenu(TSharedPtr Commands); + TSharedRef CreateXrSimToolbarEntryMenu(TSharedPtr Commands); + void AddMenuExtension(FMenuBuilder& Builder); + + TSharedRef OnSpawnPlatToolTab(const class FSpawnTabArgs& SpawnTabArgs); + +private: + TSharedPtr PluginCommands; + bool bModuleValid; +}; + +class IDetailLayoutBuilder; + +class FOculusXRHMDSettingsDetailsCustomization : public IDetailCustomization +{ +private: + FOculusXRHMDSettingsDetailsCustomization(); + + FPlatformIconInfo LaunchImageLandscape; + + const FString EngineAndroidPath; + const FString GameAndroidPath; + const FString VRSplashPath; + + IDetailLayoutBuilder* SavedLayoutBuilder; + +public: + /** Makes a new instance of this detail layout class for a specific detail view requesting it */ + static TSharedRef MakeInstance(); + + // IDetailCustomization interface + virtual void CustomizeDetails(IDetailLayoutBuilder& DetailLayout) override; + // End of IDetailCustomization interface + + EVisibility GetContextualPassthroughWarningVisibility() const; + ECheckBoxState GetShowLaunchImageCheckBoxState() const; + bool IsLaunchImageEnabled() const; + + void OnShowLaunchImageCheckStateChanged(const ECheckBoxState NewState); + bool OnLaunchImageChanged(const FString& InChosenImage); + + EVisibility GetSystemSplashImageWarningVisibility() const; + + FReply PluginClickPerfFn(bool text); + FReply PluginClickPlatFn(bool text); + FReply DisableEngineSplash(bool text); + FReply AddSplashImage(bool text); +}; diff --git a/Plugins/MetaXR/Source/OculusXREditor/Private/OculusXREditorSettings.cpp b/Plugins/MetaXR/Source/OculusXREditor/Private/OculusXREditorSettings.cpp new file mode 100644 index 0000000..52746a4 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXREditor/Private/OculusXREditorSettings.cpp @@ -0,0 +1,9 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +#include "OculusXREditorSettings.h" + +UOculusXREditorSettings::UOculusXREditorSettings() + : PerfToolTargetPlatform(EOculusXRPlatform::PC) +{ +} diff --git a/Plugins/MetaXR/Source/OculusXREditor/Private/OculusXRMovementAssetsFactories.cpp b/Plugins/MetaXR/Source/OculusXREditor/Private/OculusXRMovementAssetsFactories.cpp new file mode 100644 index 0000000..a6a739d --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXREditor/Private/OculusXRMovementAssetsFactories.cpp @@ -0,0 +1,346 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#include "OculusXRMovementAssetsFactories.h" + +#include "AssetToolsModule.h" +#include "IAssetTools.h" +#include "Kismet2/KismetEditorUtilities.h" + +#include "OculusXRLiveLinkRetargetFaceAsset.h" +#include "OculusXRLiveLinkRetargetBodyAsset.h" + +#define LOCTEXT_NAMESPACE "OculusXRMovementAssetsFactories" + +UOculusXRMetahumanRetargetAssetFactory::UOculusXRMetahumanRetargetAssetFactory(const FObjectInitializer& ObjectInitializer) + : Super(ObjectInitializer) +{ + SupportedClass = UBlueprint::StaticClass(); + + bCreateNew = true; + bEditAfterNew = true; +} + +bool UOculusXRMetahumanRetargetAssetFactory::ConfigureProperties() +{ + return true; +} + +uint32 UOculusXRMetahumanRetargetAssetFactory::GetMenuCategories() const +{ + IAssetTools& AssetTools = FModuleManager::LoadModuleChecked("AssetTools").Get(); + return AssetTools.RegisterAdvancedAssetCategory("LiveLink", LOCTEXT("AssetCategoryName", "Live Link")); +} + +UObject* UOculusXRMetahumanRetargetAssetFactory::FactoryCreateNew(UClass* Class, UObject* InParent, FName Name, EObjectFlags Flags, UObject* Context, FFeedbackContext* Warn, FName CallingContext) +{ + UBlueprint* RetargetBlueprint = FKismetEditorUtilities::CreateBlueprint(ParentClass, InParent, Name, BlueprintType, UBlueprint::StaticClass(), UBlueprintGeneratedClass::StaticClass(), CallingContext); + + if (const TSubclassOf GeneratedClass = RetargetBlueprint->GeneratedClass) + { + SetDefaults(GeneratedClass); + } + + return RetargetBlueprint; +} + +UOculusXRMetahumanFaceRetargetAssetFactory::UOculusXRMetahumanFaceRetargetAssetFactory(const FObjectInitializer& ObjectInitializer) + : Super(ObjectInitializer) +{ + ParentClass = UOculusXRLiveLinkRetargetFaceAsset::StaticClass(); +} + +FText UOculusXRMetahumanFaceRetargetAssetFactory::GetDisplayName() const +{ + return LOCTEXT("DisplayNameMetahumanFace", "Face retarget asset for OculusXRMovement and Metahuman"); +} + +void UOculusXRMetahumanFaceRetargetAssetFactory::SetDefaults(const TSubclassOf GeneratedClass) const +{ + if (UOculusXRLiveLinkRetargetFaceAsset* Retargeting = GeneratedClass->GetDefaultObject()) + { + Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::BrowLowererL, { "CTRL_expressions_BrowDownL", "CTRL_expressions_BrowLateralL" }); + Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::BrowLowererR, { "CTRL_expressions_BrowDownR", "CTRL_expressions_BrowLateralR" }); + Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::CheekPuffL, { "CTRL_expressions_mouthCheekBlowL" }); + Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::CheekPuffR, { "CTRL_expressions_mouthCheekBlowR" }); + Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::CheekRaiserL, { "CTRL_expressions_eyeCheekRaiseL" }); + Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::CheekRaiserR, { "CTRL_expressions_eyeCheekRaiseR" }); + Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::CheekSuckL, { "CTRL_expressions_mouthCheekSuckL" }); + Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::CheekSuckR, { "CTRL_expressions_mouthCheekSuckR" }); + Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::ChinRaiserB, { "CTRL_expressions_jawChinRaiseDL", "CTRL_expressions_jawChinRaiseDR" }); + Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::ChinRaiserT, { "CTRL_expressions_jawChinRaiseUL", "CTRL_expressions_jawChinRaiseUR" }); + Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::DimplerL, { "CTRL_expressions_mouthDimpleL" }); + Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::DimplerR, { "CTRL_expressions_mouthDimpleR" }); + Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::EyesClosedL, { "CTRL_expressions_eyeBlinkL" }); + Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::EyesClosedR, { "CTRL_expressions_eyeBlinkR" }); + Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::EyesLookDownL, { "CTRL_expressions_eyeLookDownL" }); + Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::EyesLookDownR, { "CTRL_expressions_eyeLookDownR" }); + Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::EyesLookLeftL, { "CTRL_expressions_eyeLookLeftL" }); + Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::EyesLookLeftR, { "CTRL_expressions_eyeLookLeftR" }); + Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::EyesLookRightL, { "CTRL_expressions_eyeLookRightL" }); + Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::EyesLookRightR, { "CTRL_expressions_eyeLookRightR" }); + Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::EyesLookUpL, { "CTRL_expressions_eyeLookUpL" }); + Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::EyesLookUpR, { "CTRL_expressions_eyeLookUpR" }); + Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::InnerBrowRaiserL, { "CTRL_expressions_browRaiseInL" }); + Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::InnerBrowRaiserR, { "CTRL_expressions_browRaiseInR" }); + Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::JawDrop, { "CTRL_expressions_jawOpen" }); + Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::JawSidewaysLeft, { "CTRL_expressions_jawLeft" }); + Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::JawSidewaysRight, { "CTRL_expressions_jawRight" }); + Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::JawThrust, { "CTRL_expressions_jawFwd", "CTRL_expressions_jawBack" }); + Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::LidTightenerL, { "CTRL_expressions_eyeSquintInnerL" }); + Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::LidTightenerR, { "CTRL_expressions_eyeSquintInnerR" }); + Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::LipCornerDepressorL, { "CTRL_expressions_mouthCornerDepressL" }); + Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::LipCornerDepressorR, { "CTRL_expressions_mouthCornerDepressR" }); + Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::LipCornerPullerL, { "CTRL_expressions_mouthCornerPullL" }); + Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::LipCornerPullerR, { "CTRL_expressions_mouthCornerPullR" }); + Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::LipFunnelerLB, { "CTRL_expressions_mouthFunnelDL" }); + Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::LipFunnelerLT, { "CTRL_expressions_mouthFunnelUL" }); + Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::LipFunnelerRB, { "CTRL_expressions_mouthFunnelDR" }); + Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::LipFunnelerRT, { "CTRL_expressions_mouthFunnelUR" }); + Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::LipPressorL, { "CTRL_expressions_mouthLipsPressL" }); + Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::LipPressorR, { "CTRL_expressions_mouthLipsPressR" }); + Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::LipPuckerL, { "CTRL_expressions_mouthLipsPurseDL", "CTRL_expressions_mouthLipsPurseUL" }); + Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::LipPuckerR, { "CTRL_expressions_mouthLipsPurseDR", "CTRL_expressions_mouthLipsPurseUR" }); + Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::LipStretcherL, { "CTRL_expressions_mouthStretchL" }); + Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::LipStretcherR, { "CTRL_expressions_mouthStretchR" }); + Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::LipSuckLB, { "CTRL_expressions_mouthLowerLipBiteL" }); + Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::LipSuckLT, { "CTRL_expressions_mouthUpperLipBiteL" }); + Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::LipSuckRB, { "CTRL_expressions_mouthLowerLipBiteR" }); + Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::LipSuckRT, { "CTRL_expressions_mouthUpperLipBiteR" }); + Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::LipTightenerL, { "CTRL_expressions_mouthLipsTightenDL", "CTRL_expressions_mouthLipsTightenUL" }); + Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::LipTightenerR, { "CTRL_expressions_mouthLipsTightenDR", "CTRL_expressions_mouthLipsTightenUR" }); + Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::LipsToward, { "CTRL_expressions_jawChinRaiseDL", "CTRL_expressions_jawChinRaiseDR", "CTRL_expressions_jawChinRaiseUL", "CTRL_expressions_jawChinRaiseUR" }); + Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::LowerLipDepressorL, { "CTRL_expressions_mouthLowerLipDepressL" }); + Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::LowerLipDepressorR, { "CTRL_expressions_mouthLowerLipDepressR" }); + Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::MouthLeft, { "CTRL_expressions_mouthLeft" }); + Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::MouthRight, { "CTRL_expressions_mouthRight" }); + Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::NoseWrinklerL, { "CTRL_expressions_noseWrinkleL" }); + Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::NoseWrinklerR, { "CTRL_expressions_noseWrinkleR" }); + Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::OuterBrowRaiserL, { "CTRL_expressions_browRaiseOuterL" }); + Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::OuterBrowRaiserR, { "CTRL_expressions_browRaiseOuterR" }); + Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::UpperLidRaiserL, { "CTRL_expressions_eyeUpperLidUpL" }); + Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::UpperLidRaiserR, { "CTRL_expressions_eyeUpperLidUpR" }); + Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::UpperLipRaiserL, { "CTRL_expressions_mouthUpperLipRaiseL" }); + Retargeting->CurveRemapping.Emplace(EOculusXRFaceExpression::UpperLipRaiserR, { "CTRL_expressions_mouthUpperLipRaiseR" }); + } +} + +UOculusXRMetahumanBodyRetargetAssetFactory::UOculusXRMetahumanBodyRetargetAssetFactory(const FObjectInitializer& ObjectInitializer) + : Super(ObjectInitializer) +{ + ParentClass = UOculusXRLiveLinkRetargetBodyAsset::StaticClass(); +} + +FText UOculusXRMetahumanBodyRetargetAssetFactory::GetDisplayName() const +{ + return LOCTEXT("DisplayNameMetahumanBody", "Body retarget asset for OculusXRMovement and Metahuman"); +} + +void UOculusXRMetahumanBodyRetargetAssetFactory::SetDefaults(const TSubclassOf GeneratedClass) const +{ + if (UOculusXRLiveLinkRetargetBodyAsset* Retargeting = GeneratedClass->GetDefaultObject()) + { + Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyRoot, "root"); + Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyHips, "pelvis"); + Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodySpineLower, "spine_01"); + Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodySpineMiddle, "spine_02"); + Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodySpineUpper, "spine_04"); + Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyChest, "spine_05"); + Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyNeck, "neck_02"); + Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyHead, "head"); + + Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyLeftShoulder, "clavicle_l"); + Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyLeftScapula, NAME_None); + Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyLeftArmUpper, "upperarm_l"); + Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyLeftArmLower, "lowerarm_l"); + Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyLeftHandWristTwist, NAME_None); + + Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyRightShoulder, "clavicle_r"); + Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyRightScapula, NAME_None); + Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyRightArmUpper, "upperarm_r"); + Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyRightArmLower, "lowerarm_r"); + Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyRightHandWristTwist, NAME_None); + + Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyLeftHandPalm, NAME_None); + Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyLeftHandWrist, "hand_l"); + Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyLeftHandThumbMetacarpal, "thumb_01_l"); + Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyLeftHandThumbProximal, "thumb_02_l"); + Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyLeftHandThumbDistal, "thumb_03_l"); + Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyLeftHandThumbTip, NAME_None); + Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyLeftHandIndexMetacarpal, "index_metacarpal_l"); + Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyLeftHandIndexProximal, "index_01_l"); + Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyLeftHandIndexIntermediate, "index_02_l"); + Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyLeftHandIndexDistal, "index_03_l"); + Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyLeftHandIndexTip, NAME_None); + Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyLeftHandMiddleMetacarpal, "middle_metacarpal_l"); + Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyLeftHandMiddleProximal, "middle_01_l"); + Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyLeftHandMiddleIntermediate, "middle_02_l"); + Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyLeftHandMiddleDistal, "middle_03_l"); + Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyLeftHandMiddleTip, NAME_None); + Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyLeftHandRingMetacarpal, "ring_metacarpal_l"); + Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyLeftHandRingProximal, "ring_01_l"); + Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyLeftHandRingIntermediate, "ring_02_l"); + Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyLeftHandRingDistal, "ring_03_l"); + Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyLeftHandRingTip, NAME_None); + Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyLeftHandLittleMetacarpal, "pinky_metacarpal_l"); + Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyLeftHandLittleProximal, "pinky_01_l"); + Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyLeftHandLittleIntermediate, "pinky_02_l"); + Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyLeftHandLittleDistal, "pinky_03_l"); + Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyLeftHandLittleTip, NAME_None); + + Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyRightHandPalm, NAME_None); + Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyRightHandWrist, "hand_r"); + Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyRightHandThumbMetacarpal, "thumb_01_r"); + Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyRightHandThumbProximal, "thumb_02_r"); + Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyRightHandThumbDistal, "thumb_03_r"); + Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyRightHandThumbTip, NAME_None); + Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyRightHandIndexMetacarpal, "index_metacarpal_r"); + Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyRightHandIndexProximal, "index_01_r"); + Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyRightHandIndexIntermediate, "index_02_r"); + Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyRightHandIndexDistal, "index_03_r"); + Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyRightHandIndexTip, NAME_None); + Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyRightHandMiddleMetacarpal, "middle_metacarpal_r"); + Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyRightHandMiddleProximal, "middle_01_r"); + Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyRightHandMiddleIntermediate, "middle_02_r"); + Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyRightHandMiddleDistal, "middle_03_r"); + Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyRightHandMiddleTip, NAME_None); + Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyRightHandRingMetacarpal, "ring_metacarpal_r"); + Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyRightHandRingProximal, "ring_01_r"); + Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyRightHandRingIntermediate, "ring_02_r"); + Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyRightHandRingDistal, "ring_03_r"); + Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyRightHandRingTip, NAME_None); + Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyRightHandLittleMetacarpal, "pinky_metacarpal_r"); + Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyRightHandLittleProximal, "pinky_01_r"); + Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyRightHandLittleIntermediate, "pinky_02_r"); + Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyRightHandLittleDistal, "pinky_03_r"); + Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyRightHandLittleTip, NAME_None); + + Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyLeftUpperLeg, "thigh_l"); + Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyLeftLowerLeg, "calf_l"); + Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyLeftFootAnkleTwist, NAME_None); + Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyLeftFootAnkle, "foot_l"); + Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyLeftFootSubtalar, NAME_None); + Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyLeftFootTransverse, NAME_None); + Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyLeftFootBall, "ball_l"); + Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyRightUpperLeg, "thigh_r"); + Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyRightLowerLeg, "calf_r"); + Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyRightFootAnkleTwist, NAME_None); + Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyRightFootAnkle, "foot_r"); + Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyRightFootSubtalar, NAME_None); + Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyRightFootTransverse, NAME_None); + Retargeting->BoneRemapping.Emplace(EOculusXRBoneID::BodyRightFootBall, "ball_r"); + + { + FOculusXRBoneCorrection FromOculusToUnreal; + FromOculusToUnreal.RotationOffset.Roll = -90; + FromOculusToUnreal.RotationOffset.Yaw = -90; + Retargeting->GlobalCorrection = FromOculusToUnreal; + } + { + FOculusXRBoneCorrectionSet Root; + Root.Bones.Add(EOculusXRBoneID::BodyRoot); + Root.BoneCorrection.RotationOffset.Roll = 90; + Retargeting->LocalCorrections.Add(Root); + } + { + FOculusXRBoneCorrectionSet Hips; + Hips.Bones.Add(EOculusXRBoneID::BodyHips); + Hips.BoneCorrection.RotationOffset.Yaw = 5; + Retargeting->LocalCorrections.Add(Hips); + } + { + FOculusXRBoneCorrectionSet SpineLowerPart; + SpineLowerPart.Bones.Add(EOculusXRBoneID::BodySpineLower); + SpineLowerPart.Bones.Add(EOculusXRBoneID::BodySpineMiddle); + SpineLowerPart.BoneCorrection.RotationOffset.Yaw = 10; + Retargeting->LocalCorrections.Add(SpineLowerPart); + } + { + FOculusXRBoneCorrectionSet SpineUpperPart; + SpineUpperPart.Bones.Add(EOculusXRBoneID::BodySpineUpper); + SpineUpperPart.BoneCorrection.PositionOffset.Y = 3; + SpineUpperPart.BoneCorrection.RotationOffset.Yaw = -5; + Retargeting->LocalCorrections.Add(SpineUpperPart); + } + { + FOculusXRBoneCorrectionSet Chest; + Chest.Bones.Add(EOculusXRBoneID::BodyChest); + Chest.BoneCorrection.PositionOffset.Y = 3; + Chest.BoneCorrection.RotationOffset.Yaw = -5; + Retargeting->LocalCorrections.Add(Chest); + } + { + FOculusXRBoneCorrectionSet Head; + Head.Bones.Add(EOculusXRBoneID::BodyHead); + Head.Bones.Add(EOculusXRBoneID::BodyNeck); + Head.BoneCorrection.PositionOffset.Y = -3; + Head.BoneCorrection.RotationOffset.Yaw = 5; + Retargeting->LocalCorrections.Add(Head); + } + { + FOculusXRBoneCorrectionSet LeftShoulder; + LeftShoulder.Bones.Add(EOculusXRBoneID::BodyLeftShoulder); + LeftShoulder.BoneCorrection.RotationOffset.Pitch = -5; + LeftShoulder.BoneCorrection.RotationOffset.Yaw = 30; + LeftShoulder.BoneCorrection.PositionOffset.X = 5; + LeftShoulder.BoneCorrection.PositionOffset.Y = -6; + Retargeting->LocalCorrections.Add(LeftShoulder); + } + { + FOculusXRBoneCorrectionSet RightShoulder; + RightShoulder.Bones.Add(EOculusXRBoneID::BodyRightShoulder); + RightShoulder.BoneCorrection.RotationOffset.Pitch = -5; + RightShoulder.BoneCorrection.RotationOffset.Yaw = 30; + RightShoulder.BoneCorrection.PositionOffset.X = -6; + RightShoulder.BoneCorrection.PositionOffset.Y = 5; + Retargeting->LocalCorrections.Add(RightShoulder); + } + { + FOculusXRBoneCorrectionSet Hands; + for (uint8 BoneId = static_cast(EOculusXRBoneID::BodyLeftHandPalm); BoneId <= static_cast(EOculusXRBoneID::BodyRightHandLittleTip); ++BoneId) + { + Hands.Bones.Emplace(static_cast(BoneId)); + } + Hands.BoneCorrection.RotationOffset.Roll = 180; + Retargeting->LocalCorrections.Add(Hands); + } + { + FOculusXRBoneCorrectionSet Legs; + Legs.Bones.Add(EOculusXRBoneID::BodyLeftUpperLeg); + Legs.Bones.Add(EOculusXRBoneID::BodyLeftLowerLeg); + Legs.Bones.Add(EOculusXRBoneID::BodyRightUpperLeg); + Legs.Bones.Add(EOculusXRBoneID::BodyRightLowerLeg); + Legs.BoneCorrection.RotationOffset.Yaw = 180; + Retargeting->LocalCorrections.Add(Legs); + } + { + FOculusXRBoneCorrectionSet FootAnkles; + FootAnkles.Bones.Add(EOculusXRBoneID::BodyLeftFootAnkle); + FootAnkles.Bones.Add(EOculusXRBoneID::BodyRightFootAnkle); + FootAnkles.BoneCorrection.RotationOffset.Roll = 180; + FootAnkles.BoneCorrection.RotationOffset.Pitch = 175; + FootAnkles.BoneCorrection.RotationOffset.Yaw = -80; + Retargeting->LocalCorrections.Add(FootAnkles); + } + { + FOculusXRBoneCorrectionSet FootBalls; + FootBalls.Bones.Add(EOculusXRBoneID::BodyLeftFootBall); + FootBalls.BoneCorrection.RotationOffset.Yaw = 200; + FootBalls.BoneCorrection.PositionOffset.Y = -5; + FootBalls.BoneCorrection.PositionOffset.Z = 1; + Retargeting->LocalCorrections.Add(FootBalls); + } + { + FOculusXRBoneCorrectionSet FootBalls; + FootBalls.Bones.Add(EOculusXRBoneID::BodyRightFootBall); + FootBalls.BoneCorrection.RotationOffset.Yaw = 200; + FootBalls.BoneCorrection.PositionOffset.Y = 5; + FootBalls.BoneCorrection.PositionOffset.Z = -1; + Retargeting->LocalCorrections.Add(FootBalls); + } + + Retargeting->RetargetingMode = EOculusXRRetargetingMode::RotationsPlusHips; + Retargeting->ForwardMesh = EOculusXRAxis::Y; + } +} + +#undef LOCTEXT_NAMESPACE diff --git a/Plugins/MetaXR/Source/OculusXREditor/Private/OculusXRMovementAssetsFactories.h b/Plugins/MetaXR/Source/OculusXREditor/Private/OculusXRMovementAssetsFactories.h new file mode 100644 index 0000000..3b6c548 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXREditor/Private/OculusXRMovementAssetsFactories.h @@ -0,0 +1,49 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#pragma once + +#include "CoreMinimal.h" +#include "Factories/BlueprintFactory.h" + +#include "OculusXRMovementAssetsFactories.generated.h" + +UCLASS(Abstract, hidecategories = Object, MinimalAPI) +class UOculusXRMetahumanRetargetAssetFactory : public UBlueprintFactory +{ + GENERATED_BODY() +public: + UOculusXRMetahumanRetargetAssetFactory(const FObjectInitializer& ObjectInitializer); + + virtual bool ConfigureProperties() override; + virtual UObject* FactoryCreateNew(UClass* Class, UObject* InParent, FName Name, EObjectFlags Flags, UObject* Context, FFeedbackContext* Warn, FName CallingContext) override; + virtual uint32 GetMenuCategories() const override; + +protected: + virtual void SetDefaults(const TSubclassOf GeneratedClass) const PURE_VIRTUAL(UOculusXRMetahumanRetargetAssetFactory::SetDefaults, ); +}; + +UCLASS(hidecategories = Object, MinimalAPI) +class UOculusXRMetahumanFaceRetargetAssetFactory : public UOculusXRMetahumanRetargetAssetFactory +{ + GENERATED_BODY() +public: + UOculusXRMetahumanFaceRetargetAssetFactory(const FObjectInitializer& ObjectInitializer); + + virtual FText GetDisplayName() const override; + +protected: + virtual void SetDefaults(const TSubclassOf GeneratedClass) const override; +}; + +UCLASS(hidecategories = Object, MinimalAPI) +class UOculusXRMetahumanBodyRetargetAssetFactory : public UOculusXRMetahumanRetargetAssetFactory +{ + GENERATED_BODY() +public: + UOculusXRMetahumanBodyRetargetAssetFactory(const FObjectInitializer& ObjectInitializer); + + virtual FText GetDisplayName() const override; + +protected: + virtual void SetDefaults(const TSubclassOf GeneratedClass) const override; +}; diff --git a/Plugins/MetaXR/Source/OculusXREditor/Private/OculusXRPassthroughColorLutAsset.cpp b/Plugins/MetaXR/Source/OculusXREditor/Private/OculusXRPassthroughColorLutAsset.cpp new file mode 100644 index 0000000..081fdaa --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXREditor/Private/OculusXRPassthroughColorLutAsset.cpp @@ -0,0 +1,59 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#include "OculusXRPassthroughColorLutAsset.h" +#include "AssetTypeCategories.h" +#include "UObject/ObjectMacros.h" +#include "UObject/Object.h" +#include "OculusXRPassthroughColorLut.h" + +#define LOCTEXT_NAMESPACE "AssetTypeActions" + +FText FAssetTypeActions_OculusXRPassthroughColorLut::GetName() const +{ + return NSLOCTEXT("AssetTypeActions", "AssetTypeActions_PassthroughColorLUT", "PassthroughColorLUT"); +} + +FColor FAssetTypeActions_OculusXRPassthroughColorLut::GetTypeColor() const +{ + return FColor(100, 100, 100); +} + +const TArray& FAssetTypeActions_OculusXRPassthroughColorLut::GetSubMenus() const +{ + static const TArray SubMenus{ + LOCTEXT("AssetOculusXRPassthroughColorLutSubMenu", "OculusXR") + }; + + return SubMenus; +} + +UClass* FAssetTypeActions_OculusXRPassthroughColorLut::GetSupportedClass() const +{ + return UOculusXRPassthroughColorLut::StaticClass(); +} + +uint32 FAssetTypeActions_OculusXRPassthroughColorLut::GetCategories() +{ + return EAssetTypeCategories::Misc; +} + +UOculusXRPassthroughColorLutFactory::UOculusXRPassthroughColorLutFactory(const FObjectInitializer& ObjectInitializer) + : Super(ObjectInitializer) +{ + SupportedClass = UOculusXRPassthroughColorLut::StaticClass(); + + bCreateNew = true; + bEditAfterNew = true; +} + +UObject* UOculusXRPassthroughColorLutFactory::FactoryCreateNew(UClass* Class, UObject* InParent, FName Name, EObjectFlags Flags, UObject* Context, + FFeedbackContext* Warn) +{ + return NewObject(InParent, Name, Flags); +} + +uint32 UOculusXRPassthroughColorLutFactory::GetMenuCategories() const +{ + return EAssetTypeCategories::Misc; +} +#undef LOCTEXT_NAMESPACE diff --git a/Plugins/MetaXR/Source/OculusXREditor/Private/OculusXRPassthroughColorLutAsset.h b/Plugins/MetaXR/Source/OculusXREditor/Private/OculusXRPassthroughColorLutAsset.h new file mode 100644 index 0000000..c2fdbad --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXREditor/Private/OculusXRPassthroughColorLutAsset.h @@ -0,0 +1,33 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#pragma once + +#include "CoreMinimal.h" +#include "Factories/Factory.h" +#include "AssetTypeActions_Base.h" + +#include "OculusXRPassthroughColorLutAsset.generated.h" + +class FAssetTypeActions_OculusXRPassthroughColorLut : public FAssetTypeActions_Base +{ +public: + virtual FText GetName() const override; + virtual FColor GetTypeColor() const override; + virtual const TArray& GetSubMenus() const override; + virtual UClass* GetSupportedClass() const override; + virtual uint32 GetCategories() override; +}; + +UCLASS(hidecategories = Object, MinimalAPI) +class UOculusXRPassthroughColorLutFactory : public UFactory +{ + GENERATED_BODY() + +public: + UOculusXRPassthroughColorLutFactory(const FObjectInitializer& ObjectInitializer); + + virtual UObject* FactoryCreateNew(UClass* Class, UObject* InParent, FName Name, EObjectFlags Flags, UObject* Context, + FFeedbackContext* Warn) override; + + virtual uint32 GetMenuCategories() const override; +}; diff --git a/Plugins/MetaXR/Source/OculusXREditor/Private/OculusXRPlatformToolSettings.cpp b/Plugins/MetaXR/Source/OculusXREditor/Private/OculusXRPlatformToolSettings.cpp new file mode 100644 index 0000000..e22aca1 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXREditor/Private/OculusXRPlatformToolSettings.cpp @@ -0,0 +1,25 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +#include "OculusXRPlatformToolSettings.h" + +UOculusXRPlatformToolSettings::UOculusXRPlatformToolSettings() + : OculusTargetPlatform(EOculusXRPlatformTarget::Rift) +{ + uint8 NumPlatforms = (uint8)EOculusXRPlatformTarget::Length; + OculusApplicationID.Init("", NumPlatforms); + OculusApplicationToken.Init("", NumPlatforms); + OculusReleaseChannel.Init("Alpha", NumPlatforms); + OculusReleaseNote.Init("", NumPlatforms); + OculusLaunchFilePath.Init("", NumPlatforms); + OculusSymbolDirPath.Init("", NumPlatforms); + OculusLanguagePacksPath.Init("", NumPlatforms); + OculusExpansionFilesPath.Init("", NumPlatforms); + OculusAssetConfigs.Init(FOculusXRAssetConfigArray(), NumPlatforms); + UploadDebugSymbols = true; + + for (int i = 0; i < NumPlatforms; i++) + { + OculusAssetConfigs[i].ConfigArray = TArray(); + } +} diff --git a/Plugins/MetaXR/Source/OculusXREditor/Private/OculusXRPlatformToolWidget.cpp b/Plugins/MetaXR/Source/OculusXREditor/Private/OculusXRPlatformToolWidget.cpp new file mode 100644 index 0000000..51c051e --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXREditor/Private/OculusXRPlatformToolWidget.cpp @@ -0,0 +1,1650 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. +#include "OculusXRPlatformToolWidget.h" +#include "Widgets/Text/SRichTextBlock.h" +#include "DesktopPlatformModule.h" +#include "Editor.h" +#include "Styling/AppStyle.h" +#include "Misc/FileHelper.h" +#include "Internationalization/Regex.h" +#include "Misc/MessageDialog.h" +#include "Widgets/Layout/SExpandableArea.h" +#include "Widgets/Images/SImage.h" +#include "HAL/FileManagerGeneric.h" +#include "DOM/JsonObject.h" +#include "Serialization/JsonSerializer.h" +#include "OculusXRHMDModule.h" +#include "GenericPlatform/GenericPlatformMisc.h" +#include "Interfaces/IPluginManager.h" +#include "SHyperlinkLaunchURL.h" +#include "Misc/EngineVersionComparison.h" + +#define LOCTEXT_NAMESPACE "OculusPlatformToolWidget" +#define TEXT_INDENT_OFFSET 20.0f + +const FString UrlPlatformUtil = "https://www.oculus.com/download_app/?id=1076686279105243"; +const FString ProjectPlatformUtilPath = "Oculus/Tools/ovr-platform-util.exe"; + +FText OculusPlatformDialogTitle = LOCTEXT("DownloadOculusPlatformUtility", "Download Oculus Platform Utility"); +FText OculusPlatformDialogMessage = LOCTEXT("DownloadOculusPlatformUtilityMessage", + "Oculus Platform Window would like to download the latest version of the Oculus Platform Utility." + " Oculus Platform Utility is a command-line tool that enables the uploading of builds to your release channels on the Oculus Developer Dashboard." + "\n\nYou can learn more about the Oculus Platform Utility at https://developer.oculus.com/distribute/publish-reference-platform-command-line-utility/" + "\n\nCanceling will prevent the download and the UPLOAD button will be unfunctional. Would you like the tool to download the Oculus Platform Utility to your project?"); + +static bool bShowUploadDebugSymbols = false; + +FString SOculusPlatformToolWidget::LogText; + +SOculusPlatformToolWidget::SOculusPlatformToolWidget() +{ + LogTextUpdated = false; + ActiveUploadButton = true; + Options2DCollapsed = true; + RequestUploadButtonActive = true; + OptionsRedistPackagesCollapsed = true; + + EnableUploadButtonDel.BindRaw(this, &SOculusPlatformToolWidget::EnableUploadButton); + UpdateLogTextDel.BindRaw(this, &SOculusPlatformToolWidget::UpdateLogText); + SetProcessDel.BindRaw(this, &SOculusPlatformToolWidget::SetPlatformProcess); + + LoadConfigSettings(); + + FOculusXRHMDModule::GetPluginWrapper().SendEvent2("oculus_platform_tool", "show_window", "integration"); +} + +void SOculusPlatformToolWidget::Tick(const FGeometry& AllottedGeometry, const double InCurrentTime, const float InDeltaTime) +{ + // Update log text if it changes, otherwise constant updating will yeild the field unselectable. + if (LogTextUpdated) + { + ToolConsoleLog->SetText(FText::FromString(LogText)); + LogTextUpdated = false; + } + + if (RequestUploadButtonActive != ActiveUploadButton) + { + ActiveUploadButton = RequestUploadButtonActive; + BuildButtonToolbar(ButtonToolbar); + } +} + +void SOculusPlatformToolWidget::Construct(const FArguments& InArgs) +{ + auto logTextBox = SNew(SMultiLineEditableTextBox).IsReadOnly(true); + ToolConsoleLog = logTextBox; + + auto mainVerticalBox = SNew(SVerticalBox); + GeneralSettingsBox = mainVerticalBox; + + auto buttonToolbarBox = SNew(SHorizontalBox); + ButtonToolbar = buttonToolbarBox; + + auto optionalSettings = SNew(SVerticalBox); + OptionalSettings = optionalSettings; + + auto expansionFilesSettings = SNew(SVerticalBox); + ExpansionFilesSettings = expansionFilesSettings; + + BuildGeneralSettingsBox(GeneralSettingsBox); + BuildButtonToolbar(ButtonToolbar); + BuildExpansionFileBox(ExpansionFilesSettings); + + if (PlatformSettings != nullptr) + { + if (PlatformSettings->GetTargetPlatform() == (uint8)EOculusXRPlatformTarget::Rift) + { + BuildRiftOptionalFields(OptionalSettings); + } + else + { + OptionalSettings.Get()->ClearChildren(); + } + } + + FString ODHIconPath = IPluginManager::Get().FindPlugin(TEXT("OculusXR"))->GetBaseDir() / TEXT("Resources/Icon128.png"); + const FName BrushName(*ODHIconPath); + FSlateApplication::Get().GetRenderer()->GenerateDynamicImageResource(BrushName); + ODHIconDynamicImageBrush = MakeShareable(new FSlateDynamicImageBrush(BrushName, FVector2D(60.0f, 60.0f))); + +#if PLATFORM_MAC + FString odhLink = "https://developer.oculus.com/downloads/package/oculus-developer-hub-mac/?source=unreal"; +#else + FString odhLink = "https://developer.oculus.com/downloads/package/oculus-developer-hub-win/?source=unreal"; +#endif + + ChildSlot + [SNew(SBorder) + .BorderImage(FAppStyle::GetBrush("ToolPanel.LightGroupBorder")) + .Padding(2) + [SNew(SVerticalBox) + + SVerticalBox::Slot().Padding(0, 0).FillHeight(1.f) + [SNew(SScrollBox) + + SScrollBox::Slot() + [SNew(SExpandableArea) + .HeaderPadding(5) + .Padding(5) + .BorderBackgroundColor(FLinearColor(0.4f, 0.4f, 0.4f, 1.0f)) + .BodyBorderImage(FAppStyle::GetBrush("ToolPanel.GroupBorder")) + .BodyBorderBackgroundColor(FLinearColor::White) + .InitiallyCollapsed(false) + .HeaderContent() + [SNew(SRichTextBlock) + .TextStyle(FAppStyle::Get(), "ToolBar.Heading") + .DecoratorStyleSet(&FAppStyle::Get()) + .AutoWrapText(true) + .Text(LOCTEXT("GeneralSettings", "General Settings"))] + .BodyContent() + [mainVerticalBox]] + + SScrollBox::Slot() + [SNew(SExpandableArea) + .HeaderPadding(5) + .Padding(5) + .BorderBackgroundColor(FLinearColor(0.4f, 0.4f, 0.4f, 1.0f)) + .BodyBorderImage(FAppStyle::GetBrush("ToolPanel.GroupBorder")) + .BodyBorderBackgroundColor(FLinearColor::White) + .InitiallyCollapsed(true) + .HeaderContent() + [SNew(SRichTextBlock) + .TextStyle(FAppStyle::Get(), "ToolBar.Heading") + .DecoratorStyleSet(&FAppStyle::Get()) + .AutoWrapText(true) + .Text(LOCTEXT("OptionalSettings", "Optional Settings"))] + .BodyContent() + [SNew(SVerticalBox) + + SVerticalBox::Slot().AutoHeight() + [optionalSettings]]] + + SScrollBox::Slot() + [SNew(SExpandableArea) + .HeaderPadding(5) + .Padding(5) + .BorderBackgroundColor(FLinearColor(0.4f, 0.4f, 0.4f, 1.0f)) + .BodyBorderImage(FAppStyle::GetBrush("ToolPanel.GroupBorder")) + .BodyBorderBackgroundColor(FLinearColor::White) + .InitiallyCollapsed(true) + .HeaderContent() + [SNew(SRichTextBlock) + .TextStyle(FAppStyle::Get(), "ToolBar.Heading") + .DecoratorStyleSet(&FAppStyle::Get()) + .AutoWrapText(true) + .Text(LOCTEXT("ExpansionFileSettings", "Expansion Files"))] + .BodyContent() + [SNew(SVerticalBox) + + SVerticalBox::Slot().AutoHeight() + [expansionFilesSettings]]]] + + SVerticalBox::Slot().AutoHeight() + [buttonToolbarBox] + + SVerticalBox::Slot().FillHeight(1.f) + [SNew(SBorder) + .BorderImage(FAppStyle::GetBrush("ToolPanel.GroupBorder")) + [logTextBox]] + + SVerticalBox::Slot().AutoHeight().Padding(2.0f) + [SNew(SBorder) + .BorderImage(FAppStyle::GetBrush("ToolPanel.GroupBorder")) + [SNew(SHorizontalBox) + + SHorizontalBox::Slot().AutoWidth() + [SNew(SBox) + .WidthOverride(60.0f) + .HeightOverride(60.0f) + [SNew(SImage) + .Image(ODHIconDynamicImageBrush.IsValid() ? ODHIconDynamicImageBrush.Get() : nullptr)]] + + SHorizontalBox::Slot().FillWidth(1.0f) + [SNew(SVerticalBox) + + SVerticalBox::Slot().AutoHeight().Padding(2.0f) + [SNew(SRichTextBlock) + .Text(LOCTEXT("ODHCallout", + "Oculus Developer Hub is a desktop companion tool that can upload builds, manage apps and reduce friction in daily Quest development.")) + .DecoratorStyleSet(&FAppStyle::Get()) + .AutoWrapText(true)] + + SVerticalBox::Slot().AutoHeight() + [SNew(SBox) + .HAlign(HAlign_Left) + [SNew(SHyperlinkLaunchURL, odhLink) + .Text(LOCTEXT("ODHDownloadPage", "Download Oculus Developer Hub")) + .ToolTipText(LOCTEXT("ODHDownloadPageTooltip", "Opens a page that provides the download link for Oculus Developer Hub"))]]]]]]]; +} + +void SOculusPlatformToolWidget::BuildGeneralSettingsBox(TSharedPtr box) +{ + if (PlatformSettings == nullptr) + { + return; + } + + box.Get()->ClearChildren(); + + BuildTextComboBoxField(GeneralSettingsBox, LOCTEXT("TargetPlatform", "Target Platform"), + &OculusPlatforms, OculusPlatforms[PlatformSettings->GetTargetPlatform()], + &SOculusPlatformToolWidget::OnPlatformSettingChanged); + + // Build field for Oculus Application ID. + BuildTextField(box, LOCTEXT("AppID", "Oculus Application ID"), FText::FromString(PlatformSettings->GetApplicationID()), + LOCTEXT("AppIDTT", "Specifies the ID of your app. Obtained from the API tab of your app in the Oculus Dashboard."), + &SOculusPlatformToolWidget::OnApplicationIDChanged); + + // Build field for Oculus Application Token. + BuildTextField(box, LOCTEXT("AppToken", "Oculus Application Token"), FText::FromString(PlatformSettings->GetApplicationToken()), + LOCTEXT("AppTokenTT", "Specifies the app secret token. Obtained from the API tab of your app in the Oculus Dashboard."), + &SOculusPlatformToolWidget::OnApplicationTokenChanged, true); + + // Build field for Release Channel. + BuildTextField(box, LOCTEXT("ReleaseChannel", "Release Channel"), FText::FromString(PlatformSettings->GetReleaseChannel()), + LOCTEXT("ReleaseChannelTT", "Specifies the release channel for uploading the build. Release channel names are not case-sensitive."), + &SOculusPlatformToolWidget::OnReleaseChannelChanged); + + // Build field for Release Notes. + BuildTextField(box, LOCTEXT("ReleaseNote", "Release Note"), FText::FromString(PlatformSettings->GetReleaseNote()), + LOCTEXT("ReleaseNoteTT", "Specifies the release note text shown to users."), + &SOculusPlatformToolWidget::OnReleaseNoteChanged); + + // Platform specific fields. + if (PlatformSettings->GetTargetPlatform() == (uint8)EOculusXRPlatformTarget::Rift) + { + // Build field for Rift Build Directory. + BuildFileDirectoryField(box, LOCTEXT("BuildPath", "Rift Build Directory"), FText::FromString(PlatformSettings->OculusRiftBuildDirectory), + LOCTEXT("BuildPathTT", "Specifies the full path to the directory containing your build files."), + &SOculusPlatformToolWidget::OnSelectRiftBuildDirectory, &SOculusPlatformToolWidget::OnClearRiftBuildDirectory); + + // Build field for Build Version. + BuildTextField(box, LOCTEXT("BuildVersion", "Build Version"), FText::FromString(PlatformSettings->OculusRiftBuildVersion), + LOCTEXT("BuildVersionTT", "Specifies the version number shown to users."), + &SOculusPlatformToolWidget::OnRiftBuildVersionChanged); + + // Build field for Launch File Path. + BuildFileDirectoryField(box, LOCTEXT("LaunchPath", "Launch File Path"), FText::FromString(PlatformSettings->GetLaunchFilePath()), + LOCTEXT("LaunchPathTT", " Specifies the path to the executable that launches your app."), + &SOculusPlatformToolWidget::OnSelectLaunchFilePath, &SOculusPlatformToolWidget::OnClearLaunchFilePath); + } + else + { + // Build field for APK File Path. + BuildFileDirectoryField(box, LOCTEXT("APKLaunchPath", "APK File Path"), FText::FromString(PlatformSettings->GetLaunchFilePath()), + LOCTEXT("APKLaunchPathTT", " Specifies the path to the APK that launches your app."), + &SOculusPlatformToolWidget::OnSelectLaunchFilePath, &SOculusPlatformToolWidget::OnClearLaunchFilePath); + + BuildCheckBoxField(box, LOCTEXT("UploadDebugSymbols", "Upload Debug Symbols"), PlatformSettings->UploadDebugSymbols, + LOCTEXT("UploadDebugSymbolsTT", "If checked, debug symbols will be uploaded along with the application."), + &SOculusPlatformToolWidget::OnUploadDebugSymbolsChanged); + + if (PlatformSettings->UploadDebugSymbols) + { + if (bShowUploadDebugSymbols != PlatformSettings->UploadDebugSymbols) + { + if (PlatformSettings->GetSymbolDirPath().IsEmpty()) + { + FString defaultPath = GenerateSymbolPath(); + PlatformSettings->SetSymbolDirPath(FPaths::ConvertRelativePathToFull(defaultPath)); + PlatformSettings->SaveConfig(); + } + } + + // Build field for Debug symbol directory path. + BuildFileDirectoryField(box, LOCTEXT("SymbolPath", "Symbol Directory Path"), FText::FromString(PlatformSettings->GetSymbolDirPath()), + LOCTEXT("SymbolPathTT", "Specifies the path to the directory containing the app symbols (libUE4.so)."), + &SOculusPlatformToolWidget::OnSelectSymbolDirPath, &SOculusPlatformToolWidget::OnClearSymbolDirPath, 1); + + BuildCheckBoxField(box, LOCTEXT("DebugSymbolsOnly", "Upload Debug Symbols Only"), PlatformSettings->DebugSymbolsOnly, + LOCTEXT("DebugSymbolsOnlyTT", "If checked, the tool will upload onyl debug symbols to an existing build. Requires Build ID, App ID, App Token, and Debug Symbols Directory."), + &SOculusPlatformToolWidget::OnDebugSymbolsOnlyChanged, 1); + + if (PlatformSettings->DebugSymbolsOnly) + { + BuildTextField(box, LOCTEXT("BuildID", "Build ID"), FText::FromString(PlatformSettings->BuildID), + LOCTEXT("BuildIDTT", "Specifies the Build ID to upload debug symbols to."), + &SOculusPlatformToolWidget::OnBuildIDChanged, false, 1); + } + } + bShowUploadDebugSymbols = PlatformSettings->UploadDebugSymbols; + } +} + +void SOculusPlatformToolWidget::BuildTextField(TSharedPtr box, FText name, FText text, FText tooltip, + PTextComittedDel deleg, bool isPassword, int32 indentAmount) +{ + FMargin textMargin = FMargin(TEXT_INDENT_OFFSET * indentAmount, 1.0f, 1.0f, 1.0f); + + box.Get()->AddSlot().Padding(1).AutoHeight() + [SNew(SHorizontalBox) + + SHorizontalBox::Slot().Padding(1).AutoWidth() + [SNew(SBox) + .WidthOverride(250.f) + .Padding(textMargin) + [SNew(STextBlock) + .Text(name) + .ToolTipText(tooltip)]] + + SHorizontalBox::Slot().Padding(1).FillWidth(1.f) + [SNew(SEditableTextBox) + .Text(text) + .IsPassword(isPassword) + .OnTextCommitted(this, deleg)]]; +} + +void SOculusPlatformToolWidget::BuildTextComboBoxField(TSharedPtr box, FText name, + TArray>* options, TSharedPtr current, PTextComboBoxDel deleg, int32 indentAmount) +{ + FMargin textMargin = FMargin(TEXT_INDENT_OFFSET * indentAmount, 1.0f, 1.0f, 1.0f); + + box.Get()->AddSlot().Padding(1).AutoHeight() + [SNew(SHorizontalBox) + + SHorizontalBox::Slot().Padding(1).AutoWidth() + [SNew(SBox) + .WidthOverride(250.f) + .Padding(textMargin) + [SNew(SRichTextBlock) + .DecoratorStyleSet(&FAppStyle::Get()) + .Text(name)]] + + SHorizontalBox::Slot().Padding(1).FillWidth(1.f) + [SNew(STextComboBox) + .OptionsSource(options) + .InitiallySelectedItem(current) + .OnSelectionChanged(this, deleg)]]; +} + +void SOculusPlatformToolWidget::BuildCheckBoxField(TSharedPtr box, FText name, bool check, + FText tooltip, PCheckBoxChangedDel deleg, int32 indentAmount) +{ + FMargin textMargin = FMargin(TEXT_INDENT_OFFSET * indentAmount, 1.0f, 1.0f, 1.0f); + + box.Get()->AddSlot().Padding(1).AutoHeight() + [SNew(SHorizontalBox) + + SHorizontalBox::Slot().Padding(1).AutoWidth() + [SNew(SBox) + .WidthOverride(250.f) + .Padding(textMargin) + [SNew(SRichTextBlock) + .DecoratorStyleSet(&FAppStyle::Get()) + .Text(name)]] + + SHorizontalBox::Slot().Padding(1).FillWidth(1.f) + [SNew(SCheckBox) + .OnCheckStateChanged(this, deleg) + .IsChecked(check ? ECheckBoxState::Checked : ECheckBoxState::Unchecked)]]; +} + +void SOculusPlatformToolWidget::BuildFileDirectoryField(TSharedPtr box, FText name, FText path, FText tooltip, + PButtonClickedDel deleg, PButtonClickedDel clearDeleg, int32 indentAmount) +{ + EVisibility cancelButtonVisibility = path.IsEmpty() ? EVisibility::Hidden : EVisibility::Visible; + FMargin textMargin = FMargin(TEXT_INDENT_OFFSET * indentAmount, 1.0f, 1.0f, 1.0f); + + box.Get()->AddSlot().Padding(1).AutoHeight() + [SNew(SHorizontalBox) + + SHorizontalBox::Slot().Padding(1).AutoWidth() + [SNew(SBox) + .WidthOverride(250.f) + .Padding(textMargin) + [SNew(STextBlock) + .Text(name) + .ToolTipText(tooltip)]] + + SHorizontalBox::Slot().Padding(1).FillWidth(1.f) + [SNew(SEditableText) + .Text(path) + .IsReadOnly(true) + .Justification(ETextJustify::Left)] + + SHorizontalBox::Slot().Padding(1).AutoWidth().HAlign(EHorizontalAlignment::HAlign_Right) + [SNew(SButton) + .Text(FText::FromString("X")) + .Visibility(cancelButtonVisibility) + .OnClicked(this, clearDeleg) + .ButtonColorAndOpacity(FLinearColor(0.36f, 0.1f, 0.05f))] + + SHorizontalBox::Slot().Padding(1).AutoWidth().HAlign(EHorizontalAlignment::HAlign_Right) + [SNew(SButton) + .Text((LOCTEXT("Choose", "Choose..."))) + .OnClicked(this, deleg)]]; +} + +void SOculusPlatformToolWidget::BuildButtonToolbar(TSharedPtr box) +{ + box.Get()->ClearChildren(); + + box.Get()->AddSlot().FillWidth(1.f); + box.Get()->AddSlot().AutoWidth().Padding(2.f) + [SNew(SButton) + .Text((LOCTEXT("Upload", "Upload"))) + .OnClicked(this, &SOculusPlatformToolWidget::OnStartPlatformUpload) + .IsEnabled(ActiveUploadButton)]; + box.Get()->AddSlot().AutoWidth().Padding(2.f) + [SNew(SButton) + .Text((LOCTEXT("Cancel", "Cancel"))) + .OnClicked(this, &SOculusPlatformToolWidget::OnCancelUpload) + .IsEnabled(!ActiveUploadButton)]; + box.Get()->AddSlot().FillWidth(1.f); +} + +void SOculusPlatformToolWidget::BuildRiftOptionalFields(TSharedPtr box) +{ + if (PlatformSettings == nullptr) + { + return; + } + + box.Get()->ClearChildren(); + + // Add Launch Parameter Field + BuildTextField(box, LOCTEXT("LaunchParams", "Launch Parameters"), FText::FromString(PlatformSettings->OculusRiftLaunchParams), + LOCTEXT("LaunchParamsTT", ""), + &SOculusPlatformToolWidget::OnRiftLaunchParamsChanged); + + // Add Firewall Exception Toggle + BuildCheckBoxField(box, LOCTEXT("Firewall", "Firewall Exception"), PlatformSettings->OculusRiftFireWallException, + LOCTEXT("FirewallTT", ""), + &SOculusPlatformToolWidget::OnRiftFirewallChanged); + + // Add Gamepad Emulation Dropdown + BuildTextComboBoxField(box, LOCTEXT("GamepadEmu", "Gamepad Emulation"), + &RiftGamepadEmulation, RiftGamepadEmulation[(uint8)PlatformSettings->GetRiftGamepadEmulation()], + &SOculusPlatformToolWidget::OnRiftGamepadEmulationChanged); + + // Generate 2D Settings Expandable Area + TSharedRef settings2DBox = SNew(SVerticalBox); + + // Add 2D Launch File Field + BuildFileDirectoryField(settings2DBox, LOCTEXT("2DLaunch", "2D Launch File"), FText::FromString(PlatformSettings->OculusRift2DLaunchPath), + LOCTEXT("2DLaunchPathTT", ""), + &SOculusPlatformToolWidget::OnSelect2DLaunchPath, &SOculusPlatformToolWidget::OnClear2DLaunchPath); + + // Add 2D Launch Parameter Field + BuildTextField(settings2DBox, LOCTEXT("2DLaunchParams", "2D Launch Parameters"), FText::FromString(PlatformSettings->OculusRift2DLaunchParams), + LOCTEXT("2DLaunchParamsTT", ""), + &SOculusPlatformToolWidget::On2DLaunchParamsChanged); + + box.Get()->AddSlot().AutoHeight().Padding(1) + [SNew(SExpandableArea) + .HeaderPadding(5) + .Padding(5) + .BorderBackgroundColor(FLinearColor(0.4f, 0.4f, 0.4f, 1.0f)) + .BodyBorderImage(FAppStyle::GetBrush("ToolPanel.GroupBorder")) + .BodyBorderBackgroundColor(FLinearColor::White) + .InitiallyCollapsed(Options2DCollapsed) + .OnAreaExpansionChanged(this, &SOculusPlatformToolWidget::On2DOptionsExpanded) + .HeaderContent() + [SNew(SRichTextBlock) + .TextStyle(FAppStyle::Get(), "ToolBar.Heading") + .DecoratorStyleSet(&FAppStyle::Get()) + .AutoWrapText(true) + .Text(LOCTEXT("2DSettings", "2D Settings"))] + .BodyContent() + [settings2DBox]]; + + BuildRedistPackagesBox(box); +} + +void SOculusPlatformToolWidget::BuildRedistPackagesBox(TSharedPtr box) +{ + // Create check box toggle for each redistributable package we loaded + TSharedRef redistBox = SNew(SVerticalBox); + for (int i = 0; i < PlatformSettings->OculusRedistPackages.Num(); i++) + { + FOculusXRRedistPackage* Package = &PlatformSettings->OculusRedistPackages[i]; + redistBox->AddSlot() + .Padding(1) + .AutoHeight() + [SNew(SHorizontalBox) + + SHorizontalBox::Slot().Padding(1).AutoWidth() + [SNew(SBox) + .WidthOverride(250.f) + [SNew(SRichTextBlock) + .DecoratorStyleSet(&FAppStyle::Get()) + .Text(FText::FromString(Package->Name))]] + + SHorizontalBox::Slot().Padding(1).FillWidth(1.f) + [SNew(SCheckBox) + .OnCheckStateChanged(this, &SOculusPlatformToolWidget::OnRedistPackageStateChanged, Package) + .IsChecked(Package->Included ? ECheckBoxState::Checked : ECheckBoxState::Unchecked)]]; + } + + box.Get()->AddSlot().AutoHeight().Padding(1) + [SNew(SExpandableArea) + .HeaderPadding(5) + .Padding(5) + .BorderBackgroundColor(FLinearColor(0.4f, 0.4f, 0.4f, 1.0f)) + .BodyBorderImage(FAppStyle::GetBrush("ToolPanel.GroupBorder")) + .BodyBorderBackgroundColor(FLinearColor::White) + .InitiallyCollapsed(OptionsRedistPackagesCollapsed) + .OnAreaExpansionChanged(this, &SOculusPlatformToolWidget::OnRedistPackagesExpanded) + .HeaderContent() + [SNew(SRichTextBlock) + .TextStyle(FAppStyle::Get(), "ToolBar.Heading") + .DecoratorStyleSet(&FAppStyle::Get()) + .AutoWrapText(true) + .Text(LOCTEXT("RedistPack", "Redistributable Packages"))] + .BodyContent() + [redistBox]]; +} + +void SOculusPlatformToolWidget::BuildExpansionFileBox(TSharedPtr box) +{ + if (PlatformSettings == nullptr) + { + return; + } + + ExpansionFilesSettings.Get()->ClearChildren(); + + if (PlatformSettings->GetTargetPlatform() == (uint8)EOculusXRPlatformTarget::Rift) + { + BuildFileDirectoryField(box, LOCTEXT("LanguagePacks", "Language Packs Directory"), FText::FromString(PlatformSettings->GetLanguagePacksPath()), + LOCTEXT("LanguagePacksTT", ""), &SOculusPlatformToolWidget::OnSelectLanguagePacksPath, &SOculusPlatformToolWidget::OnClearLanguagePacksPath); + } + + BuildFileDirectoryField(box, LOCTEXT("ExpansionFilesDirectory", "Expansion Files Directory"), FText::FromString(PlatformSettings->GetExpansionFilesPath()), + LOCTEXT("ExpansionFilesTT", ""), &SOculusPlatformToolWidget::OnSelectExpansionFilesPath, &SOculusPlatformToolWidget::OnClearExpansionFilesPath); + + TArray* AssetConfigs = PlatformSettings->GetAssetConfigs(); + if (AssetConfigs) + { + for (int i = 0; i < AssetConfigs->Num(); i++) + { + auto AssetConfigBox = SNew(SVerticalBox); + BuildAssetConfigBox(AssetConfigBox, (*AssetConfigs)[i], i); + + box.Get()->AddSlot().AutoHeight().Padding(1) + [SNew(SExpandableArea) + .HeaderPadding(5) + .Padding(5) + .BorderBackgroundColor(FLinearColor(0.4f, 0.4f, 0.4f, 1.0f)) + .BodyBorderImage(FAppStyle::GetBrush("ToolPanel.GroupBorder")) + .BodyBorderBackgroundColor(FLinearColor::White) + .HeaderContent() + [SNew(SRichTextBlock) + .TextStyle(FAppStyle::Get(), "ToolBar.Heading") + .DecoratorStyleSet(&FAppStyle::Get()) + .AutoWrapText(true) + .Text(FText::FromString((*AssetConfigs)[i].Name))] + .BodyContent() + [AssetConfigBox]]; + } + } +} + +void SOculusPlatformToolWidget::BuildAssetConfigBox(TSharedPtr box, FOculusXRAssetConfig config, int index) +{ + box.Get()->AddSlot().Padding(1).AutoHeight() + [SNew(SHorizontalBox) + + SHorizontalBox::Slot().Padding(1).AutoWidth() + [SNew(SBox) + .WidthOverride(250.f) + [SNew(SRichTextBlock) + .DecoratorStyleSet(&FAppStyle::Get()) + .Text(LOCTEXT("AssetType", "Asset Type"))]] + + SHorizontalBox::Slot().Padding(1).FillWidth(1.f) + [SNew(STextComboBox) + .OptionsSource(&AssetType) + .InitiallySelectedItem(AssetType[(uint8)config.AssetType]) + .OnSelectionChanged(this, &SOculusPlatformToolWidget::OnAssetConfigTypeChanged, index)]]; + + box.Get()->AddSlot().Padding(1).AutoHeight() + [SNew(SHorizontalBox) + + SHorizontalBox::Slot().Padding(1).AutoWidth() + [SNew(SBox) + .WidthOverride(250.f) + [SNew(SRichTextBlock) + .DecoratorStyleSet(&FAppStyle::Get()) + .Text(LOCTEXT("AssetRequired", "Required"))]] + + SHorizontalBox::Slot().Padding(1).FillWidth(1.f) + [SNew(SCheckBox) + .OnCheckStateChanged(this, &SOculusPlatformToolWidget::OnAssetConfigRequiredChanged, index) + .IsChecked(config.Required ? ECheckBoxState::Checked : ECheckBoxState::Unchecked)]]; + + box.Get()->AddSlot().Padding(1).AutoHeight() + [SNew(SHorizontalBox) + + SHorizontalBox::Slot().Padding(1).AutoWidth() + [SNew(SBox) + .WidthOverride(250.f) + [SNew(STextBlock) + .Text(LOCTEXT("SKU", "SKU"))]] + + SHorizontalBox::Slot().Padding(1).FillWidth(1.f) + [SNew(SEditableTextBox) + .Text(FText::FromString(config.Sku)) + .OnTextCommitted(this, &SOculusPlatformToolWidget::OnAssetConfigSKUChanged, index)]]; +} + +bool SOculusPlatformToolWidget::ConstructArguments(FString& args) +{ + if (PlatformSettings == nullptr) + { + return false; + } + + if (PlatformSettings->UploadDebugSymbols && PlatformSettings->DebugSymbolsOnly) + { + return ConstructDebugSymbolArguments(args); + } + + // Build the args string that will be passed to the CLI. Print all errors that occur to the log. + bool success = true; + + switch (PlatformSettings->GetTargetPlatform()) + { + case (uint8)EOculusXRPlatformTarget::Rift: + args = "upload-rift-build"; + break; + case (uint8)EOculusXRPlatformTarget::Quest: + args = "upload-quest-build"; + break; + default: + UpdateLogText(LogText + "ERROR: Invalid target platform selected"); + success = false; + break; + } + + // Oculus Application ID check and command. + ValidateTextField(&SOculusPlatformToolWidget::IDFieldValidator, PlatformSettings->GetApplicationID(), + LOCTEXT("ApplicationID", "Application ID").ToString(), success); + args += " --app_id \"" + PlatformSettings->GetApplicationID() + "\""; + + // Oculus Application Token check and command. + ValidateTextField(&SOculusPlatformToolWidget::GenericFieldValidator, PlatformSettings->GetApplicationToken(), + LOCTEXT("ApplicationToken", "Application Token").ToString(), success); + args += " --app_secret \"" + PlatformSettings->GetApplicationToken() + "\""; + + // Release Channel check and command. + ValidateTextField(&SOculusPlatformToolWidget::GenericFieldValidator, PlatformSettings->GetReleaseChannel(), + LOCTEXT("ReleaseChannel", "Release Channel").ToString(), success); + args += " --channel \"" + PlatformSettings->GetReleaseChannel() + "\""; + + // Release Note check and command. Not a required command. + if (!PlatformSettings->GetReleaseNote().IsEmpty()) + { + FString SanatizedReleaseNote = PlatformSettings->GetReleaseNote(); + SanatizedReleaseNote = SanatizedReleaseNote.Replace(TEXT("\""), TEXT("\"\"")); + args += " --notes \"" + SanatizedReleaseNote + "\""; + } + + // Platform specific commands + if (PlatformSettings->GetTargetPlatform() == (uint8)EOculusXRPlatformTarget::Rift) + { + // Launch File Path check and command. + ValidateTextField(&SOculusPlatformToolWidget::FileFieldValidator, PlatformSettings->GetLaunchFilePath(), + LOCTEXT("LaunchFile", "Launch File Path").ToString(), success); + args += " --launch-file \"" + PlatformSettings->GetLaunchFilePath() + "\""; + + // Rift Build Directory check and command. + ValidateTextField(&SOculusPlatformToolWidget::DirectoryFieldValidator, PlatformSettings->OculusRiftBuildDirectory, + LOCTEXT("RiftBuildDir", "Rift Build Directory").ToString(), success); + args += " --build_dir \"" + PlatformSettings->OculusRiftBuildDirectory + "\""; + + // Rift Build Version check and command. + ValidateTextField(&SOculusPlatformToolWidget::GenericFieldValidator, PlatformSettings->OculusRiftBuildVersion, + LOCTEXT("BuildVersion", "Build Version").ToString(), success); + args += " --version \"" + PlatformSettings->OculusRiftBuildVersion + "\""; + + // Rift Launch Parameters check and command + if (!PlatformSettings->OculusRiftLaunchParams.IsEmpty()) + { + ValidateTextField(&SOculusPlatformToolWidget::LaunchParamValidator, PlatformSettings->OculusRiftLaunchParams, + LOCTEXT("LaunchParam", "Launch Parameters").ToString(), success); + args += " --launch_params \"" + PlatformSettings->OculusRiftLaunchParams + "\""; + } + + // Rift 2D Options checks and commands + if (!PlatformSettings->OculusRift2DLaunchPath.IsEmpty()) + { + ValidateTextField(&SOculusPlatformToolWidget::FileFieldValidator, PlatformSettings->OculusRift2DLaunchPath, + LOCTEXT("2DLaunchFile", "2D Launch File Path").ToString(), success); + args += " --launch_file_2d \"" + PlatformSettings->OculusRift2DLaunchPath + "\""; + + if (!PlatformSettings->OculusRift2DLaunchParams.IsEmpty()) + { + ValidateTextField(&SOculusPlatformToolWidget::LaunchParamValidator, PlatformSettings->OculusRift2DLaunchParams, + LOCTEXT("2DLaunchParams", "2D Launch Parameters").ToString(), success); + args += " --launch_params_2d \"" + PlatformSettings->OculusRift2DLaunchParams + "\""; + } + } + + // Rift Firewall Exception command + if (PlatformSettings->OculusRiftFireWallException) + { + args += " --firewall_exceptions true"; + } + + // Rift Gamepad Emulation command + if (PlatformSettings->GetRiftGamepadEmulation() > EOculusXRGamepadEmulation::Off && PlatformSettings->GetRiftGamepadEmulation() < EOculusXRGamepadEmulation::Length) + { + args += " --gamepad-emulation "; + switch (PlatformSettings->GetRiftGamepadEmulation()) + { + case EOculusXRGamepadEmulation::Twinstick: + args += "TWINSTICK"; + break; + case EOculusXRGamepadEmulation::RightDPad: + args += "RIGHT_D_PAD"; + break; + case EOculusXRGamepadEmulation::LeftDPad: + args += "LEFT_D_PAD"; + break; + default: + args += "OFF"; + break; + } + } + + // Rift Redistributable Packages commands + TArray IncludedPackages; + for (int i = 0; i < PlatformSettings->OculusRedistPackages.Num(); i++) + { + FOculusXRRedistPackage Package = PlatformSettings->OculusRedistPackages[i]; + if (Package.Included) + { + IncludedPackages.Add(Package.Id); + } + } + if (IncludedPackages.Num() > 0) + { + args += " --redistributables \"" + FString::Join(IncludedPackages, TEXT(",")) + "\""; + } + } + else + { + // APK File Path check and command. + ValidateTextField(&SOculusPlatformToolWidget::FileFieldValidator, PlatformSettings->GetLaunchFilePath(), + LOCTEXT("APKLaunchFile", "APK File Path").ToString(), success); + args += " --apk \"" + PlatformSettings->GetLaunchFilePath() + "\""; + + if (PlatformSettings->UploadDebugSymbols) + { + ValidateTextField(&SOculusPlatformToolWidget::DirectoryFieldValidator, PlatformSettings->GetSymbolDirPath(), + LOCTEXT("SymbolDirPath", "Symbol Directory Path").ToString(), success); + if (success) + { + args += " --debug-symbols-dir \"" + PlatformSettings->GetSymbolDirPath() + "\""; + } + } + } + + if (!PlatformSettings->GetExpansionFilesPath().IsEmpty()) + { + ValidateTextField(&SOculusPlatformToolWidget::DirectoryFieldValidator, PlatformSettings->GetExpansionFilesPath(), + LOCTEXT("ExpansionFilesPath", "Expansion Files Path").ToString(), success); + args += " --assets-dir \"" + PlatformSettings->GetExpansionFilesPath() + "\""; + + TArray* AssetConfigs = PlatformSettings->GetAssetConfigs(); + if (AssetConfigs->Num() > 0) + { + TArray AssetConfig; + for (int i = 0; i < AssetConfigs->Num(); i++) + { + TArray ConfigParams; + FOculusXRAssetConfig Config = (*AssetConfigs)[i]; + + if (Config.Required) + { + ConfigParams.Add("\\\"required\\\":true"); + } + if (Config.AssetType > EOculusXRAssetType::Default && Config.AssetType < EOculusXRAssetType::Length) + { + FString command = "\\\"type\\\":"; + switch (Config.AssetType) + { + case EOculusXRAssetType::Store: + ConfigParams.Add(command + "\\\"STORE\\\""); + break; + case EOculusXRAssetType::Language_Pack: + ConfigParams.Add(command + "\\\"LANGUAGE_PACK\\\""); + break; + default: + ConfigParams.Add(command + "\\\"DEFAULT\\\""); + break; + } + } + if (!Config.Sku.IsEmpty()) + { + ConfigParams.Add("\\\"sku\\\":\\\"" + Config.Sku + "\\\""); + } + + if (ConfigParams.Num() > 0) + { + FString ConfigCommand = "\\\"" + Config.Name + "\\\":{" + FString::Join(ConfigParams, TEXT(",")) + "}"; + AssetConfig.Add(ConfigCommand); + } + } + + if (AssetConfig.Num()) + { + args += " --asset_files_config {" + FString::Join(AssetConfig, TEXT(",")) + "}"; + } + } + } + + args += " --upload-from-engine UNREAL"; + + UE_LOG(LogTemp, Warning, TEXT("%s"), *args); + return success; +} + +bool SOculusPlatformToolWidget::ConstructDebugSymbolArguments(FString& args) +{ + bool success = true; + args = "upload-debug-symbols"; + + ValidateTextField(&SOculusPlatformToolWidget::IDFieldValidator, PlatformSettings->BuildID, + LOCTEXT("BuildID", "Build ID").ToString(), success); + args += " --parent \"" + PlatformSettings->BuildID + "\""; + + // Oculus Application ID check and command. + ValidateTextField(&SOculusPlatformToolWidget::IDFieldValidator, PlatformSettings->GetApplicationID(), + LOCTEXT("ApplicationID", "Application ID").ToString(), success); + args += " --app_id \"" + PlatformSettings->GetApplicationID() + "\""; + + // Oculus Application Token check and command. + ValidateTextField(&SOculusPlatformToolWidget::GenericFieldValidator, PlatformSettings->GetApplicationToken(), + LOCTEXT("ApplicationToken", "Application Token").ToString(), success); + args += " --app_secret \"" + PlatformSettings->GetApplicationToken() + "\""; + + ValidateTextField(&SOculusPlatformToolWidget::DirectoryFieldValidator, PlatformSettings->GetSymbolDirPath(), + LOCTEXT("SymbolDirPath", "Symbol Directory Path").ToString(), success); + args += " --debug-symbols-dir \"" + PlatformSettings->GetSymbolDirPath() + "\""; + args += " --debug-symbols-pattern \"*.so\""; + + return success; +} + +void SOculusPlatformToolWidget::EnableUploadButton(bool enabled) +{ + RequestUploadButtonActive = enabled; +} + +void SOculusPlatformToolWidget::LoadConfigSettings() +{ + PlatformSettings = GetMutableDefault(); + PlatformEnum = StaticEnum(); + GamepadEmulationEnum = StaticEnum(); + AssetTypeEnum = StaticEnum(); + + RiftGamepadEmulation.Empty(); + OculusPlatforms.Empty(); + for (uint8 i = 0; i < (uint8)EOculusXRPlatformTarget::Length; i++) + { + OculusPlatforms.Add(MakeShareable(new FString(PlatformEnum->GetDisplayNameTextByIndex((int64)i).ToString()))); + } + for (uint8 i = 0; i < (uint8)EOculusXRGamepadEmulation::Length; i++) + { + RiftGamepadEmulation.Add(MakeShareable(new FString(GamepadEmulationEnum->GetDisplayNameTextByIndex((int64)i).ToString()))); + } + for (uint8 i = 0; i < (uint8)EOculusXRAssetType::Length; i++) + { + AssetType.Add(MakeShareable(new FString(AssetTypeEnum->GetDisplayNameTextByIndex((int64)i).ToString()))); + } + + LoadRedistPackages(); +} + +void SOculusPlatformToolWidget::LoadRedistPackages() +{ + (new FAsyncTask(UpdateLogTextDel))->StartBackgroundTask(); +} + +FReply SOculusPlatformToolWidget::OnStartPlatformUpload() +{ + FString launchArgs; + + UpdateLogText(""); + FOculusXRHMDModule::GetPluginWrapper().SendEvent2("oculus_platform_tool", "upload", "integration"); + if (ConstructArguments(launchArgs)) + { + UpdateLogText(LogText + LOCTEXT("StartUpload", "Starting Platform Tool Upload Process . . .\n").ToString()); + (new FAsyncTask(launchArgs, EnableUploadButtonDel, UpdateLogTextDel, SetProcessDel))->StartBackgroundTask(); + } + return FReply::Handled(); +} + +void SOculusPlatformToolWidget::OnPlatformSettingChanged(TSharedPtr ItemSelected, ESelectInfo::Type SelectInfo) +{ + if (!ItemSelected.IsValid()) + { + return; + } + + for (uint8 i = 0; i < (uint8)EOculusXRPlatformTarget::Length; i++) + { + if (PlatformEnum->GetDisplayNameTextByIndex(i).EqualTo(FText::FromString(*ItemSelected))) + { + if (PlatformSettings != nullptr) + { + PlatformSettings->SetTargetPlatform(i); + PlatformSettings->SaveConfig(); + + LoadConfigSettings(); + BuildGeneralSettingsBox(GeneralSettingsBox); + BuildExpansionFileBox(ExpansionFilesSettings); + + OptionalSettings.Get()->ClearChildren(); + if (i == (uint8)EOculusXRPlatformTarget::Rift) + { + BuildRiftOptionalFields(OptionalSettings); + } + break; + } + } + } +} + +void SOculusPlatformToolWidget::OnApplicationIDChanged(const FText& InText, ETextCommit::Type InCommitType) +{ + if (PlatformSettings != nullptr) + { + PlatformSettings->SetApplicationID(InText.ToString()); + PlatformSettings->SaveConfig(); + } +} + +void SOculusPlatformToolWidget::OnApplicationTokenChanged(const FText& InText, ETextCommit::Type InCommitType) +{ + if (PlatformSettings != nullptr) + { + PlatformSettings->SetApplicationToken(InText.ToString()); + PlatformSettings->SaveConfig(); + } +} + +void SOculusPlatformToolWidget::OnReleaseChannelChanged(const FText& InText, ETextCommit::Type InCommitType) +{ + if (PlatformSettings != nullptr) + { + PlatformSettings->SetReleaseChannel(InText.ToString()); + PlatformSettings->SaveConfig(); + } +} + +void SOculusPlatformToolWidget::OnReleaseNoteChanged(const FText& InText, ETextCommit::Type InCommitType) +{ + if (PlatformSettings != nullptr) + { + PlatformSettings->SetReleaseNote(InText.ToString()); + PlatformSettings->SaveConfig(); + } +} + +void SOculusPlatformToolWidget::OnRiftBuildVersionChanged(const FText& InText, ETextCommit::Type InCommitType) +{ + if (PlatformSettings != nullptr) + { + PlatformSettings->OculusRiftBuildVersion = InText.ToString(); + PlatformSettings->SaveConfig(); + } +} + +void SOculusPlatformToolWidget::OnRiftLaunchParamsChanged(const FText& InText, ETextCommit::Type InCommitType) +{ + if (PlatformSettings != nullptr) + { + PlatformSettings->OculusRiftLaunchParams = InText.ToString(); + PlatformSettings->SaveConfig(); + } +} + +void SOculusPlatformToolWidget::On2DLaunchParamsChanged(const FText& InText, ETextCommit::Type InCommitType) +{ + if (PlatformSettings != nullptr) + { + PlatformSettings->OculusRift2DLaunchParams = InText.ToString(); + PlatformSettings->SaveConfig(); + } +} + +void SOculusPlatformToolWidget::OnRiftFirewallChanged(ECheckBoxState CheckState) +{ + if (PlatformSettings != nullptr) + { + PlatformSettings->OculusRiftFireWallException = CheckState == ECheckBoxState::Checked ? true : false; + PlatformSettings->SaveConfig(); + } +} + +void SOculusPlatformToolWidget::OnRedistPackageStateChanged(ECheckBoxState CheckState, FOculusXRRedistPackage* Package) +{ + if (PlatformSettings != nullptr) + { + Package->Included = CheckState == ECheckBoxState::Checked; + PlatformSettings->SaveConfig(); + BuildRiftOptionalFields(OptionalSettings); + } +} + +void SOculusPlatformToolWidget::OnAssetConfigTypeChanged(TSharedPtr ItemSelected, ESelectInfo::Type SelectInfo, int i) +{ + if (PlatformSettings != nullptr) + { + TArray* AssetConfigs = PlatformSettings->GetAssetConfigs(); + for (int e = 0; e < (uint8)EOculusXRAssetType::Length; e++) + { + if (AssetTypeEnum->GetDisplayNameTextByIndex(e).ToString().Equals(*ItemSelected.Get())) + { + (*AssetConfigs)[i].AssetType = (EOculusXRAssetType)e; + break; + } + } + + PlatformSettings->SaveConfig(); + BuildExpansionFileBox(ExpansionFilesSettings); + } +} + +void SOculusPlatformToolWidget::OnAssetConfigRequiredChanged(ECheckBoxState CheckState, int i) +{ + if (PlatformSettings != nullptr) + { + TArray* AssetConfigs = PlatformSettings->GetAssetConfigs(); + (*AssetConfigs)[i].Required = CheckState == ECheckBoxState::Checked; + + PlatformSettings->SaveConfig(); + BuildExpansionFileBox(ExpansionFilesSettings); + } +} + +void SOculusPlatformToolWidget::OnAssetConfigSKUChanged(const FText& InText, ETextCommit::Type InCommitType, int i) +{ + if (PlatformSettings != nullptr) + { + TArray* AssetConfigs = PlatformSettings->GetAssetConfigs(); + (*AssetConfigs)[i].Sku = InText.ToString(); + + PlatformSettings->SaveConfig(); + BuildExpansionFileBox(ExpansionFilesSettings); + } +} + +void SOculusPlatformToolWidget::OnUploadDebugSymbolsChanged(ECheckBoxState CheckState) +{ + if (PlatformSettings != nullptr) + { + PlatformSettings->UploadDebugSymbols = CheckState == ECheckBoxState::Checked ? true : false; + PlatformSettings->SaveConfig(); + + BuildGeneralSettingsBox(GeneralSettingsBox); + } +} + +void SOculusPlatformToolWidget::OnDebugSymbolsOnlyChanged(ECheckBoxState CheckState) +{ + if (PlatformSettings != nullptr) + { + PlatformSettings->DebugSymbolsOnly = CheckState == ECheckBoxState::Checked ? true : false; + PlatformSettings->SaveConfig(); + + BuildGeneralSettingsBox(GeneralSettingsBox); + } +} + +void SOculusPlatformToolWidget::OnBuildIDChanged(const FText& InText, ETextCommit::Type InCommitType) +{ + if (PlatformSettings != nullptr) + { + PlatformSettings->BuildID = InText.ToString(); + PlatformSettings->SaveConfig(); + } +} + +void SOculusPlatformToolWidget::OnRiftGamepadEmulationChanged(TSharedPtr ItemSelected, ESelectInfo::Type SelectInfo) +{ + if (!ItemSelected.IsValid()) + { + return; + } + + for (uint8 i = 0; i < (uint8)EOculusXRGamepadEmulation::Length; i++) + { + if (GamepadEmulationEnum->GetDisplayNameTextByIndex(i).EqualTo(FText::FromString(*ItemSelected))) + { + if (PlatformSettings != nullptr) + { + PlatformSettings->SetRiftGamepadEmulation(i); + PlatformSettings->SaveConfig(); + break; + } + } + } +} + +FReply SOculusPlatformToolWidget::OnSelectRiftBuildDirectory() +{ + TSharedPtr parentWindow = FSlateApplication::Get().FindWidgetWindow(AsShared()); + const void* parentWindowHandle = (parentWindow.IsValid() && parentWindow->GetNativeWindow().IsValid()) ? parentWindow->GetNativeWindow()->GetOSWindowHandle() : nullptr; + + if (PlatformSettings != nullptr) + { + FString path; + FString defaultPath = PlatformSettings->OculusRiftBuildDirectory.IsEmpty() ? FPaths::ProjectContentDir() : PlatformSettings->OculusRiftBuildDirectory; + if (FDesktopPlatformModule::Get()->OpenDirectoryDialog(parentWindowHandle, "Choose Rift Build Directory", defaultPath, path)) + { + PlatformSettings->OculusRiftBuildDirectory = path; + PlatformSettings->SaveConfig(); + BuildGeneralSettingsBox(GeneralSettingsBox); + } + } + return FReply::Handled(); +} + +FReply SOculusPlatformToolWidget::OnClearRiftBuildDirectory() +{ + if (PlatformSettings != nullptr) + { + PlatformSettings->OculusRiftBuildDirectory.Empty(); + PlatformSettings->SaveConfig(); + BuildGeneralSettingsBox(GeneralSettingsBox); + } + return FReply::Handled(); +} + +FReply SOculusPlatformToolWidget::OnSelectLaunchFilePath() +{ + TSharedPtr parentWindow = FSlateApplication::Get().FindWidgetWindow(AsShared()); + const void* parentWindowHandle = (parentWindow.IsValid() && parentWindow->GetNativeWindow().IsValid()) ? parentWindow->GetNativeWindow()->GetOSWindowHandle() : nullptr; + + if (PlatformSettings != nullptr) + { + TArray path; + FString defaultPath = PlatformSettings->GetLaunchFilePath().IsEmpty() ? FPaths::ProjectContentDir() : PlatformSettings->GetLaunchFilePath(); + FString fileType = PlatformSettings->GetTargetPlatform() == (uint8)EOculusXRPlatformTarget::Rift ? "Executables (*.exe)|*.exe" : "APKs (*.apk)|*.apk"; + if (FDesktopPlatformModule::Get()->OpenFileDialog(parentWindowHandle, "Choose Launch File", defaultPath, defaultPath, fileType, EFileDialogFlags::None, path)) + { + if (path.Num() > 0) + { + PlatformSettings->SetLaunchFilePath(FPaths::ConvertRelativePathToFull(path[0])); + } + PlatformSettings->SaveConfig(); + BuildGeneralSettingsBox(GeneralSettingsBox); + } + } + return FReply::Handled(); +} + +FReply SOculusPlatformToolWidget::OnClearLaunchFilePath() +{ + if (PlatformSettings != nullptr) + { + PlatformSettings->SetLaunchFilePath(""); + PlatformSettings->SaveConfig(); + BuildGeneralSettingsBox(GeneralSettingsBox); + } + return FReply::Handled(); +} + +FString SOculusPlatformToolWidget::GenerateSymbolPath() +{ + return FPaths::ProjectDir() + TEXT("Binaries/Android/") + FApp::GetProjectName() + TEXT("_Symbols_v1/") + FApp::GetProjectName() + TEXT("-arm64"); +} + +FReply SOculusPlatformToolWidget::OnSelectSymbolDirPath() +{ + TSharedPtr parentWindow = FSlateApplication::Get().FindWidgetWindow(AsShared()); + const void* parentWindowHandle = (parentWindow.IsValid() && parentWindow->GetNativeWindow().IsValid()) ? parentWindow->GetNativeWindow()->GetOSWindowHandle() : nullptr; + + if (PlatformSettings != nullptr) + { + FString dirPath; + FString defaultPath = PlatformSettings->GetSymbolDirPath().IsEmpty() ? GenerateSymbolPath() : PlatformSettings->GetSymbolDirPath(); + if (FDesktopPlatformModule::Get()->OpenDirectoryDialog(parentWindowHandle, "Choose Launch File", defaultPath, dirPath)) + { + PlatformSettings->SetSymbolDirPath(FPaths::ConvertRelativePathToFull(dirPath)); + PlatformSettings->SaveConfig(); + BuildGeneralSettingsBox(GeneralSettingsBox); + } + } + return FReply::Handled(); +} + +FReply SOculusPlatformToolWidget::OnClearSymbolDirPath() +{ + if (PlatformSettings != nullptr) + { + PlatformSettings->SetSymbolDirPath(""); + PlatformSettings->SaveConfig(); + BuildGeneralSettingsBox(GeneralSettingsBox); + } + return FReply::Handled(); +} + +FReply SOculusPlatformToolWidget::OnSelect2DLaunchPath() +{ + + if (PlatformSettings != nullptr) + { + TSharedPtr parentWindow = FSlateApplication::Get().FindWidgetWindow(AsShared()); + const void* parentWindowHandle = (parentWindow.IsValid() && parentWindow->GetNativeWindow().IsValid()) ? parentWindow->GetNativeWindow()->GetOSWindowHandle() : nullptr; + TArray path; + FString defaultPath = PlatformSettings->OculusRift2DLaunchPath.IsEmpty() ? FPaths::ProjectContentDir() : PlatformSettings->OculusRift2DLaunchPath; + if (FDesktopPlatformModule::Get()->OpenFileDialog(parentWindowHandle, "Choose 2D Launch File", defaultPath, defaultPath, "Executables (*.exe)|*.exe", EFileDialogFlags::None, path)) + { + if (path.Num() > 0) + { + PlatformSettings->OculusRift2DLaunchPath = FPaths::ConvertRelativePathToFull(path[0]); + } + PlatformSettings->SaveConfig(); + BuildRiftOptionalFields(OptionalSettings); + } + } + return FReply::Handled(); +} + +FReply SOculusPlatformToolWidget::OnClear2DLaunchPath() +{ + if (PlatformSettings != nullptr) + { + PlatformSettings->OculusRift2DLaunchPath.Empty(); + PlatformSettings->SaveConfig(); + BuildRiftOptionalFields(OptionalSettings); + } + return FReply::Handled(); +} + +FReply SOculusPlatformToolWidget::OnCancelUpload() +{ + if (FMessageDialog::Open(EAppMsgType::OkCancel, LOCTEXT("CancelUploadWarning", "Are you sure you want to cancel the upload process?")) == EAppReturnType::Ok) + { + if (PlatformProcess.IsValid()) + { + FPlatformProcess::TerminateProc(PlatformProcess); + UpdateLogText(LogText + LOCTEXT("UploadCancel", "Upload process was canceled.").ToString()); + } + } + return FReply::Handled(); +} + +FReply SOculusPlatformToolWidget::OnSelectLanguagePacksPath() +{ + + if (PlatformSettings != nullptr) + { + TSharedPtr parentWindow = FSlateApplication::Get().FindWidgetWindow(AsShared()); + const void* parentWindowHandle = (parentWindow.IsValid() && parentWindow->GetNativeWindow().IsValid()) ? parentWindow->GetNativeWindow()->GetOSWindowHandle() : nullptr; + FString path; + FString defaultPath = PlatformSettings->GetLanguagePacksPath().IsEmpty() ? FPaths::ProjectContentDir() : PlatformSettings->GetLanguagePacksPath(); + if (FDesktopPlatformModule::Get()->OpenDirectoryDialog(parentWindowHandle, "Choose Language Packs Directory", defaultPath, path)) + { + PlatformSettings->SetLanguagePacksPath(path); + PlatformSettings->SaveConfig(); + BuildExpansionFileBox(ExpansionFilesSettings); + } + } + return FReply::Handled(); +} + +FReply SOculusPlatformToolWidget::OnClearLanguagePacksPath() +{ + if (PlatformSettings != nullptr) + { + PlatformSettings->SetLanguagePacksPath(""); + PlatformSettings->SaveConfig(); + BuildExpansionFileBox(ExpansionFilesSettings); + } + return FReply::Handled(); +} + +FReply SOculusPlatformToolWidget::OnSelectExpansionFilesPath() +{ + + if (PlatformSettings != nullptr) + { + TSharedPtr parentWindow = FSlateApplication::Get().FindWidgetWindow(AsShared()); + const void* parentWindowHandle = (parentWindow.IsValid() && parentWindow->GetNativeWindow().IsValid()) ? parentWindow->GetNativeWindow()->GetOSWindowHandle() : nullptr; + FString path; + FString defaultPath = PlatformSettings->GetExpansionFilesPath().IsEmpty() ? FPaths::ProjectContentDir() : PlatformSettings->GetExpansionFilesPath(); + if (FDesktopPlatformModule::Get()->OpenDirectoryDialog(parentWindowHandle, "Choose Expansion Files Directory", defaultPath, path)) + { + if (!path.Equals(PlatformSettings->GetExpansionFilesPath())) + { + if (!path.IsEmpty() && FPaths::DirectoryExists(path)) + { + TArray Files; + //FFileManagerGeneric::Get().FindFilesRecursive(Files, *path, TEXT("*.*"), true, false, false); + IFileManager::Get().FindFiles(Files, *path); + + TArray* AssetConfigs = PlatformSettings->GetAssetConfigs(); + for (int i = 0; i < Files.Num(); i++) + { + FOculusXRAssetConfig AssetConfig; + AssetConfig.Name = Files[i]; + AssetConfigs->Push(AssetConfig); + } + + PlatformSettings->SetExpansionFilesPath(path); + PlatformSettings->SaveConfig(); + BuildExpansionFileBox(ExpansionFilesSettings); + } + } + } + } + return FReply::Handled(); +} + +FReply SOculusPlatformToolWidget::OnClearExpansionFilesPath() +{ + if (PlatformSettings != nullptr) + { + PlatformSettings->SetExpansionFilesPath(""); + PlatformSettings->GetAssetConfigs()->Empty(); + PlatformSettings->SaveConfig(); + BuildExpansionFileBox(ExpansionFilesSettings); + } + return FReply::Handled(); +} + +void SOculusPlatformToolWidget::ValidateTextField(PFieldValidatorDel del, FString text, FString name, bool& success) +{ + FString error = ""; + FFieldValidatorDel fieldValidator; + + // Check the given field with the given field validator and print the error if it fails. + fieldValidator.BindSP(this, del); + if (!fieldValidator.Execute(text, error)) + { + FString errorMessage = LOCTEXT("Error", "ERROR: Please verify that the {0} is correct. ").ToString(); + errorMessage = FString::Format(*errorMessage, { name }); + UpdateLogText(LogText + errorMessage + (error.IsEmpty() ? "\n" : error + "\n")); + success = false; + } +} + +bool SOculusPlatformToolWidget::GenericFieldValidator(FString text, FString& error) +{ + if (text.IsEmpty()) + { + error = LOCTEXT("FieldEmpty", "The field is empty.").ToString(); + return false; + } + return true; +} + +bool SOculusPlatformToolWidget::IDFieldValidator(FString text, FString& error) +{ + const FRegexPattern RegExPat(TEXT("^[0-9]+$")); + FRegexMatcher RegMatcher(RegExPat, text); + + if (!GenericFieldValidator(text, error)) + { + return false; + } + else if (!RegMatcher.FindNext()) + { + error = LOCTEXT("InvalidChar", "The field contains invalid characters.").ToString(); + return false; + } + return true; +} + +bool SOculusPlatformToolWidget::DirectoryFieldValidator(FString text, FString& error) +{ + if (!GenericFieldValidator(text, error)) + { + return false; + } + if (!FPaths::DirectoryExists(text)) + { + error = LOCTEXT("DirectoryNull", "The directory does not exist.").ToString(); + return false; + } + return true; +} + +bool SOculusPlatformToolWidget::FileFieldValidator(FString text, FString& error) +{ + if (!GenericFieldValidator(text, error)) + { + return false; + } + if (!FPaths::FileExists(text)) + { + error = LOCTEXT("FileNull", "The file does not exist.").ToString(); + return false; + } + return true; +} + +bool SOculusPlatformToolWidget::LaunchParamValidator(FString text, FString& error) +{ + if (text.Contains("\"")) + { + error = LOCTEXT("LaunchParamError", "The field contains illegal characters.").ToString(); + return false; + } + return true; +} + +void SOculusPlatformToolWidget::On2DOptionsExpanded(bool bExpanded) +{ + Options2DCollapsed = !bExpanded; +} + +void SOculusPlatformToolWidget::OnRedistPackagesExpanded(bool bExpanded) +{ + OptionsRedistPackagesCollapsed = !bExpanded; +} + +void SOculusPlatformToolWidget::UpdateLogText(FString text) +{ + // Make sure that log text updating happens on the right thread. + LogText = text; + LogTextUpdated = true; +} + +void SOculusPlatformToolWidget::SetPlatformProcess(FProcHandle proc) +{ + PlatformProcess = proc; +} + +//======================================================================================= +//FPlatformDownloadTask + +FPlatformDownloadTask::FPlatformDownloadTask(FUpdateLogTextDel textDel, FEvent* saveEvent) +{ + UpdateLogText = textDel; + SaveCompleteEvent = saveEvent; + + FOculusXRHMDModule::GetPluginWrapper().SendEvent2("oculus_platform_tool", "provision_util", "integration"); +} + +void FPlatformDownloadTask::DoWork() +{ + // Create HTTP request for downloading oculus platform tool + downloadCompleteEvent = FGenericPlatformProcess::GetSynchEventFromPool(false); + TSharedRef httpRequest = FHttpModule::Get().CreateRequest(); + + httpRequest->OnProcessRequestComplete().BindRaw(this, &FPlatformDownloadTask::OnDownloadRequestComplete); + httpRequest->OnRequestProgress().BindRaw(this, &FPlatformDownloadTask::OnRequestDownloadProgress); + httpRequest->SetURL(UrlPlatformUtil); + httpRequest->SetVerb("GET"); + + httpRequest->ProcessRequest(); + + UpdateLogText.Execute(SOculusPlatformToolWidget::LogText + LOCTEXT("DownloadProgress", "Downloading Platform Tool: {0}%\n").ToString()); + ToolConsoleLog = SOculusPlatformToolWidget::LogText; + UpdateProgressLog(0); + + // Wait for download to complete + downloadCompleteEvent->Wait(); + + // Save HTTP data + FString fullPath = FPaths::ConvertRelativePathToFull(FPaths::ProjectContentDir()) + ProjectPlatformUtilPath; + if (FFileHelper::SaveArrayToFile(httpData, *fullPath)) + { + UpdateLogText.Execute(SOculusPlatformToolWidget::LogText + LOCTEXT("DownloadSuccess", "Platform tool successfully downloaded.\n").ToString()); + } + else + { + UpdateLogText.Execute(SOculusPlatformToolWidget::LogText + LOCTEXT("DownloadError", "An error has occured with downloading the platform tool.\n").ToString()); + } + + if (SaveCompleteEvent != nullptr) + { + SaveCompleteEvent->Trigger(); + } +} + +void FPlatformDownloadTask::UpdateProgressLog(int progress) +{ + UpdateLogText.Execute(FString::Format(*ToolConsoleLog, { progress })); +} + +void FPlatformDownloadTask::OnRequestDownloadProgress(FHttpRequestPtr HttpRequest, int32 BytesSend, int32 InBytesReceived) +{ + // Update progress on download in tool console log + FHttpResponsePtr httpResponse = HttpRequest->GetResponse(); + if (httpResponse.IsValid()) + { + int progress = ((float)InBytesReceived / (float)httpResponse->GetContentLength()) * 100; + UpdateProgressLog(progress); + } +} + +void FPlatformDownloadTask::OnDownloadRequestComplete(FHttpRequestPtr HttpRequest, FHttpResponsePtr HttpResponse, bool bSucceeded) +{ + // Extract data from HTTP response and trigger download complete event + if (bSucceeded && HttpResponse.IsValid()) + { + httpData = HttpResponse->GetContent(); + downloadCompleteEvent->Trigger(); + } +} + +//======================================================================================= +//FPlatformUploadTask + +FPlatformUploadTask::FPlatformUploadTask(FString args, FEnableUploadButtonDel del, FUpdateLogTextDel textDel, FSetProcessDel procDel) +{ + LaunchArgs = args; + EnableUploadButton = del; + UpdateLogText = textDel; + SetProcess = procDel; + + EnableUploadButton.Execute(false); +} + +void FPlatformUploadTask::DoWork() +{ + // Check if the platform tool exists in the project directory. If not, start process to download it. + if (!FPaths::FileExists(FPaths::ProjectContentDir() + ProjectPlatformUtilPath)) + { + FEvent* PlatformToolCreatedEvent = FGenericPlatformProcess::GetSynchEventFromPool(false); + + UpdateLogText.Execute(SOculusPlatformToolWidget::LogText + LOCTEXT("NoCLI", "Unable to find Oculus Platform Utility.\n").ToString()); +#if UE_VERSION_OLDER_THAN(5, 3, 0) + EAppReturnType::Type dialogChoice = FMessageDialog::Open(EAppMsgType::OkCancel, OculusPlatformDialogMessage, &OculusPlatformDialogTitle); +#else + EAppReturnType::Type dialogChoice = FMessageDialog::Open(EAppMsgType::OkCancel, OculusPlatformDialogMessage, OculusPlatformDialogTitle); +#endif + if (dialogChoice == EAppReturnType::Ok) + { + UpdateLogText.Execute(SOculusPlatformToolWidget::LogText + LOCTEXT("DownloadCLI", "Downloading Oculus Platform Utility . . .\n").ToString()); + (new FAsyncTask(UpdateLogText, PlatformToolCreatedEvent))->StartBackgroundTask(); + PlatformToolCreatedEvent->Wait(); + } + else + { + return; + } + + UpdateLogText.Execute(SOculusPlatformToolWidget::LogText + LOCTEXT("StartUploadAfterDownload", "Starting upload . . .\n").ToString()); + } + + // Start up the CLI and pass in arguments. + FPlatformProcess::CreatePipe(ReadPipe, WritePipe); + FProcHandle PlatformProcess = FPlatformProcess::CreateProc(*(FPaths::ProjectContentDir() + ProjectPlatformUtilPath), *LaunchArgs, false, true, true, nullptr, 0, nullptr, WritePipe, ReadPipe); + SetProcess.Execute(PlatformProcess); + + // Redirect CLI output to the tool's log. + while (FPlatformProcess::IsProcRunning(PlatformProcess)) + { + FString log = FPlatformProcess::ReadPipe(ReadPipe); + if (!log.IsEmpty()) + { + // Remove parts of the log that contain escape character codes + int32 escapeIndex = log.Find("\u001b"); + while (escapeIndex >= 0) + { + int32 lineEndIndex = log.Find("\n", ESearchCase::IgnoreCase, ESearchDir::FromStart, escapeIndex); + if (lineEndIndex < 0) // If an escape character code exists without a new line end, just remove the escape character + { + lineEndIndex = escapeIndex + 1; + } + log.RemoveAt(escapeIndex, lineEndIndex - escapeIndex); + escapeIndex = log.Find("\u001b"); + } + UpdateLogText.Execute(SOculusPlatformToolWidget::LogText + log); + } + } + EnableUploadButton.Execute(true); +} + +//======================================================================================= +//FPlatformLoadRedistPackagesTask + +FPlatformLoadRedistPackagesTask::FPlatformLoadRedistPackagesTask(FUpdateLogTextDel textDel) +{ + UpdateLogText = textDel; +} + +void FPlatformLoadRedistPackagesTask::DoWork() +{ + UOculusXRPlatformToolSettings* PlatformSettings = GetMutableDefault(); + + // Check to see if the CLI exists, we need this to load avalible redist packages + if (!FPaths::FileExists(FPaths::ProjectContentDir() + ProjectPlatformUtilPath)) + { + UpdateLogText.Execute(SOculusPlatformToolWidget::LogText + LOCTEXT("LoadRedist", "Loading redistributable packages . . .\n").ToString()); + + FEvent* PlatformToolCreatedEvent = FGenericPlatformProcess::GetSynchEventFromPool(false); + + UpdateLogText.Execute(SOculusPlatformToolWidget::LogText + LOCTEXT("NoCLI", "Unable to find Oculus Platform Utility.\n").ToString()); +#if UE_VERSION_OLDER_THAN(5, 3, 0) + EAppReturnType::Type dialogChoice = FMessageDialog::Open(EAppMsgType::OkCancel, OculusPlatformDialogMessage, &OculusPlatformDialogTitle); +#else + EAppReturnType::Type dialogChoice = FMessageDialog::Open(EAppMsgType::OkCancel, OculusPlatformDialogMessage, OculusPlatformDialogTitle); +#endif + if (dialogChoice == EAppReturnType::Ok) + { + UpdateLogText.Execute(SOculusPlatformToolWidget::LogText + LOCTEXT("DownloadCLI", "Downloading Oculus Platform Utility . . .\n").ToString()); + (new FAsyncTask(UpdateLogText, PlatformToolCreatedEvent))->StartBackgroundTask(); + PlatformToolCreatedEvent->Wait(); + } + else + { + return; + } + } + + // Launch CLI and pass command to list out redist packages currently avalible + TArray LoadedPackages; + FString Args = "list-redists"; + FPlatformProcess::CreatePipe(ReadPipe, WritePipe); + FProcHandle PlatformProcess = FPlatformProcess::CreateProc(*(FPaths::ProjectContentDir() + ProjectPlatformUtilPath), *Args, false, true, true, nullptr, 0, nullptr, WritePipe, ReadPipe); + + // Load redist packages + while (FPlatformProcess::IsProcRunning(PlatformProcess)) + { + FString log = FPlatformProcess::ReadPipe(ReadPipe); + if (!log.IsEmpty() && !log.Contains("\u001b") && !log.Contains("ID")) + { + TArray Packages; + log.ParseIntoArrayLines(Packages); + if (Packages.Num() > 0) + { + for (int i = 0; i < Packages.Num(); i++) + { + FString id, name; + Packages[i].Split("|", &id, &name); + + if (!id.IsEmpty() && !name.IsEmpty()) + { + FOculusXRRedistPackage newPackage; + newPackage.Name = name; + newPackage.Id = id; + + LoadedPackages.Add(newPackage); + } + } + } + } + } + + // Check to see if our stored copy of redist packages is outdated + if (PlatformSettings != nullptr) + { + if (LoadedPackages.Num() > PlatformSettings->OculusRedistPackages.Num()) + { + PlatformSettings->OculusRedistPackages = LoadedPackages; + PlatformSettings->SaveConfig(); + UpdateLogText.Execute(SOculusPlatformToolWidget::LogText + LOCTEXT("FinishRedistLoad", "Finished updating redistributable packages.\n").ToString()); + } + } +} + +#undef LOCTEXT_NAMESPACE diff --git a/Plugins/MetaXR/Source/OculusXREditor/Private/OculusXRPlatformToolWidget.h b/Plugins/MetaXR/Source/OculusXREditor/Private/OculusXRPlatformToolWidget.h new file mode 100644 index 0000000..b282a53 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXREditor/Private/OculusXRPlatformToolWidget.h @@ -0,0 +1,222 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. +#pragma once + +#include "CoreMinimal.h" +#include "OculusXRPlatformToolSettings.h" +#include "Widgets/SWidget.h" +#include "Widgets/SCompoundWidget.h" +#include "Widgets/DeclarativeSyntaxSupport.h" +#include "Widgets/Input/SEditableTextBox.h" +#include "Widgets/Input/SMultiLineEditableTextBox.h" +#include "Widgets/Input/SComboBox.h" +#include "Widgets/Input/STextComboBox.h" +#include "Widgets/Layout/SScrollBox.h" +#include "Widgets/Input/SButton.h" +#include "Widgets/Input/SCheckBox.h" +#include "Engine/PostProcessVolume.h" +#include "Framework/Text/SlateHyperlinkRun.h" +#include "HttpModule.h" +#include "HttpManager.h" +#include "Interfaces/IHttpResponse.h" +#include "Async/AsyncWork.h" +#include "HAL/Event.h" +#include "HAL/ThreadSafeBool.h" +#include "OculusXRPluginWrapper.h" +#include "Brushes/SlateDynamicImageBrush.h" + +class SOculusPlatformToolWidget; + +// Function Delegates +DECLARE_DELEGATE_OneParam(FEnableUploadButtonDel, bool); +DECLARE_DELEGATE_OneParam(FUpdateLogTextDel, FString); +DECLARE_DELEGATE_OneParam(FSetProcessDel, FProcHandle); +DECLARE_DELEGATE_RetVal_TwoParams(bool, FFieldValidatorDel, FString, FString&); + +class SOculusPlatformToolWidget : public SCompoundWidget +{ +public: + typedef void (SOculusPlatformToolWidget::*PTextComboBoxDel)(TSharedPtr, ESelectInfo::Type); + typedef void (SOculusPlatformToolWidget::*PTextComittedDel)(const FText&, ETextCommit::Type); + typedef FReply (SOculusPlatformToolWidget::*PButtonClickedDel)(); + typedef bool (SOculusPlatformToolWidget::*PFieldValidatorDel)(FString, FString&); + typedef void (SOculusPlatformToolWidget::*PCheckBoxChangedDel)(ECheckBoxState); + + SLATE_BEGIN_ARGS(SOculusPlatformToolWidget) + { + } + SLATE_END_ARGS(); + + SOculusPlatformToolWidget(); + void Construct(const FArguments& InArgs); + virtual void Tick(const FGeometry& AllottedGeometry, const double InCurrentTime, const float InDeltaTime) override; + + static FString LogText; + +private: + TSharedPtr ToolConsoleLog; + TSharedPtr GeneralSettingsBox; + TSharedPtr ButtonToolbar; + TSharedPtr OptionalSettings; + TSharedPtr ExpansionFilesSettings; + TSharedPtr ODHIconDynamicImageBrush; + + UEnum* PlatformEnum; + UEnum* GamepadEmulationEnum; + UEnum* AssetTypeEnum; + UOculusXRPlatformToolSettings* PlatformSettings; + TArray> OculusPlatforms; + TArray> RiftGamepadEmulation; + TArray> AssetType; + + bool Options2DCollapsed; + bool OptionsRedistPackagesCollapsed; + bool ActiveUploadButton; + bool RequestUploadButtonActive; + FProcHandle PlatformProcess; + FThreadSafeBool LogTextUpdated; + + FEnableUploadButtonDel EnableUploadButtonDel; + FUpdateLogTextDel UpdateLogTextDel; + FSetProcessDel SetProcessDel; + + // Callbacks + FReply OnStartPlatformUpload(); + FReply OnSelectRiftBuildDirectory(); + FReply OnClearRiftBuildDirectory(); + FReply OnSelectLaunchFilePath(); + FReply OnClearLaunchFilePath(); + FReply OnSelectSymbolDirPath(); + FReply OnClearSymbolDirPath(); + FReply OnSelect2DLaunchPath(); + FReply OnClear2DLaunchPath(); + FReply OnCancelUpload(); + FReply OnSelectLanguagePacksPath(); + FReply OnClearLanguagePacksPath(); + FReply OnSelectExpansionFilesPath(); + FReply OnClearExpansionFilesPath(); + + FString GenerateSymbolPath(); + + void OnPlatformSettingChanged(TSharedPtr ItemSelected, ESelectInfo::Type SelectInfo); + void OnApplicationIDChanged(const FText& InText, ETextCommit::Type InCommitType); + void OnApplicationTokenChanged(const FText& InText, ETextCommit::Type InCommitType); + void OnReleaseChannelChanged(const FText& InText, ETextCommit::Type InCommitType); + void OnReleaseNoteChanged(const FText& InText, ETextCommit::Type InCommitType); + void OnRiftBuildVersionChanged(const FText& InText, ETextCommit::Type InCommitType); + void OnRiftLaunchParamsChanged(const FText& InText, ETextCommit::Type InCommitType); + void OnRiftFirewallChanged(ECheckBoxState CheckState); + void OnRedistPackageStateChanged(ECheckBoxState CheckState, FOculusXRRedistPackage* Package); + void OnRiftGamepadEmulationChanged(TSharedPtr ItemSelected, ESelectInfo::Type SelectInfo); + void On2DLaunchParamsChanged(const FText& InText, ETextCommit::Type InCommitType); + void On2DOptionsExpanded(bool bExpanded); + void OnRedistPackagesExpanded(bool bExpanded); + void OnAssetConfigRequiredChanged(ECheckBoxState CheckState, int i); + void OnAssetConfigTypeChanged(TSharedPtr ItemSelected, ESelectInfo::Type SelectInfo, int i); + void OnAssetConfigSKUChanged(const FText& InText, ETextCommit::Type InCommitType, int i); + void OnUploadDebugSymbolsChanged(ECheckBoxState CheckState); + void OnDebugSymbolsOnlyChanged(ECheckBoxState CheckState); + void OnBuildIDChanged(const FText& InText, ETextCommit::Type InCommitType); + + // UI Constructors + void BuildGeneralSettingsBox(TSharedPtr box); + void BuildTextComboBoxField(TSharedPtr box, FText name, TArray>* options, TSharedPtr current, PTextComboBoxDel deleg, int32 indentAmount = 0); + void BuildTextField(TSharedPtr box, FText name, FText text, FText tooltip, PTextComittedDel deleg, bool isPassword = false, int32 indentAmount = 0); + void BuildFileDirectoryField(TSharedPtr box, FText name, FText path, FText tooltip, PButtonClickedDel deleg, PButtonClickedDel clearDeleg, int32 indentAmount = 0); + void BuildCheckBoxField(TSharedPtr box, FText name, bool check, FText tooltip, PCheckBoxChangedDel deleg, int32 indentAmount = 0); + void BuildButtonToolbar(TSharedPtr box); + void BuildRiftOptionalFields(TSharedPtr area); + void BuildRedistPackagesBox(TSharedPtr box); + void BuildExpansionFileBox(TSharedPtr box); + void BuildAssetConfigBox(TSharedPtr box, FOculusXRAssetConfig config, int index); + + // Text Field Validators + void ValidateTextField(PFieldValidatorDel del, FString text, FString name, bool& success); + bool GenericFieldValidator(FString text, FString& error); + bool IDFieldValidator(FString text, FString& error); + bool DirectoryFieldValidator(FString text, FString& error); + bool FileFieldValidator(FString text, FString& error); + bool LaunchParamValidator(FString text, FString& error); + + bool ConstructArguments(FString& args); + bool ConstructDebugSymbolArguments(FString& args); + void EnableUploadButton(bool enabled); + void LoadConfigSettings(); + void UpdateLogText(FString text); + void SetPlatformProcess(FProcHandle proc); + void LoadRedistPackages(); +}; + +class FPlatformDownloadTask : public FNonAbandonableTask +{ + friend class FAsyncTask; + +private: + FUpdateLogTextDel UpdateLogText; + FString ToolConsoleLog; + FEvent* downloadCompleteEvent; + FEvent* SaveCompleteEvent; + TArray httpData; + +public: + FPlatformDownloadTask(FUpdateLogTextDel textDel, FEvent* saveEvent); + + void OnDownloadRequestComplete(FHttpRequestPtr HttpRequest, FHttpResponsePtr HttpResponse, bool bSucceeded); + void OnRequestDownloadProgress(FHttpRequestPtr HttpRequest, int32 BytesSend, int32 InBytesReceived); + +protected: + void DoWork(); + void UpdateProgressLog(int progress); + + FORCEINLINE TStatId GetStatId() const + { + RETURN_QUICK_DECLARE_CYCLE_STAT(FPlatformDownloadTask, STATGROUP_ThreadPoolAsyncTasks); + } +}; + +class FPlatformUploadTask : public FNonAbandonableTask +{ + friend class FAsyncTask; + +public: + FPlatformUploadTask(FString args, FEnableUploadButtonDel del, FUpdateLogTextDel textDel, FSetProcessDel procDel); + +private: + void* ReadPipe; + void* WritePipe; + + FSetProcessDel SetProcess; + FUpdateLogTextDel UpdateLogText; + FEnableUploadButtonDel EnableUploadButton; + FString LaunchArgs; + +protected: + void DoWork(); + + FORCEINLINE TStatId GetStatId() const + { + RETURN_QUICK_DECLARE_CYCLE_STAT(FPlatformUploadTask, STATGROUP_ThreadPoolAsyncTasks); + } +}; + +class FPlatformLoadRedistPackagesTask : public FNonAbandonableTask +{ + friend class FAsyncTask; + +public: + FPlatformLoadRedistPackagesTask(FUpdateLogTextDel textDel); + +private: + void* ReadPipe; + void* WritePipe; + + FUpdateLogTextDel UpdateLogText; + +protected: + void DoWork(); + + FORCEINLINE TStatId GetStatId() const + { + RETURN_QUICK_DECLARE_CYCLE_STAT(FPlatformLoadRedistPackagesTask, STATGROUP_ThreadPoolAsyncTasks); + } +}; diff --git a/Plugins/MetaXR/Source/OculusXREditor/Private/OculusXRPrivacyNotification.cpp b/Plugins/MetaXR/Source/OculusXREditor/Private/OculusXRPrivacyNotification.cpp new file mode 100644 index 0000000..631ad86 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXREditor/Private/OculusXRPrivacyNotification.cpp @@ -0,0 +1,82 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#include "OculusXRPrivacyNotification.h" + +#include "GeneralProjectSettings.h" +#include "Framework/Notifications/NotificationManager.h" +#include "Widgets/Notifications/SNotificationList.h" + +#include "OculusXRHMDModule.h" +#include "OculusXRToolStyle.h" +#include "OculusXRTelemetryEvents.h" +#include "OculusXRTelemetryPrivacySettings.h" + +#define LOCTEXT_NAMESPACE "OculusXRTelemetryPrivacySettings" + +void OculusXRTelemetry::SpawnNotification() +{ + const auto EditorPrivacySettings = GetDefault(); + if ((!EditorPrivacySettings) || (EditorPrivacySettings->bHasNotified)) + { + return; + } + + FNotificationInfo Info(LOCTEXT("PrivacyTelemetrySettingsName", "MetaXR Usage Data")); + Info.Image = FOculusToolStyle::Get().GetBrush("OculusTool.MenuButton"); + Info.ExpireDuration = 10.0f; + Info.bFireAndForget = false; + Info.Hyperlink = FSimpleDelegate::CreateLambda([EditorPrivacySettings]() { + const FString DocsURL = EditorPrivacySettings->GetAdditionalInfoUrl(); + FPlatformProcess::LaunchURL(*DocsURL, nullptr, nullptr); + }); + Info.HyperlinkText = EditorPrivacySettings->GetAdditionalInfoUrlLabel(); + Info.SubText = EditorPrivacySettings->GetTrueStateDescription(); + Info.bUseLargeFont = true; + TPromise> BtnNotificationPromise; + const auto Clicked = [NotificationFuture = BtnNotificationPromise.GetFuture().Share()](bool bConsent) { + const TSharedPtr Notification = NotificationFuture.Get(); + Notification->SetCompletionState(bConsent ? SNotificationItem::CS_Success : SNotificationItem::CS_Fail); + Notification->Fadeout(); + + const auto EditorPrivacySettings = GetMutableDefault(); + EditorPrivacySettings->Modify(); + EditorPrivacySettings->bIsEnabled = bConsent; + EditorPrivacySettings->bHasNotified = true; + EditorPrivacySettings->SaveConfig(); + if (FOculusXRHMDModule::Get().IsOVRPluginAvailable() && FOculusXRHMDModule::GetPluginWrapper().IsInitialized()) + { + Events::FEditorConsent().End(bConsent ? EAction::Success : EAction::Fail); + OculusXRTelemetry::PropagateTelemetryConsent(); + } + }; + Info.ButtonDetails.Add( + FNotificationButtonInfo( + EditorPrivacySettings->GetFalseStateLabel(), + EditorPrivacySettings->GetFalseStateTooltip(), + FSimpleDelegate::CreateLambda(Clicked, false), + SNotificationItem::CS_Pending)); + Info.ButtonDetails.Add( + FNotificationButtonInfo( + EditorPrivacySettings->GetTrueStateLabel(), + EditorPrivacySettings->GetTrueStateTooltip(), + FSimpleDelegate::CreateLambda(Clicked, true), + SNotificationItem::CS_Pending)); + + const TSharedPtr PrivacyNotification = FSlateNotificationManager::Get().AddNotification(Info); + if (PrivacyNotification.IsValid()) + { + PrivacyNotification->SetCompletionState(SNotificationItem::CS_Pending); + BtnNotificationPromise.SetValue(PrivacyNotification); + } + + if (FOculusXRHMDModule::Get().IsOVRPluginAvailable() && FOculusXRHMDModule::GetPluginWrapper().IsInitialized()) + { + const UGeneralProjectSettings& ProjectSettings = *GetDefault(); + const FString ProjectIdString = ProjectSettings.ProjectID.ToString(); + NotEnd = Events::FEditorConsent().Start() // + .AddAnnotation(Events::ConsentOriginKey, "Notification") // + .AddAnnotation("project_hash", StringCast(*ProjectIdString).Get()); + } +} + +#undef LOCTEXT_NAMESPACE diff --git a/Plugins/MetaXR/Source/OculusXREditor/Private/OculusXRPrivacyNotification.h b/Plugins/MetaXR/Source/OculusXREditor/Private/OculusXRPrivacyNotification.h new file mode 100644 index 0000000..542c444 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXREditor/Private/OculusXRPrivacyNotification.h @@ -0,0 +1,7 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#pragma once +namespace OculusXRTelemetry +{ + void SpawnNotification(); +} diff --git a/Plugins/MetaXR/Source/OculusXREditor/Private/OculusXRSettingsToggle.cpp b/Plugins/MetaXR/Source/OculusXREditor/Private/OculusXRSettingsToggle.cpp new file mode 100644 index 0000000..6992cf9 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXREditor/Private/OculusXRSettingsToggle.cpp @@ -0,0 +1,202 @@ + +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +#include "OculusXRSettingsToggle.h" + +#include "Containers/Array.h" +#include "Delegates/Delegate.h" +#include "DetailCategoryBuilder.h" +#include "DetailLayoutBuilder.h" +#include "DetailWidgetRow.h" +#include "Engine/ImportantToggleSettingInterface.h" +#include "Fonts/SlateFontInfo.h" +#include "HAL/PlatformProcess.h" +#include "IDetailPropertyRow.h" +#include "Layout/Children.h" +#include "Layout/Margin.h" +#include "Misc/Attribute.h" +#include "PropertyHandle.h" +#include "SlotBase.h" +#include "Styling/AppStyle.h" +#include "Styling/SlateColor.h" +#include "Styling/SlateTypes.h" +#include "Templates/Casts.h" +#include "Types/SlateEnums.h" +#include "UObject/NameTypes.h" +#include "UObject/Object.h" +#include "Widgets/DeclarativeSyntaxSupport.h" +#include "Widgets/Input/SCheckBox.h" +#include "Widgets/Input/SHyperlink.h" +#include "Widgets/SBoxPanel.h" +#include "Widgets/SCompoundWidget.h" +#include "Widgets/Text/STextBlock.h" + +#define LOCTEXT_NAMESPACE "OculusXRSettingsToggle" + +class SImportantToggleButton : public SCompoundWidget +{ +public: + SLATE_BEGIN_ARGS(SImportantToggleButton) + : _Text() + { + } + + SLATE_STYLE_ARGUMENT(FCheckBoxStyle, CheckBoxStyle) + SLATE_ARGUMENT(FText, Text) + SLATE_ARGUMENT(FText, ToolTipText) + SLATE_ATTRIBUTE(bool, IsSet) + SLATE_EVENT(FSimpleDelegate, OnToggled) + + SLATE_END_ARGS() + + void Construct(const FArguments& InArgs) + { + OnToggled = InArgs._OnToggled; + IsSetAttribute = InArgs._IsSet; + + FSlateFontInfo LargeDetailsFont = IDetailLayoutBuilder::GetDetailFontBold(); + LargeDetailsFont.Size += 4; + + ChildSlot + [SNew(SCheckBox) + .Style(InArgs._CheckBoxStyle) + .IsChecked(this, &SImportantToggleButton::GetCheckedState) + .OnCheckStateChanged(this, &SImportantToggleButton::OnClick) + .ToolTipText(InArgs._ToolTipText) + .Padding(FMargin(16.0f, 12.0f)) + .ForegroundColor(FSlateColor::UseForeground()) + .IsFocusable(true) + [SNew(STextBlock) + .Text(InArgs._Text) + .Font(LargeDetailsFont)]]; + } + +private: + void OnClick(ECheckBoxState State) + { + OnToggled.ExecuteIfBound(); + } + + ECheckBoxState GetCheckedState() const + { + return IsSetAttribute.Get() ? ECheckBoxState::Checked : ECheckBoxState::Unchecked; + } + +private: + TAttribute IsSetAttribute; + FSimpleDelegate OnToggled; +}; + +TSharedRef FOculusXRSettingsToggle::MakeInstance() +{ + return MakeShareable(new FOculusXRSettingsToggle); +} + +void FOculusXRSettingsToggle::CustomizeDetails(IDetailLayoutBuilder& DetailBuilder) +{ + TArray> Objects; + DetailBuilder.GetObjectsBeingCustomized(Objects); + + if (Objects.Num() == 1) + { + ToggleSettingObject = Objects[0]; + IImportantToggleSettingInterface* ToggleSettingInterface = Cast(ToggleSettingObject.Get()); + + if (ToggleSettingInterface != nullptr) + { + FName CategoryName; + FName PropertyName; + ToggleSettingInterface->GetToggleCategoryAndPropertyNames(CategoryName, PropertyName); + + IDetailCategoryBuilder& Category = DetailBuilder.EditCategory(CategoryName); + TogglePropertyHandle = DetailBuilder.GetProperty(PropertyName); + + FSlateFontInfo StateDescriptionFont = IDetailLayoutBuilder::GetDetailFont(); + StateDescriptionFont.Size += 4; + + // Customize collision section + Category.InitiallyCollapsed(false) + .AddProperty(TogglePropertyHandle) + .ShouldAutoExpand(true) + .CustomWidget() + [SNew(SVerticalBox) + + SVerticalBox::Slot() + .AutoHeight() + .Padding(0.0f, 12.0f, 0.0f, 0.0f) + [SNew(SHorizontalBox) + + SHorizontalBox::Slot() + .AutoWidth() + [SNew(SImportantToggleButton) + .CheckBoxStyle(FAppStyle::Get(), "Property.ToggleButton.Start") + .Text(ToggleSettingInterface->GetFalseStateLabel()) + .ToolTipText(ToggleSettingInterface->GetFalseStateTooltip()) + .IsSet(this, &FOculusXRSettingsToggle::IsToggleValue, false) + .OnToggled(this, &FOculusXRSettingsToggle::OnToggledTo, false)] + + SHorizontalBox::Slot() + .AutoWidth() + [SNew(SImportantToggleButton) + .CheckBoxStyle(FAppStyle::Get(), "Property.ToggleButton.End") + .Text(ToggleSettingInterface->GetTrueStateLabel()) + .ToolTipText(ToggleSettingInterface->GetTrueStateTooltip()) + .IsSet(this, &FOculusXRSettingsToggle::IsToggleValue, true) + .OnToggled(this, &FOculusXRSettingsToggle::OnToggledTo, true)] + + SHorizontalBox::Slot() + .HAlign(HAlign_Right) + .Padding(0.0f, 12.0f) + [SNew(SVerticalBox) + + SVerticalBox::Slot() + .VAlign(VAlign_Center) + [SNew(SHyperlink) + .Text(ToggleSettingInterface->GetAdditionalInfoUrlLabel()) + .OnNavigate(this, &FOculusXRSettingsToggle::OnNavigateHyperlink, ToggleSettingInterface->GetAdditionalInfoUrl())]]] + + SVerticalBox::Slot() + .AutoHeight() + .Padding(0.0f, 12.0f) + [SNew(STextBlock) + .AutoWrapText(true) + .Text(this, &FOculusXRSettingsToggle::GetDescriptionText) + .Font(StateDescriptionFont)]]; + } + } +} + +bool FOculusXRSettingsToggle::IsToggleValue(bool bValue) const +{ + bool bPropertyValue = false; + TogglePropertyHandle->GetValue(bPropertyValue); + return bPropertyValue == bValue; +} + +void FOculusXRSettingsToggle::OnToggledTo(bool bSetTo) +{ + TogglePropertyHandle->SetValue(bSetTo); +} + +void FOculusXRSettingsToggle::OnNavigateHyperlink(FString Url) +{ + FPlatformProcess::LaunchURL(*Url, nullptr, nullptr); +} + +FText FOculusXRSettingsToggle::GetDescriptionText() const +{ + IImportantToggleSettingInterface* ToogleSettingInterface = Cast(ToggleSettingObject.Get()); + + if (ToogleSettingInterface != nullptr) + { + bool bPropertyValue = false; + TogglePropertyHandle->GetValue(bPropertyValue); + + if (bPropertyValue) + { + return ToogleSettingInterface->GetTrueStateDescription(); + } + else + { + return ToogleSettingInterface->GetFalseStateDescription(); + } + } + return FText::GetEmpty(); +} + +#undef LOCTEXT_NAMESPACE diff --git a/Plugins/MetaXR/Source/OculusXREditor/Private/OculusXRSettingsToggle.h b/Plugins/MetaXR/Source/OculusXREditor/Private/OculusXRSettingsToggle.h new file mode 100644 index 0000000..1c9fb70 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXREditor/Private/OculusXRSettingsToggle.h @@ -0,0 +1,27 @@ + +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. +#pragma once + +#include "CoreMinimal.h" +#include "IDetailCustomization.h" + +class IPropertyHandle; + +class OCULUSXREDITOR_API FOculusXRSettingsToggle : public IDetailCustomization +{ +public: + static TSharedRef MakeInstance(); + + // IDetailCustomization interface + virtual void CustomizeDetails(IDetailLayoutBuilder& DetailBuilder) override; + // End of IDetailCustomization interface +private: + bool IsToggleValue(bool bValue) const; + void OnToggledTo(bool bSetTo); + void OnNavigateHyperlink(FString Url); + FText GetDescriptionText() const; + + TSharedPtr TogglePropertyHandle; + TWeakObjectPtr ToggleSettingObject; +}; diff --git a/Plugins/MetaXR/Source/OculusXREditor/Private/OculusXRTelemetryEditorEvents.h b/Plugins/MetaXR/Source/OculusXREditor/Private/OculusXRTelemetryEditorEvents.h new file mode 100644 index 0000000..e92c412 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXREditor/Private/OculusXRTelemetryEditorEvents.h @@ -0,0 +1,10 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#pragma once + +#include "OculusXRTelemetry.h" + +namespace OculusXRTelemetry::Events +{ + using FEditorStart = TMarker<191956532>; +} // namespace OculusXRTelemetry::Events diff --git a/Plugins/MetaXR/Source/OculusXREditor/Private/OculusXRToolCommands.cpp b/Plugins/MetaXR/Source/OculusXREditor/Private/OculusXRToolCommands.cpp new file mode 100644 index 0000000..23b1912 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXREditor/Private/OculusXRToolCommands.cpp @@ -0,0 +1,30 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +#include "OculusXRToolCommands.h" + +#include "../../OculusXRProjectSetupTool/Private/OculusXRProjectSetupToolModule.h" +#include "Framework/Docking/TabManager.h" + +#define LOCTEXT_NAMESPACE "FOculusXREditorModule" + +void FOculusToolCommands::RegisterCommands() +{ + UI_COMMAND(OpenProjectSetupTool, "Meta XR Project Setup Tool", "Show Meta XR Project Setup Tool", EUserInterfaceActionType::Button, FInputChord()); + UI_COMMAND(ToggleDeploySo, "Deploy compiled .so directly to device", "Faster deploy when we only have code changes by deploying compiled .so directly to device", EUserInterfaceActionType::ToggleButton, FInputChord()); + UI_COMMAND(OpenPlatWindow, "Meta XR Platform Window", "Show Meta XR Platform Window", EUserInterfaceActionType::Button, FInputChord()); + + UI_COMMAND(ToggleMetaXRSim, "Meta XR Simulator", "Activate/Deactivate Meta XR Simulator", EUserInterfaceActionType::ToggleButton, FInputChord()); + + UI_COMMAND(LaunchGameRoom, "Launch GameRoom", "Launch GameRoom", EUserInterfaceActionType::Button, FInputChord()); + UI_COMMAND(LaunchLivingRoom, "Launch Living Room", "Launch Living Room", EUserInterfaceActionType::Button, FInputChord()); + UI_COMMAND(LaunchBedroom, "Launch Bedroom", "Launch Bedroom", EUserInterfaceActionType::Button, FInputChord()); + UI_COMMAND(StopServer, "Stop Server", "Stop Server", EUserInterfaceActionType::Button, FInputChord()); +} + +void FOculusToolCommands::ShowOculusTool() +{ + IOculusXRProjectSetupToolModule::Get().ShowProjectSetupTool("Console"); +} + +#undef LOCTEXT_NAMESPACE diff --git a/Plugins/MetaXR/Source/OculusXREditor/Private/OculusXRToolCommands.h b/Plugins/MetaXR/Source/OculusXREditor/Private/OculusXRToolCommands.h new file mode 100644 index 0000000..54a1437 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXREditor/Private/OculusXRToolCommands.h @@ -0,0 +1,44 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CoreMinimal.h" +#include "Framework/Commands/Commands.h" +#include "OculusXRToolStyle.h" +#include "OculusXREditorModule.h" +#include "HAL/IConsoleManager.h" + +class FOculusToolCommands : public TCommands +{ +public: + FOculusToolCommands() + : TCommands( + TEXT("OculusTool"), NSLOCTEXT("Contexts", "OculusXREditor", "OculusXREditor Plugin"), NAME_None, + FOculusToolStyle::GetStyleSetName()) + , ShowOculusToolCommand( + TEXT("vr.oculus.ShowToolWindow"), + *NSLOCTEXT("OculusRift", "CCommandText_ShowToolWindow", + "Show the Oculus Editor Tool window (editor only).") + .ToString(), + FConsoleCommandDelegate::CreateRaw(this, &FOculusToolCommands::ShowOculusTool)) + { + } + + // TCommands<> interface + virtual void RegisterCommands() override; + + TSharedPtr OpenProjectSetupTool; + TSharedPtr ToggleDeploySo; + TSharedPtr OpenPlatWindow; + TSharedPtr ToggleMetaXRSim; + TSharedPtr LaunchGameRoom; + TSharedPtr LaunchLivingRoom; + TSharedPtr LaunchBedroom; + TSharedPtr StopServer; + +private: + void ShowOculusTool(); + + FAutoConsoleCommand ShowOculusToolCommand; +}; diff --git a/Plugins/MetaXR/Source/OculusXREditor/Private/OculusXRToolStyle.cpp b/Plugins/MetaXR/Source/OculusXREditor/Private/OculusXRToolStyle.cpp new file mode 100644 index 0000000..e6f3675 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXREditor/Private/OculusXRToolStyle.cpp @@ -0,0 +1,72 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +#include "OculusXRToolStyle.h" +#include "Styling/SlateStyleRegistry.h" +#include "Framework/Application/SlateApplication.h" +#include "Slate/SlateGameResources.h" +#include "Interfaces/IPluginManager.h" + +TSharedPtr FOculusToolStyle::StyleInstance = nullptr; + +void FOculusToolStyle::Initialize() +{ + if (!StyleInstance.IsValid()) + { + StyleInstance = Create(); + FSlateStyleRegistry::RegisterSlateStyle(*StyleInstance); + } +} + +void FOculusToolStyle::Shutdown() +{ + FSlateStyleRegistry::UnRegisterSlateStyle(*StyleInstance); + ensure(StyleInstance.IsUnique()); + StyleInstance.Reset(); +} + +FName FOculusToolStyle::GetStyleSetName() +{ + static FName StyleSetName(TEXT("OculusToolStyle")); + return StyleSetName; +} + +#define IMAGE_BRUSH(RelativePath, ...) FSlateImageBrush(Style->RootToContentDir(RelativePath, TEXT(".png")), __VA_ARGS__) +#define BOX_BRUSH(RelativePath, ...) FSlateBoxBrush(Style->RootToContentDir(RelativePath, TEXT(".png")), __VA_ARGS__) +#define BORDER_BRUSH(RelativePath, ...) FSlateBorderBrush(Style->RootToContentDir(RelativePath, TEXT(".png")), __VA_ARGS__) +#define TTF_FONT(RelativePath, ...) FSlateFontInfo(Style->RootToContentDir(RelativePath, TEXT(".ttf")), __VA_ARGS__) +#define OTF_FONT(RelativePath, ...) FSlateFontInfo(Style->RootToContentDir(RelativePath, TEXT(".otf")), __VA_ARGS__) + +const FVector2D Icon16x16(16.0f, 16.0f); +const FVector2D Icon20x20(20.0f, 20.0f); +const FVector2D Icon40x40(40.0f, 40.0f); + +TSharedRef FOculusToolStyle::Create() +{ + TSharedRef Style = MakeShareable(new FSlateStyleSet("OculusToolStyle")); + Style->SetContentRoot(IPluginManager::Get().FindPlugin("OculusXR")->GetBaseDir() / TEXT("Resources")); + + Style->Set("OculusTool.MenuButton", new IMAGE_BRUSH(TEXT("ButtonIcon_80x"), Icon40x40)); + Style->Set("OculusTool.OpenPluginWindow", new IMAGE_BRUSH(TEXT("ButtonIcon_80x"), Icon40x40)); + + return Style; +} + +#undef IMAGE_BRUSH +#undef BOX_BRUSH +#undef BORDER_BRUSH +#undef TTF_FONT +#undef OTF_FONT + +void FOculusToolStyle::ReloadTextures() +{ + if (FSlateApplication::IsInitialized()) + { + FSlateApplication::Get().GetRenderer()->ReloadTextureResources(); + } +} + +const ISlateStyle& FOculusToolStyle::Get() +{ + return *StyleInstance; +} diff --git a/Plugins/MetaXR/Source/OculusXREditor/Private/OculusXRToolStyle.h b/Plugins/MetaXR/Source/OculusXREditor/Private/OculusXRToolStyle.h new file mode 100644 index 0000000..7af90a1 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXREditor/Private/OculusXRToolStyle.h @@ -0,0 +1,30 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CoreMinimal.h" +#include "Styling/SlateStyle.h" + +/** */ +class FOculusToolStyle +{ +public: + static void Initialize(); + + static void Shutdown(); + + /** reloads textures used by slate renderer */ + static void ReloadTextures(); + + /** @return The Slate style set for the Shooter game */ + static const ISlateStyle& Get(); + + static FName GetStyleSetName(); + +private: + static TSharedRef Create(); + +private: + static TSharedPtr StyleInstance; +}; diff --git a/Plugins/MetaXR/Source/OculusXREditor/Public/IOculusXREditorModule.h b/Plugins/MetaXR/Source/OculusXREditor/Public/IOculusXREditorModule.h new file mode 100644 index 0000000..9307db1 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXREditor/Public/IOculusXREditorModule.h @@ -0,0 +1,19 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CoreMinimal.h" +#include "Modules/ModuleInterface.h" + +class FToolBarBuilder; +class FMenuBuilder; + +#define OCULUS_EDITOR_MODULE_NAME "OculusXREditor" + +////////////////////////////////////////////////////////////////////////// +// IOculusXREditorModule + +class IOculusXREditorModule : public IModuleInterface +{ +}; diff --git a/Plugins/MetaXR/Source/OculusXREditor/Public/OculusXREditorSettings.h b/Plugins/MetaXR/Source/OculusXREditor/Public/OculusXREditorSettings.h new file mode 100644 index 0000000..ed522fc --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXREditor/Public/OculusXREditorSettings.h @@ -0,0 +1,37 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CoreMinimal.h" +#include "UObject/NoExportTypes.h" +#include "OculusXREditorSettings.generated.h" + +UENUM() +enum class EOculusXRPlatform : uint8 +{ + PC UMETA(DisplayName = "PC"), + Mobile UMETA(DisplayName = "Mobile"), + Length UMETA(DisplayName = "Invalid") +}; + +/** + * + */ +UCLASS(config = Editor) +class OCULUSXREDITOR_API UOculusXREditorSettings : public UObject +{ + GENERATED_BODY() + +public: + UOculusXREditorSettings(); + + UPROPERTY(config, EditAnywhere, Category = MetaXR) + TMap PerfToolIgnoreList; + + UPROPERTY(config, EditAnywhere, Category = MetaXR) + EOculusXRPlatform PerfToolTargetPlatform; + + UPROPERTY(globalconfig, EditAnywhere, Category = MetaXR) + bool bAddMenuOption; +}; diff --git a/Plugins/MetaXR/Source/OculusXREditor/Public/OculusXRPlatformToolSettings.h b/Plugins/MetaXR/Source/OculusXREditor/Public/OculusXRPlatformToolSettings.h new file mode 100644 index 0000000..9614bc1 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXREditor/Public/OculusXRPlatformToolSettings.h @@ -0,0 +1,272 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CoreMinimal.h" +#include "UObject/NoExportTypes.h" +#include "OculusXRPlatformToolSettings.generated.h" + +UENUM() +enum class EOculusXRPlatformTarget : uint8 +{ + Rift UMETA(DisplayName = "Rift"), + Quest UMETA(DisplayName = "Quest"), + Length UMETA(DisplayName = "Invalid") +}; + +UENUM() +enum class EOculusXRGamepadEmulation : uint8 +{ + Off UMETA(DisplayName = "Off"), + Twinstick UMETA(DisplayName = "Twinstick"), + RightDPad UMETA(DisplayName = "Right D Pad"), + LeftDPad UMETA(DisplayName = "Left D Pad"), + Length UMETA(DisplayName = "Invalid") +}; + +UENUM() +enum class EOculusXRAssetType : uint8 +{ + Default UMETA(DisplayName = "Default"), + Store UMETA(DisplayName = "Store"), + Language_Pack UMETA(DisplayName = "Language Pack"), + Length UMETA(DisplayName = "Invlaid"), +}; + +USTRUCT() +struct FOculusXRRedistPackage +{ + GENERATED_USTRUCT_BODY() + + UPROPERTY(config, EditAnywhere, Category = MetaXR) + bool Included = false; + + UPROPERTY(config, EditAnywhere, Category = MetaXR) + FString Name; + + UPROPERTY(config, EditAnywhere, Category = MetaXR) + FString Id; +}; + +USTRUCT() +struct FOculusXRAssetConfig +{ + GENERATED_USTRUCT_BODY() + + UPROPERTY(config, EditAnywhere, Category = MetaXR) + EOculusXRAssetType AssetType = EOculusXRAssetType::Default; + + UPROPERTY(config, EditAnywhere, Category = MetaXR) + bool Required = false; + + UPROPERTY(config, EditAnywhere, Category = MetaXR) + FString Name; + + UPROPERTY(config, EditAnywhere, Category = MetaXR) + FString Sku; +}; + +USTRUCT() +struct FOculusXRAssetConfigArray +{ + GENERATED_USTRUCT_BODY() + + UPROPERTY(config, EditAnywhere, Category = MetaXR) + TArray ConfigArray; +}; + +/** + * + */ +UCLASS(config = Editor) +class OCULUSXREDITOR_API UOculusXRPlatformToolSettings : public UObject +{ + GENERATED_BODY() + +public: + UOculusXRPlatformToolSettings(); + + uint8 GetTargetPlatform() + { + return (uint8)OculusTargetPlatform; + } + void SetTargetPlatform(uint8 i) + { + OculusTargetPlatform = (EOculusXRPlatformTarget)i; + } + + FString GetApplicationID() + { + return (uint8)OculusTargetPlatform < OculusApplicationID.Num() ? OculusApplicationID[(uint8)OculusTargetPlatform] : ""; + } + void SetApplicationID(FString s) + { + if (OculusTargetPlatform < EOculusXRPlatformTarget::Length) + { + OculusApplicationID[(uint8)OculusTargetPlatform] = s; + } + } + + FString GetApplicationToken() + { + return (uint8)OculusTargetPlatform < OculusApplicationToken.Num() ? OculusApplicationToken[(uint8)OculusTargetPlatform] : ""; + } + void SetApplicationToken(FString s) + { + if (OculusTargetPlatform < EOculusXRPlatformTarget::Length) + { + OculusApplicationToken[(uint8)OculusTargetPlatform] = s; + } + } + + FString GetReleaseChannel() + { + return (uint8)OculusTargetPlatform < OculusReleaseChannel.Num() ? OculusReleaseChannel[(uint8)OculusTargetPlatform] : "Alpha"; + } + void SetReleaseChannel(FString s) + { + if (OculusTargetPlatform < EOculusXRPlatformTarget::Length) + { + OculusReleaseChannel[(uint8)OculusTargetPlatform] = s; + } + } + + FString GetReleaseNote() + { + return (uint8)OculusTargetPlatform < OculusReleaseNote.Num() ? OculusReleaseNote[(uint8)OculusTargetPlatform] : ""; + } + void SetReleaseNote(FString s) + { + if (OculusTargetPlatform < EOculusXRPlatformTarget::Length) + { + OculusReleaseNote[(uint8)OculusTargetPlatform] = s; + } + } + + FString GetLaunchFilePath() + { + return (uint8)OculusTargetPlatform < OculusLaunchFilePath.Num() ? OculusLaunchFilePath[(uint8)OculusTargetPlatform] : ""; + } + void SetLaunchFilePath(FString s) + { + if (OculusTargetPlatform < EOculusXRPlatformTarget::Length) + { + OculusLaunchFilePath[(uint8)OculusTargetPlatform] = s; + } + } + + EOculusXRGamepadEmulation GetRiftGamepadEmulation() + { + return OculusRiftGamepadEmulation; + } + void SetRiftGamepadEmulation(uint8 i) + { + OculusRiftGamepadEmulation = (EOculusXRGamepadEmulation)i; + } + + FString GetLanguagePacksPath() + { + return (uint8)OculusTargetPlatform < OculusLanguagePacksPath.Num() ? OculusLanguagePacksPath[(uint8)OculusTargetPlatform] : ""; + } + void SetLanguagePacksPath(FString s) + { + if (OculusTargetPlatform < EOculusXRPlatformTarget::Length) + { + OculusLanguagePacksPath[(uint8)OculusTargetPlatform] = s; + } + } + + FString GetExpansionFilesPath() + { + return (uint8)OculusTargetPlatform < OculusExpansionFilesPath.Num() ? OculusExpansionFilesPath[(uint8)OculusTargetPlatform] : ""; + } + void SetExpansionFilesPath(FString s) + { + if (OculusTargetPlatform < EOculusXRPlatformTarget::Length) + { + OculusExpansionFilesPath[(uint8)OculusTargetPlatform] = s; + } + } + + FString GetSymbolDirPath() + { + return (uint8)OculusTargetPlatform < OculusSymbolDirPath.Num() ? OculusSymbolDirPath[(uint8)OculusTargetPlatform] : ""; + } + void SetSymbolDirPath(FString s) + { + if (OculusTargetPlatform < EOculusXRPlatformTarget::Length) + { + OculusSymbolDirPath[(uint8)OculusTargetPlatform] = s; + } + } + + TArray* GetAssetConfigs() + { + return (uint8)OculusTargetPlatform < OculusAssetConfigs.Num() ? &OculusAssetConfigs[(uint8)OculusTargetPlatform].ConfigArray : nullptr; + } + + UPROPERTY(config, EditAnywhere, Category = MetaXR) + FString OculusRiftBuildDirectory; + + UPROPERTY(config, EditAnywhere, Category = MetaXR) + FString OculusRiftBuildVersion; + + UPROPERTY(config, EditAnywhere, Category = MetaXR) + FString OculusRiftLaunchParams; + + UPROPERTY(config, EditAnywhere, Category = MetaXR) + bool OculusRiftFireWallException; + + UPROPERTY(config, EditAnywhere, Category = MetaXR) + FString OculusRift2DLaunchPath; + + UPROPERTY(config, EditAnywhere, Category = MetaXR) + FString OculusRift2DLaunchParams; + + UPROPERTY(config, EditAnywhere, Category = MetaXR) + TArray OculusRedistPackages; + + UPROPERTY(config, EditAnywhere, Category = MetaXR) + bool UploadDebugSymbols; + + UPROPERTY(config, EditAnywhere, Category = MetaXR) + bool DebugSymbolsOnly; + + UPROPERTY(config, EditAnywhere, Category = MetaXR) + FString BuildID; + +private: + UPROPERTY(config, EditAnywhere, Category = MetaXR) + EOculusXRPlatformTarget OculusTargetPlatform; + + UPROPERTY(config, EditAnywhere, Category = MetaXR) + TArray OculusApplicationID; + + UPROPERTY(config, EditAnywhere, Category = MetaXR) + TArray OculusApplicationToken; + + UPROPERTY(config, EditAnywhere, Category = MetaXR) + TArray OculusReleaseChannel; + + UPROPERTY(config, EditAnywhere, Category = MetaXR) + TArray OculusReleaseNote; + + UPROPERTY(config, EditAnywhere, Category = MetaXR) + TArray OculusLaunchFilePath; + + UPROPERTY(config, EditAnywhere, Category = MetaXR) + EOculusXRGamepadEmulation OculusRiftGamepadEmulation; + + UPROPERTY(config, EditAnywhere, Category = MetaXR) + TArray OculusLanguagePacksPath; + + UPROPERTY(config, EditAnywhere, Category = MetaXR) + TArray OculusExpansionFilesPath; + + UPROPERTY(config, EditAnywhere, Category = MetaXR) + TArray OculusSymbolDirPath; + + UPROPERTY(config, EditAnywhere, Category = MetaXR) + TArray OculusAssetConfigs; +}; diff --git a/Plugins/MetaXR/Source/OculusXREyeTracker/OculusXREyeTracker.Build.cs b/Plugins/MetaXR/Source/OculusXREyeTracker/OculusXREyeTracker.Build.cs new file mode 100644 index 0000000..e3299a6 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXREyeTracker/OculusXREyeTracker.Build.cs @@ -0,0 +1,42 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +namespace UnrealBuildTool.Rules +{ + public class OculusXREyeTracker : ModuleRules + { + public OculusXREyeTracker(ReadOnlyTargetRules Target) : base(Target) + { + bUseUnity = true; + + if (Target.Platform == UnrealTargetPlatform.Win64 || + Target.Platform == UnrealTargetPlatform.Android) + { + PrivateIncludePaths.AddRange( + new string[] { + "OculusXRHMD/Private", + }); + + PublicDependencyModuleNames.AddRange( + new string[] + { + "InputDevice", + "EyeTracker", + "OVRPluginXR", + "OculusXRHMD", + } + ); + + PrivateDependencyModuleNames.AddRange( + new string[] + { + "Core", + "CoreUObject", + "Engine", + "InputCore", + } + ); + } + } + } +} diff --git a/Plugins/MetaXR/Source/OculusXREyeTracker/Private/OculusXREyeTracker.cpp b/Plugins/MetaXR/Source/OculusXREyeTracker/Private/OculusXREyeTracker.cpp new file mode 100644 index 0000000..8b1d3b3 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXREyeTracker/Private/OculusXREyeTracker.cpp @@ -0,0 +1,214 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#include "IEyeTrackerModule.h" +#include "EyeTrackerTypes.h" +#include "IEyeTracker.h" +#include "Modules/ModuleManager.h" + +#include "GameFramework/WorldSettings.h" +#include "Engine/World.h" +#include "IXRTrackingSystem.h" +#include "Engine/Engine.h" + +#include "OculusXRHMDModule.h" +#include "OculusXRHMDPrivate.h" +#include "OculusXRTelemetryEyeTrackerEvents.h" + +#if OCULUS_HMD_SUPPORTED_PLATFORMS + +namespace OculusXRHMD +{ + class FOculusXREyeTracker : public IEyeTracker + { + public: + FOculusXREyeTracker() + { + GetUnitScaleFactorFromSettings(GWorld, WorldToMeters); + if (GEngine != nullptr) + { + OculusXRHMD = GEngine->XRSystem.Get(); + } + OculusXRTelemetry::TScopedMarker(); + } + + virtual ~FOculusXREyeTracker() + { + if (bIsTrackerStarted) + { + ensureMsgf(OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().StopEyeTracking()), TEXT("Cannot stop eye tracker.")); + } + } + + private: + // IEyeTracker + virtual void SetEyeTrackedPlayer(APlayerController*) override + { + unimplemented(); + } + + virtual bool GetEyeTrackerGazeData(FEyeTrackerGazeData& OutGazeData) const override + { + return ReactOnEyeTrackerState([this, &OutGazeData](const ovrpEyeGazesState& OVREyeGazesState, const FTransform& TrackingToWorld) { + OutGazeData.FixationPoint = GetFixationPoint(OVREyeGazesState); + OutGazeData.ConfidenceValue = MergeConfidence(OVREyeGazesState); + + OutGazeData.GazeDirection = TrackingToWorld.TransformVector(MergeOrientation(OVREyeGazesState).GetForwardVector()); + OutGazeData.GazeOrigin = TrackingToWorld.TransformPosition(MergePosition(OVREyeGazesState) * WorldToMeters); + }); + } + + virtual bool GetEyeTrackerStereoGazeData(FEyeTrackerStereoGazeData& OutGazeData) const override + { + return ReactOnEyeTrackerState([this, &OutGazeData](const ovrpEyeGazesState& OVREyeGazesState, const FTransform& TrackingToWorld) { + OutGazeData.FixationPoint = GetFixationPoint(OVREyeGazesState); + OutGazeData.ConfidenceValue = MergeConfidence(OVREyeGazesState); + + const auto& LeftEyePose = OVREyeGazesState.EyeGazes[ovrpEye_Left].Pose; + const auto& RightEyePose = OVREyeGazesState.EyeGazes[ovrpEye_Right].Pose; + OutGazeData.LeftEyeDirection = TrackingToWorld.TransformVector(OculusXRHMD::ToFQuat(LeftEyePose.Orientation).GetForwardVector()); + OutGazeData.RightEyeDirection = TrackingToWorld.TransformVector(OculusXRHMD::ToFQuat(RightEyePose.Orientation).GetForwardVector()); + OutGazeData.LeftEyeOrigin = TrackingToWorld.TransformPosition(OculusXRHMD::ToFVector(LeftEyePose.Position) * WorldToMeters); + OutGazeData.RightEyeOrigin = TrackingToWorld.TransformPosition(OculusXRHMD::ToFVector(RightEyePose.Position) * WorldToMeters); + }); + } + + virtual EEyeTrackerStatus GetEyeTrackerStatus() const override + { + ovrpBool IsSupported = ovrpBool_False; + ovrpBool IsEnabled = ovrpBool_False; + const ovrpResult TrackingSupportedResult = FOculusXRHMDModule::GetPluginWrapper().GetEyeTrackingSupported(&IsSupported); + const ovrpResult TrackingEnabledResult = FOculusXRHMDModule::GetPluginWrapper().GetEyeTrackingEnabled(&IsEnabled); + if (OVRP_SUCCESS(TrackingSupportedResult) && OVRP_SUCCESS(TrackingEnabledResult)) + { + if ((IsSupported == ovrpBool_True) && (IsEnabled == ovrpBool_True)) + { + return EEyeTrackerStatus::Tracking; + } + if (IsSupported == ovrpBool_True) + { + return EEyeTrackerStatus::NotTracking; + } + } + + return EEyeTrackerStatus::NotConnected; + } + + virtual bool IsStereoGazeDataAvailable() const override + { + return true; + } + + private: + // FOculusXREyeTracker + template + bool ReactOnEyeTrackerState(ReactOnState&& React) const + { + if (!bIsTrackerStarted) + { + bIsTrackerStarted = OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().StartEyeTracking()); + } + + if (bIsTrackerStarted) + { + ovrpEyeGazesState OVREyeGazesState; + const ovrpResult OVREyeGazesStateResult = FOculusXRHMDModule::GetPluginWrapper().GetEyeGazesState(ovrpStep_Render, OVRP_CURRENT_FRAMEINDEX, &OVREyeGazesState); + checkf(OVREyeGazesStateResult != ovrpFailure_NotYetImplemented, TEXT("Eye tracking is not implemented on this platform.")); + + if (OVRP_SUCCESS(OVREyeGazesStateResult) && IsStateValidForBothEyes(OVREyeGazesState)) + { + FTransform TrackingToWorld = OculusXRHMD ? OculusXRHMD->GetTrackingToWorldTransform() : FTransform::Identity; + React(OVREyeGazesState, TrackingToWorld); + + return true; + } + } + + return false; + } + + static float IsStateValidForBothEyes(const ovrpEyeGazesState& OVREyeGazesState) + { + return OVREyeGazesState.EyeGazes[ovrpEye_Left].IsValid && OVREyeGazesState.EyeGazes[ovrpEye_Right].IsValid; + } + + static float MergeConfidence(const ovrpEyeGazesState& OVREyeGazesState) + { + const auto& LeftEyeConfidence = OVREyeGazesState.EyeGazes[ovrpEye_Left].Confidence; + const auto& RightEyeConfidence = OVREyeGazesState.EyeGazes[ovrpEye_Right].Confidence; + return FGenericPlatformMath::Min(LeftEyeConfidence, RightEyeConfidence); + } + + /// Warn: The result of MergedOrientation is not normalized. + static FQuat MergeOrientation(const ovrpEyeGazesState& OVREyeGazesState) + { + const auto& LeftEyeOrientation = OculusXRHMD::ToFQuat(OVREyeGazesState.EyeGazes[ovrpEye_Left].Pose.Orientation); + const auto& RightEyeOrientation = OculusXRHMD::ToFQuat(OVREyeGazesState.EyeGazes[ovrpEye_Right].Pose.Orientation); + return FQuat::FastLerp(LeftEyeOrientation, RightEyeOrientation, 0.5f); + } + + static FVector MergePosition(const ovrpEyeGazesState& OVREyeGazesState) + { + const auto& LeftEyePosition = OculusXRHMD::ToFVector(OVREyeGazesState.EyeGazes[ovrpEye_Left].Pose.Position); + const auto& RightEyePosition = OculusXRHMD::ToFVector(OVREyeGazesState.EyeGazes[ovrpEye_Right].Pose.Position); + return (LeftEyePosition + RightEyePosition) / 2.f; + } + + static FVector GetFixationPoint(const ovrpEyeGazesState& OVREyeGazesState) + { + return FVector::ZeroVector; // Not supported + } + + float WorldToMeters = 100.f; + IXRTrackingSystem* OculusXRHMD = nullptr; + mutable bool bIsTrackerStarted = false; + }; +} // namespace OculusXRHMD +#endif // OCULUS_HMD_SUPPORTED_PLATFORMS + +class FOculusXREyeTrackerModule : public IEyeTrackerModule +{ +public: + static inline FOculusXREyeTrackerModule& Get() + { + return FModuleManager::LoadModuleChecked("OculusXREyeTracker"); + } + + static inline bool IsAvailable() + { + return FModuleManager::Get().IsModuleLoaded("OculusXREyeTracker"); + } + + virtual FString GetModuleKeyName() const override + { + return TEXT("OculusXREyeTracker"); + } + + virtual bool IsEyeTrackerConnected() const override + { +#if OCULUS_HMD_SUPPORTED_PLATFORMS + if (FOculusXRHMDModule::Get().IsOVRPluginAvailable() && FOculusXRHMDModule::GetPluginWrapper().IsInitialized()) + { + ovrpBool IsSupported = ovrpBool_False; + const ovrpResult trackingSupportedResult = FOculusXRHMDModule::GetPluginWrapper().GetEyeTrackingSupported(&IsSupported); + if (OVRP_SUCCESS(trackingSupportedResult)) + { + return (IsSupported == ovrpBool_True); + } + } +#endif // OCULUS_HMD_SUPPORTED_PLATFORMS + return false; + } + + virtual TSharedPtr CreateEyeTracker() override + { +#if OCULUS_HMD_SUPPORTED_PLATFORMS + if (FOculusXRHMDModule::Get().IsOVRPluginAvailable() && FOculusXRHMDModule::GetPluginWrapper().IsInitialized()) + { + return MakeShared(); + } +#endif // OCULUS_HMD_SUPPORTED_PLATFORMS + return TSharedPtr(); + } +}; + +IMPLEMENT_MODULE(FOculusXREyeTrackerModule, OculusXREyeTracker) diff --git a/Plugins/MetaXR/Source/OculusXREyeTracker/Private/OculusXRTelemetryEyeTrackerEvents.h b/Plugins/MetaXR/Source/OculusXREyeTracker/Private/OculusXRTelemetryEyeTrackerEvents.h new file mode 100644 index 0000000..f7c8c5e --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXREyeTracker/Private/OculusXRTelemetryEyeTrackerEvents.h @@ -0,0 +1,10 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#pragma once + +#include "OculusXRTelemetry.h" + +namespace OculusXRTelemetry::Events +{ + using FMovementSDKEyeTrackerCreated = TMarker<191957973>; +} diff --git a/Plugins/MetaXR/Source/OculusXRHMD/OculusMobile_APL.xml b/Plugins/MetaXR/Source/OculusXRHMD/OculusMobile_APL.xml new file mode 100644 index 0000000..c304ad0 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRHMD/OculusMobile_APL.xml @@ -0,0 +1,549 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +-keep class com.oculus.** { +*; +} +-keep class android.app.** { +*; +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Plugins/MetaXR/Source/OculusXRHMD/OculusXRHMD.Build.cs b/Plugins/MetaXR/Source/OculusXRHMD/OculusXRHMD.Build.cs new file mode 100644 index 0000000..61ccd32 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRHMD/OculusXRHMD.Build.cs @@ -0,0 +1,139 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +using System; +using System.IO; + +namespace UnrealBuildTool.Rules +{ + public class OculusXRHMD : ModuleRules + { + public OculusXRHMD(ReadOnlyTargetRules Target) : base(Target) + { + bUseUnity = true; + + var EngineDir = Path.GetFullPath(Target.RelativeEnginePath); + + PrivateIncludePaths.AddRange( + new string[] { + Path.Combine(EngineDir, "Source/Runtime/Renderer/Private"), + Path.Combine(EngineDir, "Source/Runtime/Renderer/Private"), + Path.Combine(EngineDir, "Source/Runtime/OpenGLDrv/Private"), + Path.Combine(EngineDir, "Source/Runtime/Engine/Classes/Components"), + Path.Combine(EngineDir, "Source/Runtime/Engine/Classes/Kismet"), + }); + + PublicIncludePathModuleNames.AddRange( + new string[] { + "Launch", + "ProceduralMeshComponent", + "AndroidPermission" + }); + + PrivateDependencyModuleNames.AddRange( + new string[] + { + "Core", + "CoreUObject", + "Engine", + "InputCore", + "RHI", + "RHICore", + "RenderCore", + "Renderer", + "Slate", + "SlateCore", + "ImageWrapper", + "MediaAssets", + "Analytics", + "OpenGLDrv", + "VulkanRHI", + "OVRPluginXR", + "OculusOpenXRLoader", + "ProceduralMeshComponent", + "Projects", + }); + + PublicDependencyModuleNames.AddRange( + new string[] + { + "HeadMountedDisplay", + }); + + if (Target.Version.MajorVersion > 5 || (Target.Version.MajorVersion == 5 && Target.Version.MinorVersion >= 3)) + { + PublicDependencyModuleNames.AddRange( + new string[] + { + "XRBase", + }); + } + + if (Target.bBuildEditor == true) + { + PrivateDependencyModuleNames.Add("UnrealEd"); + } + + AddEngineThirdPartyPrivateStaticDependencies(Target, "OpenGL"); + + if (Target.Platform == UnrealTargetPlatform.Win64) + { + // D3D + { + PrivateDependencyModuleNames.AddRange( + new string[] + { + "D3D11RHI", + "D3D12RHI", + }); + + PrivateIncludePaths.AddRange( + new string[] + { + "OculusXRMR/Public", + }); + + AddEngineThirdPartyPrivateStaticDependencies(Target, "DX11"); + AddEngineThirdPartyPrivateStaticDependencies(Target, "DX12"); + AddEngineThirdPartyPrivateStaticDependencies(Target, "NVAPI"); + AddEngineThirdPartyPrivateStaticDependencies(Target, "DX11Audio"); + AddEngineThirdPartyPrivateStaticDependencies(Target, "DirectSound"); + AddEngineThirdPartyPrivateStaticDependencies(Target, "NVAftermath"); + AddEngineThirdPartyPrivateStaticDependencies(Target, "IntelMetricsDiscovery"); + AddEngineThirdPartyPrivateStaticDependencies(Target, "IntelExtensionsFramework"); + } + + // Vulkan + { + AddEngineThirdPartyPrivateStaticDependencies(Target, "Vulkan"); + } + + // OVRPlugin + if (Target.Platform == UnrealTargetPlatform.Win64) + { + RuntimeDependencies.Add("$(PluginDir)/Source/ThirdParty/OVRPlugin/OVRPlugin/Lib/" + Target.Platform.ToString() + "/OpenXR/OVRPlugin.dll"); + } + } + else if (Target.Platform == UnrealTargetPlatform.Android) + { + // We are not currently supporting Mixed Reality on Android, but we need to include IOculusXRMRModule.h for OCULUS_MR_SUPPORTED_PLATFORMS definition + PrivateIncludePaths.AddRange( + new string[] + { + "OculusXRMR/Public" + }); + + // Vulkan + { + AddEngineThirdPartyPrivateStaticDependencies(Target, "Vulkan"); + } + + // AndroidPlugin + { + string PluginPath = Utils.MakePathRelativeTo(ModuleDirectory, Target.RelativeEnginePath); + AdditionalPropertiesForReceipt.Add("AndroidPlugin", Path.Combine(PluginPath, "OculusMobile_APL.xml")); + } + } + } + } +} diff --git a/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusStressTestShader.usf b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusStressTestShader.usf new file mode 100644 index 0000000..f708b36 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusStressTestShader.usf @@ -0,0 +1,65 @@ +#include "Common.ush" + +void MainVertexShader( + float4 InPosition : ATTRIBUTE0, + float2 InUV : ATTRIBUTE1, + out float2 OutUV : TEXCOORD0, + out float4 OutPosition : SV_POSITION + ) +{ + OutPosition = InPosition; + OutUV = InUV; +} + +Texture2D TextureParameter; + +#define Zoom 2 +#define Pan float2(0.5, 0) +#define Aspect 1 +#define Iterations int(128*PSVariables.IterationsMultiplier) +#define JuliaSeed float2(0.39, 0.2) +#define ColorScale float3(4, 5, 6) + +float ComputeValue(float2 v, float2 offset) +{ + float vxsquare = 0; + float vysquare = 0; + + int iteration = 0; + int lastIteration = Iterations; + + do + { + vxsquare = v.x * v.x; + vysquare = v.y * v.y; + + v = float2(vxsquare - vysquare, v.x * v.y * 2) + offset; + + iteration++; + + if ((lastIteration == Iterations) && (vxsquare + vysquare) > 4.0) + { + lastIteration = iteration + 1; + } + } while (iteration < lastIteration); + + return (float(iteration) - (log(log(sqrt(vxsquare + vysquare))) / log(2.0))) / float(Iterations); +} + +float4 Mandelbrot_Func(float2 texCoord : TEXCOORD0) : COLOR0 +{ + float2 v = (texCoord - 0.5) * Zoom * float2(1, Aspect) - Pan; + + float val = ComputeValue(v, v); + + return float4(sin(val * ColorScale.x), sin(val * ColorScale.y), sin(val * ColorScale.z), 1); +} + +void MainPixelShader( + in float2 uv : TEXCOORD0, + out float4 OutColor : SV_Target0 + ) +{ + OutColor = Mandelbrot_Func(uv); +} + diff --git a/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRAssetManager.cpp b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRAssetManager.cpp new file mode 100644 index 0000000..5c5a02a --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRAssetManager.cpp @@ -0,0 +1,294 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +#include "OculusXRAssetManager.h" +#include "OculusXRHMDPrivate.h" +#include "OculusXRHMDModule.h" +#include "Engine/StaticMesh.h" +#include "Components/StaticMeshComponent.h" +#include "UObject/SoftObjectPath.h" +#include "Engine/SkeletalMesh.h" +#include "Components/SkeletalMeshComponent.h" +#include "OculusXRAssetDirectory.h" +#include "UObject/GCObject.h" + +/* FOculusAssetDirectory + *****************************************************************************/ + +enum EOculusAsset +{ + LeftTouchRiftS, + RightTouchRiftS, + LeftTouchQuest2, + RightTouchQuest2, + LeftTouchQuestPro, + RightTouchQuestPro, + LeftTouchQuest3, + RightTouchQuest3, + OculusAssetTotal +}; + +FSoftObjectPath FOculusAssetDirectory::AssetListing[OculusAssetTotal] = { + FString(TEXT("/OculusXR/Meshes/LeftTouchForQuestRiftSController.LeftTouchForQuestRiftSController")), + FString(TEXT("/OculusXR/Meshes/RightTouchForQuestRiftSController.RightTouchForQuestRiftSController")), + FString(TEXT("/OculusXR/Meshes/LeftTouchForQuest2.LeftTouchForQuest2")), + FString(TEXT("/OculusXR/Meshes/RightTouchForQuest2.RightTouchForQuest2")), + FString(TEXT("/OculusXR/Meshes/LeftMetaQuestTouchPro.LeftMetaQuestTouchPro")), + FString(TEXT("/OculusXR/Meshes/RightMetaQuestTouchPro.RightMetaQuestTouchPro")), + FString(TEXT("/OculusXR/Meshes/LeftMetaQuestTouchPlus.LeftMetaQuestTouchPlus")), + FString(TEXT("/OculusXR/Meshes/RightMetaQuestTouchPlus.RightMetaQuestTouchPlus")), +}; + +#if WITH_EDITORONLY_DATA +class FOculusAssetRepo : public FGCObject, public TArray +{ +public: + // made an on-demand singleton rather than a static global, to avoid issues with FGCObject initialization + static FOculusAssetRepo& Get() + { + static FOculusAssetRepo AssetRepository; + return AssetRepository; + } + + UObject* LoadAndAdd(const FSoftObjectPath& AssetPath) + { + UObject* AssetObj = AssetPath.TryLoad(); + if (AssetObj != nullptr) + { + AddUnique(AssetObj); + } + return AssetObj; + } + +public: + //~ FGCObject interface + virtual void AddReferencedObjects(FReferenceCollector& Collector) override + { + Collector.AddReferencedObjects(*this); + } + virtual FString GetReferencerName() const override + { + return TEXT("FOculusAssetRepo"); + } +}; + +void FOculusAssetDirectory::LoadForCook() +{ + FOculusAssetRepo& AssetRepro = FOculusAssetRepo::Get(); + for (int32 AssetIndex = 0; AssetIndex < UE_ARRAY_COUNT(FOculusAssetDirectory::AssetListing); ++AssetIndex) + { + AssetRepro.LoadAndAdd(FOculusAssetDirectory::AssetListing[AssetIndex]); + } +} + +void FOculusAssetDirectory::ReleaseAll() +{ + FOculusAssetRepo::Get().Empty(); +} +#endif // WITH_EDITORONLY_DATA + +/* OculusAssetManager_Impl + *****************************************************************************/ + +namespace OculusAssetManager_Impl +{ +#if OCULUS_HMD_SUPPORTED_PLATFORMS + struct FRenderableDevice + { + ovrpNode OVRNode; + ovrpSystemHeadset MinDeviceRange; + ovrpSystemHeadset MaxDeviceRange; + FSoftObjectPath MeshAssetRef; + }; + + static FRenderableDevice RenderableDevices[] = { +#if PLATFORM_ANDROID + //Quest 1 & 2 + { ovrpNode_HandLeft, ovrpSystemHeadset_Oculus_Quest, ovrpSystemHeadset_Oculus_Quest_2, FOculusAssetDirectory::AssetListing[LeftTouchQuest2] }, + { ovrpNode_HandRight, ovrpSystemHeadset_Oculus_Quest, ovrpSystemHeadset_Oculus_Quest_2, FOculusAssetDirectory::AssetListing[RightTouchQuest2] }, + + //Quest Pro + { ovrpNode_HandLeft, ovrpSystemHeadset_Meta_Quest_Pro, ovrpSystemHeadset_Meta_Quest_Pro, FOculusAssetDirectory::AssetListing[LeftTouchQuestPro] }, + { ovrpNode_HandRight, ovrpSystemHeadset_Meta_Quest_Pro, ovrpSystemHeadset_Meta_Quest_Pro, FOculusAssetDirectory::AssetListing[RightTouchQuestPro] }, + + //Quest 3 + { ovrpNode_HandLeft, ovrpSystemHeadset_Meta_Quest_3, ovrpSystemHeadset_Meta_Quest_3, FOculusAssetDirectory::AssetListing[LeftTouchQuest3] }, + { ovrpNode_HandRight, ovrpSystemHeadset_Meta_Quest_3, ovrpSystemHeadset_Meta_Quest_3, FOculusAssetDirectory::AssetListing[RightTouchQuest3] }, +#else + //PC - Rift S + { ovrpNode_HandLeft, ovrpSystemHeadset_Rift_S, ovrpSystemHeadset_Rift_S, FOculusAssetDirectory::AssetListing[LeftTouchRiftS] }, + { ovrpNode_HandRight, ovrpSystemHeadset_Rift_S, ovrpSystemHeadset_Rift_S, FOculusAssetDirectory::AssetListing[RightTouchRiftS] }, + + //PC - Quest 1 & 2 + { ovrpNode_HandLeft, ovrpSystemHeadset_Oculus_Link_Quest, ovrpSystemHeadset_Oculus_Link_Quest_2, FOculusAssetDirectory::AssetListing[LeftTouchQuest2] }, + { ovrpNode_HandRight, ovrpSystemHeadset_Oculus_Link_Quest, ovrpSystemHeadset_Oculus_Link_Quest_2, FOculusAssetDirectory::AssetListing[RightTouchQuest2] }, + + //PC - Quest Pro + { ovrpNode_HandLeft, ovrpSystemHeadset_Meta_Link_Quest_Pro, ovrpSystemHeadset_Meta_Link_Quest_Pro, FOculusAssetDirectory::AssetListing[LeftTouchQuestPro] }, + { ovrpNode_HandRight, ovrpSystemHeadset_Meta_Link_Quest_Pro, ovrpSystemHeadset_Meta_Link_Quest_Pro, FOculusAssetDirectory::AssetListing[RightTouchQuestPro] }, + + //Quest 3 + { ovrpNode_HandLeft, ovrpSystemHeadset_Meta_Link_Quest_3, ovrpSystemHeadset_Meta_Link_Quest_3, FOculusAssetDirectory::AssetListing[LeftTouchQuest3] }, + { ovrpNode_HandRight, ovrpSystemHeadset_Meta_Link_Quest_3, ovrpSystemHeadset_Meta_Link_Quest_3, FOculusAssetDirectory::AssetListing[RightTouchQuest3] }, +#endif + }; + + static uint32 RenderableDeviceCount = sizeof(RenderableDevices) / sizeof(RenderableDevices[0]); +#endif // #if OCULUS_HMD_SUPPORTED_PLATFORMS + + static UObject* FindDeviceMesh(const int32 DeviceID); +}; // namespace OculusAssetManager_Impl + +static UObject* OculusAssetManager_Impl::FindDeviceMesh(const int32 DeviceID) +{ + UObject* DeviceMesh = nullptr; +#if OCULUS_HMD_SUPPORTED_PLATFORMS + const ovrpNode DeviceOVRNode = OculusXRHMD::ToOvrpNode(DeviceID); + + bool bUseSystemHeadsetType = false; + ovrpSystemHeadset HeadsetType; + if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetSystemHeadsetType2(&HeadsetType))) + { + bUseSystemHeadsetType = true; + } + + if (DeviceOVRNode != ovrpNode_None) + { + for (uint32 DeviceIndex = 0; DeviceIndex < RenderableDeviceCount; ++DeviceIndex) + { + const FRenderableDevice& RenderableDevice = RenderableDevices[DeviceIndex]; + if (RenderableDevice.OVRNode == DeviceOVRNode) + { + // If we have information about the current headset, load the model based of the headset information, otherwise load defaults. + if (bUseSystemHeadsetType) + { + if (HeadsetType >= RenderableDevice.MinDeviceRange && HeadsetType <= RenderableDevice.MaxDeviceRange) + { + DeviceMesh = RenderableDevice.MeshAssetRef.TryLoad(); + break; + } + } + else + { + DeviceMesh = RenderableDevice.MeshAssetRef.TryLoad(); + break; + } + } + } + } +#endif + return DeviceMesh; +} + +/* FOculusAssetManager +*****************************************************************************/ + +FOculusAssetManager::FOculusAssetManager() +{ + IModularFeatures::Get().RegisterModularFeature(IXRSystemAssets::GetModularFeatureName(), this); + + ResourceHolder = NewObject(); + ResourceHolder->AddToRoot(); +} + +FOculusAssetManager::~FOculusAssetManager() +{ + if (ResourceHolder) + { + ResourceHolder->ConditionalBeginDestroy(); + ResourceHolder = nullptr; + } + + IModularFeatures::Get().UnregisterModularFeature(IXRSystemAssets::GetModularFeatureName(), this); +} + +bool FOculusAssetManager::EnumerateRenderableDevices(TArray& DeviceListOut) +{ +#if OCULUS_HMD_SUPPORTED_PLATFORMS + using namespace OculusAssetManager_Impl; + DeviceListOut.Empty(RenderableDeviceCount); + + for (uint32 DeviceIndex = 0; DeviceIndex < RenderableDeviceCount; ++DeviceIndex) + { + const FRenderableDevice& RenderableDevice = RenderableDevices[DeviceIndex]; + + const int32 ExternalDeviceId = OculusXRHMD::ToExternalDeviceId(RenderableDevice.OVRNode); + DeviceListOut.Add(ExternalDeviceId); + } + + return true; +#else + return false; +#endif +} + +int32 FOculusAssetManager::GetDeviceId(EControllerHand ControllerHand) +{ +#if OCULUS_HMD_SUPPORTED_PLATFORMS + ovrpNode ControllerOVRNode = ovrpNode_None; + + switch (ControllerHand) + { + case EControllerHand::AnyHand: + // @TODO: maybe check if the right is tracking, if not choose left (if tracking)? + case EControllerHand::Right: + ControllerOVRNode = ovrpNode_HandRight; + break; + case EControllerHand::Left: + ControllerOVRNode = ovrpNode_HandLeft; + break; + + case EControllerHand::ExternalCamera: + ControllerOVRNode = ovrpNode_TrackerZero; + break; + // case EControllerHand::Special_1: + // ControllerOVRNode = ovrpNode_TrackerOne; + // break; + // case EControllerHand::Special_2: + // ControllerOVRNode = ovrpNode_TrackerTwo; + // break; + // case EControllerHand::Special_3: + // ControllerOVRNode = ovrpNode_TrackerThree; + // break; + + // case EControllerHand::Special_4: + // ControllerOVRNode = ovrpNode_DeviceObjectZero; + // break; + + default: + // ControllerOVRNode = ovrpNode_None => returns -1 + break; + } + return OculusXRHMD::ToExternalDeviceId(ControllerOVRNode); +#else + return INDEX_NONE; +#endif +} + +UPrimitiveComponent* FOculusAssetManager::CreateRenderComponent(const int32 DeviceId, AActor* Owner, EObjectFlags Flags, const bool /*bForceSynchronous*/, const FXRComponentLoadComplete& OnLoadComplete) +{ + UPrimitiveComponent* NewRenderComponent = nullptr; + if (UObject* DeviceMesh = OculusAssetManager_Impl::FindDeviceMesh(DeviceId)) + { + if (UStaticMesh* AsStaticMesh = Cast(DeviceMesh)) + { + const FName ComponentName = MakeUniqueObjectName(Owner, UStaticMeshComponent::StaticClass(), *FString::Printf(TEXT("%s_Device%d"), TEXT("Oculus"), DeviceId)); + UStaticMeshComponent* MeshComponent = NewObject(Owner, ComponentName, Flags); + + MeshComponent->SetStaticMesh(AsStaticMesh); + NewRenderComponent = MeshComponent; + } + else if (USkeletalMesh* AsSkeletalMesh = Cast(DeviceMesh)) + { + const FName ComponentName = MakeUniqueObjectName(Owner, USkeletalMeshComponent::StaticClass(), *FString::Printf(TEXT("%s_Device%d"), TEXT("Oculus"), DeviceId)); + USkeletalMeshComponent* SkelMeshComponent = NewObject(Owner, ComponentName, Flags); + + SkelMeshComponent->SetSkeletalMesh(AsSkeletalMesh); + NewRenderComponent = SkelMeshComponent; + } + NewRenderComponent->SetCollisionEnabled(ECollisionEnabled::NoCollision); + } + + OnLoadComplete.ExecuteIfBound(NewRenderComponent); + return NewRenderComponent; +} diff --git a/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRAssetManager.h b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRAssetManager.h new file mode 100644 index 0000000..7254e3a --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRAssetManager.h @@ -0,0 +1,30 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "IXRSystemAssets.h" +#include "OculusXRResourceHolder.h" +#include "UObject/SoftObjectPtr.h" + +/** + * + */ +class FOculusAssetManager : public IXRSystemAssets +{ +public: + FOculusAssetManager(); + virtual ~FOculusAssetManager(); + +public: + UOculusXRResourceHolder* GetResourceHolder() { return ResourceHolder; } + + //~ IXRSystemAssets interface + + virtual bool EnumerateRenderableDevices(TArray& DeviceListOut) override; + virtual int32 GetDeviceId(EControllerHand ControllerHand) override; + virtual UPrimitiveComponent* CreateRenderComponent(const int32 DeviceId, AActor* Owner, EObjectFlags Flags, const bool bForceSynchronous, const FXRComponentLoadComplete& OnLoadComplete) override; + +protected: + UOculusXRResourceHolder* ResourceHolder; +}; diff --git a/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRDelegates.cpp b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRDelegates.cpp new file mode 100644 index 0000000..1543219 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRDelegates.cpp @@ -0,0 +1,8 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +#include "OculusXRDelegates.h" + +FOculusEventDelegates::FOculusDisplayRefreshRateChangedEvent FOculusEventDelegates::OculusDisplayRefreshRateChanged; + +FOculusEventDelegates::FOculusEyeTrackingStateChangedEvent FOculusEventDelegates::OculusEyeTrackingStateChanged; diff --git a/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRDelegates.h b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRDelegates.h new file mode 100644 index 0000000..d49078a --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRDelegates.h @@ -0,0 +1,19 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CoreTypes.h" +#include "Delegates/Delegate.h" + +class FOculusEventDelegates +{ +public: + /** When the display refresh rate is changed */ + DECLARE_MULTICAST_DELEGATE_TwoParams(FOculusDisplayRefreshRateChangedEvent, float /*fromRefreshRate*/, float /*toRefreshRate*/); + static FOculusDisplayRefreshRateChangedEvent OculusDisplayRefreshRateChanged; + + /** When the eye tracking status changes */ + DECLARE_MULTICAST_DELEGATE_OneParam(FOculusEyeTrackingStateChangedEvent, bool /*bIsEyeTrackingOn*/); + static FOculusEyeTrackingStateChangedEvent OculusEyeTrackingStateChanged; +}; diff --git a/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXREventComponent.cpp b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXREventComponent.cpp new file mode 100644 index 0000000..9ab5d46 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXREventComponent.cpp @@ -0,0 +1,21 @@ +// @lint-ignore-every LICENSELINT +// Copyright 1998-2020 Epic Games, Inc. All Rights Reserved. +#include "OculusXREventComponent.h" +#include "OculusXRHMD.h" +#include "OculusXRDelegates.h" + +void UOculusXREventComponent::OnRegister() +{ + Super::OnRegister(); + + FOculusEventDelegates::OculusDisplayRefreshRateChanged.AddUObject(this, &UOculusXREventComponent::OculusDisplayRefreshRateChanged_Handler); + FOculusEventDelegates::OculusEyeTrackingStateChanged.AddUObject(this, &UOculusXREventComponent::OculusEyeTrackingStateChanged_Handler); +} + +void UOculusXREventComponent::OnUnregister() +{ + Super::OnUnregister(); + + FOculusEventDelegates::OculusDisplayRefreshRateChanged.RemoveAll(this); + FOculusEventDelegates::OculusEyeTrackingStateChanged.RemoveAll(this); +} diff --git a/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRFunctionLibrary.cpp b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRFunctionLibrary.cpp new file mode 100644 index 0000000..d030185 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRFunctionLibrary.cpp @@ -0,0 +1,985 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +#include "OculusXRFunctionLibrary.h" +#include "OculusXRHMDPrivate.h" +#include "OculusXRHMD.h" +#include "Logging/MessageLog.h" + +#define LOCTEXT_NAMESPACE "OculusFunctionLibrary" + +//------------------------------------------------------------------------------------------------- +// UOculusXRFunctionLibrary +//------------------------------------------------------------------------------------------------- + +UOculusXRFunctionLibrary::UOculusXRFunctionLibrary(const FObjectInitializer& ObjectInitializer) + : Super(ObjectInitializer) +{ +} + +OculusXRHMD::FOculusXRHMD* UOculusXRFunctionLibrary::GetOculusXRHMD() +{ + return OculusXRHMD::FOculusXRHMD::GetOculusXRHMD(); +} + +void UOculusXRFunctionLibrary::GetPose(FRotator& DeviceRotation, FVector& DevicePosition, FVector& NeckPosition, bool bUseOrienationForPlayerCamera, bool bUsePositionForPlayerCamera, const FVector PositionScale) +{ +#if OCULUS_HMD_SUPPORTED_PLATFORMS + OculusXRHMD::FOculusXRHMD* OculusXRHMD = GetOculusXRHMD(); + if (OculusXRHMD && OculusXRHMD->IsHeadTrackingAllowed()) + { + FQuat HeadOrientation = FQuat::Identity; + FVector HeadPosition = FVector::ZeroVector; + + OculusXRHMD->GetCurrentPose(OculusXRHMD->HMDDeviceId, HeadOrientation, HeadPosition); + + DeviceRotation = HeadOrientation.Rotator(); + DevicePosition = HeadPosition; + NeckPosition = OculusXRHMD->GetNeckPosition(HeadOrientation, HeadPosition); + } + else +#endif // #if OCULUS_HMD_SUPPORTED_PLATFORMS + { + DeviceRotation = FRotator::ZeroRotator; + DevicePosition = FVector::ZeroVector; + NeckPosition = FVector::ZeroVector; + } +} + +void UOculusXRFunctionLibrary::SetBaseRotationAndBaseOffsetInMeters(FRotator Rotation, FVector BaseOffsetInMeters, EOrientPositionSelector::Type Options) +{ +#if OCULUS_HMD_SUPPORTED_PLATFORMS + OculusXRHMD::FOculusXRHMD* OculusXRHMD = GetOculusXRHMD(); + if (OculusXRHMD != nullptr) + { + if ((Options == EOrientPositionSelector::Orientation) || (Options == EOrientPositionSelector::OrientationAndPosition)) + { + OculusXRHMD->SetBaseRotation(Rotation); + } + if ((Options == EOrientPositionSelector::Position) || (Options == EOrientPositionSelector::OrientationAndPosition)) + { + OculusXRHMD->SetBaseOffsetInMeters(BaseOffsetInMeters); + } + } +#endif // OCULUS_HMD_SUPPORTED_PLATFORMS +} + +void UOculusXRFunctionLibrary::GetBaseRotationAndBaseOffsetInMeters(FRotator& OutRotation, FVector& OutBaseOffsetInMeters) +{ +#if OCULUS_HMD_SUPPORTED_PLATFORMS + OculusXRHMD::FOculusXRHMD* OculusXRHMD = GetOculusXRHMD(); + if (OculusXRHMD != nullptr) + { + OutRotation = OculusXRHMD->GetBaseRotation(); + OutBaseOffsetInMeters = OculusXRHMD->GetBaseOffsetInMeters(); + } + else + { + OutRotation = FRotator::ZeroRotator; + OutBaseOffsetInMeters = FVector::ZeroVector; + } +#endif // OCULUS_HMD_SUPPORTED_PLATFORMS +} + +void UOculusXRFunctionLibrary::GetRawSensorData(FVector& AngularAcceleration, FVector& LinearAcceleration, FVector& AngularVelocity, FVector& LinearVelocity, float& TimeInSeconds, EOculusXRTrackedDeviceType DeviceType) +{ +#if OCULUS_HMD_SUPPORTED_PLATFORMS + OculusXRHMD::FOculusXRHMD* OculusXRHMD = GetOculusXRHMD(); + if (OculusXRHMD != nullptr && OculusXRHMD->IsHMDActive()) + { + ovrpPoseStatef state; + if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetNodePoseState3(ovrpStep_Render, OVRP_CURRENT_FRAMEINDEX, OculusXRHMD::ToOvrpNode(DeviceType), &state))) + { + AngularAcceleration = OculusXRHMD::ToFVector(state.AngularAcceleration); + LinearAcceleration = OculusXRHMD::ToFVector(state.Acceleration); + AngularVelocity = OculusXRHMD::ToFVector(state.AngularVelocity); + LinearVelocity = OculusXRHMD::ToFVector(state.Velocity); + TimeInSeconds = state.Time; + } + } +#endif // OCULUS_HMD_SUPPORTED_PLATFORMS +} + +bool UOculusXRFunctionLibrary::IsDeviceTracked(EOculusXRTrackedDeviceType DeviceType) +{ +#if OCULUS_HMD_SUPPORTED_PLATFORMS + OculusXRHMD::FOculusXRHMD* OculusXRHMD = GetOculusXRHMD(); + if (OculusXRHMD != nullptr && OculusXRHMD->IsHMDActive()) + { + ovrpBool Present; + if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetNodePresent2(OculusXRHMD::ToOvrpNode(DeviceType), &Present))) + { + return Present != ovrpBool_False; + } + else + { + return false; + } + } +#endif // OCULUS_HMD_SUPPORTED_PLATFORMS + return false; +} + +void UOculusXRFunctionLibrary::GetSuggestedCpuAndGpuPerformanceLevels(EOculusXRProcessorPerformanceLevel& CpuPerfLevel, EOculusXRProcessorPerformanceLevel& GpuPerfLevel) +{ +#if OCULUS_HMD_SUPPORTED_PLATFORMS + OculusXRHMD::FOculusXRHMD* OculusXRHMD = GetOculusXRHMD(); + if (OculusXRHMD != nullptr && OculusXRHMD->IsHMDActive()) + { + OculusXRHMD->GetSuggestedCpuAndGpuPerformanceLevels(CpuPerfLevel, GpuPerfLevel); + } +#endif // OCULUS_HMD_SUPPORTED_PLATFORMS +} + +void UOculusXRFunctionLibrary::SetSuggestedCpuAndGpuPerformanceLevels(EOculusXRProcessorPerformanceLevel CpuPerfLevel, EOculusXRProcessorPerformanceLevel GpuPerfLevel) +{ +#if OCULUS_HMD_SUPPORTED_PLATFORMS + OculusXRHMD::FOculusXRHMD* OculusXRHMD = GetOculusXRHMD(); + if (OculusXRHMD != nullptr && OculusXRHMD->IsHMDActive()) + { + OculusXRHMD->SetSuggestedCpuAndGpuPerformanceLevels(CpuPerfLevel, GpuPerfLevel); + } +#endif // OCULUS_HMD_SUPPORTED_PLATFORMS +} + +void UOculusXRFunctionLibrary::SetCPUAndGPULevels(int CPULevel, int GPULevel) +{ + // Deprecated. Please use Get/SetSuggestedCpuAndGpuPerformanceLevels instead. +} + +bool UOculusXRFunctionLibrary::GetUserProfile(FOculusXRHmdUserProfile& Profile) +{ +#if OCULUS_HMD_SUPPORTED_PLATFORMS + OculusXRHMD::FOculusXRHMD* OculusXRHMD = GetOculusXRHMD(); + if (OculusXRHMD != nullptr) + { + OculusXRHMD::FOculusXRHMD::UserProfile Data; + if (OculusXRHMD->GetUserProfile(Data)) + { + Profile.Name = ""; + Profile.Gender = "Unknown"; + Profile.PlayerHeight = 0.0f; + Profile.EyeHeight = Data.EyeHeight; + Profile.IPD = Data.IPD; + Profile.NeckToEyeDistance = FVector2D(Data.EyeDepth, 0.0f); + return true; + } + } +#endif // OCULUS_HMD_SUPPORTED_PLATFORMS + return false; +} + +void UOculusXRFunctionLibrary::SetBaseRotationAndPositionOffset(FRotator BaseRot, FVector PosOffset, EOrientPositionSelector::Type Options) +{ +#if OCULUS_HMD_SUPPORTED_PLATFORMS + OculusXRHMD::FOculusXRHMD* OculusXRHMD = GetOculusXRHMD(); + if (OculusXRHMD != nullptr) + { + if (Options == EOrientPositionSelector::Orientation || Options == EOrientPositionSelector::OrientationAndPosition) + { + OculusXRHMD->SetBaseRotation(BaseRot); + } + } +#endif // OCULUS_HMD_SUPPORTED_PLATFORMS +} + +void UOculusXRFunctionLibrary::GetBaseRotationAndPositionOffset(FRotator& OutRot, FVector& OutPosOffset) +{ +#if OCULUS_HMD_SUPPORTED_PLATFORMS + OculusXRHMD::FOculusXRHMD* OculusXRHMD = GetOculusXRHMD(); + if (OculusXRHMD != nullptr) + { + OutRot = OculusXRHMD->GetBaseRotation(); + OutPosOffset = FVector::ZeroVector; + } +#endif // OCULUS_HMD_SUPPORTED_PLATFORMS +} + +void UOculusXRFunctionLibrary::AddLoadingSplashScreen(class UTexture2D* Texture, FVector TranslationInMeters, FRotator Rotation, FVector2D SizeInMeters, FRotator DeltaRotation, bool bClearBeforeAdd) +{ +#if OCULUS_HMD_SUPPORTED_PLATFORMS + OculusXRHMD::FOculusXRHMD* OculusXRHMD = GetOculusXRHMD(); + if (OculusXRHMD != nullptr) + { + OculusXRHMD::FSplash* Splash = OculusXRHMD->GetSplash(); + if (Splash) + { + if (bClearBeforeAdd) + { + Splash->ClearSplashes(); + } + + FOculusXRSplashDesc Desc; + Desc.LoadingTexture = Texture; + Desc.QuadSizeInMeters = SizeInMeters; + Desc.TransformInMeters = FTransform(Rotation, TranslationInMeters); + Desc.DeltaRotation = FQuat(DeltaRotation); + Splash->AddSplash(Desc); + } + } +#endif // OCULUS_HMD_SUPPORTED_PLATFORMS +} + +void UOculusXRFunctionLibrary::ClearLoadingSplashScreens() +{ +#if OCULUS_HMD_SUPPORTED_PLATFORMS + OculusXRHMD::FOculusXRHMD* OculusXRHMD = GetOculusXRHMD(); + if (OculusXRHMD != nullptr) + { + OculusXRHMD::FSplash* Splash = OculusXRHMD->GetSplash(); + if (Splash) + { + Splash->ClearSplashes(); + } + } +#endif // OCULUS_HMD_SUPPORTED_PLATFORMS +} + +bool UOculusXRFunctionLibrary::HasInputFocus() +{ +#if OCULUS_HMD_SUPPORTED_PLATFORMS + const OculusXRHMD::FOculusXRHMD* const OculusXRHMD = GetOculusXRHMD(); + if (OculusXRHMD != nullptr && OculusXRHMD->IsHMDActive()) + { + ovrpBool HasFocus; + if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetAppHasInputFocus(&HasFocus))) + { + return HasFocus != ovrpBool_False; + } + } +#endif // OCULUS_HMD_SUPPORTED_PLATFORMS + return false; +} + +bool UOculusXRFunctionLibrary::HasSystemOverlayPresent() +{ +#if OCULUS_HMD_SUPPORTED_PLATFORMS + const OculusXRHMD::FOculusXRHMD* const OculusXRHMD = GetOculusXRHMD(); + if (OculusXRHMD != nullptr && OculusXRHMD->IsHMDActive()) + { + ovrpBool HasFocus; + if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetAppHasInputFocus(&HasFocus))) + { + return HasFocus == ovrpBool_False; + } + } +#endif // OCULUS_HMD_SUPPORTED_PLATFORMS + return false; +} + +void UOculusXRFunctionLibrary::GetGPUUtilization(bool& IsGPUAvailable, float& GPUUtilization) +{ + GPUUtilization = 0.0f; +#if OCULUS_HMD_SUPPORTED_PLATFORMS + const OculusXRHMD::FOculusXRHMD* const OculusXRHMD = GetOculusXRHMD(); + if (OculusXRHMD != nullptr) + { + ovrpBool bIsSupported = ovrpBool_False; + if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().IsPerfMetricsSupported(ovrpPerfMetrics_System_GpuUtilPercentage_Float, &bIsSupported)) && bIsSupported == ovrpBool_True) + { + if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetPerfMetricsFloat(ovrpPerfMetrics_System_GpuUtilPercentage_Float, &GPUUtilization))) + { + IsGPUAvailable = true; + GPUUtilization *= 100; + } + } + } +#endif // OCULUS_HMD_SUPPORTED_PLATFORMS +} + +float UOculusXRFunctionLibrary::GetGPUFrameTime() +{ + float FrameTime = 0; +#if OCULUS_HMD_SUPPORTED_PLATFORMS + const OculusXRHMD::FOculusXRHMD* const OculusXRHMD = GetOculusXRHMD(); + if (OculusXRHMD != nullptr) + { + ovrpBool bIsSupported = ovrpBool_False; + if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().IsPerfMetricsSupported(ovrpPerfMetrics_App_GpuTime_Float, &bIsSupported)) && bIsSupported == ovrpBool_True) + { + if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetPerfMetricsFloat(ovrpPerfMetrics_App_GpuTime_Float, &FrameTime))) + { + return FrameTime * 1000; + } + } + } +#endif // OCULUS_HMD_SUPPORTED_PLATFORMS + return 0.0f; +} + +EOculusXRFoveatedRenderingMethod UOculusXRFunctionLibrary::GetFoveatedRenderingMethod() +{ +#if OCULUS_HMD_SUPPORTED_PLATFORMS + OculusXRHMD::FOculusXRHMD* OculusXRHMD = GetOculusXRHMD(); + if (OculusXRHMD != nullptr) + { + ovrpBool enabled; + if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetFoveationEyeTracked(&enabled))) + { + return enabled == ovrpBool_True ? EOculusXRFoveatedRenderingMethod::EyeTrackedFoveatedRendering : EOculusXRFoveatedRenderingMethod::FixedFoveatedRendering; + } + } +#endif // OCULUS_HMD_SUPPORTED_PLATFORMS + return EOculusXRFoveatedRenderingMethod::FixedFoveatedRendering; +} + +void UOculusXRFunctionLibrary::SetFoveatedRenderingMethod(EOculusXRFoveatedRenderingMethod Method) +{ +#if OCULUS_HMD_SUPPORTED_PLATFORMS + OculusXRHMD::FOculusXRHMD* OculusXRHMD = GetOculusXRHMD(); + if (OculusXRHMD != nullptr) + { + OculusXRHMD->SetFoveatedRenderingMethod(Method); + } +#endif // OCULUS_HMD_SUPPORTED_PLATFORMS +} + +void UOculusXRFunctionLibrary::SetFoveatedRenderingLevel(EOculusXRFoveatedRenderingLevel level, bool isDynamic) +{ +#if OCULUS_HMD_SUPPORTED_PLATFORMS + OculusXRHMD::FOculusXRHMD* OculusXRHMD = GetOculusXRHMD(); + if (OculusXRHMD != nullptr) + { + OculusXRHMD->SetFoveatedRenderingLevel(level, isDynamic); + } +#endif // OCULUS_HMD_SUPPORTED_PLATFORMS +} + +EOculusXRFoveatedRenderingLevel UOculusXRFunctionLibrary::GetFoveatedRenderingLevel() +{ +#if OCULUS_HMD_SUPPORTED_PLATFORMS + OculusXRHMD::FOculusXRHMD* OculusXRHMD = GetOculusXRHMD(); + if (OculusXRHMD != nullptr) + { + ovrpTiledMultiResLevel Lvl; + if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetTiledMultiResLevel(&Lvl))) + { + return (EOculusXRFoveatedRenderingLevel)Lvl; + } + } +#endif // OCULUS_HMD_SUPPORTED_PLATFORMS + return EOculusXRFoveatedRenderingLevel::Off; +} + +bool UOculusXRFunctionLibrary::GetEyeTrackedFoveatedRenderingSupported() +{ +#if OCULUS_HMD_SUPPORTED_PLATFORMS + // Always return false on other engine releases, since they don't have FDM offset support +#ifdef WITH_OCULUS_BRANCH + OculusXRHMD::FOculusXRHMD* OculusXRHMD = GetOculusXRHMD(); + if (OculusXRHMD != nullptr) + { + ovrpBool Supported; + if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetFoveationEyeTrackedSupported(&Supported))) + { + return Supported == ovrpBool_True; + } + } +#endif // WITH_OCULUS_BRANCH +#endif // OCULUS_HMD_SUPPORTED_PLATFORMS + return false; +} + +FString UOculusXRFunctionLibrary::GetDeviceName() +{ +#if OCULUS_HMD_SUPPORTED_PLATFORMS + OculusXRHMD::FOculusXRHMD* OculusXRHMD = GetOculusXRHMD(); + if (OculusXRHMD != nullptr) + { + const char* NameString; + if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetSystemProductName2(&NameString)) && NameString) + { + return FString(NameString); + } + } +#endif + return FString(); +} + +EOculusXRDeviceType UOculusXRFunctionLibrary::GetDeviceType() +{ +#if OCULUS_HMD_SUPPORTED_PLATFORMS + OculusXRHMD::FOculusXRHMD* OculusXRHMD = GetOculusXRHMD(); + if (OculusXRHMD != nullptr) + { + if (OculusXRHMD->GetSettings()) + { + switch (OculusXRHMD->GetSettings()->SystemHeadset) + { + case ovrpSystemHeadset_Oculus_Quest: + return EOculusXRDeviceType::OculusQuest_Deprecated; + case ovrpSystemHeadset_Oculus_Quest_2: + return EOculusXRDeviceType::OculusQuest2; + case ovrpSystemHeadset_Meta_Quest_Pro: + return EOculusXRDeviceType::MetaQuestPro; + case ovrpSystemHeadset_Meta_Quest_3: + return EOculusXRDeviceType::MetaQuest3; + case ovrpSystemHeadset_Rift_CV1: + return EOculusXRDeviceType::Rift; + case ovrpSystemHeadset_Rift_S: + return EOculusXRDeviceType::Rift_S; + case ovrpSystemHeadset_Oculus_Link_Quest: + return EOculusXRDeviceType::Quest_Link_Deprecated; + case ovrpSystemHeadset_Oculus_Link_Quest_2: + return EOculusXRDeviceType::Quest2_Link; + case ovrpSystemHeadset_Meta_Link_Quest_Pro: + return EOculusXRDeviceType::MetaQuestProLink; + case ovrpSystemHeadset_Meta_Link_Quest_3: + return EOculusXRDeviceType::MetaQuest3Link; + default: + break; + } + } + } +#endif + return EOculusXRDeviceType::OculusUnknown; +} + +EOculusXRControllerType UOculusXRFunctionLibrary::GetControllerType(EControllerHand deviceHand) +{ +#if OCULUS_HMD_SUPPORTED_PLATFORMS + auto getOVRPHand = [](EControllerHand hand) { + switch (hand) + { + case EControllerHand::Left: + return ovrpHand::ovrpHand_Left; + case EControllerHand::Right: + return ovrpHand::ovrpHand_Right; + default: + return ovrpHand::ovrpHand_None; + } + return ovrpHand::ovrpHand_None; + }; + + auto getEControllerType = [](ovrpInteractionProfile profile) { + switch (profile) + { + case ovrpInteractionProfile::ovrpInteractionProfile_Touch: + return EOculusXRControllerType::MetaQuestTouch; + case ovrpInteractionProfile::ovrpInteractionProfile_TouchPro: + return EOculusXRControllerType::MetaQuestTouchPro; + case ovrpInteractionProfile::ovrpInteractionProfile_TouchPlus: + return EOculusXRControllerType::MetaQuestTouchPlus; + default: + return EOculusXRControllerType::None; + } + return EOculusXRControllerType::None; + }; + + ovrpInteractionProfile interactionProfile = ovrpInteractionProfile::ovrpInteractionProfile_None; + ovrpHand hand = getOVRPHand(deviceHand); + if (hand == ovrpHand::ovrpHand_None) + return EOculusXRControllerType::Unknown; + if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetCurrentInteractionProfile(hand, &interactionProfile))) + { + return getEControllerType(interactionProfile); + } + return EOculusXRControllerType::Unknown; +#endif + return EOculusXRControllerType::Unknown; +} + +TArray UOculusXRFunctionLibrary::GetAvailableDisplayFrequencies() +{ +#if OCULUS_HMD_SUPPORTED_PLATFORMS + OculusXRHMD::FOculusXRHMD* OculusXRHMD = GetOculusXRHMD(); + if (OculusXRHMD != nullptr) + { + int NumberOfFrequencies; + if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetSystemDisplayAvailableFrequencies(nullptr, &NumberOfFrequencies))) + { + TArray freqArray; + freqArray.SetNum(NumberOfFrequencies); + FOculusXRHMDModule::GetPluginWrapper().GetSystemDisplayAvailableFrequencies(freqArray.GetData(), &NumberOfFrequencies); + return freqArray; + } + } +#endif + return TArray(); +} + +float UOculusXRFunctionLibrary::GetCurrentDisplayFrequency() +{ +#if OCULUS_HMD_SUPPORTED_PLATFORMS + OculusXRHMD::FOculusXRHMD* OculusXRHMD = GetOculusXRHMD(); + if (OculusXRHMD != nullptr) + { + float Frequency; + if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetSystemDisplayFrequency2(&Frequency))) + { + return Frequency; + } + } +#endif + return 0.0f; +} + +void UOculusXRFunctionLibrary::SetDisplayFrequency(float RequestedFrequency) +{ +#if OCULUS_HMD_SUPPORTED_PLATFORMS + OculusXRHMD::FOculusXRHMD* OculusXRHMD = GetOculusXRHMD(); + if (OculusXRHMD != nullptr) + { + FOculusXRHMDModule::GetPluginWrapper().SetSystemDisplayFrequency(RequestedFrequency); + } +#endif +} + +void UOculusXRFunctionLibrary::EnablePositionTracking(bool bPositionTracking) +{ +#if OCULUS_HMD_SUPPORTED_PLATFORMS + OculusXRHMD::FOculusXRHMD* OculusXRHMD = GetOculusXRHMD(); + if (OculusXRHMD != nullptr) + { + FOculusXRHMDModule::GetPluginWrapper().SetTrackingPositionEnabled2(bPositionTracking); + } +#endif +} + +void UOculusXRFunctionLibrary::EnableOrientationTracking(bool bOrientationTracking) +{ +#if OCULUS_HMD_SUPPORTED_PLATFORMS + OculusXRHMD::FOculusXRHMD* OculusXRHMD = GetOculusXRHMD(); + if (OculusXRHMD != nullptr) + { + FOculusXRHMDModule::GetPluginWrapper().SetTrackingOrientationEnabled2(bOrientationTracking); + } +#endif +} + +void UOculusXRFunctionLibrary::SetColorScaleAndOffset(FLinearColor ColorScale, FLinearColor ColorOffset, bool bApplyToAllLayers) +{ +#if OCULUS_HMD_SUPPORTED_PLATFORMS + OculusXRHMD::FOculusXRHMD* OculusXRHMD = GetOculusXRHMD(); + if (OculusXRHMD != nullptr) + { + OculusXRHMD->SetColorScaleAndOffset(ColorScale, ColorOffset, bApplyToAllLayers); + } +#endif +} + +class IStereoLayers* UOculusXRFunctionLibrary::GetStereoLayers() +{ +#if OCULUS_HMD_SUPPORTED_PLATFORMS + OculusXRHMD::FOculusXRHMD* OculusXRHMD = GetOculusXRHMD(); + if (OculusXRHMD != nullptr) + { + return OculusXRHMD; + } +#endif // OCULUS_HMD_SUPPORTED_PLATFORMS + return nullptr; +} + +/** Helper that converts EOculusXRBoundaryType to ovrpBoundaryType */ +#if OCULUS_HMD_SUPPORTED_PLATFORMS +static ovrpBoundaryType ToOvrpBoundaryType(EOculusXRBoundaryType Source) +{ + switch (Source) + { + case EOculusXRBoundaryType::Boundary_PlayArea: + return ovrpBoundary_PlayArea; + + case EOculusXRBoundaryType::Boundary_Outer: + default: + return ovrpBoundary_Outer; + } +} +#endif // OCULUS_HMD_SUPPORTED_PLATFORMS + +bool UOculusXRFunctionLibrary::IsGuardianConfigured() +{ +#if OCULUS_HMD_SUPPORTED_PLATFORMS + OculusXRHMD::FOculusXRHMD* OculusXRHMD = GetOculusXRHMD(); + if (OculusXRHMD != nullptr) + { + ovrpBool boundaryConfigured; + return OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetBoundaryConfigured2(&boundaryConfigured)) && boundaryConfigured; + } +#endif + return false; +} + +bool UOculusXRFunctionLibrary::IsGuardianDisplayed() +{ +#if OCULUS_HMD_SUPPORTED_PLATFORMS + OculusXRHMD::FOculusXRHMD* OculusXRHMD = GetOculusXRHMD(); + if (OculusXRHMD != nullptr) + { + ovrpBool boundaryVisible; + return OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetBoundaryVisible2(&boundaryVisible)) && boundaryVisible; + } +#endif + return false; +} + +TArray UOculusXRFunctionLibrary::GetGuardianPoints(EOculusXRBoundaryType BoundaryType, bool UsePawnSpace /* = false */) +{ + TArray BoundaryPointList; +#if OCULUS_HMD_SUPPORTED_PLATFORMS + OculusXRHMD::FOculusXRHMD* OculusXRHMD = GetOculusXRHMD(); + if (OculusXRHMD != nullptr) + { + ovrpBool bBoundaryConfigured = false; + if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetBoundaryConfigured2(&bBoundaryConfigured)) && bBoundaryConfigured) + { + ovrpBoundaryType obt = ToOvrpBoundaryType(BoundaryType); + int NumPoints = 0; + + if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetBoundaryGeometry3(obt, nullptr, &NumPoints))) + { + //allocate points + const int BufferSize = NumPoints; + ovrpVector3f* BoundaryPoints = new ovrpVector3f[BufferSize]; + + if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetBoundaryGeometry3(obt, BoundaryPoints, &NumPoints))) + { + NumPoints = FMath::Min(BufferSize, NumPoints); + check(NumPoints <= BufferSize); // For static analyzer + BoundaryPointList.Reserve(NumPoints); + + for (int i = 0; i < NumPoints; i++) + { + FVector point; + if (UsePawnSpace) + { + point = OculusXRHMD->ConvertVector_M2U(BoundaryPoints[i]); + } + else + { + point = OculusXRHMD->ScaleAndMovePointWithPlayer(BoundaryPoints[i]); + } + BoundaryPointList.Add(point); + } + } + + delete[] BoundaryPoints; + } + } + } +#endif + return BoundaryPointList; +} + +FVector UOculusXRFunctionLibrary::GetGuardianDimensions(EOculusXRBoundaryType BoundaryType) +{ +#if OCULUS_HMD_SUPPORTED_PLATFORMS + OculusXRHMD::FOculusXRHMD* OculusXRHMD = GetOculusXRHMD(); + if (OculusXRHMD != nullptr) + { + ovrpBoundaryType obt = ToOvrpBoundaryType(BoundaryType); + ovrpVector3f Dimensions; + + if (OVRP_FAILURE(FOculusXRHMDModule::GetPluginWrapper().GetBoundaryDimensions2(obt, &Dimensions))) + return FVector::ZeroVector; + + Dimensions.z *= -1.0; + return OculusXRHMD->ConvertVector_M2U(Dimensions); + } +#endif + return FVector::ZeroVector; +} + +FTransform UOculusXRFunctionLibrary::GetPlayAreaTransform() +{ +#if OCULUS_HMD_SUPPORTED_PLATFORMS + OculusXRHMD::FOculusXRHMD* OculusXRHMD = GetOculusXRHMD(); + if (OculusXRHMD != nullptr) + { + ovrpBool bBoundaryConfigured = false; + if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetBoundaryConfigured2(&bBoundaryConfigured)) && bBoundaryConfigured) + { + int NumPoints = 4; + ovrpVector3f BoundaryPoints[4]; + + if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetBoundaryGeometry3(ovrpBoundary_PlayArea, BoundaryPoints, &NumPoints))) + { + FVector ConvertedPoints[4]; + + for (int i = 0; i < NumPoints; i++) + { + ConvertedPoints[i] = OculusXRHMD->ScaleAndMovePointWithPlayer(BoundaryPoints[i]); + } + + float metersScale = OculusXRHMD->GetWorldToMetersScale(); + + FVector Edge = ConvertedPoints[1] - ConvertedPoints[0]; + float Angle = FMath::Acos((Edge).GetSafeNormal() | FVector::RightVector); + FQuat Rotation(FVector::UpVector, Edge.X < 0 ? Angle : -Angle); + + FVector Position = (ConvertedPoints[0] + ConvertedPoints[1] + ConvertedPoints[2] + ConvertedPoints[3]) / 4; + FVector Scale(FVector::Distance(ConvertedPoints[3], ConvertedPoints[0]) / metersScale, FVector::Distance(ConvertedPoints[1], ConvertedPoints[0]) / metersScale, 1.0); + + return FTransform(Rotation, Position, Scale); + } + } + } +#endif + return FTransform(); +} + +FOculusXRGuardianTestResult UOculusXRFunctionLibrary::GetPointGuardianIntersection(const FVector Point, EOculusXRBoundaryType BoundaryType) +{ + FOculusXRGuardianTestResult InteractionInfo; + memset(&InteractionInfo, 0, sizeof(FOculusXRGuardianTestResult)); + +#if OCULUS_HMD_SUPPORTED_PLATFORMS + OculusXRHMD::FOculusXRHMD* OculusXRHMD = GetOculusXRHMD(); + if (OculusXRHMD != nullptr) + { + ovrpVector3f OvrpPoint = OculusXRHMD->WorldLocationToOculusPoint(Point); + ovrpBoundaryType OvrpBoundaryType = ToOvrpBoundaryType(BoundaryType); + ovrpBoundaryTestResult InteractionResult; + + if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().TestBoundaryPoint2(OvrpPoint, OvrpBoundaryType, &InteractionResult))) + { + InteractionInfo.IsTriggering = (InteractionResult.IsTriggering != 0); + InteractionInfo.ClosestDistance = OculusXRHMD->ConvertFloat_M2U(InteractionResult.ClosestDistance); + InteractionInfo.ClosestPoint = OculusXRHMD->ScaleAndMovePointWithPlayer(InteractionResult.ClosestPoint); + InteractionInfo.ClosestPointNormal = OculusXRHMD->ConvertVector_M2U(InteractionResult.ClosestPointNormal); + InteractionInfo.DeviceType = EOculusXRTrackedDeviceType::None; + } + } +#endif + + return InteractionInfo; +} + +FOculusXRGuardianTestResult UOculusXRFunctionLibrary::GetNodeGuardianIntersection(EOculusXRTrackedDeviceType DeviceType, EOculusXRBoundaryType BoundaryType) +{ + FOculusXRGuardianTestResult InteractionInfo; + memset(&InteractionInfo, 0, sizeof(FOculusXRGuardianTestResult)); + +#if OCULUS_HMD_SUPPORTED_PLATFORMS + OculusXRHMD::FOculusXRHMD* OculusXRHMD = GetOculusXRHMD(); + if (OculusXRHMD != nullptr) + { + ovrpNode OvrpNode = OculusXRHMD::ToOvrpNode(DeviceType); + ovrpBoundaryType OvrpBoundaryType = ToOvrpBoundaryType(BoundaryType); + ovrpBoundaryTestResult TestResult; + + if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().TestBoundaryNode2(OvrpNode, ovrpBoundary_PlayArea, &TestResult)) && TestResult.IsTriggering) + { + InteractionInfo.IsTriggering = true; + InteractionInfo.DeviceType = OculusXRHMD::ToEOculusXRTrackedDeviceType(OvrpNode); + InteractionInfo.ClosestDistance = OculusXRHMD->ConvertFloat_M2U(TestResult.ClosestDistance); + InteractionInfo.ClosestPoint = OculusXRHMD->ScaleAndMovePointWithPlayer(TestResult.ClosestPoint); + InteractionInfo.ClosestPointNormal = OculusXRHMD->ConvertVector_M2U(TestResult.ClosestPointNormal); + } + } +#endif + + return InteractionInfo; +} + +void UOculusXRFunctionLibrary::SetGuardianVisibility(bool GuardianVisible) +{ +#if OCULUS_HMD_SUPPORTED_PLATFORMS + OculusXRHMD::FOculusXRHMD* OculusXRHMD = GetOculusXRHMD(); + if (OculusXRHMD != nullptr) + { + FOculusXRHMDModule::GetPluginWrapper().SetBoundaryVisible2(GuardianVisible); + } +#endif +} + +bool UOculusXRFunctionLibrary::GetSystemHmd3DofModeEnabled() +{ +#if OCULUS_HMD_SUPPORTED_PLATFORMS + OculusXRHMD::FOculusXRHMD* OculusXRHMD = GetOculusXRHMD(); + if (OculusXRHMD != nullptr) + { + ovrpBool enabled; + return OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetSystemHmd3DofModeEnabled(&enabled)) && enabled; + } +#endif + return false; +} + +EOculusXRColorSpace UOculusXRFunctionLibrary::GetHmdColorDesc() +{ +#if OCULUS_HMD_SUPPORTED_PLATFORMS + OculusXRHMD::FOculusXRHMD* OculusXRHMD = GetOculusXRHMD(); + if (OculusXRHMD != nullptr) + { + ovrpColorSpace HmdColorSpace; + if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetHmdColorDesc(&HmdColorSpace))) + { + return (EOculusXRColorSpace)HmdColorSpace; + } + } +#endif + return EOculusXRColorSpace::Unknown; +} + +void UOculusXRFunctionLibrary::SetClientColorDesc(EOculusXRColorSpace ColorSpace) +{ +#if OCULUS_HMD_SUPPORTED_PLATFORMS + OculusXRHMD::FOculusXRHMD* OculusXRHMD = GetOculusXRHMD(); + if (OculusXRHMD != nullptr) + { + ovrpColorSpace ClientColorSpace = (ovrpColorSpace)ColorSpace; +#if PLATFORM_ANDROID + if (ClientColorSpace == ovrpColorSpace_Unknown) + { + ClientColorSpace = ovrpColorSpace_Quest; + } +#endif + FOculusXRHMDModule::GetPluginWrapper().SetClientColorDesc(ClientColorSpace); + } +#endif +} + +void UOculusXRFunctionLibrary::SetLocalDimmingOn(bool LocalDimmingOn) +{ +#if OCULUS_HMD_SUPPORTED_PLATFORMS + OculusXRHMD::FOculusXRHMD* OculusXRHMD = GetOculusXRHMD(); + if (OculusXRHMD != nullptr) + { + UE_LOG(LogHMD, Log, TEXT("SetLocalDimmingOn %d"), LocalDimmingOn); + FOculusXRHMDModule::GetPluginWrapper().SetLocalDimming(LocalDimmingOn); + } +#endif +} + +bool UOculusXRFunctionLibrary::IsPassthroughSupported() +{ +#if OCULUS_HMD_SUPPORTED_PLATFORMS + OculusXRHMD::FOculusXRHMD* OculusXRHMD = GetOculusXRHMD(); + if (OculusXRHMD != nullptr) + { + ovrpInsightPassthroughCapabilityFlags capabilities; + + if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetPassthroughCapabilityFlags(&capabilities))) + { + return (capabilities & ovrpInsightPassthroughCapabilityFlags::ovrpInsightPassthroughCapabilityFlags_Passthrough) + == ovrpInsightPassthroughCapabilityFlags::ovrpInsightPassthroughCapabilityFlags_Passthrough; + } + + return false; + } +#endif + return false; +} + +bool UOculusXRFunctionLibrary::IsColorPassthroughSupported() +{ +#if OCULUS_HMD_SUPPORTED_PLATFORMS + OculusXRHMD::FOculusXRHMD* OculusXRHMD = GetOculusXRHMD(); + if (OculusXRHMD != nullptr) + { + ovrpInsightPassthroughCapabilityFlags capabilities; + if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetPassthroughCapabilityFlags(&capabilities))) + { + return (capabilities & ovrpInsightPassthroughCapabilityFlags::ovrpInsightPassthroughCapabilityFlags_Color) + == ovrpInsightPassthroughCapabilityFlags::ovrpInsightPassthroughCapabilityFlags_Color; + } + return false; + } +#endif + return false; +} + +void UOculusXRFunctionLibrary::StartEnvironmentDepth() +{ +#if OCULUS_HMD_SUPPORTED_PLATFORMS + OculusXRHMD::FOculusXRHMD* OculusXRHMD = GetOculusXRHMD(); + if (OculusXRHMD != nullptr) + { + int CreateFlags = 0; + OculusXRHMD->StartEnvironmentDepth(CreateFlags); + } +#endif +} + +void UOculusXRFunctionLibrary::StopEnvironmentDepth() +{ +#if OCULUS_HMD_SUPPORTED_PLATFORMS + OculusXRHMD::FOculusXRHMD* OculusXRHMD = GetOculusXRHMD(); + if (OculusXRHMD != nullptr) + { + OculusXRHMD->StopEnvironmentDepth(); + } +#endif +} + +bool UOculusXRFunctionLibrary::IsEnvironmentDepthStarted() +{ +#if OCULUS_HMD_SUPPORTED_PLATFORMS + OculusXRHMD::FOculusXRHMD* OculusXRHMD = GetOculusXRHMD(); + if (OculusXRHMD != nullptr) + { + return OculusXRHMD->IsEnvironmentDepthStarted(); + } +#endif + return false; +} + +void UOculusXRFunctionLibrary::SetEnvironmentDepthHandRemoval(bool RemoveHands) +{ +#if OCULUS_HMD_SUPPORTED_PLATFORMS + OculusXRHMD::FOculusXRHMD* OculusXRHMD = GetOculusXRHMD(); + if (OculusXRHMD != nullptr) + { + OculusXRHMD->SetEnvironmentDepthHandRemoval(RemoveHands); + } +#endif +} + +void UOculusXRFunctionLibrary::SetXROcclusionsMode(UObject* WorldContextObject, EOculusXROcclusionsMode Mode) +{ +#if OCULUS_HMD_SUPPORTED_PLATFORMS + OculusXRHMD::FOculusXRHMD* OculusXRHMD = GetOculusXRHMD(); + if (OculusXRHMD != nullptr) + { + OculusXRHMD->EnableHardOcclusions(Mode == EOculusXROcclusionsMode::HardOcclusions); + } +#if defined(WITH_OCULUS_BRANCH) + WorldContextObject->GetWorld()->Scene->SetEnableXRPassthroughSoftOcclusions(Mode == EOculusXROcclusionsMode::SoftOcclusions); +#else + ensureMsgf(Mode != EOculusXROcclusionsMode::SoftOcclusions, TEXT("Soft occlusions are only supported with the Oculus branch of the Unreal Engine")); +#endif // defined(WITH_OCULUS_BRANCH) +#endif // OCULUS_HMD_SUPPORTED_PLATFORMS +} + +void UOculusXRFunctionLibrary::SetEyeBufferSharpenType(EOculusXREyeBufferSharpenType EyeBufferSharpenType) +{ +#if OCULUS_HMD_SUPPORTED_PLATFORMS + OculusXRHMD::FOculusXRHMD* OculusXRHMD = GetOculusXRHMD(); + if (OculusXRHMD != nullptr) + { + switch (EyeBufferSharpenType) + { + case EOculusXREyeBufferSharpenType::SLST_Normal: + FOculusXRHMDModule::GetPluginWrapper().SetEyeBufferSharpenType(ovrpLayerSubmitFlag_EfficientSharpen); + break; + case EOculusXREyeBufferSharpenType::SLST_Quality: + FOculusXRHMDModule::GetPluginWrapper().SetEyeBufferSharpenType(ovrpLayerSubmitFlag_QualitySharpen); + break; + case EOculusXREyeBufferSharpenType::SLST_Auto: + FOculusXRHMDModule::GetPluginWrapper().SetEyeBufferSharpenType(ovrpLayerSubmitFlag_AutoLayerFilter); + break; + default: + FOculusXRHMDModule::GetPluginWrapper().SetEyeBufferSharpenType(ovrpLayerSubmitFlags(0)); + break; + } + } +#endif +} + +bool UOculusXRFunctionLibrary::IsPassthroughRecommended() +{ +#if OCULUS_HMD_SUPPORTED_PLATFORMS + const OculusXRHMD::FOculusXRHMD* OculusHMD = GetOculusXRHMD(); + if (OculusHMD != nullptr) + { + ovrpPassthroughPreferences Preferences; + if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetPassthroughPreferences(&Preferences))) + { + return (Preferences.Flags & ovrpPassthroughPreferenceFlags::ovrpPassthroughPreferenceFlags_DefaultToActive) + == ovrpPassthroughPreferenceFlags::ovrpPassthroughPreferenceFlags_DefaultToActive; + }; + } +#endif + return false; +} +#undef LOCTEXT_NAMESPACE diff --git a/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD.cpp b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD.cpp new file mode 100644 index 0000000..c22b42e --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD.cpp @@ -0,0 +1,4876 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +#include "OculusXRHMD.h" +#include "OculusXRHMDPrivateRHI.h" + +#include "EngineAnalytics.h" +#include "Interfaces/IAnalyticsProvider.h" +#include "AnalyticsEventAttribute.h" +#include "Slate/SceneViewport.h" +#include "PostProcess/PostProcessHMD.h" +#include "PostProcess/SceneRenderTargets.h" +#include "HardwareInfo.h" +#include "ScreenRendering.h" +#include "GameFramework/PlayerController.h" +#include "Math/UnrealMathUtility.h" +#include "Math/TranslationMatrix.h" +#include "Widgets/SViewport.h" +#include "Layout/WidgetPath.h" +#include "Framework/Application/SlateApplication.h" +#include "Engine/Canvas.h" +#include "Engine/GameEngine.h" +#include "Engine/RendererSettings.h" +#include "Misc/CoreDelegates.h" +#include "GameFramework/WorldSettings.h" +#include "Engine/StaticMesh.h" +#include "Engine/StaticMeshActor.h" +#include "Components/InstancedStaticMeshComponent.h" +#include "Misc/EngineVersion.h" +#include "ClearQuad.h" +#include "DynamicResolutionState.h" +#include "DynamicResolutionProxy.h" +#include "OculusXRHMDRuntimeSettings.h" +#include "OculusXRDelegates.h" +#include "DataDrivenShaderPlatformInfo.h" +#include "GenericPlatform/GenericPlatformMath.h" +#include "LegacyScreenPercentageDriver.h" + +#if PLATFORM_ANDROID +#include "Android/AndroidJNI.h" +#include "Android/AndroidApplication.h" +#include "HAL/IConsoleManager.h" +#include "AndroidPermissionFunctionLibrary.h" +#include "AndroidPermissionCallbackProxy.h" +#endif +#include "OculusShaders.h" +#include "PipelineStateCache.h" + +#include "IOculusXRMRModule.h" + +#if WITH_EDITOR +#include "Editor/UnrealEd/Classes/Editor/EditorEngine.h" +#include "Settings/LevelEditorPlaySettings.h" +#endif + +#if !UE_BUILD_SHIPPING +#include "Debug/DebugDrawService.h" +#endif + +#if OCULUS_HMD_SUPPORTED_PLATFORMS + +static TAutoConsoleVariable CVarOculusEnableSubsampledLayout( + TEXT("r.Mobile.Oculus.EnableSubsampled"), + 0, + TEXT("0: Disable subsampled layout (Default)\n") + TEXT("1: Enable subsampled layout on supported platforms\n"), + ECVF_Scalability | ECVF_RenderThreadSafe); + +static TAutoConsoleVariable CVarOculusEnableLowLatencyVRS( + TEXT("r.Mobile.Oculus.EnableLowLatencyVRS"), + 0, + TEXT("0: Disable late update of VRS textures (Default)\n") + TEXT("1: Enable late update of VRS textures\n"), + ECVF_Scalability | ECVF_RenderThreadSafe); + +static TAutoConsoleVariable CVarOculusForceSymmetric( + TEXT("r.Mobile.Oculus.ForceSymmetric"), + 0, + TEXT("0: Use standard runtime-provided projection matrices (Default)\n") + TEXT("1: Render both eyes with a symmetric projection, union of both FOVs (and corresponding higher rendertarget size to maintain PD)\n"), + ECVF_Scalability | ECVF_RenderThreadSafe); + +// AppSpaceWarp +static TAutoConsoleVariable CVarOculusEnableSpaceWarpUser( + TEXT("r.Mobile.Oculus.SpaceWarp.Enable"), + 0, + TEXT("0 Disable spacewarp at runtime.\n") + TEXT("1 Enable spacewarp at runtime.\n"), + ECVF_Scalability | ECVF_RenderThreadSafe); + +static TAutoConsoleVariable CVarOculusEnableSpaceWarpInternal( + TEXT("r.Mobile.Oculus.SpaceWarp.EnableInternal"), + 0, + TEXT("0 Disable spacewarp, for internal engine checking, don't modify.\n") + TEXT("1 Enable spacewarp, for internal enegine checking, don't modify.\n"), + ECVF_Scalability | ECVF_RenderThreadSafe); + +// Foveated Rendering +static TAutoConsoleVariable CVarOculusFoveatedRenderingMethod( + TEXT("r.Mobile.Oculus.FoveatedRendering.Method"), + -1, + TEXT("0 Fixed Foveated Rendering.\n") + TEXT("1 Eye-Tracked Foveated Rendering.\n"), + ECVF_Scalability | ECVF_RenderThreadSafe); + +static TAutoConsoleVariable CVarOculusFoveatedRenderingLevel( + TEXT("r.Mobile.Oculus.FoveatedRendering.Level"), + -1, + TEXT("0 Off.\n") + TEXT("1 Low.\n") + TEXT("2 Medium.\n") + TEXT("3 High.\n") + TEXT("4 High Top.\n"), + ECVF_Scalability | ECVF_RenderThreadSafe); + +static TAutoConsoleVariable CVarOculusDynamicFoveatedRendering( + TEXT("r.Mobile.Oculus.FoveatedRendering.Dynamic"), + -1, + TEXT("0 Disable Dynamic Foveated Rendering at runtime.\n") + TEXT("1 Enable Dynamic Foveated Rendering at runtime.\n"), + ECVF_Scalability | ECVF_RenderThreadSafe); + +static TAutoConsoleVariable CVarOculusDynamicResolutionPixelDensity( + TEXT("r.Oculus.DynamicResolution.PixelDensity"), + 0, + TEXT("0 Static Pixel Density corresponding to Pixel Density 1.0 (default)\n") + TEXT(">0 Manual Pixel Density Override\n"), + ECVF_Scalability | ECVF_RenderThreadSafe); + +#define OCULUS_PAUSED_IDLE_FPS 10 + +static const FString USE_SCENE_PERMISSION_NAME("com.oculus.permission.USE_SCENE"); + +namespace OculusXRHMD +{ + +#if !UE_BUILD_SHIPPING + static void __cdecl OvrpLogCallback(ovrpLogLevel level, const char* message) + { + FString tbuf = ANSI_TO_TCHAR(message); + const TCHAR* levelStr = TEXT(""); + switch (level) + { + case ovrpLogLevel_Debug: + levelStr = TEXT(" Debug:"); + break; + case ovrpLogLevel_Info: + levelStr = TEXT(" Info:"); + break; + case ovrpLogLevel_Error: + levelStr = TEXT(" Error:"); + break; + } + + GLog->Logf(TEXT("OCULUS:%s %s"), levelStr, *tbuf); + } +#endif // !UE_BUILD_SHIPPING + + //------------------------------------------------------------------------------------------------- + // FOculusXRHMD + //------------------------------------------------------------------------------------------------- + + const FName FOculusXRHMD::OculusSystemName(TEXT("OculusXRHMD")); + + FName FOculusXRHMD::GetSystemName() const + { + return OculusSystemName; + } + int32 FOculusXRHMD::GetXRSystemFlags() const + { + return EXRSystemFlags::IsHeadMounted; + } + + FString FOculusXRHMD::GetVersionString() const + { + const char* Version; + + if (OVRP_FAILURE(FOculusXRHMDModule::GetPluginWrapper().GetVersion2(&Version))) + { + Version = "Unknown"; + } + + return FString::Printf(TEXT("OVRPlugin: %s"), UTF8_TO_TCHAR(Version)); + } + + bool FOculusXRHMD::DoesSupportPositionalTracking() const + { + ovrpBool trackingPositionSupported; + return OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetTrackingPositionSupported2(&trackingPositionSupported)) && trackingPositionSupported; + } + + bool FOculusXRHMD::HasValidTrackingPosition() + { + ovrpBool nodePositionTracked; + return OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetNodePositionTracked2(ovrpNode_Head, &nodePositionTracked)) && nodePositionTracked; + } + + struct TrackedDevice + { + ovrpNode Node; + EXRTrackedDeviceType Type; + }; + + static TrackedDevice TrackedDevices[] = { + { ovrpNode_Head, EXRTrackedDeviceType::HeadMountedDisplay }, + { ovrpNode_HandLeft, EXRTrackedDeviceType::Controller }, + { ovrpNode_HandRight, EXRTrackedDeviceType::Controller }, + { ovrpNode_TrackerZero, EXRTrackedDeviceType::TrackingReference }, + { ovrpNode_TrackerOne, EXRTrackedDeviceType::TrackingReference }, + { ovrpNode_TrackerTwo, EXRTrackedDeviceType::TrackingReference }, + { ovrpNode_TrackerThree, EXRTrackedDeviceType::TrackingReference }, + { ovrpNode_DeviceObjectZero, EXRTrackedDeviceType::Other }, + }; + + static uint32 TrackedDeviceCount = sizeof(TrackedDevices) / sizeof(TrackedDevices[0]); + + bool FOculusXRHMD::EnumerateTrackedDevices(TArray& OutDevices, EXRTrackedDeviceType Type) + { + CheckInGameThread(); + + for (uint32 TrackedDeviceId = 0; TrackedDeviceId < TrackedDeviceCount; TrackedDeviceId++) + { + if (Type == EXRTrackedDeviceType::Any || Type == TrackedDevices[TrackedDeviceId].Type) + { + ovrpBool nodePresent; + + ovrpNode Node = TrackedDevices[TrackedDeviceId].Node; + if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetNodePresent2(Node, &nodePresent)) && nodePresent) + { + const int32 ExternalDeviceId = OculusXRHMD::ToExternalDeviceId(Node); + OutDevices.Add(ExternalDeviceId); + } + } + } + + return true; + } + + void FOculusXRHMD::UpdateRTPoses() + { + CheckInRenderThread(); + FGameFrame* CurrentFrame = GetFrame_RenderThread(); + if (CurrentFrame) + { + if (!CurrentFrame->Flags.bRTLateUpdateDone) + { + FOculusXRHMDModule::GetPluginWrapper().Update3(ovrpStep_Render, CurrentFrame->FrameNumber, 0.0); + CurrentFrame->Flags.bRTLateUpdateDone = true; + } + } + // else, Frame_RenderThread has already been reset/rendered (or not created yet). + // This can happen when DoEnableStereo() is called, as SetViewportSize (which it calls) enques a render + // immediately - meaning two render frames were enqueued in the span of one game tick. + } + + bool FOculusXRHMD::GetCurrentPose(int32 InDeviceId, FQuat& OutOrientation, FVector& OutPosition) + { + OutOrientation = FQuat::Identity; + OutPosition = FVector::ZeroVector; + + if ((size_t)InDeviceId >= TrackedDeviceCount) + { + return false; + } + + ovrpNode Node = OculusXRHMD::ToOvrpNode(InDeviceId); + const FSettings* CurrentSettings; + FGameFrame* CurrentFrame; + + if (InRenderThread()) + { + CurrentSettings = GetSettings_RenderThread(); + CurrentFrame = GetFrame_RenderThread(); + UpdateRTPoses(); + } + else if (InGameThread()) + { + CurrentSettings = GetSettings(); + CurrentFrame = NextFrameToRender.Get(); + } + else + { + return false; + } + + if (!CurrentSettings || !CurrentFrame) + { + return false; + } + + ovrpPoseStatef PoseState; + FPose Pose; + + if (OVRP_FAILURE(FOculusXRHMDModule::GetPluginWrapper().GetNodePoseState3(ovrpStep_Render, CurrentFrame->FrameNumber, Node, &PoseState)) || !ConvertPose_Internal(PoseState.Pose, Pose, CurrentSettings, CurrentFrame->WorldToMetersScale)) + { + return false; + } + + OutPosition = Pose.Position; + OutOrientation = Pose.Orientation; + return true; + } + + bool FOculusXRHMD::GetRelativeEyePose(int32 InDeviceId, int32 ViewIndex, FQuat& OutOrientation, FVector& OutPosition) + { + OutOrientation = FQuat::Identity; + OutPosition = FVector::ZeroVector; + + if (InDeviceId != HMDDeviceId) + { + return false; + } + + ovrpNode Node; + + switch (ViewIndex) + { + case EStereoscopicEye::eSSE_LEFT_EYE: + Node = ovrpNode_EyeLeft; + break; + case EStereoscopicEye::eSSE_RIGHT_EYE: + Node = ovrpNode_EyeRight; + break; + case EStereoscopicEye::eSSE_MONOSCOPIC: + Node = ovrpNode_EyeCenter; + break; + default: + return false; + } + + const FSettings* CurrentSettings; + FGameFrame* CurrentFrame; + + if (InRenderThread()) + { + CurrentSettings = GetSettings_RenderThread(); + CurrentFrame = GetFrame_RenderThread(); + UpdateRTPoses(); + } + else if (InGameThread()) + { + CurrentSettings = GetSettings(); + CurrentFrame = NextFrameToRender.Get(); + } + else + { + return false; + } + + if (!CurrentSettings || !CurrentFrame) + { + return false; + } + + ovrpPoseStatef HmdPoseState, EyePoseState; + + if (OVRP_FAILURE(FOculusXRHMDModule::GetPluginWrapper().GetNodePoseState3(ovrpStep_Render, CurrentFrame->FrameNumber, ovrpNode_Head, &HmdPoseState)) || OVRP_FAILURE(FOculusXRHMDModule::GetPluginWrapper().GetNodePoseState3(ovrpStep_Render, CurrentFrame->FrameNumber, Node, &EyePoseState))) + { + return false; + } + + FPose HmdPose, EyePose; + HmdPose.Orientation = ToFQuat(HmdPoseState.Pose.Orientation); + HmdPose.Position = ToFVector(HmdPoseState.Pose.Position) * CurrentFrame->WorldToMetersScale; + EyePose.Orientation = ToFQuat(EyePoseState.Pose.Orientation); + EyePose.Position = ToFVector(EyePoseState.Pose.Position) * CurrentFrame->WorldToMetersScale; + + FQuat HmdOrientationInv = HmdPose.Orientation.Inverse(); + OutOrientation = HmdOrientationInv * EyePose.Orientation; + OutOrientation.Normalize(); + OutPosition = HmdOrientationInv.RotateVector(EyePose.Position - HmdPose.Position); + return true; + } + + bool FOculusXRHMD::GetTrackingSensorProperties(int32 InDeviceId, FQuat& OutOrientation, FVector& OutPosition, FXRSensorProperties& OutSensorProperties) + { + CheckInGameThread(); + + if ((size_t)InDeviceId >= TrackedDeviceCount) + { + return false; + } + + ovrpNode Node = OculusXRHMD::ToOvrpNode(InDeviceId); + ovrpPoseStatef PoseState; + FPose Pose; + ovrpFrustum2f Frustum; + + if (OVRP_FAILURE(FOculusXRHMDModule::GetPluginWrapper().GetNodePoseState3(ovrpStep_Render, OVRP_CURRENT_FRAMEINDEX, Node, &PoseState)) || !ConvertPose(PoseState.Pose, Pose) || OVRP_FAILURE(FOculusXRHMDModule::GetPluginWrapper().GetNodeFrustum2(Node, &Frustum))) + { + return false; + } + + OutPosition = Pose.Position; + OutOrientation = Pose.Orientation; + OutSensorProperties.LeftFOV = FMath::RadiansToDegrees(FMath::Atan(Frustum.Fov.LeftTan)); + OutSensorProperties.RightFOV = FMath::RadiansToDegrees(FMath::Atan(Frustum.Fov.RightTan)); + OutSensorProperties.TopFOV = FMath::RadiansToDegrees(FMath::Atan(Frustum.Fov.UpTan)); + OutSensorProperties.BottomFOV = FMath::RadiansToDegrees(FMath::Atan(Frustum.Fov.DownTan)); + OutSensorProperties.NearPlane = Frustum.zNear * Frame->WorldToMetersScale; + OutSensorProperties.FarPlane = Frustum.zFar * Frame->WorldToMetersScale; + OutSensorProperties.CameraDistance = 1.0f * Frame->WorldToMetersScale; + return true; + } + + void FOculusXRHMD::SetTrackingOrigin(EHMDTrackingOrigin::Type InOrigin) + { + TrackingOrigin = InOrigin; + ovrpTrackingOrigin ovrpOrigin = ovrpTrackingOrigin_EyeLevel; + if (InOrigin == EHMDTrackingOrigin::Floor) + ovrpOrigin = ovrpTrackingOrigin_FloorLevel; + + if (InOrigin == EHMDTrackingOrigin::Stage) + ovrpOrigin = ovrpTrackingOrigin_Stage; + + if (FOculusXRHMDModule::GetPluginWrapper().GetInitialized()) + { + EHMDTrackingOrigin::Type lastOrigin = GetTrackingOrigin(); + FOculusXRHMDModule::GetPluginWrapper().SetTrackingOriginType2(ovrpOrigin); + OCFlags.NeedSetTrackingOrigin = false; + + if (lastOrigin != InOrigin) + Settings->BaseOffset = FVector::ZeroVector; + } + + OnTrackingOriginChanged(); + } + + EHMDTrackingOrigin::Type FOculusXRHMD::GetTrackingOrigin() const + { + EHMDTrackingOrigin::Type rv = EHMDTrackingOrigin::Eye; + ovrpTrackingOrigin ovrpOrigin = ovrpTrackingOrigin_EyeLevel; + + if (FOculusXRHMDModule::GetPluginWrapper().GetInitialized() && OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetTrackingOriginType2(&ovrpOrigin))) + { + switch (ovrpOrigin) + { + case ovrpTrackingOrigin_EyeLevel: + rv = EHMDTrackingOrigin::Eye; + break; + case ovrpTrackingOrigin_FloorLevel: + rv = EHMDTrackingOrigin::Floor; + break; + case ovrpTrackingOrigin_Stage: + rv = EHMDTrackingOrigin::Stage; + break; + default: + UE_LOG(LogHMD, Error, TEXT("Unsupported ovr tracking origin type %d"), int(ovrpOrigin)); + break; + } + } + return rv; + } + + bool FOculusXRHMD::GetFloorToEyeTrackingTransform(FTransform& OutFloorToEye) const + { + float EyeHeight = 0.f; + const bool bSuccess = FOculusXRHMDModule::GetPluginWrapper().GetInitialized() && OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetUserEyeHeight2(&EyeHeight)); + OutFloorToEye = FTransform(FVector(0.f, 0.f, -ConvertFloat_M2U(EyeHeight))); + + return bSuccess; + } + + void FOculusXRHMD::ResetOrientationAndPosition(float yaw) + { + Recenter(RecenterOrientationAndPosition, yaw); + } + + void FOculusXRHMD::ResetOrientation(float yaw) + { + Recenter(RecenterOrientation, yaw); + } + + void FOculusXRHMD::ResetPosition() + { + Recenter(RecenterPosition, 0); + } + + void FOculusXRHMD::Recenter(FRecenterTypes RecenterType, float Yaw) + { + CheckInGameThread(); + + if (NextFrameToRender) + { + const bool floorLevel = GetTrackingOrigin() != EHMDTrackingOrigin::Eye; + ovrpPoseStatef poseState; + FOculusXRHMDModule::GetPluginWrapper().Update3(ovrpStep_Render, NextFrameToRender->FrameNumber, 0.0); + FOculusXRHMDModule::GetPluginWrapper().GetNodePoseState3(ovrpStep_Render, NextFrameToRender->FrameNumber, ovrpNode_Head, &poseState); + + if (RecenterType & RecenterPosition) + { + Settings->BaseOffset = ToFVector(poseState.Pose.Position); + if (floorLevel) + Settings->BaseOffset.Z = 0; + } + + if (RecenterType & RecenterOrientation) + { + Settings->BaseOrientation = FRotator(0, FRotator(ToFQuat(poseState.Pose.Orientation)).Yaw - Yaw, 0).Quaternion(); + } + } + } + + void FOculusXRHMD::SetBaseRotation(const FRotator& BaseRot) + { + SetBaseOrientation(BaseRot.Quaternion()); + } + + FRotator FOculusXRHMD::GetBaseRotation() const + { + return GetBaseOrientation().Rotator(); + } + + void FOculusXRHMD::SetBaseOrientation(const FQuat& BaseOrient) + { + CheckInGameThread(); + + Settings->BaseOrientation = BaseOrient; + } + + FQuat FOculusXRHMD::GetBaseOrientation() const + { + CheckInGameThread(); + + return Settings->BaseOrientation; + } + + bool FOculusXRHMD::IsHeadTrackingEnforced() const + { + if (IsInGameThread()) + { + return Settings.IsValid() && Settings->Flags.bHeadTrackingEnforced; + } + else + { + CheckInRenderThread(); + return Settings_RenderThread.IsValid() && Settings_RenderThread->Flags.bHeadTrackingEnforced; + } + } + + void FOculusXRHMD::SetHeadTrackingEnforced(bool bEnabled) + { + CheckInGameThread(); + check(Settings.IsValid()); + + const bool bOldValue = Settings->Flags.bHeadTrackingEnforced; + Settings->Flags.bHeadTrackingEnforced = bEnabled; + + if (!bEnabled) + { + ResetControlRotation(); + } + else if (!bOldValue) + { + InitDevice(); + } + } + + bool FOculusXRHMD::IsHeadTrackingAllowed() const + { + bool bNeedEnableStereo = false; + CheckInGameThread(); + + if (!FOculusXRHMDModule::GetPluginWrapper().GetInitialized()) + { + return false; + } + +#if PLATFORM_WINDOWS + // TODO: This is a temp fix of the case that callers wants to use IsHeadTrackingAllowed() to do something in UGameEngine::Start(). + // Settings->Flags.bStereoEnabled won't be true until Window.IsValid() and UGameEngine::Tick() starts which is very late. + // We might need a better mechanism to decouple Window.IsValid() and Settings->Flags.bStereoEnabled. + bNeedEnableStereo = !GIsEditor && Flags.bNeedEnableStereo; +#endif + return (FHeadMountedDisplayBase::IsHeadTrackingAllowed() || bNeedEnableStereo); + } + + void FOculusXRHMD::OnBeginPlay(FWorldContext& InWorldContext) + { + CheckInGameThread(); + + CachedViewportWidget.Reset(); + CachedWindow.Reset(); + + bHardOcclusionsEnabled = false; + +#if WITH_EDITOR + // @TODO: add more values here. + // This call make sense when 'Play' is used from the Editor; + if (GIsEditor && !GEnableVREditorHacks) + { + Settings->BaseOrientation = FQuat::Identity; + Settings->BaseOffset = FVector::ZeroVector; + Settings->ColorScale = ovrpVector4f{ 1, 1, 1, 1 }; + Settings->ColorOffset = ovrpVector4f{ 0, 0, 0, 0 }; + + //Settings->WorldToMetersScale = InWorldContext.World()->GetWorldSettings()->WorldToMeters; + //Settings->Flags.bWorldToMetersOverride = false; + InitDevice(); + + FApp::SetUseVRFocus(true); + FApp::SetHasVRFocus(true); + OnStartGameFrame(InWorldContext); + } +#endif + } + + void FOculusXRHMD::OnEndPlay(FWorldContext& InWorldContext) + { + CheckInGameThread(); + +#if WITH_EDITOR + if (GIsEditor && !GEnableVREditorHacks) + { + // @todo vreditor: If we add support for starting PIE while in VR Editor, we don't want to kill stereo mode when exiting PIE + if (Splash->IsShown()) + { + Splash->HideLoadingScreen(); // This will only request hiding the screen + Splash->UpdateLoadingScreen_GameThread(); // Update is needed to complete removing the loading screen + } + EnableStereo(false); + ReleaseDevice(); + + FApp::SetUseVRFocus(false); + FApp::SetHasVRFocus(false); + } +#endif + } + + DECLARE_STATS_GROUP(TEXT("Oculus System Metrics"), STATGROUP_OculusSystemMetrics, STATCAT_Advanced); + + DECLARE_FLOAT_COUNTER_STAT_EXTERN(TEXT("App CPU Time (ms)"), STAT_OculusSystem_AppCpuTime, STATGROUP_OculusSystemMetrics, ); + DECLARE_FLOAT_COUNTER_STAT_EXTERN(TEXT("App GPU Time (ms)"), STAT_OculusSystem_AppGpuTime, STATGROUP_OculusSystemMetrics, ); + DECLARE_FLOAT_COUNTER_STAT_EXTERN(TEXT("Compositor CPU Time (ms)"), STAT_OculusSystem_ComCpuTime, STATGROUP_OculusSystemMetrics, ); + DECLARE_FLOAT_COUNTER_STAT_EXTERN(TEXT("Compositor GPU Time (ms)"), STAT_OculusSystem_ComGpuTime, STATGROUP_OculusSystemMetrics, ); + DECLARE_DWORD_COUNTER_STAT_EXTERN(TEXT("Compositor Dropped Frames"), STAT_OculusSystem_DroppedFrames, STATGROUP_OculusSystemMetrics, ); + DECLARE_FLOAT_COUNTER_STAT_EXTERN(TEXT("System GPU Util %"), STAT_OculusSystem_GpuUtil, STATGROUP_OculusSystemMetrics, ); + DECLARE_FLOAT_COUNTER_STAT_EXTERN(TEXT("System CPU Util Avg %"), STAT_OculusSystem_CpuUtilAvg, STATGROUP_OculusSystemMetrics, ); + DECLARE_FLOAT_COUNTER_STAT_EXTERN(TEXT("System CPU Util Worst %"), STAT_OculusSystem_CpuUtilWorst, STATGROUP_OculusSystemMetrics, ); + DECLARE_FLOAT_COUNTER_STAT_EXTERN(TEXT("CPU Clock Freq (MHz)"), STAT_OculusSystem_CpuFreq, STATGROUP_OculusSystemMetrics, ); + DECLARE_FLOAT_COUNTER_STAT_EXTERN(TEXT("GPU Clock Freq (MHz)"), STAT_OculusSystem_GpuFreq, STATGROUP_OculusSystemMetrics, ); + DECLARE_DWORD_COUNTER_STAT_EXTERN(TEXT("CPU Clock Level"), STAT_OculusSystem_CpuClockLvl, STATGROUP_OculusSystemMetrics, ); + DECLARE_DWORD_COUNTER_STAT_EXTERN(TEXT("GPU Clock Level"), STAT_OculusSystem_GpuClockLvl, STATGROUP_OculusSystemMetrics, ); + DECLARE_DWORD_COUNTER_STAT_EXTERN(TEXT("SpaceWarp Mode"), STAT_OculusSystem_ComSpaceWarpMode, STATGROUP_OculusSystemMetrics, ); + DECLARE_DWORD_COUNTER_STAT_EXTERN(TEXT("CPU Core0 Util %"), STAT_OculusSystem_CpuCore0Util, STATGROUP_OculusSystemMetrics, ); + DECLARE_DWORD_COUNTER_STAT_EXTERN(TEXT("CPU Core1 Util %"), STAT_OculusSystem_CpuCore1Util, STATGROUP_OculusSystemMetrics, ); + DECLARE_DWORD_COUNTER_STAT_EXTERN(TEXT("CPU Core2 Util %"), STAT_OculusSystem_CpuCore2Util, STATGROUP_OculusSystemMetrics, ); + DECLARE_DWORD_COUNTER_STAT_EXTERN(TEXT("CPU Core3 Util %"), STAT_OculusSystem_CpuCore3Util, STATGROUP_OculusSystemMetrics, ); + DECLARE_DWORD_COUNTER_STAT_EXTERN(TEXT("CPU Core4 Util %"), STAT_OculusSystem_CpuCore4Util, STATGROUP_OculusSystemMetrics, ); + DECLARE_DWORD_COUNTER_STAT_EXTERN(TEXT("CPU Core5 Util %"), STAT_OculusSystem_CpuCore5Util, STATGROUP_OculusSystemMetrics, ); + DECLARE_DWORD_COUNTER_STAT_EXTERN(TEXT("CPU Core6 Util %"), STAT_OculusSystem_CpuCore6Util, STATGROUP_OculusSystemMetrics, ); + DECLARE_DWORD_COUNTER_STAT_EXTERN(TEXT("CPU Core7 Util %"), STAT_OculusSystem_CpuCore7Util, STATGROUP_OculusSystemMetrics, ); + + DEFINE_STAT(STAT_OculusSystem_AppCpuTime); + DEFINE_STAT(STAT_OculusSystem_AppGpuTime); + DEFINE_STAT(STAT_OculusSystem_ComCpuTime); + DEFINE_STAT(STAT_OculusSystem_ComGpuTime); + DEFINE_STAT(STAT_OculusSystem_DroppedFrames); + DEFINE_STAT(STAT_OculusSystem_GpuUtil); + DEFINE_STAT(STAT_OculusSystem_CpuUtilAvg); + DEFINE_STAT(STAT_OculusSystem_CpuUtilWorst); + DEFINE_STAT(STAT_OculusSystem_CpuFreq); + DEFINE_STAT(STAT_OculusSystem_GpuFreq); + DEFINE_STAT(STAT_OculusSystem_CpuClockLvl); + DEFINE_STAT(STAT_OculusSystem_GpuClockLvl); + DEFINE_STAT(STAT_OculusSystem_ComSpaceWarpMode); + DEFINE_STAT(STAT_OculusSystem_CpuCore0Util); + DEFINE_STAT(STAT_OculusSystem_CpuCore1Util); + DEFINE_STAT(STAT_OculusSystem_CpuCore2Util); + DEFINE_STAT(STAT_OculusSystem_CpuCore3Util); + DEFINE_STAT(STAT_OculusSystem_CpuCore4Util); + DEFINE_STAT(STAT_OculusSystem_CpuCore5Util); + DEFINE_STAT(STAT_OculusSystem_CpuCore6Util); + DEFINE_STAT(STAT_OculusSystem_CpuCore7Util); + + void UpdateOculusSystemMetricsStats() + { + if (FOculusXRHMDModule::GetPluginWrapper().GetInitialized() == ovrpBool_False) + { + return; + } + + ovrpBool bIsSupported; + float valueFloat = 0; + int valueInt = 0; + if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().IsPerfMetricsSupported(ovrpPerfMetrics_App_CpuTime_Float, &bIsSupported)) && bIsSupported == ovrpBool_True) + { + if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetPerfMetricsFloat(ovrpPerfMetrics_App_CpuTime_Float, &valueFloat))) + { + SET_FLOAT_STAT(STAT_OculusSystem_AppCpuTime, valueFloat * 1000); + } + } + if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().IsPerfMetricsSupported(ovrpPerfMetrics_App_GpuTime_Float, &bIsSupported)) && bIsSupported == ovrpBool_True) + { + if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetPerfMetricsFloat(ovrpPerfMetrics_App_GpuTime_Float, &valueFloat))) + { + SET_FLOAT_STAT(STAT_OculusSystem_AppGpuTime, valueFloat * 1000); + } + } + if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().IsPerfMetricsSupported(ovrpPerfMetrics_Compositor_CpuTime_Float, &bIsSupported)) && bIsSupported == ovrpBool_True) + { + if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetPerfMetricsFloat(ovrpPerfMetrics_Compositor_CpuTime_Float, &valueFloat))) + { + SET_FLOAT_STAT(STAT_OculusSystem_ComCpuTime, valueFloat * 1000); + } + } + if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().IsPerfMetricsSupported(ovrpPerfMetrics_Compositor_GpuTime_Float, &bIsSupported)) && bIsSupported == ovrpBool_True) + { + if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetPerfMetricsFloat(ovrpPerfMetrics_Compositor_GpuTime_Float, &valueFloat))) + { + SET_FLOAT_STAT(STAT_OculusSystem_ComGpuTime, valueFloat * 1000); + } + } + if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().IsPerfMetricsSupported(ovrpPerfMetrics_Compositor_DroppedFrameCount_Int, &bIsSupported)) && bIsSupported == ovrpBool_True) + { + if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetPerfMetricsInt(ovrpPerfMetrics_Compositor_DroppedFrameCount_Int, &valueInt))) + { + SET_DWORD_STAT(STAT_OculusSystem_DroppedFrames, valueInt); + } + } + if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().IsPerfMetricsSupported(ovrpPerfMetrics_System_GpuUtilPercentage_Float, &bIsSupported)) && bIsSupported == ovrpBool_True) + { + if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetPerfMetricsFloat(ovrpPerfMetrics_System_GpuUtilPercentage_Float, &valueFloat))) + { + SET_FLOAT_STAT(STAT_OculusSystem_GpuUtil, valueFloat * 100); + } + } + if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().IsPerfMetricsSupported(ovrpPerfMetrics_System_CpuUtilAveragePercentage_Float, &bIsSupported)) && bIsSupported == ovrpBool_True) + { + if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetPerfMetricsFloat(ovrpPerfMetrics_System_CpuUtilAveragePercentage_Float, &valueFloat))) + { + SET_FLOAT_STAT(STAT_OculusSystem_CpuUtilAvg, valueFloat * 100); + } + } + if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().IsPerfMetricsSupported(ovrpPerfMetrics_System_CpuUtilWorstPercentage_Float, &bIsSupported)) && bIsSupported == ovrpBool_True) + { + if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetPerfMetricsFloat(ovrpPerfMetrics_System_CpuUtilWorstPercentage_Float, &valueFloat))) + { + SET_FLOAT_STAT(STAT_OculusSystem_CpuUtilWorst, valueFloat * 100); + } + } + if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().IsPerfMetricsSupported(ovrpPerfMetrics_Device_CpuClockFrequencyInMHz_Float, &bIsSupported)) && bIsSupported == ovrpBool_True) + { + if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetPerfMetricsFloat(ovrpPerfMetrics_Device_CpuClockFrequencyInMHz_Float, &valueFloat))) + { + SET_FLOAT_STAT(STAT_OculusSystem_CpuFreq, valueFloat); + } + } + if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().IsPerfMetricsSupported(ovrpPerfMetrics_Device_GpuClockFrequencyInMHz_Float, &bIsSupported)) && bIsSupported == ovrpBool_True) + { + if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetPerfMetricsFloat(ovrpPerfMetrics_Device_GpuClockFrequencyInMHz_Float, &valueFloat))) + { + SET_FLOAT_STAT(STAT_OculusSystem_GpuFreq, valueFloat); + } + } + if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().IsPerfMetricsSupported(ovrpPerfMetrics_Device_CpuClockLevel_Int, &bIsSupported)) && bIsSupported == ovrpBool_True) + { + if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetPerfMetricsInt(ovrpPerfMetrics_Device_CpuClockLevel_Int, &valueInt))) + { + SET_DWORD_STAT(STAT_OculusSystem_CpuClockLvl, valueInt); + } + } + if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().IsPerfMetricsSupported(ovrpPerfMetrics_Device_GpuClockLevel_Int, &bIsSupported)) && bIsSupported == ovrpBool_True) + { + if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetPerfMetricsInt(ovrpPerfMetrics_Device_GpuClockLevel_Int, &valueInt))) + { + SET_DWORD_STAT(STAT_OculusSystem_GpuClockLvl, valueInt); + } + } + if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().IsPerfMetricsSupported(ovrpPerfMetrics_Compositor_SpaceWarp_Mode_Int, &bIsSupported)) && bIsSupported == ovrpBool_True) + { + if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetPerfMetricsInt(ovrpPerfMetrics_Compositor_SpaceWarp_Mode_Int, &valueInt))) + { + SET_DWORD_STAT(STAT_OculusSystem_ComSpaceWarpMode, valueInt); + } + } + if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().IsPerfMetricsSupported(ovrpPerfMetrics_Device_CpuCore0UtilPercentage_Float, &bIsSupported)) && bIsSupported == ovrpBool_True) + { + if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetPerfMetricsFloat(ovrpPerfMetrics_Device_CpuCore0UtilPercentage_Float, &valueFloat))) + { + SET_FLOAT_STAT(STAT_OculusSystem_CpuCore0Util, valueFloat); + } + } + if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().IsPerfMetricsSupported(ovrpPerfMetrics_Device_CpuCore1UtilPercentage_Float, &bIsSupported)) && bIsSupported == ovrpBool_True) + { + if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetPerfMetricsFloat(ovrpPerfMetrics_Device_CpuCore1UtilPercentage_Float, &valueFloat))) + { + SET_FLOAT_STAT(STAT_OculusSystem_CpuCore1Util, valueFloat); + } + } + if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().IsPerfMetricsSupported(ovrpPerfMetrics_Device_CpuCore2UtilPercentage_Float, &bIsSupported)) && bIsSupported == ovrpBool_True) + { + if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetPerfMetricsFloat(ovrpPerfMetrics_Device_CpuCore2UtilPercentage_Float, &valueFloat))) + { + SET_FLOAT_STAT(STAT_OculusSystem_CpuCore2Util, valueFloat); + } + } + if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().IsPerfMetricsSupported(ovrpPerfMetrics_Device_CpuCore3UtilPercentage_Float, &bIsSupported)) && bIsSupported == ovrpBool_True) + { + if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetPerfMetricsFloat(ovrpPerfMetrics_Device_CpuCore3UtilPercentage_Float, &valueFloat))) + { + SET_FLOAT_STAT(STAT_OculusSystem_CpuCore3Util, valueFloat); + } + } + if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().IsPerfMetricsSupported(ovrpPerfMetrics_Device_CpuCore4UtilPercentage_Float, &bIsSupported)) && bIsSupported == ovrpBool_True) + { + if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetPerfMetricsFloat(ovrpPerfMetrics_Device_CpuCore4UtilPercentage_Float, &valueFloat))) + { + SET_FLOAT_STAT(STAT_OculusSystem_CpuCore4Util, valueFloat); + } + } + if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().IsPerfMetricsSupported(ovrpPerfMetrics_Device_CpuCore5UtilPercentage_Float, &bIsSupported)) && bIsSupported == ovrpBool_True) + { + if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetPerfMetricsFloat(ovrpPerfMetrics_Device_CpuCore5UtilPercentage_Float, &valueFloat))) + { + SET_FLOAT_STAT(STAT_OculusSystem_CpuCore5Util, valueFloat); + } + } + if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().IsPerfMetricsSupported(ovrpPerfMetrics_Device_CpuCore6UtilPercentage_Float, &bIsSupported)) && bIsSupported == ovrpBool_True) + { + if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetPerfMetricsFloat(ovrpPerfMetrics_Device_CpuCore6UtilPercentage_Float, &valueFloat))) + { + SET_FLOAT_STAT(STAT_OculusSystem_CpuCore6Util, valueFloat); + } + } + if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().IsPerfMetricsSupported(ovrpPerfMetrics_Device_CpuCore7UtilPercentage_Float, &bIsSupported)) && bIsSupported == ovrpBool_True) + { + if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetPerfMetricsFloat(ovrpPerfMetrics_Device_CpuCore7UtilPercentage_Float, &valueFloat))) + { + SET_FLOAT_STAT(STAT_OculusSystem_CpuCore7Util, valueFloat); + } + } + } + + void FOculusXRHMD::OnBeginRendering_GameThread() + { + CheckInGameThread(); + // We need to make sure we keep the Wait/Begin/End triplet in sync, so here we signal that we + // can wait for the next frame in the next tick. Without this signal it's possible that two ticks + // happen before the next frame is actually rendered. + bShouldWait_GameThread = true; + } + + bool FOculusXRHMD::OnStartGameFrame(FWorldContext& InWorldContext) + { +#if WITH_EDITOR + // In the editor there can be multiple worlds. An editor world, pie worlds, other viewport worlds for editor pages. + // XR hardware can only be running with one of them. + if (GIsEditor && GEditor && GEditor->GetPIEWorldContext() != nullptr) + { + if (!InWorldContext.bIsPrimaryPIEInstance) + { + return false; + } + } +#endif // WITH_EDITOR + + CheckInGameThread(); + + if (IsEngineExitRequested()) + { + return false; + } + + UpdateOculusSystemMetricsStats(); + + RefreshTrackingToWorldTransform(InWorldContext); + + // check if HMD is marked as invalid and needs to be killed. + ovrpBool appShouldRecreateDistortionWindow; + + if (FOculusXRHMDModule::GetPluginWrapper().GetInitialized() && OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetAppShouldRecreateDistortionWindow2(&appShouldRecreateDistortionWindow)) && appShouldRecreateDistortionWindow) + { + DoEnableStereo(false); + ReleaseDevice(); + + if (!OCFlags.DisplayLostDetected) + { + FCoreDelegates::VRHeadsetLost.Broadcast(); + OCFlags.DisplayLostDetected = true; + } + + Flags.bNeedEnableStereo = true; + } +#if PLATFORM_ANDROID + Flags.bNeedEnableStereo = true; // !!! +#endif + + check(Settings.IsValid()); + if (!Settings->IsStereoEnabled()) + { + FApp::SetUseVRFocus(false); + FApp::SetHasVRFocus(false); + } + +#if OCULUS_STRESS_TESTS_ENABLED + FStressTester::TickCPU_GameThread(this); +#endif + + if (bShutdownRequestQueued) + { + bShutdownRequestQueued = false; + DoSessionShutdown(); + } + + if (!InWorldContext.World() || (!(GEnableVREditorHacks && InWorldContext.WorldType == EWorldType::Editor) && !InWorldContext.World()->IsGameWorld())) // @todo vreditor: (Also see OnEndGameFrame()) Kind of a hack here so we can use VR in editor viewports. We need to consider when running GameWorld viewports inside the editor with VR. + { + // ignore all non-game worlds + return false; + } + + bool bStereoEnabled = Settings->Flags.bStereoEnabled; + bool bStereoDesired = bStereoEnabled; + + if (Flags.bNeedEnableStereo) + { + bStereoDesired = true; + } + + if (bStereoDesired && (Flags.bNeedDisableStereo || !Settings->Flags.bHMDEnabled)) + { + bStereoDesired = false; + } + + bool bStereoDesiredAndIsConnected = bStereoDesired; + + if (bStereoDesired && !(bStereoEnabled ? IsHMDActive() : IsHMDEnabled())) + { + bStereoDesiredAndIsConnected = false; + } + + Flags.bNeedEnableStereo = false; + Flags.bNeedDisableStereo = false; + + if (bStereoEnabled != bStereoDesiredAndIsConnected) + { + bStereoEnabled = DoEnableStereo(bStereoDesiredAndIsConnected); + } + + // Keep trying to enable stereo until we succeed + Flags.bNeedEnableStereo = bStereoDesired && !bStereoEnabled; + + if (!Settings->IsStereoEnabled() && !Settings->Flags.bHeadTrackingEnforced) + { + return false; + } + + if (Flags.bApplySystemOverridesOnStereo) + { + ApplySystemOverridesOnStereo(); + Flags.bApplySystemOverridesOnStereo = false; + } + + CachedWorldToMetersScale = InWorldContext.World()->GetWorldSettings()->WorldToMeters; + + // this should have already happened in FOculusXRInput, so this is usually a no-op. + StartGameFrame_GameThread(); + + bool retval = true; + + UpdateHMDEvents(); + + if (FOculusXRHMDModule::GetPluginWrapper().GetInitialized()) + { + if (OCFlags.DisplayLostDetected) + { + FCoreDelegates::VRHeadsetReconnected.Broadcast(); + OCFlags.DisplayLostDetected = false; + } + + if (OCFlags.NeedSetTrackingOrigin) + { + SetTrackingOrigin(TrackingOrigin); + } + + ovrpBool bAppHasVRFocus = ovrpBool_False; + FOculusXRHMDModule::GetPluginWrapper().GetAppHasVrFocus2(&bAppHasVRFocus); + + FApp::SetUseVRFocus(true); + FApp::SetHasVRFocus(bAppHasVRFocus != ovrpBool_False); + + // Do not pause if Editor is running (otherwise it will become very laggy) + if (!GIsEditor) + { + if (!bAppHasVRFocus) + { + // not visible, + if (!Settings->Flags.bPauseRendering) + { + UE_LOG(LogHMD, Log, TEXT("The app went out of VR focus, seizing rendering...")); + } + } + else if (Settings->Flags.bPauseRendering) + { + UE_LOG(LogHMD, Log, TEXT("The app got VR focus, restoring rendering...")); + } + if (OCFlags.NeedSetFocusToGameViewport) + { + if (bAppHasVRFocus) + { + UE_LOG(LogHMD, Log, TEXT("Setting user focus to game viewport since session status is visible...")); + FSlateApplication::Get().SetAllUserFocusToGameViewport(); + OCFlags.NeedSetFocusToGameViewport = false; + } + } + + bool bPrevPause = Settings->Flags.bPauseRendering; + Settings->Flags.bPauseRendering = !bAppHasVRFocus; + + if (Settings->Flags.bPauseRendering && (GEngine->GetMaxFPS() != OCULUS_PAUSED_IDLE_FPS)) + { + GEngine->SetMaxFPS(OCULUS_PAUSED_IDLE_FPS); + } + + if (bPrevPause != Settings->Flags.bPauseRendering) + { + APlayerController* const PC = GEngine->GetFirstLocalPlayerController(InWorldContext.World()); + if (Settings->Flags.bPauseRendering) + { + // focus is lost + GEngine->SetMaxFPS(OCULUS_PAUSED_IDLE_FPS); + + if (!FCoreDelegates::ApplicationWillEnterBackgroundDelegate.IsBound()) + { + OCFlags.AppIsPaused = false; + // default action: set pause if not already paused + if (PC && !PC->IsPaused()) + { + PC->SetPause(true); + OCFlags.AppIsPaused = true; + } + } + else + { + FCoreDelegates::ApplicationWillEnterBackgroundDelegate.Broadcast(); + } + } + else + { + // focus is gained + GEngine->SetMaxFPS(0); + + if (!FCoreDelegates::ApplicationHasEnteredForegroundDelegate.IsBound()) + { + // default action: unpause if was paused by the plugin + if (PC && OCFlags.AppIsPaused) + { + PC->SetPause(false); + } + OCFlags.AppIsPaused = false; + } + else + { + FCoreDelegates::ApplicationHasEnteredForegroundDelegate.Broadcast(); + } + } + } + } + + ovrpBool AppShouldQuit; + ovrpBool AppShouldRecenter; + + if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetAppShouldQuit2(&AppShouldQuit)) && AppShouldQuit || OCFlags.EnforceExit) + { + FPlatformMisc::LowLevelOutputDebugString(TEXT("OculusXRHMD plugin requested exit (ShouldQuit == 1)\n")); +#if WITH_EDITOR + if (GIsEditor) + { + FSceneViewport* SceneVP = FindSceneViewport(); + if (SceneVP && SceneVP->IsStereoRenderingAllowed()) + { + TSharedPtr Window = SceneVP->FindWindow(); + Window->RequestDestroyWindow(); + } + } + else +#endif //WITH_EDITOR + { + // ApplicationWillTerminateDelegate will fire from inside of the RequestExit + FPlatformMisc::RequestExit(false); + } + OCFlags.EnforceExit = false; + retval = false; + } + else if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetAppShouldRecenter2(&AppShouldRecenter)) && AppShouldRecenter) + { + FPlatformMisc::LowLevelOutputDebugString(TEXT("OculusXRHMD plugin was requested to recenter\n")); + if (FCoreDelegates::VRHeadsetRecenter.IsBound()) + { + FCoreDelegates::VRHeadsetRecenter.Broadcast(); + } + else + { + ResetOrientationAndPosition(); + } + + // Call FOculusXRHMDModule::GetPluginWrapper().RecenterTrackingOrigin2 to clear AppShouldRecenter flag + FOculusXRHMDModule::GetPluginWrapper().RecenterTrackingOrigin2(ovrpRecenterFlag_IgnoreAll); + } + + UpdateHMDWornState(); + } + +#if OCULUS_MR_SUPPORTED_PLATFORMS + if (FOculusXRHMDModule::GetPluginWrapper().GetMixedRealityInitialized()) + { + FOculusXRHMDModule::GetPluginWrapper().UpdateExternalCamera(); + } +#endif + + if (IsEngineExitRequested()) + { + PreShutdown(); + } + + return retval; + } + + void FOculusXRHMD::DoSessionShutdown() + { + // Release resources + ExecuteOnRenderThread([this]() { + ExecuteOnRHIThread([this]() { + for (int32 LayerIndex = 0; LayerIndex < Layers_RenderThread.Num(); LayerIndex++) + { + Layers_RenderThread[LayerIndex]->ReleaseResources_RHIThread(); + } + + for (int32 LayerIndex = 0; LayerIndex < Layers_RHIThread.Num(); LayerIndex++) + { + Layers_RHIThread[LayerIndex]->ReleaseResources_RHIThread(); + } + + if (Splash.IsValid()) + { + Splash->ReleaseResources_RHIThread(); + } + + if (CustomPresent) + { + CustomPresent->ReleaseResources_RHIThread(); + } + + Settings_RHIThread.Reset(); + Frame_RHIThread.Reset(); + Layers_RHIThread.Reset(); + }); + + Settings_RenderThread.Reset(); + Frame_RenderThread.Reset(); + Layers_RenderThread.Reset(); + EyeLayer_RenderThread.Reset(); + + DeferredDeletion.HandleLayerDeferredDeletionQueue_RenderThread(true); + + EnableInsightPassthrough_RenderThread(false); + }); + + Frame.Reset(); + NextFrameToRender.Reset(); + LastFrameToRender.Reset(); + +#if !UE_BUILD_SHIPPING + UDebugDrawService::Unregister(DrawDebugDelegateHandle); +#endif + + // The Editor may release VR focus in OnEndPlay + if (!GIsEditor) + { + FApp::SetUseVRFocus(false); + FApp::SetHasVRFocus(false); + } + + ShutdownSession(); + } + + bool FOculusXRHMD::OnEndGameFrame(FWorldContext& InWorldContext) + { + CheckInGameThread(); + + FGameFrame* const CurrentGameFrame = Frame.Get(); + + if (CurrentGameFrame) + { + // don't use the cached value, as it could be affected by the player's position, so we update it here at the latest point in the game frame + CurrentGameFrame->TrackingToWorld = ComputeTrackingToWorldTransform(InWorldContext); + CurrentGameFrame->LastTrackingToWorld = LastTrackingToWorld; + LastTrackingToWorld = CurrentGameFrame->TrackingToWorld; + } + else + { + return false; + } + + if (!InWorldContext.World() || (!(GEnableVREditorHacks && InWorldContext.WorldType == EWorldType::Editor) && !InWorldContext.World()->IsGameWorld())) + { + // ignore all non-game worlds + return false; + } + + FinishGameFrame_GameThread(); + + return true; + } + + FVector2D FOculusXRHMD::GetPlayAreaBounds(EHMDTrackingOrigin::Type Origin) const + { + ovrpVector3f Dimensions; + + if (Origin == EHMDTrackingOrigin::Stage && OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetBoundaryDimensions2(ovrpBoundary_PlayArea, &Dimensions))) + { + Dimensions.z *= -1.0; + FVector Bounds = ConvertVector_M2U(Dimensions); + return FVector2D(Bounds.X, Bounds.Z); + } + return FVector2D::ZeroVector; + } + + bool FOculusXRHMD::IsHMDEnabled() const + { + CheckInGameThread(); + + return (Settings->Flags.bHMDEnabled); + } + + EHMDWornState::Type FOculusXRHMD::GetHMDWornState() + { + ovrpBool userPresent; + + if (FOculusXRHMDModule::GetPluginWrapper().GetInitialized() && OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetUserPresent2(&userPresent)) && userPresent) + { + return EHMDWornState::Worn; + } + else + { + return EHMDWornState::NotWorn; + } + } + + void FOculusXRHMD::EnableHMD(bool enable) + { + CheckInGameThread(); + + Settings->Flags.bHMDEnabled = enable; + if (!Settings->Flags.bHMDEnabled) + { + EnableStereo(false); + } + } + + bool FOculusXRHMD::GetHMDMonitorInfo(MonitorInfo& MonitorDesc) + { + CheckInGameThread(); + + MonitorDesc.MonitorName = FString("Oculus Window"); + MonitorDesc.MonitorId = 0; + MonitorDesc.DesktopX = MonitorDesc.DesktopY = 0; + MonitorDesc.ResolutionX = MonitorDesc.ResolutionY = 0; + MonitorDesc.WindowSizeX = MonitorDesc.WindowSizeY = 0; + + if (Settings.IsValid()) + { + MonitorDesc.ResolutionX = MonitorDesc.WindowSizeX = Settings->RenderTargetSize.X; + MonitorDesc.ResolutionY = MonitorDesc.WindowSizeY = Settings->RenderTargetSize.Y; + } + + return true; + } + + void FOculusXRHMD::GetFieldOfView(float& InOutHFOVInDegrees, float& InOutVFOVInDegrees) const + + { + ovrpFrustum2f Frustum; + + if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetNodeFrustum2(ovrpNode_EyeCenter, &Frustum))) + { + InOutVFOVInDegrees = FMath::RadiansToDegrees(FMath::Atan(Frustum.Fov.UpTan) + FMath::Atan(Frustum.Fov.DownTan)); + InOutHFOVInDegrees = FMath::RadiansToDegrees(FMath::Atan(Frustum.Fov.LeftTan) + FMath::Atan(Frustum.Fov.RightTan)); + } + } + + void FOculusXRHMD::SetInterpupillaryDistance(float NewInterpupillaryDistance) + { + CheckInGameThread(); + + if (FOculusXRHMDModule::GetPluginWrapper().GetInitialized()) + { + FOculusXRHMDModule::GetPluginWrapper().SetUserIPD2(NewInterpupillaryDistance); + } + } + + float FOculusXRHMD::GetInterpupillaryDistance() const + { + CheckInGameThread(); + + float UserIPD; + + if (!FOculusXRHMDModule::GetPluginWrapper().GetInitialized() || OVRP_FAILURE(FOculusXRHMDModule::GetPluginWrapper().GetUserIPD2(&UserIPD))) + { + return 0.0f; + } + + return UserIPD; + } + + bool FOculusXRHMD::GetHMDDistortionEnabled(EShadingPath /* ShadingPath */) const + { + return false; + } + + bool FOculusXRHMD::IsChromaAbCorrectionEnabled() const + { + CheckInGameThread(); + + return true; + } + + bool FOculusXRHMD::HasHiddenAreaMesh() const + { + if (IsInParallelRenderingThread()) + { + if (ShouldDisableHiddenAndVisibileAreaMeshForSpectatorScreen_RenderThread()) + { + return false; + } + } + + return HiddenAreaMeshes[0].IsValid() && HiddenAreaMeshes[1].IsValid(); + } + + bool FOculusXRHMD::HasVisibleAreaMesh() const + { + if (IsInParallelRenderingThread()) + { + if (ShouldDisableHiddenAndVisibileAreaMeshForSpectatorScreen_RenderThread()) + { + return false; + } + } + + return VisibleAreaMeshes[0].IsValid() && VisibleAreaMeshes[1].IsValid(); + } + + static void DrawOcclusionMesh(FRHICommandList& RHICmdList, int32 ViewIndex, const FHMDViewMesh MeshAssets[]) + { + check(ViewIndex != INDEX_NONE); + + const uint32 MeshIndex = (ViewIndex == EStereoscopicEye::eSSE_LEFT_EYE) ? 0 : 1; + const FHMDViewMesh& Mesh = MeshAssets[MeshIndex]; + check(Mesh.IsValid()); + + RHICmdList.SetStreamSource(0, Mesh.VertexBufferRHI, 0); + RHICmdList.DrawIndexedPrimitive(Mesh.IndexBufferRHI, 0, 0, Mesh.NumVertices, 0, Mesh.NumTriangles, 1); + } + + void FOculusXRHMD::DrawHiddenAreaMesh(FRHICommandList& RHICmdList, int32 ViewIndex) const + { + DrawOcclusionMesh(RHICmdList, ViewIndex, HiddenAreaMeshes); + } + + void FOculusXRHMD::DrawVisibleAreaMesh(FRHICommandList& RHICmdList, int32 ViewIndex) const + { + DrawOcclusionMesh(RHICmdList, ViewIndex, VisibleAreaMeshes); + } + + float FOculusXRHMD::GetPixelDenity() const + { + if (IsInGameThread()) + { + return Settings.IsValid() ? Settings->PixelDensity : 1.0f; + } + else + { + return Settings_RenderThread.IsValid() ? Settings_RenderThread->PixelDensity : 1.0f; + } + } + + void FOculusXRHMD::SetPixelDensity(const float NewPixelDensity) + { + CheckInGameThread(); + Settings->SetPixelDensity(NewPixelDensity); + } + + FIntPoint FOculusXRHMD::GetIdealRenderTargetSize() const + { + if (IsInGameThread()) + { + return Settings.IsValid() ? Settings->RenderTargetSize : 1.0f; + } + else + { + return Settings_RenderThread.IsValid() ? Settings_RenderThread->RenderTargetSize : 1.0f; + } + } + + void FOculusXRHMD::GetMotionControllerData(UObject* WorldContext, const EControllerHand Hand, FXRMotionControllerData& MotionControllerData) + { + MotionControllerData.DeviceName = OculusSystemName; + MotionControllerData.ApplicationInstanceID = FApp::GetInstanceId(); + MotionControllerData.DeviceVisualType = EXRVisualType::Controller; + MotionControllerData.TrackingStatus = ETrackingStatus::NotTracked; + MotionControllerData.HandIndex = Hand; + MotionControllerData.bValid = false; + + if ((Hand == EControllerHand::Left) || (Hand == EControllerHand::Right)) + { + const FName MotionControllerName("OculusXRInputDevice"); + TArray MotionControllers = IModularFeatures::Get().GetModularFeatureImplementations(IMotionController::GetModularFeatureName()); + const IMotionController* MotionController = nullptr; + for (const IMotionController* Itr : MotionControllers) + { + if (Itr->GetMotionControllerDeviceTypeName() == MotionControllerName) + { + MotionController = Itr; + break; + } + } + + const float WorldToMeters = GetWorldToMetersScale(); + if (MotionController) + { + bool bSuccess = false; + FVector Position = FVector::ZeroVector; + FRotator Rotation = FRotator::ZeroRotator; + const FTransform TrackingToWorld = GetTrackingToWorldTransform(); + const FName AimSource = Hand == EControllerHand::Left ? FName("LeftAim") : FName("RightAim"); + bSuccess = MotionController->GetControllerOrientationAndPosition(0, AimSource, Rotation, Position, WorldToMeters); + if (bSuccess) + { + MotionControllerData.AimPosition = TrackingToWorld.TransformPosition(Position); + MotionControllerData.AimRotation = TrackingToWorld.TransformRotation(FQuat(Rotation)); + } + MotionControllerData.bValid |= bSuccess; + + FName GripSource = Hand == EControllerHand::Left ? FName("LeftGrip") : FName("RightGrip"); + bSuccess = MotionController->GetControllerOrientationAndPosition(0, GripSource, Rotation, Position, WorldToMeters); + if (bSuccess) + { + MotionControllerData.GripPosition = TrackingToWorld.TransformPosition(Position); + MotionControllerData.GripRotation = TrackingToWorld.TransformRotation(FQuat(Rotation)); + } + MotionControllerData.bValid |= bSuccess; + + MotionControllerData.TrackingStatus = MotionController->GetControllerTrackingStatus(0, GripSource); + } + } + } + + bool FOculusXRHMD::IsStereoEnabled() const + { + if (IsInGameThread()) + { + return Settings.IsValid() && Settings->IsStereoEnabled(); + } + else + { + return Settings_RenderThread.IsValid() && Settings_RenderThread->IsStereoEnabled(); + } + } + + bool FOculusXRHMD::IsStereoEnabledOnNextFrame() const + { + // !!! + + return Settings.IsValid() && Settings->IsStereoEnabled(); + } + + bool FOculusXRHMD::EnableStereo(bool bStereo) + { + CheckInGameThread(); + + if (bStereo) + { + LoadFromSettings(); + CheckMultiPlayer(); + } + + return DoEnableStereo(bStereo); + } + + void FOculusXRHMD::AdjustViewRect(int32 ViewIndex, int32& X, int32& Y, uint32& SizeX, uint32& SizeY) const + { + if (Settings.IsValid()) + { + X = Settings->EyeUnscaledRenderViewport[ViewIndex].Min.X; + Y = Settings->EyeUnscaledRenderViewport[ViewIndex].Min.Y; + SizeX = Settings->EyeUnscaledRenderViewport[ViewIndex].Size().X; + SizeY = Settings->EyeUnscaledRenderViewport[ViewIndex].Size().Y; + } + else + { + SizeX = SizeX / 2; + X += SizeX * ViewIndex; + } + } + + FIntRect FOculusXRHMD::GetAsymmetricViewRect(const int32 ViewIndex, const FIntRect& ViewRect) + { + FIntRect AsymmetricViewRect = ViewRect; + if (Settings_RenderThread.IsValid() && Frame_RenderThread.IsValid()) + { + const ovrpFovf& EyeBufferFov = Frame_RenderThread->Fov[ViewIndex]; + const ovrpFovf& FrameFov = Frame_RenderThread->SymmetricFov[ViewIndex]; + const int32 ViewPixelSize = AsymmetricViewRect.Size().X; + + // if using symmetric rendering, only send UVs of the asymmetrical subrect (the rest isn't useful) to the VR runtime + const float symTanSize = FrameFov.LeftTan + FrameFov.RightTan; + + AsymmetricViewRect.Min.X += (FrameFov.LeftTan - EyeBufferFov.LeftTan) * (ViewPixelSize / symTanSize); + AsymmetricViewRect.Max.X -= (FrameFov.RightTan - EyeBufferFov.RightTan) * (ViewPixelSize / symTanSize); + } + + return AsymmetricViewRect; + } + + void FOculusXRHMD::SetFinalViewRect(FRHICommandListImmediate& RHICmdList, const int32 ViewIndex, const FIntRect& FinalViewRect) + { + CheckInRenderThread(); + if (ViewIndex == INDEX_NONE || ViewIndex < 0 || ViewIndex >= ovrpEye_Count) + { + return; + } + + FIntRect AsymmetricViewRect = GetAsymmetricViewRect(ViewIndex, FinalViewRect); + + if (Settings_RenderThread.IsValid()) + { + Settings_RenderThread->EyeRenderViewport[ViewIndex] = AsymmetricViewRect; + } + + // Called after RHIThread has already started. Need to update Settings_RHIThread as well. + ExecuteOnRHIThread_DoNotWait([this, ViewIndex, AsymmetricViewRect]() { + CheckInRHIThread(); + + if (Settings_RHIThread.IsValid()) + { + Settings_RHIThread->EyeRenderViewport[ViewIndex] = AsymmetricViewRect; + } + }); + } + +#ifdef WITH_OCULUS_BRANCH + void FOculusXRHMD::CalculateScissorRect(const int32 ViewIndex, const FIntRect& ViewRect, FIntRect& OutRect) + { + CheckInRenderThread(); + if (ViewIndex == INDEX_NONE || ViewIndex < 0 || ViewIndex >= ovrpEye_Count) + { + return; + } + + OutRect = GetAsymmetricViewRect(ViewIndex, ViewRect); + } +#endif // WITH_OCULUS_BRANCH + + void FOculusXRHMD::CalculateStereoViewOffset(const int32 ViewIndex, FRotator& ViewRotation, const float WorldToMeters, FVector& ViewLocation) + { + // This method is called from GetProjectionData on a game thread. + if (InGameThread() && ViewIndex == EStereoscopicEye::eSSE_LEFT_EYE && NextFrameToRender.IsValid()) + { + // Inverse out GameHeadPose.Rotation since PlayerOrientation already contains head rotation. + FQuat HeadOrientation = FQuat::Identity; + FVector HeadPosition; + + GetCurrentPose(HMDDeviceId, HeadOrientation, HeadPosition); + + NextFrameToRender->HeadOrientation = HeadOrientation; + NextFrameToRender->PlayerOrientation = LastPlayerOrientation = ViewRotation.Quaternion() * HeadOrientation.Inverse(); + NextFrameToRender->PlayerLocation = LastPlayerLocation = ViewLocation; + } + + FHeadMountedDisplayBase::CalculateStereoViewOffset(ViewIndex, ViewRotation, WorldToMeters, ViewLocation); + } + + FMatrix FOculusXRHMD::GetStereoProjectionMatrix(int32 ViewIndex) const + { + CheckInGameThread(); + + check(IsStereoEnabled()); + + FMatrix proj = (ViewIndex == EStereoscopicEye::eSSE_MONOSCOPIC) ? ToFMatrix(Settings->MonoProjectionMatrix) : ToFMatrix(Settings->EyeProjectionMatrices[ViewIndex]); + + // correct far and near planes for reversed-Z projection matrix + const float WorldScale = GetWorldToMetersScale() * (1.0 / 100.0f); // physical scale is 100 UUs/meter + float InNearZ = GNearClippingPlane * WorldScale; + + proj.M[3][3] = 0.0f; + proj.M[2][3] = 1.0f; + + proj.M[2][2] = 0.0f; + proj.M[3][2] = InNearZ; + + return proj; + } + + void FOculusXRHMD::InitCanvasFromView(FSceneView* InView, UCanvas* Canvas) + { + // This is used for placing small HUDs (with names) + // over other players (for example, in Capture Flag). + // HmdOrientation should be initialized by GetCurrentOrientation (or + // user's own value). + } + + void FOculusXRHMD::RenderTexture_RenderThread(class FRHICommandListImmediate& RHICmdList, class FRHITexture* BackBuffer, class FRHITexture* SrcTexture, FVector2D WindowSize) const + { + CheckInRenderThread(); + check(CustomPresent); + +#if PLATFORM_ANDROID + return; +#endif + + if (SpectatorScreenController) + { + SpectatorScreenController->RenderSpectatorScreen_RenderThread(RHICmdList, BackBuffer, SrcTexture, WindowSize); + } + } + + FVector2D FOculusXRHMD::GetEyeCenterPoint_RenderThread(int32 ViewIndex) const + { + CheckInRenderThread(); + + check(IsStereoEnabled() || IsHeadTrackingEnforced()); + + // Don't use GetStereoProjectionMatrix because it is game thread only on oculus, we also don't need the zplane adjustments for this. + const FMatrix StereoProjectionMatrix = ToFMatrix(Settings_RenderThread->EyeProjectionMatrices[ViewIndex]); + + //0,0,1 is the straight ahead point, wherever it maps to is the center of the projection plane in -1..1 coordinates. -1,-1 is bottom left. + const FVector4 ScreenCenter = StereoProjectionMatrix.TransformPosition(FVector(0.0f, 0.0f, 1.0f)); + //transform into 0-1 screen coordinates 0,0 is top left. + const FVector2D CenterPoint(0.5f + (ScreenCenter.X / 2.0f), 0.5f - (ScreenCenter.Y / 2.0f)); + + return CenterPoint; + } + + FIntRect FOculusXRHMD::GetFullFlatEyeRect_RenderThread(FTexture2DRHIRef EyeTexture) const + { + CheckInRenderThread(); + + // Rift does this differently than other platforms, it already has an idea of what rectangle it wants to use stored. + FIntRect& EyeRect = Settings_RenderThread->EyeRenderViewport[0]; + + // But the rectangle rift specifies has corners cut off, so we will crop a little more. + if (ShouldDisableHiddenAndVisibileAreaMeshForSpectatorScreen_RenderThread()) + { + return EyeRect; + } + else + { + static FVector2D SrcNormRectMin(0.05f, 0.0f); + static FVector2D SrcNormRectMax(0.95f, 1.0f); + const int32 SizeX = EyeRect.Max.X - EyeRect.Min.X; + const int32 SizeY = EyeRect.Max.Y - EyeRect.Min.Y; + return FIntRect(EyeRect.Min.X + SizeX * SrcNormRectMin.X, EyeRect.Min.Y + SizeY * SrcNormRectMin.Y, EyeRect.Min.X + SizeX * SrcNormRectMax.X, EyeRect.Min.Y + SizeY * SrcNormRectMax.Y); + } + } + + void FOculusXRHMD::CopyTexture_RenderThread(FRHICommandListImmediate& RHICmdList, FRHITexture2D* SrcTexture, FIntRect SrcRect, FRHITexture2D* DstTexture, FIntRect DstRect, bool bClearBlack, bool bNoAlpha) const + { + if (bClearBlack) + { + FRHIRenderPassInfo RPInfo(DstTexture, ERenderTargetActions::DontLoad_Store); + RHICmdList.BeginRenderPass(RPInfo, TEXT("ClearToBlack")); + { + const FIntRect ClearRect(0, 0, DstTexture->GetSizeX(), DstTexture->GetSizeY()); + RHICmdList.SetViewport(ClearRect.Min.X, ClearRect.Min.Y, 0, ClearRect.Max.X, ClearRect.Max.Y, 1.0f); + DrawClearQuad(RHICmdList, FLinearColor::Black); + } + RHICmdList.EndRenderPass(); + } + + check(CustomPresent); + CustomPresent->CopyTexture_RenderThread(RHICmdList, DstTexture, SrcTexture, DstRect, SrcRect, false, bNoAlpha, true, true); + } + + bool FOculusXRHMD::PopulateAnalyticsAttributes(TArray& EventAttributes) + { + if (!FHeadMountedDisplayBase::PopulateAnalyticsAttributes(EventAttributes)) + { + return false; + } + + EventAttributes.Add(FAnalyticsEventAttribute(TEXT("HQBuffer"), (bool)Settings->Flags.bHQBuffer)); + EventAttributes.Add(FAnalyticsEventAttribute(TEXT("HQDistortion"), (bool)Settings->Flags.bHQDistortion)); + EventAttributes.Add(FAnalyticsEventAttribute(TEXT("UpdateOnRT"), (bool)Settings->Flags.bUpdateOnRT)); + + return true; + } + + bool FOculusXRHMD::ShouldUseSeparateRenderTarget() const + { + return IsStereoEnabled(); + } + + void FOculusXRHMD::CalculateRenderTargetSize(const FViewport& Viewport, uint32& InOutSizeX, uint32& InOutSizeY) + { + // TODO this should use Settings_RenderThread if !CheckInGameThread() + // This is called before StartRenderFrame_GameThread() on startup + if (!Settings->IsStereoEnabled()) + { + return; + } + + InOutSizeX = Settings->RenderTargetSize.X; + InOutSizeY = Settings->RenderTargetSize.Y; + + check(InOutSizeX != 0 && InOutSizeY != 0); + } + + void FOculusXRHMD::AllocateEyeBuffer() + { + CheckInGameThread(); + + ExecuteOnRenderThread([&]() { + InitializeEyeLayer_RenderThread(GetImmediateCommandList_ForRenderCommand()); + + const FXRSwapChainPtr& SwapChain = EyeLayer_RenderThread->GetSwapChain(); + if (SwapChain.IsValid()) + { + const FRHITexture2D* const SwapChainTexture = SwapChain->GetTexture2DArray() ? SwapChain->GetTexture2DArray() : SwapChain->GetTexture2D(); + UE_LOG(LogHMD, Log, TEXT("Allocating Oculus %d x %d rendertarget swapchain"), SwapChainTexture->GetSizeX(), SwapChainTexture->GetSizeY()); + } + }); + + bNeedReAllocateViewportRenderTarget = true; + } + + bool FOculusXRHMD::NeedReAllocateViewportRenderTarget(const FViewport& Viewport) + { + CheckInGameThread(); + + return ensureMsgf(Settings.IsValid(), TEXT("Unexpected issue with Oculus settings on the GameThread. This should be valid when this is called in EnqueueBeginRenderFrame() - has the callsite changed?")) && Settings->IsStereoEnabled() && bNeedReAllocateViewportRenderTarget; + } + + bool FOculusXRHMD::NeedReAllocateDepthTexture(const TRefCountPtr& DepthTarget) + { + CheckInRenderThread(); + + return ensureMsgf(Settings_RenderThread.IsValid(), TEXT("Unexpected issue with Oculus settings on the RenderThread. This should be valid when this is called in AllocateCommonDepthTargets() - has the callsite changed?")) && Settings_RenderThread->IsStereoEnabled() && bNeedReAllocateDepthTexture_RenderThread; + } + + bool FOculusXRHMD::NeedReAllocateShadingRateTexture(const TRefCountPtr& FoveationTarget) + { + CheckInRenderThread(); + + return ensureMsgf(Settings_RenderThread.IsValid(), TEXT("Unexpected issue with Oculus settings on the RenderThread. This should be valid when this is called in AllocateFoveationTexture() - has the callsite changed?")) && Settings_RenderThread->IsStereoEnabled() && bNeedReAllocateFoveationTexture_RenderThread; + } + +#ifdef WITH_OCULUS_BRANCH + bool FOculusXRHMD::NeedReAllocateMotionVectorTexture(const TRefCountPtr& MotionVectorTarget, const TRefCountPtr& MotionVectorDepthTarget) + { + CheckInRenderThread(); + + return ensureMsgf(Settings_RenderThread.IsValid(), TEXT("Unexpected issue with Oculus settings on the RenderThread. This should be valid when this is called in AllocateMotionVectorTexture() - has the callsite changed?")) && Settings_RenderThread->IsStereoEnabled() && bNeedReAllocateMotionVectorTexture_RenderThread; + } +#endif // WITH_OCULUS_BRANCH + + bool FOculusXRHMD::AllocateRenderTargetTexture(uint32 Index, uint32 SizeX, uint32 SizeY, uint8 Format, uint32 NumMips, ETextureCreateFlags InTexFlags, ETextureCreateFlags InTargetableTextureFlags, FTexture2DRHIRef& OutTargetableTexture, FTexture2DRHIRef& OutShaderResourceTexture, uint32 NumSamples) + { + CheckInRenderThread(); + + check(Index == 0); + + if (LayerMap[0].IsValid()) + { + const FXRSwapChainPtr& SwapChain = EyeLayer_RenderThread->GetSwapChain(); + if (SwapChain.IsValid()) + { + OutTargetableTexture = OutShaderResourceTexture = SwapChain->GetTexture2DArray() ? SwapChain->GetTexture2DArray() : SwapChain->GetTexture2D(); + bNeedReAllocateViewportRenderTarget = false; + return true; + } + } + + OutTargetableTexture = OutShaderResourceTexture = nullptr; + return false; + } + + bool FOculusXRHMD::AllocateDepthTexture(uint32 Index, uint32 SizeX, uint32 SizeY, uint8 Format, uint32 NumMips, ETextureCreateFlags FlagsIn, ETextureCreateFlags TargetableTextureFlags, FTexture2DRHIRef& OutTargetableTexture, FTexture2DRHIRef& OutShaderResourceTexture, uint32 NumSamples) + { + CheckInRenderThread(); + + check(Index == 0); + + if (EyeLayer_RenderThread.IsValid()) + { + const FXRSwapChainPtr& SwapChain = EyeLayer_RenderThread->GetDepthSwapChain(); + + if (SwapChain.IsValid()) + { + FTexture2DRHIRef Texture = SwapChain->GetTexture2DArray() ? SwapChain->GetTexture2DArray() : SwapChain->GetTexture2D(); + FIntPoint TexSize = Texture->GetSizeXY(); + + // Ensure the texture size matches the eye layer. We may get other depth allocations unrelated to the main scene render. + if (FIntPoint(SizeX, SizeY) == TexSize) + { + if (bNeedReAllocateDepthTexture_RenderThread) + { + UE_LOG(LogHMD, Log, TEXT("Allocating Oculus %d x %d depth rendertarget swapchain"), SizeX, SizeY); + bNeedReAllocateDepthTexture_RenderThread = false; + } + + OutTargetableTexture = OutShaderResourceTexture = Texture; + return true; + } + } + } + + OutTargetableTexture = OutShaderResourceTexture = nullptr; + return false; + } + + bool FOculusXRHMD::AllocateShadingRateTexture(uint32 Index, uint32 RenderSizeX, uint32 RenderSizeY, uint8 Format, uint32 NumMips, ETextureCreateFlags InTexFlags, ETextureCreateFlags InTargetableTextureFlags, FTexture2DRHIRef& OutTexture, FIntPoint& OutTextureSize) + { + CheckInRenderThread(); + + check(Index == 0); + + if (EyeLayer_RenderThread.IsValid()) + { + const FXRSwapChainPtr& SwapChain = EyeLayer_RenderThread->GetFoveationSwapChain(); + + if (SwapChain.IsValid()) + { + FTexture2DRHIRef Texture = SwapChain->GetTexture2DArray() ? SwapChain->GetTexture2DArray() : SwapChain->GetTexture2D(); + FIntPoint TexSize = Texture->GetSizeXY(); + + // Only set texture and return true if we have a valid texture of compatible size + if (Texture->IsValid() && TexSize.X > 0 && TexSize.Y > 0) + { + if (bNeedReAllocateFoveationTexture_RenderThread) + { + UE_LOG(LogHMD, Log, TEXT("Allocating Oculus %d x %d variable resolution swapchain"), TexSize.X, TexSize.Y, Index); + bNeedReAllocateFoveationTexture_RenderThread = false; + } + + // This is a hack to turn force the runtime to use FDM over FSR when we allocate our FDM to avoid a crash on Quest 3 + // TODO: Remove this for UE 5.3 after there's an engine-side fix + ExecuteOnRHIThread_DoNotWait([this]() { + // Set this in AllocateShadingRateTexture because it guarantees that this runs after VulkanExtensions has initially + // selected the shading rate type, before the FDM is actually going to be used, and only when we actually have an FDM + CustomPresent->UseFragmentDensityMapOverShadingRate_RHIThread(); + }); + + OutTexture = Texture; + OutTextureSize = TexSize; + return true; + } + } + } + + OutTexture = nullptr; + return false; + } + +#ifdef WITH_OCULUS_BRANCH + bool FOculusXRHMD::AllocateMotionVectorTexture(uint32 Index, uint8 Format, uint32 NumMips, ETextureCreateFlags InTexFlags, ETextureCreateFlags InTargetableTextureFlags, FTexture2DRHIRef& OutTexture, FIntPoint& OutTextureSize, FTexture2DRHIRef& OutDepthTexture, FIntPoint& OutDepthTextureSize) + { + CheckInRenderThread(); + + check(Index == 0); + if (EyeLayer_RenderThread.IsValid()) + { + const FXRSwapChainPtr& SwapChain = EyeLayer_RenderThread->GetMotionVectorSwapChain(); + if (SwapChain.IsValid()) + { + FTexture2DRHIRef Texture = SwapChain->GetTexture2DArray() ? SwapChain->GetTexture2DArray() : SwapChain->GetTexture2D(); + FIntPoint TexSize = Texture->GetSizeXY(); + + const FXRSwapChainPtr& DepthSwapChain = EyeLayer_RenderThread->GetMotionVectorDepthSwapChain(); + if (DepthSwapChain.IsValid()) + { + FTexture2DRHIRef DepthTexture = DepthSwapChain->GetTexture2DArray() ? DepthSwapChain->GetTexture2DArray() : DepthSwapChain->GetTexture2D(); + FIntPoint DepthTexSize = DepthTexture->GetSizeXY(); + + if (DepthTexture->IsValid() && DepthTexSize.X > 0 && DepthTexSize.Y > 0) + { + OutDepthTextureSize = DepthTexSize; + OutDepthTexture = DepthTexture; + } + else + { + return false; + } + } + + // Only set texture and return true if we have a valid texture of compatible size + if (Texture->IsValid() && TexSize.X > 0 && TexSize.Y > 0) + { + if (bNeedReAllocateMotionVectorTexture_RenderThread) + { + UE_LOG(LogHMD, Log, TEXT("[Mobile SpaceWarp] Allocating Oculus %d x %d motion vector swapchain"), TexSize.X, TexSize.Y, Index); + bNeedReAllocateMotionVectorTexture_RenderThread = false; + } + + OutTexture = Texture; + OutTextureSize = TexSize; + return true; + } + } + } + + OutTexture = nullptr; + return false; + } +#endif // WITH_OCULUS_BRANCH + +#if defined(WITH_OCULUS_BRANCH) + bool FOculusXRHMD::FindEnvironmentDepthTexture_RenderThread(FTextureRHIRef& OutTexture, FVector2f& OutDepthFactors, FMatrix44f OutScreenToDepthMatrices[2], FMatrix44f OutDepthViewProjMatrices[2]) + { + CheckInRenderThread(); + + if (Frame_RenderThread.IsValid()) + { + int SwapchainIndex; + if (ComputeEnvironmentDepthParameters_RenderThread(OutDepthFactors, OutScreenToDepthMatrices, OutDepthViewProjMatrices, SwapchainIndex)) + { + if (SwapchainIndex >= EnvironmentDepthSwapchain.Num()) + { + return false; + } + OutTexture = EnvironmentDepthSwapchain[SwapchainIndex]; + return true; + } + } + return false; + } +#endif // defined(WITH_OCULUS_BRANCH) + + EPixelFormat FOculusXRHMD::GetActualColorSwapchainFormat() const + { + if (!CustomPresent.IsValid()) + { + UE_LOG(LogHMD, Log, TEXT("Invalid CustomPresent! PF_R8G8B8A8 will be used as the default swapchain format!")); + return PF_R8G8B8A8; + } + return CustomPresent->GetDefaultPixelFormat(); + } + + void FOculusXRHMD::UpdateViewportWidget(bool bUseSeparateRenderTarget, const class FViewport& Viewport, class SViewport* ViewportWidget) + { + CheckInGameThread(); + check(ViewportWidget); + + TSharedPtr Window = CachedWindow.Pin(); + TSharedPtr CurrentlyCachedWidget = CachedViewportWidget.Pin(); + TSharedRef Widget = ViewportWidget->AsShared(); + + if (!Window.IsValid() || Widget != CurrentlyCachedWidget) + { + Window = FSlateApplication::Get().FindWidgetWindow(Widget); + + CachedViewportWidget = Widget; + CachedWindow = Window; + } + + if (!Settings->IsStereoEnabled()) + { + // Restore AutoResizeViewport mode for the window + if (Window.IsValid()) + { + Window->SetMirrorWindow(false); + Window->SetViewportSizeDrivenByWindow(true); + } + return; + } + + if (bUseSeparateRenderTarget && Frame.IsValid()) + { + if (Window.IsValid()) + { + const auto SlateWindowSize = Window->GetSizeInScreen(); + CachedWindowSize = FIntPoint(static_cast(SlateWindowSize.X), static_cast(SlateWindowSize.Y)); + } + else + { + CachedWindowSize = Viewport.GetSizeXY(); + } + } + } + + FXRRenderBridge* FOculusXRHMD::GetActiveRenderBridge_GameThread(bool bUseSeparateRenderTarget) + { + CheckInGameThread(); + + if (bUseSeparateRenderTarget && NextFrameToRender.IsValid()) + { + return CustomPresent; + } + else + { + return nullptr; + } + } + + void FOculusXRHMD::UpdateHMDWornState() + { + const EHMDWornState::Type NewHMDWornState = GetHMDWornState(); + + if (NewHMDWornState != HMDWornState) + { + HMDWornState = NewHMDWornState; + if (HMDWornState == EHMDWornState::Worn) + { + FCoreDelegates::VRHeadsetPutOnHead.Broadcast(); + } + else if (HMDWornState == EHMDWornState::NotWorn) + { + FCoreDelegates::VRHeadsetRemovedFromHead.Broadcast(); + } + } + } + + void FOculusXRHMD::UpdateHMDEvents() + { + ovrpEventDataBuffer buf; + while (FOculusXRHMDModule::GetPluginWrapper().PollEvent(&buf) == ovrpSuccess) + { + if (buf.EventType == ovrpEventType_None) + { + break; + } + else if (buf.EventType == ovrpEventType_DisplayRefreshRateChange) + { + ovrpEventDisplayRefreshRateChange* rateChangedEvent = (ovrpEventDisplayRefreshRateChange*)&buf; + FOculusEventDelegates::OculusDisplayRefreshRateChanged.Broadcast(rateChangedEvent->FromRefreshRate, rateChangedEvent->ToRefreshRate); + } + else + { + for (auto& it : EventPollingDelegates) + { + bool HandledEvent = false; + it.ExecuteIfBound(&buf, HandledEvent); + } + } + } + } + + uint32 FOculusXRHMD::CreateLayer(const IStereoLayers::FLayerDesc& InLayerDesc) + { + CheckInGameThread(); + + uint32 LayerId = NextLayerId++; + FLayerPtr Layer = MakeShareable(new FLayer(LayerId)); + LayerMap.Add(LayerId, Layer); + Layer->SetDesc(Settings.Get(), InLayerDesc); + return LayerId; + } + + void FOculusXRHMD::DestroyLayer(uint32 LayerId) + { + CheckInGameThread(); + FLayerPtr* LayerFound = LayerMap.Find(LayerId); + if (LayerFound) + { + (*LayerFound)->DestroyLayer(); + } + LayerMap.Remove(LayerId); + } + + void FOculusXRHMD::SetLayerDesc(uint32 LayerId, const IStereoLayers::FLayerDesc& InLayerDesc) + { + CheckInGameThread(); + FLayerPtr* LayerFound = LayerMap.Find(LayerId); + + if (LayerFound) + { + FLayer* Layer = new FLayer(**LayerFound); + Layer->SetDesc(Settings.Get(), InLayerDesc); + *LayerFound = MakeShareable(Layer); + } + } + + bool FOculusXRHMD::GetLayerDesc(uint32 LayerId, IStereoLayers::FLayerDesc& OutLayerDesc) + { + CheckInGameThread(); + FLayerPtr* LayerFound = LayerMap.Find(LayerId); + + if (LayerFound) + { + OutLayerDesc = (*LayerFound)->GetDesc(); + return true; + } + + return false; + } + + void FOculusXRHMD::MarkTextureForUpdate(uint32 LayerId) + { + CheckInGameThread(); + FLayerPtr* LayerFound = LayerMap.Find(LayerId); + + if (LayerFound) + { + (*LayerFound)->MarkTextureForUpdate(); + } + } + + void FOculusXRHMD::SetSplashRotationToForward() + { + //if update splash screen is shown, update the head orientation default to recenter splash screens + FQuat HeadOrientation = FQuat::Identity; + FVector HeadPosition; + GetCurrentPose(HMDDeviceId, HeadOrientation, HeadPosition); + SplashRotation = FRotator(HeadOrientation); + SplashRotation.Pitch = 0; + SplashRotation.Roll = 0; + } + + FOculusXRSplashDesc FOculusXRHMD::GetUESplashScreenDesc() + { + FOculusXRSplashDesc Desc; + Desc.LoadedTexture = bSplashShowMovie ? SplashMovie : SplashTexture; + Desc.TransformInMeters = Desc.TransformInMeters * FTransform(SplashOffset / GetWorldToMetersScale()); + Desc.bNoAlphaChannel = true; + Desc.bIsDynamic = bSplashShowMovie; + Desc.QuadSizeInMeters *= SplashScale; + return Desc; + } + + void FOculusXRHMD::EyeTrackedFoveatedRenderingFallback() + { + FoveatedRenderingMethod = EOculusXRFoveatedRenderingMethod::FixedFoveatedRendering; + FoveatedRenderingLevel = EOculusXRFoveatedRenderingLevel::High; + bDynamicFoveatedRendering = true; + } + + void FOculusXRHMD::GetAllocatedTexture(uint32 LayerId, FTextureRHIRef& Texture, FTextureRHIRef& LeftTexture) + { + Texture = LeftTexture = nullptr; + FLayerPtr* LayerFound = nullptr; + + if (IsInGameThread()) + { + LayerFound = LayerMap.Find(LayerId); + } + else if (IsInParallelRenderingThread()) + { + for (int32 LayerIndex = 0; LayerIndex < Layers_RenderThread.Num(); LayerIndex++) + { + if (Layers_RenderThread[LayerIndex]->GetId() == LayerId) + { + LayerFound = &Layers_RenderThread[LayerIndex]; + } + } + } + else if (IsInRHIThread()) + { + for (int32 LayerIndex = 0; LayerIndex < Layers_RHIThread.Num(); LayerIndex++) + { + if (Layers_RHIThread[LayerIndex]->GetId() == LayerId) + { + LayerFound = &Layers_RHIThread[LayerIndex]; + } + } + } + else + { + return; + } + + if (LayerFound && (*LayerFound)->GetSwapChain().IsValid()) + { + bool bRightTexture = (*LayerFound)->GetRightSwapChain().IsValid(); + const IStereoLayers::FLayerDesc& Desc = (*LayerFound)->GetDesc(); + + if (Desc.HasShape()) + { + if (bRightTexture) + { + Texture = (*LayerFound)->GetRightSwapChain()->GetTextureCube(); + LeftTexture = (*LayerFound)->GetSwapChain()->GetTextureCube(); + } + else + { + Texture = LeftTexture = (*LayerFound)->GetSwapChain()->GetTextureCube(); + } + } + else if (Desc.HasShape() || Desc.HasShape()) + { + if (bRightTexture) + { + Texture = (*LayerFound)->GetRightSwapChain()->GetTexture2D(); + LeftTexture = (*LayerFound)->GetSwapChain()->GetTexture2D(); + } + else + { + Texture = LeftTexture = (*LayerFound)->GetSwapChain()->GetTexture2D(); + } + } + } + } + + IStereoLayers::FLayerDesc FOculusXRHMD::GetDebugCanvasLayerDesc(FTextureRHIRef Texture) + { + IStereoLayers::FLayerDesc StereoLayerDesc; + + ovrpBool cylinderSupported = ovrpBool_False; + ovrpResult result = FOculusXRHMDModule::GetPluginWrapper().IsLayerShapeSupported(ovrpShape_Cylinder, &cylinderSupported); + if (OVRP_SUCCESS(result) && cylinderSupported) + { + StereoLayerDesc = IStereoLayers::FLayerDesc(FCylinderLayer(100.f, 488.f / 4, 180.f)); + StereoLayerDesc.Transform = FTransform(FVector(0.f, 0, 0)); // 100/0/0 for quads + } + else + { + StereoLayerDesc.Transform = FTransform(FVector(100.f, 0, 0)); + } + + StereoLayerDesc.QuadSize = FVector2D(180.f, 180.f); + StereoLayerDesc.PositionType = IStereoLayers::ELayerType::FaceLocked; + StereoLayerDesc.LayerSize = Texture->GetTexture2D()->GetSizeXY(); + StereoLayerDesc.Flags = IStereoLayers::ELayerFlags::LAYER_FLAG_TEX_CONTINUOUS_UPDATE; + StereoLayerDesc.Flags |= IStereoLayers::ELayerFlags::LAYER_FLAG_QUAD_PRESERVE_TEX_RATIO; + return StereoLayerDesc; + } + + void FOculusXRHMD::SetupViewFamily(FSceneViewFamily& InViewFamily) + { + InViewFamily.EngineShowFlags.StereoRendering = IsStereoEnabled(); + } + + void FOculusXRHMD::SetupView(FSceneViewFamily& InViewFamily, FSceneView& InView) + { + CheckInGameThread(); + } + + void FOculusXRHMD::BeginRenderViewFamily(FSceneViewFamily& InViewFamily) + { + CheckInGameThread(); + + if (Settings.IsValid() && Settings->IsStereoEnabled()) + { + // This should already have been set by UpdateStereoRenderingParams(). + // It must still match the value used there. + check(Settings->CurrentShaderPlatform == InViewFamily.Scene->GetShaderPlatform()); + Settings->Flags.bsRGBEyeBuffer = IsMobilePlatform(Settings->CurrentShaderPlatform) && IsMobileColorsRGB(); + + if (NextFrameToRender.IsValid()) + { + NextFrameToRender->ShowFlags = InViewFamily.EngineShowFlags; + } + + if (SpectatorScreenController != nullptr) + { + SpectatorScreenController->BeginRenderViewFamily(); + } + } + + StartRenderFrame_GameThread(); + } + + void FOculusXRHMD::EnableInsightPassthrough_RenderThread(bool bEnablePassthrough) + { + const bool bShouldEnable = (InsightInitStatus == FInsightInitStatus::NotInitialized) && bEnablePassthrough; + + if (bShouldEnable) + { + if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().InitializeInsightPassthrough())) + { + UE_LOG(LogHMD, Log, TEXT("Passthrough Initialized")); + InsightInitStatus = FInsightInitStatus::Initialized; + } + else + { + InsightInitStatus = FInsightInitStatus::Failed; + UE_LOG(LogHMD, Log, TEXT("Passthrough initialization failed")); + } + } + else + { + const bool bShouldShutdown = (InsightInitStatus == FInsightInitStatus::Initialized) && !bEnablePassthrough; + if (bShouldShutdown) + { + // it may already be deinitialized. + if (!FOculusXRHMDModule::GetPluginWrapper().GetInsightPassthroughInitialized() || OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().ShutdownInsightPassthrough())) + { + UE_LOG(LogHMD, Log, TEXT("Passthrough shutdown")); + InsightInitStatus = FInsightInitStatus::NotInitialized; + } + else + { + UE_LOG(LogHMD, Log, TEXT("Failed to shut down passthrough. It may be still in use.")); + } + } + } + } + + void FOculusXRHMD::PreRenderViewFamily_RenderThread(FRDGBuilder& GraphBuilder, FSceneViewFamily& ViewFamily) + { + CheckInRenderThread(); + } + + void FOculusXRHMD::OnBeginRendering_RenderThread(FRHICommandListImmediate& RHICmdList, FSceneViewFamily& ViewFamily) + { + CheckInRenderThread(); + + if (!Frame_RenderThread.IsValid()) + { + return; + } + + if (!Settings_RenderThread.IsValid() || !Settings_RenderThread->IsStereoEnabled()) + { + return; + } + + // If using OVRPlugin OpenXR, only update spectator screen mode with VR focus, since we are running the frameloop + // and cycling through the swapchain even without VR focus with OVRPlugin OpenXR + ovrpXrApi NativeXrApi; + FOculusXRHMDModule::GetPluginWrapper().GetNativeXrApiType(&NativeXrApi); + if (SpectatorScreenController && (NativeXrApi != ovrpXrApi_OpenXR || FApp::HasVRFocus())) + { + SpectatorScreenController->UpdateSpectatorScreenMode_RenderThread(); + Frame_RenderThread->Flags.bSpectatorScreenActive = SpectatorScreenController->GetSpectatorScreenMode() != ESpectatorScreenMode::Disabled; + } + + // Update mirror texture + CustomPresent->UpdateMirrorTexture_RenderThread(); + +#if !PLATFORM_ANDROID +#if 0 // The entire target should be cleared by the tonemapper and pp material \ + // Clear the padding between two eyes + const int32 GapMinX = ViewFamily.Views[0]->UnscaledViewRect.Max.X; + const int32 GapMaxX = ViewFamily.Views[1]->UnscaledViewRect.Min.X; + + if (GapMinX < GapMaxX) + { + SCOPED_DRAW_EVENT(RHICmdList, OculusClearQuad) + + const int32 GapMinY = ViewFamily.Views[0]->UnscaledViewRect.Min.Y; + const int32 GapMaxY = ViewFamily.Views[1]->UnscaledViewRect.Max.Y; + + FRHIRenderPassInfo RPInfo(ViewFamily.RenderTarget->GetRenderTargetTexture(), ERenderTargetActions::DontLoad_Store); + RHICmdList.BeginRenderPass(RPInfo, TEXT("Clear")); + { + RHICmdList.SetViewport(GapMinX, GapMinY, 0, GapMaxX, GapMaxY, 1.0f); + DrawClearQuad(RHICmdList, FLinearColor::Black); + } + RHICmdList.EndRenderPass(); + } +#endif +#else + // ensure we have attached JNI to this thread - this has to happen persistently as the JNI could detach if the app loses focus + FAndroidApplication::GetJavaEnv(); +#endif + + EnableInsightPassthrough_RenderThread(Settings_RenderThread->Flags.bInsightPassthroughEnabled); + + // Start RHI frame + StartRHIFrame_RenderThread(); + + // Update performance stats + PerformanceStats.Frames++; + PerformanceStats.Seconds = FPlatformTime::Seconds(); + } + + void FOculusXRHMD::PreRenderView_RenderThread(FRDGBuilder& GraphBuilder, FSceneView& InView) + { + } + + void FOculusXRHMD::PostRenderViewFamily_RenderThread(FRDGBuilder& GraphBuilder, FSceneViewFamily& InViewFamily) + { + CheckInRenderThread(); + + if (InViewFamily.Views[0]->StereoPass != EStereoscopicPass::eSSP_FULL) + { + FinishRenderFrame_RenderThread(GraphBuilder); + } + } + +#if UE_VERSION_OLDER_THAN(5, 3, 0) + void FOculusXRHMD::PostRenderBasePassMobile_RenderThread(FRHICommandListImmediate& RHICmdList, FSceneView& InView) +#else + void FOculusXRHMD::PostRenderBasePassMobile_RenderThread(FRHICommandList& RHICmdList, FSceneView& InView) +#endif + { + if (bHardOcclusionsEnabled) + { + RenderHardOcclusions_RenderThread(RHICmdList, InView); + } +#ifndef WITH_OCULUS_BRANCH + UpdateFoveationOffsets_RenderThread(); +#endif + } + + BEGIN_SHADER_PARAMETER_STRUCT(FPostBasePassViewExtensionParameters, ) + SHADER_PARAMETER_RDG_UNIFORM_BUFFER(FSceneTextureUniformParameters, SceneTextures) + RENDER_TARGET_BINDING_SLOTS() + END_SHADER_PARAMETER_STRUCT() + + void FOculusXRHMD::PostRenderBasePassDeferred_RenderThread(FRDGBuilder& GraphBuilder, FSceneView& InView, const FRenderTargetBindingSlots& RenderTargets, TRDGUniformBufferRef SceneTextures) + { + if (bHardOcclusionsEnabled) + { + auto* PassParameters = GraphBuilder.AllocParameters(); + PassParameters->RenderTargets = RenderTargets; + PassParameters->SceneTextures = SceneTextures; + + GraphBuilder.AddPass(RDG_EVENT_NAME("RenderHardOcclusions_RenderThread"), PassParameters, ERDGPassFlags::Raster, [this, &InView](FRHICommandListImmediate& RHICmdList) { + RenderHardOcclusions_RenderThread(RHICmdList, InView); + }); + } + } + +#ifdef WITH_OCULUS_BRANCH +#if UE_VERSION_OLDER_THAN(5, 3, 0) + void FOculusXRHMD::PostSceneColorRenderingMobile_RenderThread(FRHICommandListImmediate& RHICmdList, FSceneView& InView) +#else + void FOculusXRHMD::PostSceneColorRenderingMobile_RenderThread(FRHICommandList& RHICmdList, FSceneView& InView) +#endif + { + UpdateFoveationOffsets_RenderThread(); + } +#endif + + int32 FOculusXRHMD::GetPriority() const + { + // We want to run after the FDefaultXRCamera's view extension + return -1; + } + +#ifdef WITH_OCULUS_BRANCH + bool FOculusXRHMD::LateLatchingEnabled() const + { +#if OCULUS_HMD_SUPPORTED_PLATFORMS_VULKAN && PLATFORM_ANDROID + // No LateLatching supported when occlusion culling is enabled due to mid frame submission + // No LateLatching supported for non Multi view ATM due to viewUniformBuffer reusing. + // The setting can be disabled in FOculusXRHMD::UpdateStereoRenderingParams + return Settings->bLateLatching; +#else + return false; +#endif + } + + void FOculusXRHMD::PreLateLatchingViewFamily_RenderThread(FRHICommandListImmediate& RHICmdList, FSceneViewFamily& InViewFamily) + { + CheckInRenderThread(); + FGameFrame* CurrentFrame = GetFrame_RenderThread(); + if (CurrentFrame) + { + CurrentFrame->Flags.bRTLateUpdateDone = false; // Allow LateLatching to update poses again + } + } +#endif + + bool FOculusXRHMD::SupportsSpaceWarp() const + { +#if PLATFORM_ANDROID + // Use All static value here since those can't be change at runtime + ensureMsgf(CustomPresent.IsValid(), TEXT("SupportsSpaceWarp can only be called post CustomPresent created")); + const bool bOvrPlugin_OpenXR = Settings->XrApi == EOculusXRXrApi::OVRPluginOpenXR; + static const auto CVarMobileMultiView = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("vr.MobileMultiView")); + static const auto CVarSupportMobileSpaceWarp = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("vr.SupportMobileSpaceWarp")); + bool bIsMobileMultiViewEnabled = (CVarMobileMultiView && CVarMobileMultiView->GetValueOnAnyThread() != 0); + bool bIsUsingMobileMultiView = GSupportsMobileMultiView && bIsMobileMultiViewEnabled; + bool bIsVulkan = CustomPresent->GetRenderAPI() == ovrpRenderAPI_Vulkan; + bool spaceWarpSupported = bOvrPlugin_OpenXR && bIsVulkan && bIsUsingMobileMultiView && CVarSupportMobileSpaceWarp && (CVarSupportMobileSpaceWarp->GetValueOnAnyThread() != 0); + return spaceWarpSupported; +#else + return false; +#endif + } + + FOculusXRHMD::FOculusXRHMD(const FAutoRegister& AutoRegister) + : FHeadMountedDisplayBase(nullptr) + , FHMDSceneViewExtension(AutoRegister) + , ConsoleCommands(this) + , InsightInitStatus(FInsightInitStatus::NotInitialized) + , bShutdownRequestQueued(false) + , bShouldWait_GameThread(true) + , bIsRendering_RenderThread(false) + { + Flags.Raw = 0; + OCFlags.Raw = 0; + TrackingOrigin = EHMDTrackingOrigin::Type::Eye; + DeltaControlRotation = FRotator::ZeroRotator; // used from ApplyHmdRotation + LastPlayerOrientation = FQuat::Identity; + LastPlayerLocation = FVector::ZeroVector; + CachedWindowSize = FIntPoint::ZeroValue; + CachedWorldToMetersScale = 100.0f; + LastTrackingToWorld = FTransform::Identity; + + NextFrameNumber = 0; + WaitFrameNumber = (uint32)-1; + NextLayerId = 0; + + Settings = CreateNewSettings(); + + RendererModule = nullptr; + + SplashLayerHandle = -1; + + SplashRotation = FRotator(); + + bIsStandaloneStereoOnlyDevice = IHeadMountedDisplayModule::IsAvailable() && IHeadMountedDisplayModule::Get().IsStandaloneStereoOnlyDevice(); + + bMultiPlayer = false; + } + + FOculusXRHMD::~FOculusXRHMD() + { + Shutdown(); + } + + bool FOculusXRHMD::Startup() + { + if (GIsEditor) + { + Settings->Flags.bHeadTrackingEnforced = true; + } + + check(!CustomPresent.IsValid()); + + FString RHIString; + { + FString HardwareDetails = FHardwareInfo::GetHardwareDetailsString(); + FString RHILookup = NAME_RHI.ToString() + TEXT("="); + + if (!FParse::Value(*HardwareDetails, *RHILookup, RHIString)) + { + return false; + } + } + +#if OCULUS_HMD_SUPPORTED_PLATFORMS_D3D11 + if (RHIString == TEXT("D3D11")) + { + CustomPresent = CreateCustomPresent_D3D11(this); + } + else +#endif +#if OCULUS_HMD_SUPPORTED_PLATFORMS_D3D12 + if (RHIString == TEXT("D3D12")) + { + CustomPresent = CreateCustomPresent_D3D12(this); + } + else +#endif +#if OCULUS_HMD_SUPPORTED_PLATFORMS_VULKAN + if (RHIString == TEXT("Vulkan")) + { + CustomPresent = CreateCustomPresent_Vulkan(this); + } + else +#endif + { + UE_LOG(LogHMD, Warning, TEXT("%s is not currently supported by OculusXRHMD plugin"), *RHIString); + return false; + } + + // grab a pointer to the renderer module for displaying our mirror window + static const FName RendererModuleName("Renderer"); + RendererModule = FModuleManager::GetModulePtr(RendererModuleName); + +#if PLATFORM_ANDROID + // register our application lifetime delegates + FCoreDelegates::ApplicationWillEnterBackgroundDelegate.AddRaw(this, &FOculusXRHMD::ApplicationPauseDelegate); + FCoreDelegates::ApplicationHasEnteredForegroundDelegate.AddRaw(this, &FOculusXRHMD::ApplicationResumeDelegate); +#endif + + // Create eye layer + IStereoLayers::FLayerDesc EyeLayerDesc; + EyeLayerDesc.Priority = INT_MIN; + EyeLayerDesc.Flags = LAYER_FLAG_TEX_CONTINUOUS_UPDATE; + uint32 EyeLayerId = CreateLayer(EyeLayerDesc); + check(EyeLayerId == 0); + + Splash = MakeShareable(new FSplash(this)); + Splash->Startup(); + +#if !PLATFORM_ANDROID + SpectatorScreenController = MakeUnique(this); +#endif + UE_LOG(LogHMD, Log, TEXT("Oculus plugin initialized. Version: %s"), *GetVersionString()); + + return true; + } + + void FOculusXRHMD::PreShutdown() + { + if (Splash.IsValid()) + { + Splash->PreShutdown(); + } + } + + void FOculusXRHMD::Shutdown() + { + CheckInGameThread(); + + if (Splash.IsValid()) + { + Splash->Shutdown(); + Splash = nullptr; + // The base implementation stores a raw pointer to the Splash object and tries to deallocate it in its destructor + LoadingScreen = nullptr; + } + + if (CustomPresent.IsValid()) + { + CustomPresent->Shutdown(); + CustomPresent = nullptr; + } + + ReleaseDevice(); + + Settings.Reset(); + LayerMap.Reset(); + } + + void FOculusXRHMD::ApplicationPauseDelegate() + { + ExecuteOnRenderThread([this]() { + ExecuteOnRHIThread([this]() { + FOculusXRHMDModule::GetPluginWrapper().DestroyDistortionWindow2(); + }); + }); + OCFlags.AppIsPaused = true; + } + + void FOculusXRHMD::ApplicationResumeDelegate() + { + if (OCFlags.AppIsPaused && !InitializeSession()) + { + UE_LOG(LogHMD, Log, TEXT("HMD initialization failed")); + } + OCFlags.AppIsPaused = false; + } + + static const FString EYE_TRACKING_PERMISSION_NAME("com.oculus.permission.EYE_TRACKING"); + + bool FOculusXRHMD::CheckEyeTrackingPermission(EOculusXRFoveatedRenderingMethod InFoveatedRenderingMethod) + { +#if PLATFORM_ANDROID + // Check and request eye tracking permissions, bind delegate for handling permission request result + if (!UAndroidPermissionFunctionLibrary::CheckPermission(EYE_TRACKING_PERMISSION_NAME)) + { + TArray Permissions; + Permissions.Add(EYE_TRACKING_PERMISSION_NAME); + UAndroidPermissionCallbackProxy* Proxy = UAndroidPermissionFunctionLibrary::AcquirePermissions(Permissions); + Proxy->OnPermissionsGrantedDelegate.AddLambda([this, InFoveatedRenderingMethod](const TArray& Permissions, const TArray& GrantResults) { + int PermIndex = Permissions.Find(EYE_TRACKING_PERMISSION_NAME); + if (PermIndex != INDEX_NONE && GrantResults[PermIndex]) + { + UE_LOG(LogHMD, Verbose, TEXT("com.oculus.permission.EYE_TRACKING permission granted")); + FoveatedRenderingMethod = InFoveatedRenderingMethod; + FOculusEventDelegates::OculusEyeTrackingStateChanged.Broadcast(true); + } + else + { + UE_LOG(LogHMD, Log, TEXT("com.oculus.permission.EYE_TRACKING permission denied")); + if (InFoveatedRenderingMethod == EOculusXRFoveatedRenderingMethod::EyeTrackedFoveatedRendering) + { + EyeTrackedFoveatedRenderingFallback(); + } + FOculusEventDelegates::OculusEyeTrackingStateChanged.Broadcast(false); + } + }); + return false; + } +#endif // PLATFORM_ANDROID + return true; + } + + bool FOculusXRHMD::InitializeSession() + { + UE_LOG(LogHMD, Log, TEXT("Initializing OVRPlugin session")); + + if (!FOculusXRHMDModule::GetPluginWrapper().GetInitialized()) + { +#if !UE_BUILD_SHIPPING + ovrpLogCallback logCallback = OvrpLogCallback; +#else + ovrpLogCallback logCallback = nullptr; +#endif + +#if PLATFORM_ANDROID + void* activity = (void*)FAndroidApplication::GetGameActivityThis(); +#else + void* activity = nullptr; +#endif + + int initializeFlags = GIsEditor ? ovrpInitializeFlag_SupportsVRToggle : 0; + + initializeFlags |= CustomPresent->SupportsSRGB() ? ovrpInitializeFlag_SupportSRGBFrameBuffer : 0; + + if (Settings->Flags.bSupportsDash) + { + initializeFlags |= ovrpInitializeFlag_FocusAware; + } + + if (SupportsSpaceWarp()) // Configure for space warp + { + initializeFlags |= ovrpInitializeFlag_SupportAppSpaceWarp; + UE_LOG(LogHMD, Log, TEXT("[Mobile SpaceWarp] Application is configured to support mobile spacewarp")); + } + bNeedReAllocateMotionVectorTexture_RenderThread = false; + +#if WITH_EDITOR && PLATFORM_WINDOWS + // Attempt Late Initialization in-editor + // FOculusXRHMDModule::PreInit always returns true in this case, + // so we need to check the flag directly. + if (GIsEditor && FOculusXRHMDModule::Get().PreInit() && !FOculusXRHMDModule::Get().bPreInit) + { + return false; + } +#endif + + if (OVRP_FAILURE(FOculusXRHMDModule::GetPluginWrapper().Initialize7( + CustomPresent->GetRenderAPI(), + logCallback, + activity, + CustomPresent->GetOvrpInstance(), + CustomPresent->GetOvrpPhysicalDevice(), + CustomPresent->GetOvrpDevice(), + CustomPresent->GetOvrpCommandQueue(), + nullptr /*vkGetInstanceProcAddr*/, + 0 /*vkQueueFamilyIndex*/, + nullptr /*d3dDevice*/, + initializeFlags, + { OVRP_VERSION }))) + { + return false; + } + + ovrpBool Supported = ovrpBool_False; + if (Settings->bSupportEyeTrackedFoveatedRendering) + { + FOculusXRHMDModule::GetPluginWrapper().GetFoveationEyeTrackedSupported(&Supported); + } + bEyeTrackedFoveatedRenderingSupported = Supported == ovrpBool_True; + SetFoveatedRenderingMethod(Settings->FoveatedRenderingMethod); + SetFoveatedRenderingLevel(Settings->FoveatedRenderingLevel, Settings->bDynamicFoveatedRendering); + + NextFrameNumber = 0; + WaitFrameNumber = (uint32)-1; + } + + FOculusXRHMDModule::GetPluginWrapper().SetAppEngineInfo2( + "Unreal Engine", + TCHAR_TO_ANSI(*FEngineVersion::Current().ToString()), + GIsEditor ? ovrpBool_True : ovrpBool_False); + + int flag = ovrpDistortionWindowFlag_None; + + FOculusXRHMDModule::GetPluginWrapper().SetupDistortionWindow3(flag); + FOculusXRHMDModule::GetPluginWrapper().SetSuggestedCpuPerformanceLevel((ovrpProcessorPerformanceLevel)Settings->SuggestedCpuPerfLevel); + FOculusXRHMDModule::GetPluginWrapper().SetSuggestedGpuPerformanceLevel((ovrpProcessorPerformanceLevel)Settings->SuggestedGpuPerfLevel); + FOculusXRHMDModule::GetPluginWrapper().SetFoveationEyeTracked(FoveatedRenderingMethod == EOculusXRFoveatedRenderingMethod::EyeTrackedFoveatedRendering); + FOculusXRHMDModule::GetPluginWrapper().SetTiledMultiResLevel((ovrpTiledMultiResLevel)FoveatedRenderingLevel.load()); + FOculusXRHMDModule::GetPluginWrapper().SetTiledMultiResDynamic(bDynamicFoveatedRendering.load()); + FOculusXRHMDModule::GetPluginWrapper().SetAppCPUPriority2(ovrpBool_True); + FOculusXRHMDModule::GetPluginWrapper().SetLocalDimming(ovrpBool_True); + + OCFlags.NeedSetTrackingOrigin = true; + + FOculusXRHMDModule::GetPluginWrapper().SetClientColorDesc((ovrpColorSpace)Settings->ColorSpace); + + return true; + } + + void FOculusXRHMD::ShutdownSession() + { + ExecuteOnRenderThread([this]() { + ExecuteOnRHIThread([this]() { + FOculusXRHMDModule::GetPluginWrapper().DestroyDistortionWindow2(); + }); + }); + + FOculusXRHMDModule::GetPluginWrapper().Shutdown2(); + + bIsRendering_RenderThread = false; + } + + bool FOculusXRHMD::InitDevice() + { + CheckInGameThread(); + + if (FOculusXRHMDModule::GetPluginWrapper().GetInitialized()) + { + // Already created and present + return true; + } + + if (!IsHMDEnabled()) + { + // Don't bother if HMD is not connected + return false; + } + + LoadFromSettings(); + + if (!InitializeSession()) + { + UE_LOG(LogHMD, Log, TEXT("HMD initialization failed")); + return false; + } + + // Don't need to reset these flags on application resume, so put them in InitDevice instead of InitializeSession + bNeedReAllocateViewportRenderTarget = true; + bNeedReAllocateDepthTexture_RenderThread = false; + bNeedReAllocateFoveationTexture_RenderThread = false; + Flags.bNeedDisableStereo = false; + OCFlags.NeedSetFocusToGameViewport = true; + + if (!CustomPresent->IsUsingCorrectDisplayAdapter()) + { + UE_LOG(LogHMD, Error, TEXT("Using incorrect display adapter for HMD.")); + ShutdownSession(); + return false; + } + + if (OVRP_FAILURE(FOculusXRHMDModule::GetPluginWrapper().GetSystemHeadsetType2(&Settings->SystemHeadset))) + { + Settings->SystemHeadset = ovrpSystemHeadset_None; + } + + FOculusXRHMDModule::GetPluginWrapper().Update3(ovrpStep_Render, 0, 0.0); + + if (Settings->Flags.bPixelDensityAdaptive) + { + static const auto DynamicResOperationCVar = IConsoleManager::Get().FindConsoleVariable(TEXT("r.DynamicRes.OperationMode")); + if (DynamicResOperationCVar) + { + DynamicResOperationCVar->Set(2); + } + GEngine->ChangeDynamicResolutionStateAtNextFrame(MakeShareable(new FDynamicResolutionState(Settings))); + } + + UpdateHmdRenderInfo(); + UpdateStereoRenderingParams(); + + const bool bEnablePassthrough = Settings->Flags.bInsightPassthroughEnabled; + + ExecuteOnRenderThread([this, bEnablePassthrough](FRHICommandListImmediate& RHICmdList) { + InitializeEyeLayer_RenderThread(RHICmdList); + EnableInsightPassthrough_RenderThread(bEnablePassthrough); + }); + + if (!EyeLayer_RenderThread.IsValid() || !EyeLayer_RenderThread->GetSwapChain().IsValid()) + { + UE_LOG(LogHMD, Error, TEXT("Failed to create eye layer swap chain.")); + ShutdownSession(); + return false; + } + + if (!HiddenAreaMeshes[0].IsValid() || !HiddenAreaMeshes[1].IsValid()) + { + SetupOcclusionMeshes(); + } + +#if !UE_BUILD_SHIPPING + DrawDebugDelegateHandle = UDebugDrawService::Register(TEXT("Game"), FDebugDrawDelegate::CreateRaw(this, &FOculusXRHMD::DrawDebug)); +#endif + + // Do not set VR focus in Editor by just creating a device; Editor may have it created w/o requiring focus. + // Instead, set VR focus in OnBeginPlay (VR Preview will run there first). + if (!GIsEditor) + { + FApp::SetUseVRFocus(true); + FApp::SetHasVRFocus(true); + } + + FOculusXRHMDModule::GetPluginWrapper().SetClientColorDesc((ovrpColorSpace)Settings->ColorSpace); + + return true; + } + + void FOculusXRHMD::ReleaseDevice() + { + CheckInGameThread(); + + if (FOculusXRHMDModule::GetPluginWrapper().GetInitialized()) + { + // Wait until the next frame before ending the session (workaround for DX12/Vulkan resources being ripped out from under us before we're done with them). + bShutdownRequestQueued = true; + } + } + + void BuildOcclusionMesh(FRHICommandList& RHICmdList, FHMDViewMesh& Mesh, ovrpEye Eye, ovrpViewportStencilType MeshType) + { + int VertexCount = 0; + int IndexCount = 0; + + ovrpResult Result = ovrpResult::ovrpFailure; + if (OVRP_FAILURE(Result = FOculusXRHMDModule::GetPluginWrapper().GetViewportStencil(Eye, MeshType, nullptr, &VertexCount, nullptr, &IndexCount))) + { + return; + } + + FRHIResourceCreateInfo CreateInfo(TEXT("FOculusXRHMD")); +#if UE_VERSION_OLDER_THAN(5, 3, 0) + Mesh.VertexBufferRHI = RHICreateVertexBuffer(sizeof(FFilterVertex) * VertexCount, BUF_Static, CreateInfo); + void* VoidPtr = RHILockBuffer(Mesh.VertexBufferRHI, 0, sizeof(FFilterVertex) * VertexCount, RLM_WriteOnly); +#else + Mesh.VertexBufferRHI = RHICmdList.CreateVertexBuffer(sizeof(FFilterVertex) * VertexCount, BUF_Static, CreateInfo); + void* VoidPtr = RHICmdList.LockBuffer(Mesh.VertexBufferRHI, 0, sizeof(FFilterVertex) * VertexCount, RLM_WriteOnly); +#endif + FFilterVertex* pVertices = reinterpret_cast(VoidPtr); + +#if UE_VERSION_OLDER_THAN(5, 3, 0) + Mesh.IndexBufferRHI = RHICreateIndexBuffer(sizeof(uint16), sizeof(uint16) * IndexCount, BUF_Static, CreateInfo); + void* VoidPtr2 = RHILockBuffer(Mesh.IndexBufferRHI, 0, sizeof(uint16) * IndexCount, RLM_WriteOnly); +#else + Mesh.IndexBufferRHI = RHICmdList.CreateIndexBuffer(sizeof(uint16), sizeof(uint16) * IndexCount, BUF_Static, CreateInfo); + void* VoidPtr2 = RHICmdList.LockBuffer(Mesh.IndexBufferRHI, 0, sizeof(uint16) * IndexCount, RLM_WriteOnly); +#endif + uint16* pIndices = reinterpret_cast(VoidPtr2); + + ovrpVector2f* const ovrpVertices = new ovrpVector2f[VertexCount]; + + FOculusXRHMDModule::GetPluginWrapper().GetViewportStencil(Eye, MeshType, ovrpVertices, &VertexCount, pIndices, &IndexCount); + + for (int i = 0; i < VertexCount; ++i) + { + FFilterVertex& Vertex = pVertices[i]; + CA_SUPPRESS(6385); // warning C6385: Reading invalid data from 'ovrpVertices': the readable size is 'VertexCount*8' bytes, but '16' bytes may be read + const ovrpVector2f& Position = ovrpVertices[i]; + if (MeshType == ovrpViewportStencilType_HiddenArea) + { + Vertex.Position.X = (Position.x * 2.0f) - 1.0f; + Vertex.Position.Y = (Position.y * 2.0f) - 1.0f; + Vertex.Position.Z = 1.0f; + Vertex.Position.W = 1.0f; + Vertex.UV.X = 0.0f; + Vertex.UV.Y = 0.0f; + } + else if (MeshType == ovrpViewportStencilType_VisibleArea) + { + Vertex.Position.X = Position.x; + Vertex.Position.Y = 1.0f - Position.y; + Vertex.Position.Z = 0.0f; + Vertex.Position.W = 1.0f; + Vertex.UV.X = Position.x; + Vertex.UV.Y = 1.0f - Position.y; + } + else + { + check(0); + } + } + + Mesh.NumIndices = IndexCount; + Mesh.NumVertices = VertexCount; + Mesh.NumTriangles = IndexCount / 3; + + delete[] ovrpVertices; + +#if UE_VERSION_OLDER_THAN(5, 3, 0) + RHIUnlockBuffer(Mesh.VertexBufferRHI); + RHIUnlockBuffer(Mesh.IndexBufferRHI); +#else + RHICmdList.UnlockBuffer(Mesh.VertexBufferRHI); + RHICmdList.UnlockBuffer(Mesh.IndexBufferRHI); +#endif + } + + void FOculusXRHMD::SetupOcclusionMeshes() + { + CheckInGameThread(); + + FOculusXRHMD* const Self = this; + ENQUEUE_RENDER_COMMAND(SetupOcclusionMeshesCmd) + ([Self](FRHICommandList& RHICmdList) { + BuildOcclusionMesh(RHICmdList, Self->HiddenAreaMeshes[0], ovrpEye_Left, ovrpViewportStencilType_HiddenArea); + BuildOcclusionMesh(RHICmdList, Self->HiddenAreaMeshes[1], ovrpEye_Right, ovrpViewportStencilType_HiddenArea); + BuildOcclusionMesh(RHICmdList, Self->VisibleAreaMeshes[0], ovrpEye_Left, ovrpViewportStencilType_VisibleArea); + BuildOcclusionMesh(RHICmdList, Self->VisibleAreaMeshes[1], ovrpEye_Right, ovrpViewportStencilType_VisibleArea); + }); + } + + static ovrpMatrix4f ovrpMatrix4f_Projection(const ovrpFrustum2f& frustum, bool leftHanded) + { + float handednessScale = leftHanded ? 1.0f : -1.0f; + + // A projection matrix is very like a scaling from NDC, so we can start with that. + float projXScale = 2.0f / (frustum.Fov.LeftTan + frustum.Fov.RightTan); + float projXOffset = (frustum.Fov.LeftTan - frustum.Fov.RightTan) * projXScale * 0.5f; + float projYScale = 2.0f / (frustum.Fov.UpTan + frustum.Fov.DownTan); + float projYOffset = (frustum.Fov.UpTan - frustum.Fov.DownTan) * projYScale * 0.5f; + + ovrpMatrix4f projection; + + // Produces X result, mapping clip edges to [-w,+w] + projection.M[0][0] = projXScale; + projection.M[0][1] = 0.0f; + projection.M[0][2] = handednessScale * projXOffset; + projection.M[0][3] = 0.0f; + + // Produces Y result, mapping clip edges to [-w,+w] + // Hey - why is that YOffset negated? + // It's because a projection matrix transforms from world coords with Y=up, + // whereas this is derived from an NDC scaling, which is Y=down. + projection.M[1][0] = 0.0f; + projection.M[1][1] = projYScale; + projection.M[1][2] = handednessScale * -projYOffset; + projection.M[1][3] = 0.0f; + + // Produces Z-buffer result + projection.M[2][0] = 0.0f; + projection.M[2][1] = 0.0f; + if (FGenericPlatformMath::IsFinite(frustum.zFar)) + { + projection.M[2][2] = -handednessScale * frustum.zFar / (frustum.zNear - frustum.zFar); + projection.M[2][3] = (frustum.zFar * frustum.zNear) / (frustum.zNear - frustum.zFar); + } + else + { + projection.M[2][2] = handednessScale; + projection.M[2][3] = -frustum.zNear; + } + + // Produces W result (= Z in) + projection.M[3][0] = 0.0f; + projection.M[3][1] = 0.0f; + projection.M[3][2] = handednessScale; + projection.M[3][3] = 0.0f; + + return projection; + } + + void FOculusXRHMD::UpdateStereoRenderingParams() + { + CheckInGameThread(); + + // Update PixelDensity + bool bSupportsDepth = true; + + if (Settings->Flags.bPixelDensityAdaptive) + { + FLayer* EyeLayer = EyeLayer_RenderThread.Get(); + float NewPixelDensity = 1.0; + if (EyeLayer && EyeLayer->GetOvrpId()) + { + ovrpSizei RecommendedResolution = { 0, 0 }; + FOculusXRHMDModule::GetPluginWrapper().GetLayerRecommendedResolution(EyeLayer->GetOvrpId(), &RecommendedResolution); + if (RecommendedResolution.h > 0) + { + NewPixelDensity = RecommendedResolution.h * (float)Settings->PixelDensityMax / Settings->RenderTargetSize.Y; + } + } + + const float PixelDensityCVarOverride = CVarOculusDynamicResolutionPixelDensity.GetValueOnAnyThread(); + if (PixelDensityCVarOverride > 0) + { + NewPixelDensity = PixelDensityCVarOverride; + } + Settings->SetPixelDensitySmooth(NewPixelDensity); + } + else + { + static const auto PixelDensityCVar = IConsoleManager::Get().FindConsoleVariable(TEXT("vr.PixelDensity")); + Settings->SetPixelDensity(PixelDensityCVar ? PixelDensityCVar->GetFloat() : 1.0f); + + // Due to hijacking the depth target directly from the scene context, we can't support depth compositing if it's being scaled by screen percentage since it wont match our color render target dimensions. + static const auto ScreenPercentageCVar = IConsoleManager::Get().FindConsoleVariable(TEXT("r.ScreenPercentage")); + float ScreenPercentage = (!ScreenPercentageCVar) ? 100.0f : ScreenPercentageCVar->GetFloat(); +#if !UE_VERSION_OLDER_THAN(5, 3, 0) + // 5.3 changes the default screen percentage to 0 and uses r.ScreenPercentage.Default values to determine screen percentage + if (ScreenPercentageCVar->GetFloat() <= 0.0f) + { + static const auto VRScreenPercentageModeCVar = IConsoleManager::Get().FindConsoleVariable(TEXT("r.ScreenPercentage.Default.VR.Mode")); + // With default VR screen percentage modes, only support depth with manual screen percentage set to 100 + if (VRScreenPercentageModeCVar && VRScreenPercentageModeCVar->GetInt() == static_cast(EScreenPercentageMode::Manual)) + { + static const auto ManualScreenPercentageCVar = IConsoleManager::Get().FindConsoleVariable(TEXT("r.ScreenPercentage.Default")); + ScreenPercentage = ManualScreenPercentageCVar->GetFloat(); + } + } +#endif + bSupportsDepth = ScreenPercentage == 100.0f; + } + + // Update EyeLayer + FLayerPtr* EyeLayerFound = LayerMap.Find(0); + FLayer* EyeLayer = new FLayer(**EyeLayerFound); + *EyeLayerFound = MakeShareable(EyeLayer); + + ovrpLayout Layout = ovrpLayout_DoubleWide; + + static const auto CVarMobileMultiView = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("vr.MobileMultiView")); + const bool bIsMobileMultiViewEnabled = (CVarMobileMultiView && CVarMobileMultiView->GetValueOnAnyThread() != 0); + + const bool bIsUsingMobileMultiView = (GSupportsMobileMultiView || GRHISupportsArrayIndexFromAnyShader) && bIsMobileMultiViewEnabled; + + Settings->CurrentFeatureLevel = GEngine ? GEngine->GetDefaultWorldFeatureLevel() : GMaxRHIFeatureLevel; + Settings->CurrentShaderPlatform = GShaderPlatformForFeatureLevel[Settings->CurrentFeatureLevel]; + + // for now only mobile rendering codepaths use the array rendering system, so PC-native should stay in doublewide + if (bIsUsingMobileMultiView && IsMobilePlatform(Settings->CurrentShaderPlatform)) + { + Layout = ovrpLayout_Array; + } + +#if PLATFORM_ANDROID + if (!bIsUsingMobileMultiView && Settings->bLateLatching) + { + UE_CLOG(true, LogHMD, Error, TEXT("LateLatching can't be used when Multiview is off, force disabling.")); + Settings->bLateLatching = false; + } + + if (GetMutableDefault()->bOcclusionCulling && Settings->bLateLatching) + { + UE_CLOG(true, LogHMD, Error, TEXT("LateLatching can't used when Occlusion culling is on due to mid frame vkQueueSubmit, force disabling")); + Settings->bLateLatching = false; + } +#endif + + const bool bForceSymmetric = CVarOculusForceSymmetric.GetValueOnAnyThread() == 1 && (Layout == ovrpLayout_Array); + + ovrpLayerDesc_EyeFov EyeLayerDesc; + const bool requestsSubsampled = CVarOculusEnableSubsampledLayout.GetValueOnAnyThread() == 1 && CustomPresent->SupportsSubsampled(); + int eyeLayerFlags = requestsSubsampled ? ovrpLayerFlag_Subsampled : 0; + + ovrpTextureFormat MvPixelFormat = ovrpTextureFormat_R16G16B16A16_FP; + ovrpTextureFormat MvDepthFormat = ovrpTextureFormat_D24_S8; + int SpaceWarpAllocateFlag = 0; + + if (SupportsSpaceWarp()) + { + SpaceWarpAllocateFlag = ovrpLayerFlag_SpaceWarpDataAllocation | ovrpLayerFlag_SpaceWarpDedicatedDepth; + + bool spaceWarpEnabledByUser = CVarOculusEnableSpaceWarpUser.GetValueOnAnyThread() != 0; + bool spaceWarpEnabledInternal = CVarOculusEnableSpaceWarpInternal.GetValueOnAnyThread() != 0; + if (spaceWarpEnabledByUser != spaceWarpEnabledInternal) + { + CVarOculusEnableSpaceWarpInternal->Set(spaceWarpEnabledByUser); + } + } + + const bool bCompositeDepth = Settings->Flags.bCompositeDepth; + + if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().CalculateEyeLayerDesc3( + Layout, + Settings->Flags.bPixelDensityAdaptive ? Settings->PixelDensityMax : Settings->PixelDensity, + Settings->Flags.bHQDistortion ? 0 : 1, + 1, // UNDONE + CustomPresent->GetOvrpTextureFormat(CustomPresent->GetDefaultPixelFormat(), Settings->Flags.bsRGBEyeBuffer), + (bCompositeDepth && bSupportsDepth) ? CustomPresent->GetDefaultDepthOvrpTextureFormat() : ovrpTextureFormat_None, + MvPixelFormat, + MvDepthFormat, + 1.0f, + CustomPresent->GetLayerFlags() | eyeLayerFlags | SpaceWarpAllocateFlag, + &EyeLayerDesc))) + { + ovrpFovf FrameFov[ovrpEye_Count] = { EyeLayerDesc.Fov[0], EyeLayerDesc.Fov[1] }; + if (bForceSymmetric) + { + // calculate symmetric FOV from runtime-provided asym in EyeLayerDesc + FrameFov[0].RightTan = FrameFov[1].RightTan = FMath::Max(EyeLayerDesc.Fov[0].RightTan, EyeLayerDesc.Fov[1].RightTan); + FrameFov[0].LeftTan = FrameFov[1].LeftTan = FMath::Max(EyeLayerDesc.Fov[0].LeftTan, EyeLayerDesc.Fov[1].LeftTan); + + const float asymTanSize = EyeLayerDesc.Fov[0].RightTan + EyeLayerDesc.Fov[0].LeftTan; + const float symTanSize = FrameFov[0].RightTan + FrameFov[0].LeftTan; + + // compute new resolution from a number of tile multiple, and the increase in width from symmetric FOV + const int numberTiles = (int)floor(EyeLayerDesc.TextureSize.w * symTanSize / (96.0 * asymTanSize)); + EyeLayerDesc.TextureSize.w = EyeLayerDesc.MaxViewportSize.w = numberTiles * 96; + } + + // Scaling for DynamicResolution will happen later - see FSceneRenderer::PrepareViewRectsForRendering. + // If scaling does occur, EyeRenderViewport will be updated in FOculusXRHMD::SetFinalViewRect. + FIntPoint UnscaledViewportSize = FIntPoint(EyeLayerDesc.MaxViewportSize.w, EyeLayerDesc.MaxViewportSize.h); + if (Settings->Flags.bPixelDensityAdaptive) + { + FIntPoint ViewRect = FIntPoint( + FMath::CeilToInt(EyeLayerDesc.MaxViewportSize.w / Settings->PixelDensityMax), + FMath::CeilToInt(EyeLayerDesc.MaxViewportSize.h / Settings->PixelDensityMax)); + UnscaledViewportSize = ViewRect; + + FIntPoint UpperViewRect = FIntPoint( + FMath::CeilToInt(ViewRect.X * Settings->PixelDensityMax), + FMath::CeilToInt(ViewRect.Y * Settings->PixelDensityMax)); + + FIntPoint TextureSize; + QuantizeSceneBufferSize(UpperViewRect, TextureSize); + + EyeLayerDesc.MaxViewportSize.w = TextureSize.X; + EyeLayerDesc.MaxViewportSize.h = TextureSize.Y; + } + + // Unreal assumes no gutter between eyes + EyeLayerDesc.TextureSize.w = EyeLayerDesc.MaxViewportSize.w; + EyeLayerDesc.TextureSize.h = EyeLayerDesc.MaxViewportSize.h; + + if (Layout == ovrpLayout_DoubleWide) + { + EyeLayerDesc.TextureSize.w *= 2; + } + + EyeLayer->SetEyeLayerDesc(EyeLayerDesc); + EyeLayer->bNeedsTexSrgbCreate = Settings->Flags.bsRGBEyeBuffer; + + Settings->RenderTargetSize = FIntPoint(EyeLayerDesc.TextureSize.w, EyeLayerDesc.TextureSize.h); + Settings->EyeRenderViewport[0].Min = FIntPoint::ZeroValue; + Settings->EyeRenderViewport[0].Max = UnscaledViewportSize; + Settings->EyeRenderViewport[1].Min = FIntPoint(Layout == ovrpLayout_DoubleWide ? UnscaledViewportSize.X : 0, 0); + Settings->EyeRenderViewport[1].Max = Settings->EyeRenderViewport[1].Min + UnscaledViewportSize; + + Settings->EyeUnscaledRenderViewport[0] = Settings->EyeRenderViewport[0]; + Settings->EyeUnscaledRenderViewport[1] = Settings->EyeRenderViewport[1]; + + // Update projection matrices + ovrpFrustum2f frustumLeft = { 0.001f, 1000.0f, FrameFov[0] }; + ovrpFrustum2f frustumRight = { 0.001f, 1000.0f, FrameFov[1] }; + ovrpFrustum2f frustumCenter = { 0.001f, 1000.0f, { FrameFov[0].UpTan, FrameFov[0].DownTan, FrameFov[0].LeftTan, FrameFov[1].RightTan } }; + + Settings->EyeProjectionMatrices[0] = ovrpMatrix4f_Projection(frustumLeft, true); + Settings->EyeProjectionMatrices[1] = ovrpMatrix4f_Projection(frustumRight, true); + Settings->MonoProjectionMatrix = ovrpMatrix4f_Projection(frustumCenter, true); + + // given that we send a subrect in vpRectSubmit, the FOV is the default asym one in EyeLayerDesc, not FrameFov + if (Frame.IsValid()) + { + Frame->Fov[0] = EyeLayerDesc.Fov[0]; + Frame->Fov[1] = EyeLayerDesc.Fov[1]; + Frame->SymmetricFov[0] = FrameFov[0]; + Frame->SymmetricFov[1] = FrameFov[1]; + } + + // Flag if need to recreate render targets + if (!EyeLayer->CanReuseResources(EyeLayer_RenderThread.Get())) + { + AllocateEyeBuffer(); + } + } + } + + void FOculusXRHMD::UpdateHmdRenderInfo() + { + CheckInGameThread(); + FOculusXRHMDModule::GetPluginWrapper().GetSystemDisplayFrequency2(&Settings->VsyncToNextVsync); + } + + void FOculusXRHMD::InitializeEyeLayer_RenderThread(FRHICommandListImmediate& RHICmdList) + { + check(!InGameThread()); + CheckInRenderThread(); + + if (LayerMap[0].IsValid()) + { + FLayerPtr EyeLayer = LayerMap[0]->Clone(); + EyeLayer->Initialize_RenderThread(Settings_RenderThread.Get(), CustomPresent, &DeferredDeletion, RHICmdList, EyeLayer_RenderThread.Get()); + + if (Layers_RenderThread.Num() > 0) + { + Layers_RenderThread[0] = EyeLayer; + } + else + { + Layers_RenderThread.Add(EyeLayer); + } + + if (EyeLayer->GetDepthSwapChain().IsValid()) + { + if (!EyeLayer_RenderThread.IsValid() || EyeLayer->GetDepthSwapChain() != EyeLayer_RenderThread->GetDepthSwapChain()) + { + bNeedReAllocateDepthTexture_RenderThread = true; + } + } + if (EyeLayer->GetFoveationSwapChain().IsValid()) + { + if (!EyeLayer_RenderThread.IsValid() || EyeLayer->GetFoveationSwapChain() != EyeLayer_RenderThread->GetFoveationSwapChain()) + { + bNeedReAllocateFoveationTexture_RenderThread = true; + } +#if !UE_VERSION_OLDER_THAN(5, 3, 0) + FoveationImageGenerator = MakeShared(EyeLayer->GetFoveationSwapChain()); +#endif // !UE_VERSION_OLDER_THAN(5, 3, 0) + } + + if (EyeLayer->GetMotionVectorSwapChain().IsValid()) + { + if (!EyeLayer_RenderThread.IsValid() || EyeLayer->GetMotionVectorSwapChain() != EyeLayer_RenderThread->GetMotionVectorSwapChain() + || EyeLayer->GetMotionVectorDepthSwapChain() != EyeLayer_RenderThread->GetMotionVectorDepthSwapChain()) + { + bNeedReAllocateMotionVectorTexture_RenderThread = true; + UE_LOG(LogHMD, VeryVerbose, TEXT("[Mobile SpaceWarp] request to re-allocate motionVector textures")); + } + } + + if (EyeLayer_RenderThread.IsValid()) + { + DeferredDeletion.AddLayerToDeferredDeletionQueue(EyeLayer_RenderThread); + } + + EyeLayer_RenderThread = EyeLayer; + } + } + + void FOculusXRHMD::ApplySystemOverridesOnStereo(bool force) + { + CheckInGameThread(); + // ALWAYS SET r.FinishCurrentFrame to 0! Otherwise the perf might be poor. + // @TODO: revise the FD3D11DynamicRHI::RHIEndDrawingViewport code (and other renderers) + // to ignore this var completely. + static const auto CFinishFrameVar = IConsoleManager::Get().FindConsoleVariable(TEXT("r.FinishCurrentFrame")); + CFinishFrameVar->Set(0); + } + + bool FOculusXRHMD::OnOculusStateChange(bool bIsEnabledNow) + { + if (!bIsEnabledNow) + { + // Switching from stereo + ReleaseDevice(); + + ResetControlRotation(); + return true; + } + else + { + // Switching to stereo + if (InitDevice()) + { + Flags.bApplySystemOverridesOnStereo = true; + return true; + } + DeltaControlRotation = FRotator::ZeroRotator; + } + return false; + } + + class FSceneViewport* FOculusXRHMD::FindSceneViewport() + { + if (!GIsEditor) + { + UGameEngine* GameEngine = Cast(GEngine); + return GameEngine->SceneViewport.Get(); + } +#if WITH_EDITOR + else + { + UEditorEngine* EditorEngine = CastChecked(GEngine); + FSceneViewport* PIEViewport = (FSceneViewport*)EditorEngine->GetPIEViewport(); + if (PIEViewport != nullptr && PIEViewport->IsStereoRenderingAllowed()) + { + // PIE is setup for stereo rendering + return PIEViewport; + } + else + { + // Check to see if the active editor viewport is drawing in stereo mode + // @todo vreditor: Should work with even non-active viewport! + FSceneViewport* EditorViewport = (FSceneViewport*)EditorEngine->GetActiveViewport(); + if (EditorViewport != nullptr && EditorViewport->IsStereoRenderingAllowed()) + { + return EditorViewport; + } + } + } +#endif + return nullptr; + } + + bool FOculusXRHMD::ShouldDisableHiddenAndVisibileAreaMeshForSpectatorScreen_RenderThread() const + { + CheckInRenderThread(); + + // If you really need the eye corners to look nice, and can't just crop more, + // and are willing to suffer a frametime hit... you could do this: +#if 0 + switch(GetSpectatorScreenMode_RenderThread()) + { + case ESpectatorScreenMode::SingleEyeLetterboxed: + case ESpectatorScreenMode::SingleEyeCroppedToFill: + case ESpectatorScreenMode::TexturePlusEye: + return true; + } +#endif + + return false; + } + + ESpectatorScreenMode FOculusXRHMD::GetSpectatorScreenMode_RenderThread() const + { + CheckInRenderThread(); + return SpectatorScreenController ? SpectatorScreenController->GetSpectatorScreenMode() : ESpectatorScreenMode::Disabled; + } + +#if !UE_BUILD_SHIPPING + static const char* FormatLatencyReading(char* buff, size_t size, float val) + { + if (val < 0.000001f) + { + FCStringAnsi::Strcpy(buff, size, "N/A "); + } + else + { + FCStringAnsi::Snprintf(buff, size, "%4.2fms", val * 1000.0f); + } + return buff; + } + + void FOculusXRHMD::DrawDebug(UCanvas* InCanvas, APlayerController* InPlayerController) + { + CheckInGameThread(); + + if (InCanvas && IsStereoEnabled() && Settings->Flags.bShowStats) + { + static const FColor TextColor(0, 255, 0); + // Pick a larger font on console. + UFont* const Font = FPlatformProperties::SupportsWindowedMode() ? GEngine->GetSmallFont() : GEngine->GetMediumFont(); + const int32 RowHeight = FMath::TruncToInt(Font->GetMaxCharHeight() * 1.1f); + + float ClipX = InCanvas->ClipX; + float ClipY = InCanvas->ClipY; + float LeftPos = 0; + + ClipX -= 100; + LeftPos = ClipX * 0.3f; + float TopPos = ClipY * 0.4f; + + int32 X = (int32)LeftPos; + int32 Y = (int32)TopPos; + + FString Str; + + if (!Settings->Flags.bPixelDensityAdaptive) + { + Str = FString::Printf(TEXT("PD: %.2f"), Settings->PixelDensity); + } + else + { + Str = FString::Printf(TEXT("PD: %.2f [%0.2f, %0.2f]"), Settings->PixelDensity, + Settings->PixelDensityMin, Settings->PixelDensityMax); + } + InCanvas->Canvas->DrawShadowedString(X, Y, *Str, Font, TextColor); + Y += RowHeight; + + Str = FString::Printf(TEXT("W-to-m scale: %.2f uu/m"), GetWorldToMetersScale()); + InCanvas->Canvas->DrawShadowedString(X, Y, *Str, Font, TextColor); + + ovrpAppLatencyTimings AppLatencyTimings; + if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetAppLatencyTimings2(&AppLatencyTimings))) + { + Y += RowHeight; + + char buf[5][20]; + char destStr[100]; + + FCStringAnsi::Snprintf(destStr, sizeof(destStr), "Latency, ren: %s tw: %s pp: %s err: %s %s", + FormatLatencyReading(buf[0], sizeof(buf[0]), AppLatencyTimings.LatencyRender), + FormatLatencyReading(buf[1], sizeof(buf[1]), AppLatencyTimings.LatencyTimewarp), + FormatLatencyReading(buf[2], sizeof(buf[2]), AppLatencyTimings.LatencyPostPresent), + FormatLatencyReading(buf[3], sizeof(buf[3]), AppLatencyTimings.ErrorRender), + FormatLatencyReading(buf[4], sizeof(buf[4]), AppLatencyTimings.ErrorTimewarp)); + + Str = ANSI_TO_TCHAR(destStr); + InCanvas->Canvas->DrawShadowedString(X, Y, *Str, Font, TextColor); + } + + // Second row + X = (int32)LeftPos + 200; + Y = (int32)TopPos; + + Str = FString::Printf(TEXT("HQ dist: %s"), (Settings->Flags.bHQDistortion) ? TEXT("ON") : TEXT("OFF")); + InCanvas->Canvas->DrawShadowedString(X, Y, *Str, Font, TextColor); + Y += RowHeight; + + float UserIPD; + if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetUserIPD2(&UserIPD))) + { + Str = FString::Printf(TEXT("IPD: %.2f mm"), UserIPD * 1000.f); + InCanvas->Canvas->DrawShadowedString(X, Y, *Str, Font, TextColor); + Y += RowHeight; + } + } + } +#endif // #if !UE_BUILD_SHIPPING + + FOculusXRHMD* FOculusXRHMD::GetOculusXRHMD() + { +#if OCULUS_HMD_SUPPORTED_PLATFORMS + if (GEngine && GEngine->XRSystem.IsValid()) + { + if (GEngine->XRSystem->GetSystemName() == OculusXRHMD::FOculusXRHMD::OculusSystemName) + { + return static_cast(GEngine->XRSystem.Get()); + } + } +#endif + return nullptr; + } + + bool FOculusXRHMD::IsHMDActive() const + { + return FOculusXRHMDModule::GetPluginWrapper().GetInitialized() != ovrpBool_False; + } + + float FOculusXRHMD::GetWorldToMetersScale() const + { + CheckInGameThread(); + + if (NextFrameToRender.IsValid()) + { + return NextFrameToRender->WorldToMetersScale; + } + + if (GWorld != nullptr) + { +#if WITH_EDITOR + // Workaround to allow WorldToMeters scaling to work correctly for controllers while running inside PIE. + // The main world will most likely not be pointing at the PIE world while polling input, so if we find a world context + // of that type, use that world's WorldToMeters instead. + if (GIsEditor) + { + for (const FWorldContext& Context : GEngine->GetWorldContexts()) + { + if (Context.WorldType == EWorldType::PIE) + { + return Context.World()->GetWorldSettings()->WorldToMeters; + } + } + } +#endif //WITH_EDITOR + + // We're not currently rendering a frame, so just use whatever world to meters the main world is using. + // This can happen when we're polling input in the main engine loop, before ticking any worlds. + return GWorld->GetWorldSettings()->WorldToMeters; + } + + return 100.0f; + } + + FVector FOculusXRHMD::GetNeckPosition(const FQuat& HeadOrientation, const FVector& HeadPosition) + { + CheckInGameThread(); + + FVector NeckPosition = HeadOrientation.Inverse().RotateVector(HeadPosition); + + ovrpVector2f NeckEyeDistance; + if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetUserNeckEyeDistance2(&NeckEyeDistance))) + { + const float WorldToMetersScale = GetWorldToMetersScale(); + NeckPosition.X -= NeckEyeDistance.x * WorldToMetersScale; + NeckPosition.Z -= NeckEyeDistance.y * WorldToMetersScale; + } + + return NeckPosition; + } + + void FOculusXRHMD::SetBaseOffsetInMeters(const FVector& BaseOffset) + { + CheckInGameThread(); + + Settings->BaseOffset = BaseOffset; + } + + FVector FOculusXRHMD::GetBaseOffsetInMeters() const + { + CheckInGameThread(); + + return Settings->BaseOffset; + } + + bool FOculusXRHMD::ConvertPose(const ovrpPosef& InPose, FPose& OutPose) const + { + CheckInGameThread(); + + if (!NextFrameToRender.IsValid()) + { + return false; + } + + return ConvertPose_Internal(InPose, OutPose, Settings.Get(), NextFrameToRender->WorldToMetersScale); + } + + bool FOculusXRHMD::ConvertPose(const FPose& InPose, ovrpPosef& OutPose) const + { + CheckInGameThread(); + + if (!NextFrameToRender.IsValid()) + { + return false; + } + + return ConvertPose_Internal(InPose, OutPose, Settings.Get(), NextFrameToRender->WorldToMetersScale); + } + + bool FOculusXRHMD::ConvertPose_RenderThread(const ovrpPosef& InPose, FPose& OutPose) const + { + CheckInRenderThread(); + + if (!Frame_RenderThread.IsValid()) + { + return false; + } + + return ConvertPose_Internal(InPose, OutPose, Settings_RenderThread.Get(), Frame_RenderThread->WorldToMetersScale); + } + + bool FOculusXRHMD::ConvertPose_Internal(const ovrpPosef& InPose, FPose& OutPose, const FSettings* Settings, float WorldToMetersScale) + { + return OculusXRHMD::ConvertPose_Internal(InPose, OutPose, Settings->BaseOrientation, Settings->BaseOffset, WorldToMetersScale); + } + + bool FOculusXRHMD::ConvertPose_Internal(const FPose& InPose, ovrpPosef& OutPose, const FSettings* Settings, float WorldToMetersScale) + { + return OculusXRHMD::ConvertPose_Internal(InPose, OutPose, Settings->BaseOrientation, Settings->BaseOffset, WorldToMetersScale); + } + + FVector FOculusXRHMD::ScaleAndMovePointWithPlayer(ovrpVector3f& OculusXRHMDPoint) + { + CheckInGameThread(); + + FMatrix TranslationMatrix; + TranslationMatrix.SetIdentity(); + TranslationMatrix = TranslationMatrix.ConcatTranslation(LastPlayerLocation); + + FVector ConvertedPoint = ToFVector(OculusXRHMDPoint) * GetWorldToMetersScale(); + FRotator RotateWithPlayer = LastPlayerOrientation.Rotator(); + FVector TransformWithPlayer = RotateWithPlayer.RotateVector(ConvertedPoint); + TransformWithPlayer = FVector(TranslationMatrix.TransformPosition(TransformWithPlayer)); + + if (GetXRCamera(HMDDeviceId)->GetUseImplicitHMDPosition()) + { + FQuat HeadOrientation = FQuat::Identity; + FVector HeadPosition; + GetCurrentPose(HMDDeviceId, HeadOrientation, HeadPosition); + TransformWithPlayer -= RotateWithPlayer.RotateVector(HeadPosition); + } + + return TransformWithPlayer; + } + + ovrpVector3f FOculusXRHMD::WorldLocationToOculusPoint(const FVector& InUnrealPosition) + { + CheckInGameThread(); + FQuat AdjustedPlayerOrientation = GetBaseOrientation().Inverse() * LastPlayerOrientation; + AdjustedPlayerOrientation.Normalize(); + + FVector AdjustedPlayerLocation = LastPlayerLocation; + if (GetXRCamera(HMDDeviceId)->GetUseImplicitHMDPosition()) + { + FQuat HeadOrientation = FQuat::Identity; // Unused + FVector HeadPosition; + GetCurrentPose(HMDDeviceId, HeadOrientation, HeadPosition); + AdjustedPlayerLocation -= LastPlayerOrientation.Inverse().RotateVector(HeadPosition); + } + const FTransform InvWorldTransform = FTransform(AdjustedPlayerOrientation, AdjustedPlayerLocation).Inverse(); + const FVector ConvertedPosition = InvWorldTransform.TransformPosition(InUnrealPosition) / GetWorldToMetersScale(); + + return ToOvrpVector3f(ConvertedPosition); + } + + float FOculusXRHMD::ConvertFloat_M2U(float OculusFloat) const + { + CheckInGameThread(); + + return OculusFloat * GetWorldToMetersScale(); + } + + FVector FOculusXRHMD::ConvertVector_M2U(ovrpVector3f OculusXRHMDPoint) const + { + CheckInGameThread(); + + return ToFVector(OculusXRHMDPoint) * GetWorldToMetersScale(); + } + + bool FOculusXRHMD::GetUserProfile(UserProfile& OutProfile) + { + float UserIPD; + ovrpVector2f UserNeckEyeDistance; + float UserEyeHeight; + + if (FOculusXRHMDModule::GetPluginWrapper().GetInitialized() && OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetUserIPD2(&UserIPD)) && OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetUserNeckEyeDistance2(&UserNeckEyeDistance)) && OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetUserEyeHeight2(&UserEyeHeight))) + { + OutProfile.IPD = UserIPD; + OutProfile.EyeDepth = UserNeckEyeDistance.x; + OutProfile.EyeHeight = UserEyeHeight; + return true; + } + + return false; + } + + float FOculusXRHMD::GetVsyncToNextVsync() const + { + CheckInGameThread(); + + return Settings->VsyncToNextVsync; + } + + FPerformanceStats FOculusXRHMD::GetPerformanceStats() const + { + return PerformanceStats; + } + + void FOculusXRHMD::GetSuggestedCpuAndGpuPerformanceLevels(EOculusXRProcessorPerformanceLevel& CpuPerfLevel, EOculusXRProcessorPerformanceLevel& GpuPerfLevel) + { + CheckInGameThread(); + CpuPerfLevel = Settings->SuggestedCpuPerfLevel; + GpuPerfLevel = Settings->SuggestedGpuPerfLevel; + } + + void FOculusXRHMD::SetSuggestedCpuAndGpuPerformanceLevels(EOculusXRProcessorPerformanceLevel CpuPerfLevel, EOculusXRProcessorPerformanceLevel GpuPerfLevel) + { + CheckInGameThread(); + FOculusXRHMDModule::GetPluginWrapper().SetSuggestedCpuPerformanceLevel((ovrpProcessorPerformanceLevel)CpuPerfLevel); + FOculusXRHMDModule::GetPluginWrapper().SetSuggestedGpuPerformanceLevel((ovrpProcessorPerformanceLevel)GpuPerfLevel); + Settings->SuggestedCpuPerfLevel = CpuPerfLevel; + Settings->SuggestedGpuPerfLevel = GpuPerfLevel; + } + + void FOculusXRHMD::SetFoveatedRenderingMethod(EOculusXRFoveatedRenderingMethod InFoveatedRenderingMethod) + { +#ifdef WITH_OCULUS_BRANCH + Settings->FoveatedRenderingMethod = InFoveatedRenderingMethod; + // Don't switch to eye tracked foveated rendering when it's not supported or permissions are denied + if (InFoveatedRenderingMethod == EOculusXRFoveatedRenderingMethod::EyeTrackedFoveatedRendering && !(bEyeTrackedFoveatedRenderingSupported && CheckEyeTrackingPermission(InFoveatedRenderingMethod))) + { + return; + } +#else + Settings->FoveatedRenderingMethod = EOculusXRFoveatedRenderingMethod::FixedFoveatedRendering; + if (InFoveatedRenderingMethod == EOculusXRFoveatedRenderingMethod::EyeTrackedFoveatedRendering) + { + UE_LOG(LogHMD, Warning, TEXT("Eye Tracked Foveated Rendering is not supported on this engine version, using Fixed Foveated Rendering instead")); + } +#endif // WITH_OCULUS_BRANCH + + FoveatedRenderingMethod = Settings->FoveatedRenderingMethod; + } + + void FOculusXRHMD::SetFoveatedRenderingLevel(EOculusXRFoveatedRenderingLevel InFoveationLevel, bool isDynamic) + { + FoveatedRenderingLevel = Settings->FoveatedRenderingLevel = InFoveationLevel; + bDynamicFoveatedRendering = Settings->bDynamicFoveatedRendering = isDynamic; + } + + void FOculusXRHMD::SetColorScaleAndOffset(FLinearColor ColorScale, FLinearColor ColorOffset, bool bApplyToAllLayers) + { + CheckInGameThread(); + Settings->bApplyColorScaleAndOffsetToAllLayers = bApplyToAllLayers; + Settings->ColorScale = LinearColorToOvrpVector4f(ColorScale); + Settings->ColorOffset = LinearColorToOvrpVector4f(ColorOffset); + } + + void FOculusXRHMD::SetEnvironmentDepthHandRemoval(bool RemoveHands) + { + FOculusXRHMDModule::GetPluginWrapper().SetEnvironmentDepthHandRemoval(RemoveHands); + bEnvironmentDepthHandRemovalEnabled = RemoveHands; + } + + void FOculusXRHMD::StartEnvironmentDepth(int CreateFlags) + { +#if PLATFORM_ANDROID + // Check and request scene permissions (this is needed for environment depth to work) + // bind delegate for handling permission request result + if (!UAndroidPermissionFunctionLibrary::CheckPermission(USE_SCENE_PERMISSION_NAME)) + { + TArray Permissions; + Permissions.Add(USE_SCENE_PERMISSION_NAME); + UAndroidPermissionCallbackProxy* Proxy = UAndroidPermissionFunctionLibrary::AcquirePermissions(Permissions); + static FDelegateHandle DelegateHandle; + DelegateHandle = Proxy->OnPermissionsGrantedDelegate.AddLambda([this, Proxy, CreateFlags](const TArray& Permissions, const TArray& GrantResults) { + int PermIndex = Permissions.Find(USE_SCENE_PERMISSION_NAME); + if (PermIndex != INDEX_NONE && GrantResults[PermIndex]) + { + UE_LOG(LogHMD, Verbose, TEXT("%s permission granted"), *USE_SCENE_PERMISSION_NAME); + StartEnvironmentDepth(CreateFlags); + } + else + { + UE_LOG(LogHMD, Log, TEXT("%s permission denied"), *USE_SCENE_PERMISSION_NAME); + } + Proxy->OnPermissionsGrantedDelegate.Remove(DelegateHandle); + }); + return; + } +#endif // PLATFORM_ANDROID + + ExecuteOnRenderThread_DoNotWait([this, CreateFlags]() { + ovrpEnvironmentDepthTextureDesc DepthTextureDesc; + if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().InitializeEnvironmentDepth(CreateFlags)) && OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetEnvironmentDepthTextureDesc(&DepthTextureDesc))) + { + TArray DepthTextures; + int32 TextureCount; + if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetEnvironmentDepthTextureStageCount(&TextureCount))) + { + // We don't really do different depth texture formats right now and it's always a + // single multiview texture, so no need for a separate right eye texture for now. + // We may need a separate Left/RightDepthTextures in the future. + DepthTextures.SetNum(TextureCount); + + for (int32 TextureIndex = 0; TextureIndex < TextureCount; TextureIndex++) + { + if (OVRP_FAILURE(FOculusXRHMDModule::GetPluginWrapper().GetEnvironmentDepthTexture(TextureIndex, ovrpEye_Left, &DepthTextures[TextureIndex]))) + { + UE_LOG(LogHMD, Error, TEXT("Failed to create insight depth texture. NOTE: This causes a leak of %d other texture(s), which will go unused."), TextureIndex); + return; + } + } + + uint32 SizeX = DepthTextureDesc.TextureSize.w; + uint32 SizeY = DepthTextureDesc.TextureSize.h; + EPixelFormat DepthFormat = CustomPresent->GetPixelFormat(DepthTextureDesc.Format); + uint32 NumMips = DepthTextureDesc.MipLevels; + uint32 NumSamples = DepthTextureDesc.SampleCount; + uint32 NumSamplesTileMem = 1; + ETextureCreateFlags DepthTexCreateFlags = TexCreate_ShaderResource | TexCreate_InputAttachmentRead; + FClearValueBinding DepthTextureBinding = FClearValueBinding::DepthFar; + ERHIResourceType ResourceType; + if (DepthTextureDesc.Layout == ovrpLayout_Array) + { + ResourceType = RRT_Texture2DArray; + } + else + { + ResourceType = RRT_Texture2D; + } + + if (CustomPresent) + { + if (!EnvironmentDepthSwapchain.IsEmpty()) + { + EnvironmentDepthSwapchain.Empty(); + } + EnvironmentDepthSwapchain = CustomPresent->CreateSwapChainTextures_RenderThread(SizeX, SizeY, DepthFormat, DepthTextureBinding, NumMips, NumSamples, NumSamplesTileMem, ResourceType, DepthTextures, DepthTexCreateFlags, *FString::Printf(TEXT("Oculus Environment Depth Swapchain"))); + } + + FOculusXRHMDModule::GetPluginWrapper().SetEnvironmentDepthHandRemoval(bEnvironmentDepthHandRemovalEnabled); + FOculusXRHMDModule::GetPluginWrapper().StartEnvironmentDepth(); + } + } + }); + } + + void FOculusXRHMD::StopEnvironmentDepth() + { + ExecuteOnRenderThread_DoNotWait([this]() { + ExecuteOnRHIThread_DoNotWait([this]() { + if (!EnvironmentDepthSwapchain.IsEmpty()) + { + EnvironmentDepthSwapchain.Empty(); + } + if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().StopEnvironmentDepth())) + { + FOculusXRHMDModule::GetPluginWrapper().DestroyEnvironmentDepth(); + } + }); + }); + } + + bool FOculusXRHMD::IsEnvironmentDepthStarted() + { + return !EnvironmentDepthSwapchain.IsEmpty(); + } + + void FOculusXRHMD::EnableHardOcclusions(bool bEnable) + { + bHardOcclusionsEnabled = bEnable; + } + + bool FOculusXRHMD::DoEnableStereo(bool bStereo) + { + CheckInGameThread(); + + FSceneViewport* SceneVP = FindSceneViewport(); + + if (!Settings->Flags.bHMDEnabled || (SceneVP && !SceneVP->IsStereoRenderingAllowed())) + { + bStereo = false; + } + + if (Settings->Flags.bStereoEnabled && bStereo || !Settings->Flags.bStereoEnabled && !bStereo) + { + // already in the desired mode + return Settings->Flags.bStereoEnabled; + } + + TSharedPtr Window; + + if (SceneVP) + { + Window = SceneVP->FindWindow(); + } + + if (!Window.IsValid() || !SceneVP || !SceneVP->GetViewportWidget().IsValid()) + { + // try again next frame + if (bStereo) + { + Flags.bNeedEnableStereo = true; + + // a special case when stereo is enabled while window is not available yet: + // most likely this is happening from BeginPlay. In this case, if frame exists (created in OnBeginPlay) + // then we need init device and populate the initial tracking for head/hand poses. + if (Frame.IsValid()) + { + InitDevice(); + } + } + else + { + Flags.bNeedDisableStereo = true; + } + + return Settings->Flags.bStereoEnabled; + } + + if (OnOculusStateChange(bStereo)) + { + Settings->Flags.bStereoEnabled = bStereo; + + // Uncap fps to enable FPS higher than 62 + GEngine->bForceDisableFrameRateSmoothing = bStereo; + + // Set MirrorWindow state on the Window + Window->SetMirrorWindow(bStereo); + + if (bStereo) + { + // Start frame + StartGameFrame_GameThread(); + StartRenderFrame_GameThread(); + + // Set viewport size to Rift resolution + // NOTE: this can enqueue a render frame right away as a result (calling into FOculusXRHMD::BeginRenderViewFamily) + SceneVP->SetViewportSize(Settings->RenderTargetSize.X, Settings->RenderTargetSize.Y); + + if (Settings->Flags.bPauseRendering) + { + GEngine->SetMaxFPS(10); + } + } + else + { + // Work around an error log that can happen when enabling stereo rendering again + if (NextFrameNumber == WaitFrameNumber) + { + NextFrameNumber++; + } + + if (Settings->Flags.bPauseRendering) + { + GEngine->SetMaxFPS(0); + } + + // Restore viewport size to window size + FVector2D size = Window->GetSizeInScreen(); + SceneVP->SetViewportSize(size.X, size.Y); + Window->SetViewportSizeDrivenByWindow(true); + } + } + + return Settings->Flags.bStereoEnabled; + } + + void FOculusXRHMD::ResetControlRotation() const + { + // Switching back to non-stereo mode: reset player rotation and aim. + // Should we go through all playercontrollers here? + APlayerController* pc = GEngine->GetFirstLocalPlayerController(GWorld); + if (pc) + { + // Reset Aim? @todo + FRotator r = pc->GetControlRotation(); + r.Normalize(); + // Reset roll and pitch of the player + r.Roll = 0; + r.Pitch = 0; + pc->SetControlRotation(r); + } + } + + void FOculusXRHMD::UpdateFoveationOffsets_RenderThread() + { +#ifdef WITH_OCULUS_BRANCH + CheckInRenderThread(); + + SCOPED_NAMED_EVENT(UpdateFoveationOffsets_RenderThread, FColor::Red); + + // Don't execute anything if we're not using Eye Tracked Foveated Rendering (this already takes into account if it's supported or not) + if (!Frame_RenderThread.IsValid() || Frame_RenderThread->FoveatedRenderingMethod != EOculusXRFoveatedRenderingMethod::EyeTrackedFoveatedRendering) + { + return; + } + + const FXRSwapChainPtr& SwapChain = EyeLayer_RenderThread->GetSwapChain(); + if (!SwapChain.IsValid()) + { + return; + } + + const FRHITexture2D* const SwapChainTexture = SwapChain->GetTexture2DArray() ? SwapChain->GetTexture2DArray() : SwapChain->GetTexture2D(); + if (!SwapChainTexture) + { + return; + } + const FIntPoint SwapChainDimensions = SwapChainTexture->GetSizeXY(); + + // Enqueue the actual update on the RHI thread, which should execute right before the EndRenderPass call + ExecuteOnRHIThread_DoNotWait([this, SwapChainDimensions]() { + SCOPED_NAMED_EVENT(UpdateFoveationEyeTracked_RHIThread, FColor::Red); + + bool bUseOffsets = false; + FIntPoint Offsets[2]; + // Make sure the the Foveated Rendering Method is still eye tracked at RHI thread time before getting offsets. + // If the base setting was changed to fixed, even if the frame's setting is still eye tracked, we should switch to fixed. This + // usually indicates that eye tracking failed on the previous frame, so we don't need to try it again. + if (Frame_RHIThread.IsValid() && Frame_RHIThread->FoveatedRenderingMethod == EOculusXRFoveatedRenderingMethod::EyeTrackedFoveatedRendering && FoveatedRenderingMethod == EOculusXRFoveatedRenderingMethod::EyeTrackedFoveatedRendering) + { + if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().SetFoveationEyeTracked(ovrpBool_True))) + { + ovrpVector2f fovCenter[2]; + ovrpResult Result = FOculusXRHMDModule::GetPluginWrapper().GetFoveationEyeTrackedCenter(fovCenter); + if (OVRP_SUCCESS(Result)) + { + Offsets[0].X = fovCenter[0].x * SwapChainDimensions.X / 2; + Offsets[0].Y = fovCenter[0].y * SwapChainDimensions.Y / 2; + Offsets[1].X = fovCenter[1].x * SwapChainDimensions.X / 2; + Offsets[1].Y = fovCenter[1].y * SwapChainDimensions.Y / 2; + bUseOffsets = true; + } + else if (Result != ovrpFailure_DataIsInvalid) + { + // Fall back to dynamic FFR High if OVRPlugin call actually fails, since we're not expecting GFR to work again. + // Additional rendering changes can be made by binding the changes to OculusEyeTrackingStateChanged + EyeTrackedFoveatedRenderingFallback(); + FOculusEventDelegates::OculusEyeTrackingStateChanged.Broadcast(false); + } + } + } + + if (CustomPresent) + { + CustomPresent->UpdateFoveationOffsets_RHIThread(bUseOffsets, Offsets); + } + }); +#endif // WITH_OCULUS_BRANCH + } + + class FHardOcclusionsPS : public FGlobalShader + { + DECLARE_SHADER_TYPE(FHardOcclusionsPS, Global); + + static void ModifyCompilationEnvironment(const FGlobalShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment) + { + FGlobalShader::ModifyCompilationEnvironment(Parameters, OutEnvironment); + } + + static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters) + { + // This file is already guarded with OCULUS_HMD_SUPPORTED_PLATFORMS + return true; + } + + /** Default constructor. */ + FHardOcclusionsPS() {} + + /** Initialization constructor. */ + FHardOcclusionsPS(const ShaderMetaType::CompiledShaderInitializerType& Initializer) + : FGlobalShader(Initializer) + { + EnvironmentDepthTexture.Bind(Initializer.ParameterMap, TEXT("EnvironmentDepthTexture")); + EnvironmentDepthSampler.Bind(Initializer.ParameterMap, TEXT("EnvironmentDepthSampler")); + DepthFactors.Bind(Initializer.ParameterMap, TEXT("DepthFactors")); + ScreenToDepthMatrices.Bind(Initializer.ParameterMap, TEXT("ScreenToDepthMatrices")); + DepthViewId.Bind(Initializer.ParameterMap, TEXT("DepthViewId")); + } + +#if UE_VERSION_OLDER_THAN(5, 3, 0) + template + void SetParameters( + FRHICommandListImmediate& RHICmdList, + const TShaderRHIParamRef ShaderRHI, + FRHISamplerState* Sampler, + FRHITexture* Texture, + const FVector2f& Factors, + const FMatrix44f ScreenToDepth[ovrpEye_Count], + const int ViewId) + { + SetTextureParameter(RHICmdList, ShaderRHI, EnvironmentDepthTexture, EnvironmentDepthSampler, Sampler, Texture); + + SetShaderValue(RHICmdList, ShaderRHI, DepthFactors, Factors); + SetShaderValueArray(RHICmdList, ShaderRHI, ScreenToDepthMatrices, ScreenToDepth, ovrpEye_Count); + SetShaderValue(RHICmdList, ShaderRHI, DepthViewId, ViewId); + } +#else + void SetParameters( + FRHIBatchedShaderParameters& BatchedParameters, + FRHISamplerState* Sampler, + FRHITexture* Texture, + const FVector2f& Factors, + const FMatrix44f ScreenToDepth[ovrpEye_Count], + const int ViewId) + { + SetTextureParameter(BatchedParameters, EnvironmentDepthTexture, EnvironmentDepthSampler, Sampler, Texture); + + SetShaderValue(BatchedParameters, DepthFactors, Factors); + SetShaderValueArray(BatchedParameters, ScreenToDepthMatrices, ScreenToDepth, ovrpEye_Count); + SetShaderValue(BatchedParameters, DepthViewId, ViewId); + } +#endif + + private: + LAYOUT_FIELD(FShaderResourceParameter, EnvironmentDepthTexture); + LAYOUT_FIELD(FShaderResourceParameter, EnvironmentDepthSampler); + LAYOUT_FIELD(FShaderParameter, DepthFactors); + LAYOUT_FIELD(FShaderParameter, ScreenToDepthMatrices); + LAYOUT_FIELD(FShaderParameter, DepthViewId); + }; + + IMPLEMENT_SHADER_TYPE(, FHardOcclusionsPS, TEXT("/Plugin/OculusXR/Private/HardOcclusions.usf"), TEXT("HardOcclusionsPS"), SF_Pixel); + + FMatrix44f MakeProjectionMatrix(ovrpFovf cameraFovAngles) + { + const float tanAngleWidth = cameraFovAngles.RightTan + cameraFovAngles.LeftTan; + const float tanAngleHeight = cameraFovAngles.UpTan + cameraFovAngles.DownTan; + + FMatrix44f Matrix = FMatrix44f::Identity; + + // Scale + Matrix.M[0][0] = 1.0f / tanAngleWidth; + Matrix.M[1][1] = 1.0f / tanAngleHeight; + + // Offset + Matrix.M[0][3] = cameraFovAngles.LeftTan / tanAngleWidth; + Matrix.M[1][3] = cameraFovAngles.DownTan / tanAngleHeight; + Matrix.M[2][3] = -1.0f; + + return Matrix; + } + + FMatrix44f MakeUnprojectionMatrix(ovrpFovf cameraFovAngles) + { + FMatrix44f Matrix = FMatrix44f::Identity; + + // Scale + Matrix.M[0][0] = cameraFovAngles.RightTan + cameraFovAngles.LeftTan; + Matrix.M[1][1] = cameraFovAngles.UpTan + cameraFovAngles.DownTan; + + // Offset + Matrix.M[0][3] = -cameraFovAngles.LeftTan; + Matrix.M[1][3] = -cameraFovAngles.DownTan; + Matrix.M[2][3] = 1.0; + + return Matrix; + } + + bool FOculusXRHMD::ComputeEnvironmentDepthParameters_RenderThread(FVector2f& DepthFactors, FMatrix44f ScreenToDepth[ovrpEye_Count], FMatrix44f DepthViewProj[ovrpEye_Count], int& SwapchainIndex) + { + float ScreenNearZ = GNearClippingPlane / Frame_RenderThread->WorldToMetersScale; + ovrpFovf* ScreenFov = Frame_RenderThread->SymmetricFov; + + ovrpEnvironmentDepthFrameDesc DepthFrameDesc[ovrpEye_Count]; + if (FOculusXRHMDModule::GetPluginWrapper().GetEnvironmentDepthFrameDesc(ovrpEye_Left, &DepthFrameDesc[0]) != ovrpSuccess || !DepthFrameDesc[0].IsValid) + { + return false; + } + if (FOculusXRHMDModule::GetPluginWrapper().GetEnvironmentDepthFrameDesc(ovrpEye_Right, &DepthFrameDesc[1]) != ovrpSuccess || !DepthFrameDesc[1].IsValid) + { + return false; + } + + SwapchainIndex = DepthFrameDesc[0].SwapchainIndex; + const float WorldToMetersScale = Frame_RenderThread->WorldToMetersScale; + + if (DepthViewProj != nullptr) + { + for (int i = 0; i < ovrpEye_Count; ++i) + { + ovrpFrustum2f DepthFrustum; + DepthFrustum.Fov = DepthFrameDesc[i].Fov; + DepthFrustum.zNear = DepthFrameDesc[i].NearZ * WorldToMetersScale; + DepthFrustum.zFar = DepthFrameDesc[i].FarZ * WorldToMetersScale; + FMatrix DepthProjectionMatrix = ToFMatrix(ovrpMatrix4f_Projection(DepthFrustum, true)); + + auto DepthOrientation = ToFQuat(DepthFrameDesc[i].CreatePose.Orientation); + + // NOTE: This matrix is the same as applied in SetupViewFrustum in SceneView.cpp + auto ViewMatrix = DepthOrientation.Inverse().ToMatrix() * FMatrix(FPlane(0, 0, 1, 0), FPlane(1, 0, 0, 0), FPlane(0, 1, 0, 0), FPlane(0, 0, 0, 1)); + + ovrpPoseStatef EyePoseState; + if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetNodePoseState3(ovrpStep_Render, Frame_RenderThread->FrameNumber, (ovrpNode)i, &EyePoseState))) + { + auto DepthTranslation = ToFVector(DepthFrameDesc[i].CreatePose.Position) * WorldToMetersScale; + auto EyePos = ToFVector(EyePoseState.Pose.Position) * WorldToMetersScale; + auto Delta = EyePos - DepthTranslation; + + // NOTE: The view matrix here is relative to the VR camera, this is necessary to support + // Large Worlds and avoid rounding errors when getting very far away from the origin + ViewMatrix = ViewMatrix.ConcatTranslation(ViewMatrix.TransformPosition(Delta)); + } + + DepthViewProj[i] = (FMatrix44f)(ViewMatrix * DepthProjectionMatrix); + } + } + + // Assume NearZ and FarZ are the same for left and right eyes + float DepthNearZ = DepthFrameDesc[ovrpEye_Left].NearZ; + float DepthFarZ = DepthFrameDesc[ovrpEye_Left].FarZ; + + float Scale; + float Offset; + + if (DepthFarZ < DepthNearZ || (!FGenericPlatformMath::IsFinite(DepthFarZ))) + { + // Inf far plane: + Scale = DepthNearZ; + Offset = 0.0f; + } + else + { + // Finite far plane: + Scale = (DepthFarZ * DepthNearZ) / (DepthFarZ - DepthNearZ); + Offset = DepthNearZ / (DepthFarZ - DepthNearZ); + } + + DepthFactors.X = -ScreenNearZ / Scale; + DepthFactors.Y = Offset * ScreenNearZ / Scale + 1.0f; + + // The pose extrapolated to the predicted display time of the current frame + FQuat ScreenOrientation = Frame_RenderThread->HeadOrientation; + + for (int i = 0; i < ovrpEye_Count; ++i) + { + // Screen To Depth represents the transformation matrix used to map normalised screen UV coordinates to + // normalised environment depth texture UV coordinates. This needs to account for 2 things: + // 1. The field of view of the two textures may be different, Unreal typically renders using a symmetric fov. + // That is to say the FOV of the left and right eyes is the same. The environment depth on the other hand + // has a different FOV for the left and right eyes. So we need to scale and offset accordingly to account + // for this difference. + auto T_ScreenCamera_ScreenNormCoord = MakeUnprojectionMatrix(ScreenFov[i]); + auto T_DepthNormCoord_DepthCamera = MakeProjectionMatrix(DepthFrameDesc[i].Fov); + + // 2. The headset may have moved in between capturing the environment depth and rendering the frame. We + // can only account for rotation of the headset, not translation. + auto DepthOrientation = ToFQuat(DepthFrameDesc[i].CreatePose.Orientation); + if (!DepthOrientation.IsNormalized()) + { + UE_LOG(LogHMD, Error, TEXT("DepthOrientation is not normalized %f %f %f %f"), DepthOrientation.X, DepthOrientation.Y, DepthOrientation.Z, DepthOrientation.W); + DepthOrientation.Normalize(); + } + auto ScreenToDepthQuat = ScreenOrientation.Inverse() * DepthOrientation; + + FMatrix44f R_DepthCamera_ScreenCamera = FQuat4f(ScreenToDepthQuat.Y, ScreenToDepthQuat.Z, ScreenToDepthQuat.X, ScreenToDepthQuat.W).GetNormalized().ToMatrix(); + + ScreenToDepth[i] = T_DepthNormCoord_DepthCamera * R_DepthCamera_ScreenCamera * T_ScreenCamera_ScreenNormCoord; + } + return true; + } + +#if !UE_VERSION_OLDER_THAN(5, 3, 0) + BEGIN_SHADER_PARAMETER_STRUCT(FDrawRectangleParameters, ) + SHADER_PARAMETER(FVector4f, PosScaleBias) + SHADER_PARAMETER(FVector4f, UVScaleBias) + SHADER_PARAMETER(FVector4f, InvTargetSizeAndTextureSize) + END_SHADER_PARAMETER_STRUCT() +#endif + + void FOculusXRHMD::DrawHmdViewMesh( + FRHICommandList& RHICmdList, + float X, + float Y, + float SizeX, + float SizeY, + float U, + float V, + float SizeU, + float SizeV, + FIntPoint TargetSize, + FIntPoint TextureSize, + int32 StereoView, + const TShaderRef& VertexShader) + { + FDrawRectangleParameters Parameters; + Parameters.PosScaleBias = FVector4f(SizeX, SizeY, X, Y); + Parameters.UVScaleBias = FVector4f(SizeU, SizeV, U, V); + + Parameters.InvTargetSizeAndTextureSize = FVector4f( + 1.0f / TargetSize.X, 1.0f / TargetSize.Y, + 1.0f / TextureSize.X, 1.0f / TextureSize.Y); + +#if UE_VERSION_OLDER_THAN(5, 3, 0) + SetUniformBufferParameterImmediate(RHICmdList, VertexShader.GetVertexShader(), VertexShader->GetUniformBufferParameter(), Parameters); +#else + FRHIBatchedShaderParameters& BatchedParameters = RHICmdList.GetScratchShaderParameters(); + SetUniformBufferParameterImmediate(BatchedParameters, VertexShader->GetUniformBufferParameter(), Parameters); + RHICmdList.SetBatchedShaderParameters(VertexShader.GetVertexShader(), BatchedParameters); +#endif + RendererModule->DrawRectangle( + RHICmdList, + X, Y, + SizeX, SizeY, + 0, 0, + TextureSize.X, TextureSize.Y, + TargetSize, + TextureSize, + VertexShader); + } + +#if UE_VERSION_OLDER_THAN(5, 3, 0) + void FOculusXRHMD::RenderHardOcclusions_RenderThread(FRHICommandListImmediate& RHICmdList, const FSceneView& InView) +#else + void FOculusXRHMD::RenderHardOcclusions_RenderThread(FRHICommandList& RHICmdList, const FSceneView& InView) +#endif + { + checkSlow(RHICmdList.IsInsideRenderPass()); + + FVector2f DepthFactors; + FMatrix44f ScreenToDepthMatrices[ovrpEye_Count]; + int SwapchainIndex; + + if (!Frame_RenderThread.IsValid() || InView.bIsSceneCapture || InView.bIsReflectionCapture || InView.bIsPlanarReflection || !ComputeEnvironmentDepthParameters_RenderThread(DepthFactors, ScreenToDepthMatrices, nullptr, SwapchainIndex)) + { + return; + } + if (SwapchainIndex >= EnvironmentDepthSwapchain.Num()) + { + return; + } + + FGraphicsPipelineStateInitializer GraphicsPSOInit; + RHICmdList.ApplyCachedRenderTargets(GraphicsPSOInit); + + GraphicsPSOInit.BlendState = TStaticBlendState<>::GetRHI(); + GraphicsPSOInit.RasterizerState = TStaticRasterizerState<>::GetRHI(); + GraphicsPSOInit.DepthStencilState = TStaticDepthStencilState<>::GetRHI(); + + FGlobalShaderMap* GlobalShaderMap = GetGlobalShaderMap(InView.FeatureLevel); + TShaderMapRef VertexShader(GlobalShaderMap); + TShaderMapRef PixelShader(GlobalShaderMap); + + GraphicsPSOInit.BoundShaderState.VertexDeclarationRHI = GFilterVertexDeclaration.VertexDeclarationRHI; + GraphicsPSOInit.BoundShaderState.VertexShaderRHI = VertexShader.GetVertexShader(); + GraphicsPSOInit.BoundShaderState.PixelShaderRHI = PixelShader.GetPixelShader(); + GraphicsPSOInit.PrimitiveType = PT_TriangleList; + + SetGraphicsPipelineState(RHICmdList, GraphicsPSOInit, 0); + + FRHITexture* DepthTexture = EnvironmentDepthSwapchain[SwapchainIndex]; + FRHISamplerState* DepthSampler = TStaticSamplerState<>::GetRHI(); + + FIntPoint TextureSize = DepthTexture->GetDesc().Extent; + FIntRect ScreenRect = InView.UnscaledViewRect; + +#if UE_VERSION_OLDER_THAN(5, 3, 0) + PixelShader->SetParameters(RHICmdList, PixelShader.GetPixelShader(), DepthSampler, DepthTexture, DepthFactors, ScreenToDepthMatrices, InView.StereoViewIndex); +#else + FRHIBatchedShaderParameters& BatchedParameters = RHICmdList.GetScratchShaderParameters(); + PixelShader->SetParameters(BatchedParameters, DepthSampler, DepthTexture, DepthFactors, ScreenToDepthMatrices, InView.StereoViewIndex); + RHICmdList.SetBatchedShaderParameters(PixelShader.GetPixelShader(), BatchedParameters); +#endif + + check(Settings->CurrentShaderPlatform == InView.Family->Scene->GetShaderPlatform()); + if (!IsMobilePlatform(Settings->CurrentShaderPlatform) && InView.StereoViewIndex != INDEX_NONE) + { + SCOPED_DRAW_EVENTF(RHICmdList, RenderHardOcclusions_RenderThread, TEXT("View %d"), InView.StereoViewIndex); + + int32 width = ScreenRect.Width() / 2; + int32 height = ScreenRect.Height(); + int32 x = InView.StereoViewIndex == EStereoscopicEye::eSSE_LEFT_EYE ? 0 : width; + int32 y = 0; + + DrawHmdViewMesh( + RHICmdList, + x, y, + width, height, + 0, 0, + TextureSize.X, TextureSize.Y, + FIntPoint(ScreenRect.Width(), ScreenRect.Height()), + TextureSize, + InView.StereoViewIndex, + VertexShader); + } + else + { + SCOPED_DRAW_EVENT(RHICmdList, RenderHardOcclusions_RenderThread); + + RendererModule->DrawRectangle( + RHICmdList, + 0, 0, + ScreenRect.Width(), ScreenRect.Height(), + 0, 0, + TextureSize.X, TextureSize.Y, + FIntPoint(ScreenRect.Width(), ScreenRect.Height()), + TextureSize, + VertexShader); + } + } + + FSettingsPtr FOculusXRHMD::CreateNewSettings() const + { + FSettingsPtr Result(MakeShareable(new FSettings())); + return Result; + } + + FGameFramePtr FOculusXRHMD::CreateNewGameFrame() const + { + FGameFramePtr Result(MakeShareable(new FGameFrame())); + Result->FrameNumber = NextFrameNumber; + Result->WindowSize = CachedWindowSize; + Result->WorldToMetersScale = CachedWorldToMetersScale; + Result->NearClippingPlane = GNearClippingPlane; + // Allow CVars to override the app's foveated rendering settings (set -1 to restore app's setting) + Result->FoveatedRenderingMethod = CVarOculusFoveatedRenderingMethod.GetValueOnAnyThread() >= 0 ? (EOculusXRFoveatedRenderingMethod)CVarOculusFoveatedRenderingMethod.GetValueOnAnyThread() : FoveatedRenderingMethod.load(); + Result->FoveatedRenderingLevel = CVarOculusFoveatedRenderingLevel.GetValueOnAnyThread() >= 0 ? (EOculusXRFoveatedRenderingLevel)CVarOculusFoveatedRenderingLevel.GetValueOnAnyThread() : FoveatedRenderingLevel.load(); + Result->bDynamicFoveatedRendering = CVarOculusDynamicFoveatedRendering.GetValueOnAnyThread() >= 0 ? (bool)CVarOculusDynamicFoveatedRendering.GetValueOnAnyThread() : bDynamicFoveatedRendering.load(); + Result->Flags.bSplashIsShown = Splash->IsShown(); + return Result; + } + + void FOculusXRHMD::StartGameFrame_GameThread() + { + CheckInGameThread(); + check(Settings.IsValid()); + + // TODO: Below check should NOT be limited to bMultiPlayer specificially even though we haven't found a non-MultiPlayer case falling into this case yet. + // Remove bMultiPlayer. + if (bMultiPlayer && !bShouldWait_GameThread) + { + return; + } + + if (!Frame.IsValid()) + { + Splash->UpdateLoadingScreen_GameThread(); //the result of this is used in CreateGameFrame to know if Frame is a "real" one or a "splash" one. + if (Settings->Flags.bHMDEnabled) + { + Frame = CreateNewGameFrame(); + NextFrameToRender = Frame; + + UE_LOG(LogHMD, VeryVerbose, TEXT("StartGameFrame %u"), Frame->FrameNumber); + + if (!Splash->IsShown()) + { + FThreadIdleStats::FScopeIdle Scope; + + if (FOculusXRHMDModule::GetPluginWrapper().GetInitialized() && WaitFrameNumber != Frame->FrameNumber) + { + SCOPED_NAMED_EVENT(WaitFrame, FColor::Red); + + UE_LOG(LogHMD, Verbose, TEXT("FOculusXRHMDModule::GetPluginWrapper().WaitToBeginFrame %u"), Frame->FrameNumber); + + ovrpResult Result; + if (OVRP_FAILURE(Result = FOculusXRHMDModule::GetPluginWrapper().WaitToBeginFrame(Frame->FrameNumber))) + { + UE_LOG(LogHMD, Error, TEXT("FOculusXRHMDModule::GetPluginWrapper().WaitToBeginFrame %u failed (%d)"), Frame->FrameNumber, Result); + } + else + { + WaitFrameNumber = Frame->FrameNumber; + bShouldWait_GameThread = false; + } + } + + FOculusXRHMDModule::GetPluginWrapper().Update3(ovrpStep_Render, Frame->FrameNumber, 0.0); + } + } + + UpdateStereoRenderingParams(); + } + } + + void FOculusXRHMD::FinishGameFrame_GameThread() + { + CheckInGameThread(); + + if (Frame.IsValid()) + { + UE_LOG(LogHMD, VeryVerbose, TEXT("FinishGameFrame %u"), Frame->FrameNumber); + } + + Frame.Reset(); + } + + void FOculusXRHMD::StartRenderFrame_GameThread() + { + CheckInGameThread(); + + if (NextFrameToRender.IsValid() && NextFrameToRender != LastFrameToRender) + { + UE_LOG(LogHMD, VeryVerbose, TEXT("StartRenderFrame %u"), NextFrameToRender->FrameNumber); + + LastFrameToRender = NextFrameToRender; + NextFrameToRender->Flags.bSplashIsShown = Splash->IsShown(); + + ovrpXrApi NativeXrApi; + FOculusXRHMDModule::GetPluginWrapper().GetNativeXrApiType(&NativeXrApi); + if ((NextFrameToRender->ShowFlags.Rendering || NativeXrApi == ovrpXrApi_OpenXR) && !NextFrameToRender->Flags.bSplashIsShown) + { + NextFrameNumber++; + } + + FSettingsPtr XSettings = Settings->Clone(); + FGameFramePtr XFrame = NextFrameToRender->Clone(); + TArray XLayers; + + XLayers.Empty(LayerMap.Num()); + + for (auto Pair : LayerMap) + { + XLayers.Emplace(Pair.Value->Clone()); + } + + XLayers.Sort(FLayerPtr_CompareId()); + + ExecuteOnRenderThread_DoNotWait([this, XSettings, XFrame, XLayers](FRHICommandListImmediate& RHICmdList) { + if (XFrame.IsValid()) + { + Settings_RenderThread = XSettings; + Frame_RenderThread = XFrame; + + int32 XLayerIndex = 0; + int32 LayerIndex_RenderThread = 0; + TArray ValidXLayers; + + while (XLayerIndex < XLayers.Num() && LayerIndex_RenderThread < Layers_RenderThread.Num()) + { + uint32 LayerIdA = XLayers[XLayerIndex]->GetId(); + uint32 LayerIdB = Layers_RenderThread[LayerIndex_RenderThread]->GetId(); + + if (LayerIdA < LayerIdB) + { + if (XLayers[XLayerIndex]->Initialize_RenderThread(Settings_RenderThread.Get(), CustomPresent, &DeferredDeletion, RHICmdList)) + { + ValidXLayers.Add(XLayers[XLayerIndex]); + } + XLayerIndex++; + } + else if (LayerIdA > LayerIdB) + { + DeferredDeletion.AddLayerToDeferredDeletionQueue(Layers_RenderThread[LayerIndex_RenderThread++]); + } + else + { + if (XLayers[XLayerIndex]->Initialize_RenderThread(Settings_RenderThread.Get(), CustomPresent, &DeferredDeletion, RHICmdList, Layers_RenderThread[LayerIndex_RenderThread].Get())) + { + LayerIndex_RenderThread++; + ValidXLayers.Add(XLayers[XLayerIndex]); + } + XLayerIndex++; + } + } + + while (XLayerIndex < XLayers.Num()) + { + if (XLayers[XLayerIndex]->Initialize_RenderThread(Settings_RenderThread.Get(), CustomPresent, &DeferredDeletion, RHICmdList)) + { + ValidXLayers.Add(XLayers[XLayerIndex]); + } + XLayerIndex++; + } + + while (LayerIndex_RenderThread < Layers_RenderThread.Num()) + { + DeferredDeletion.AddLayerToDeferredDeletionQueue(Layers_RenderThread[LayerIndex_RenderThread++]); + } + + Layers_RenderThread = ValidXLayers; + + DeferredDeletion.HandleLayerDeferredDeletionQueue_RenderThread(); + } + }); + } + } + + void FOculusXRHMD::FinishRenderFrame_RenderThread(FRDGBuilder& GraphBuilder) + { + CheckInRenderThread(); + + // TODO: Below check should NOT be limited to bMultiPlayer specificially even though we haven't found a non-MultiPlayer case falling into this case yet. + // Remove bMultiPlayer. + if (bMultiPlayer && !bIsRendering_RenderThread) + { //we must keep Frame_RenderThread alive if we haven't started to use it to render yet! + return; + } + + if (Frame_RenderThread.IsValid()) + { + UE_LOG(LogHMD, VeryVerbose, TEXT("FinishRenderFrame %u"), Frame_RenderThread->FrameNumber); + + AddPass(GraphBuilder, RDG_EVENT_NAME("FinishRenderFrame"), [this](FRHICommandListImmediate& RHICmdList) { + if (Frame_RenderThread->ShowFlags.Rendering) + { + for (int32 LayerIndex = 0; LayerIndex < Layers_RenderThread.Num(); LayerIndex++) + { + Layers_RenderThread[LayerIndex]->UpdateTexture_RenderThread(Settings_RenderThread.Get(), CustomPresent, RHICmdList); + Layers_RenderThread[LayerIndex]->UpdatePassthrough_RenderThread(CustomPresent, RHICmdList, Frame_RenderThread.Get()); + } + } + Frame_RenderThread.Reset(); + }); + } + + bIsRendering_RenderThread = false; + } + + void FOculusXRHMD::StartRHIFrame_RenderThread() + { + CheckInRenderThread(); + + if (Frame_RenderThread.IsValid()) + { + UE_LOG(LogHMD, VeryVerbose, TEXT("StartRHIFrame %u"), Frame_RenderThread->FrameNumber); + + FSettingsPtr XSettings = Settings_RenderThread->Clone(); + FGameFramePtr XFrame = Frame_RenderThread->Clone(); + TArray XLayers = Layers_RenderThread; + + for (int32 XLayerIndex = 0; XLayerIndex < XLayers.Num(); XLayerIndex++) + { + XLayers[XLayerIndex] = XLayers[XLayerIndex]->Clone(); + } + + ExecuteOnRHIThread_DoNotWait([this, XSettings, XFrame, XLayers]() { + if (XFrame.IsValid()) + { + Settings_RHIThread = XSettings; + Frame_RHIThread = XFrame; + Layers_RHIThread = XLayers; + + ovrpXrApi NativeXrApi; + FOculusXRHMDModule::GetPluginWrapper().GetNativeXrApiType(&NativeXrApi); + if ((Frame_RHIThread->ShowFlags.Rendering || NativeXrApi == ovrpXrApi_OpenXR) && !Frame_RHIThread->Flags.bSplashIsShown) + { + SCOPED_NAMED_EVENT(BeginFrame, FColor::Red); + + UE_LOG(LogHMD, Verbose, TEXT("FOculusXRHMDModule::GetPluginWrapper().BeginFrame4 %u"), Frame_RHIThread->FrameNumber); + + ovrpResult Result; + if (OVRP_FAILURE(Result = FOculusXRHMDModule::GetPluginWrapper().BeginFrame4(Frame_RHIThread->FrameNumber, CustomPresent->GetOvrpCommandQueue()))) + { + UE_LOG(LogHMD, Error, TEXT("FOculusXRHMDModule::GetPluginWrapper().BeginFrame4 %u failed (%d)"), Frame_RHIThread->FrameNumber, Result); + Frame_RHIThread->ShowFlags.Rendering = false; + } + else + { +#if PLATFORM_ANDROID + FOculusXRHMDModule::GetPluginWrapper().SetTiledMultiResLevel((ovrpTiledMultiResLevel)Frame_RHIThread->FoveatedRenderingLevel); + FOculusXRHMDModule::GetPluginWrapper().SetTiledMultiResDynamic(Frame_RHIThread->bDynamicFoveatedRendering ? ovrpBool_True : ovrpBool_False); +#ifdef WITH_OCULUS_BRANCH + // If we're using eye tracked foveated rendering, set that at the end of the render pass instead (through UpdateFoveationOffsets_RenderThread) + if (Frame_RHIThread->FoveatedRenderingMethod != EOculusXRFoveatedRenderingMethod::EyeTrackedFoveatedRendering) + { + FOculusXRHMDModule::GetPluginWrapper().SetFoveationEyeTracked(ovrpBool_False); + // Need to also not use offsets when turning off eye tracked foveated rendering + if (CustomPresent) + { + CustomPresent->UpdateFoveationOffsets_RHIThread(false, nullptr); + } + } +#endif // WITH_OCULUS_BRANCH +#endif // PLATFORM_ANDROID + } + } + } + }); + + // TODO: Add a hook to resolve discarded frames before we start a new frame. + // TODO: Below check should NOT be limited to bMultiPlayer specificially even though we haven't found a non-MultiPlayer case falling into this case yet. + // Remove bMultiPlayer. + UE_CLOG(bMultiPlayer && bIsRendering_RenderThread, LogHMD, Verbose, TEXT("Discarded previous frame and started rendering a new frame.")); + bIsRendering_RenderThread = true; + } + } + + void FOculusXRHMD::FinishRHIFrame_RHIThread() + { + CheckInRHIThread(); + + if (Frame_RHIThread.IsValid()) + { + UE_LOG(LogHMD, VeryVerbose, TEXT("FinishRHIFrame %u"), Frame_RHIThread->FrameNumber); + + ovrpXrApi NativeXrApi; + FOculusXRHMDModule::GetPluginWrapper().GetNativeXrApiType(&NativeXrApi); + if ((Frame_RHIThread->ShowFlags.Rendering || NativeXrApi == ovrpXrApi_OpenXR) && !Frame_RHIThread->Flags.bSplashIsShown) + { + SCOPED_NAMED_EVENT(EndFrame, FColor::Red); + + TArray Layers = Layers_RHIThread; + Layers.Sort(FLayerPtr_CompareTotal()); + TArray LayerSubmitPtr; + + int32 LayerNum = Layers.Num(); + + LayerSubmitPtr.SetNum(LayerNum); + + int32 FinalLayerNumber = 0; + for (int32 LayerIndex = 0; LayerIndex < LayerNum; LayerIndex++) + { + if (Layers[LayerIndex]->IsVisible()) + { + LayerSubmitPtr[FinalLayerNumber++] = Layers[LayerIndex]->UpdateLayer_RHIThread(Settings_RHIThread.Get(), Frame_RHIThread.Get(), LayerIndex); + } + } + + UE_LOG(LogHMD, Verbose, TEXT("FOculusXRHMDModule::GetPluginWrapper().EndFrame4 %u"), Frame_RHIThread->FrameNumber); + FOculusXRHMDModule::GetPluginWrapper().SetEyeFovPremultipliedAlphaMode(false); + + ovrpResult Result; + if (OVRP_FAILURE(Result = FOculusXRHMDModule::GetPluginWrapper().EndFrame4(Frame_RHIThread->FrameNumber, LayerSubmitPtr.GetData(), FinalLayerNumber, CustomPresent->GetOvrpCommandQueue()))) + { + UE_LOG(LogHMD, Error, TEXT("FOculusXRHMDModule::GetPluginWrapper().EndFrame4 %u failed (%d)"), Frame_RHIThread->FrameNumber, Result); + } + else + { + for (int32 LayerIndex = 0; LayerIndex < Layers.Num(); LayerIndex++) + { + Layers[LayerIndex]->IncrementSwapChainIndex_RHIThread(CustomPresent); + } + } + } + } + + Frame_RHIThread.Reset(); + } + + void FOculusXRHMD::AddEventPollingDelegate(const FOculusXRHMDEventPollingDelegate& NewDelegate) + { + EventPollingDelegates.Add(NewDelegate); + } + + /// @cond DOXYGEN_WARNINGS + +#define BOOLEAN_COMMAND_HANDLER_BODY(ConsoleName, FieldExpr) \ + do \ + { \ + if (Args.Num()) \ + { \ + if (Args[0].Equals(TEXT("toggle"), ESearchCase::IgnoreCase)) \ + { \ + (FieldExpr) = !(FieldExpr); \ + } \ + else \ + { \ + (FieldExpr) = FCString::ToBool(*Args[0]); \ + } \ + } \ + Ar.Logf(ConsoleName TEXT(" = %s"), (FieldExpr) ? TEXT("On") : TEXT("Off")); \ + } \ + while (false) + + void FOculusXRHMD::UpdateOnRenderThreadCommandHandler(const TArray& Args, UWorld* World, FOutputDevice& Ar) + { + CheckInGameThread(); + + BOOLEAN_COMMAND_HANDLER_BODY(TEXT("vr.oculus.bUpdateOnRenderThread"), Settings->Flags.bUpdateOnRT); + } + + void FOculusXRHMD::PixelDensityMinCommandHandler(const TArray& Args, UWorld*, FOutputDevice& Ar) + { + CheckInGameThread(); + + if (Args.Num()) + { + Settings->SetPixelDensityMin(FCString::Atof(*Args[0])); + } + Ar.Logf(TEXT("vr.oculus.PixelDensity.min = \"%1.2f\""), Settings->PixelDensityMin); + } + + void FOculusXRHMD::PixelDensityMaxCommandHandler(const TArray& Args, UWorld*, FOutputDevice& Ar) + { + CheckInGameThread(); + + if (Args.Num()) + { + Settings->SetPixelDensityMax(FCString::Atof(*Args[0])); + } + Ar.Logf(TEXT("vr.oculus.PixelDensity.max = \"%1.2f\""), Settings->PixelDensityMax); + } + + void FOculusXRHMD::HQBufferCommandHandler(const TArray& Args, UWorld*, FOutputDevice& Ar) + { + CheckInGameThread(); + + BOOLEAN_COMMAND_HANDLER_BODY(TEXT("vr.oculus.bHQBuffer"), Settings->Flags.bHQBuffer); + } + + void FOculusXRHMD::HQDistortionCommandHandler(const TArray& Args, UWorld*, FOutputDevice& Ar) + { + CheckInGameThread(); + + BOOLEAN_COMMAND_HANDLER_BODY(TEXT("vr.oculus.bHQDistortion"), Settings->Flags.bHQDistortion); + } + + void FOculusXRHMD::ShowGlobalMenuCommandHandler(const TArray& Args, UWorld* World, FOutputDevice& Ar) + { + CheckInGameThread(); + + if (OVRP_FAILURE(FOculusXRHMDModule::GetPluginWrapper().ShowSystemUI2(ovrpUI::ovrpUI_GlobalMenu))) + { + Ar.Logf(TEXT("Could not show platform menu")); + } + } + + void FOculusXRHMD::ShowQuitMenuCommandHandler(const TArray& Args, UWorld* World, FOutputDevice& Ar) + { + CheckInGameThread(); + + if (OVRP_FAILURE(FOculusXRHMDModule::GetPluginWrapper().ShowSystemUI2(ovrpUI::ovrpUI_ConfirmQuit))) + { + Ar.Logf(TEXT("Could not show platform menu")); + } + } + +#if !UE_BUILD_SHIPPING + void FOculusXRHMD::StatsCommandHandler(const TArray& Args, UWorld*, FOutputDevice& Ar) + { + CheckInGameThread(); + + BOOLEAN_COMMAND_HANDLER_BODY(TEXT("vr.oculus.Debug.bShowStats"), Settings->Flags.bShowStats); + } + + void FOculusXRHMD::ShowSettingsCommandHandler(const TArray& Args, UWorld* World, FOutputDevice& Ar) + { + Ar.Logf(TEXT("stereo ipd=%.4f\n nearPlane=%.4f"), GetInterpupillaryDistance(), GNearClippingPlane); + } + + void FOculusXRHMD::IPDCommandHandler(const TArray& Args, UWorld* World, FOutputDevice& Ar) + { + if (Args.Num() > 0) + { + SetInterpupillaryDistance(FCString::Atof(*Args[0])); + } + Ar.Logf(TEXT("vr.oculus.Debug.IPD = %f"), GetInterpupillaryDistance()); + } + +#endif // !UE_BUILD_SHIPPING + + void FOculusXRHMD::LoadFromSettings() + { + UOculusXRHMDRuntimeSettings* HMDSettings = GetMutableDefault(); + check(HMDSettings); + + Settings->Flags.bSupportsDash = HMDSettings->bSupportsDash; +#if PLATFORM_ANDROID + Settings->Flags.bCompositeDepth = HMDSettings->bCompositeDepthMobile; +#else + Settings->Flags.bCompositeDepth = HMDSettings->bCompositesDepth; +#endif + Settings->Flags.bHQDistortion = HMDSettings->bHQDistortion; + Settings->Flags.bInsightPassthroughEnabled = HMDSettings->bInsightPassthroughEnabled; +#ifdef WITH_OCULUS_BRANCH + Settings->Flags.bPixelDensityAdaptive = HMDSettings->bDynamicResolution; +#endif + Settings->SuggestedCpuPerfLevel = HMDSettings->SuggestedCpuPerfLevel; + Settings->SuggestedGpuPerfLevel = HMDSettings->SuggestedGpuPerfLevel; + Settings->FoveatedRenderingMethod = HMDSettings->FoveatedRenderingMethod; + Settings->FoveatedRenderingLevel = HMDSettings->FoveatedRenderingLevel; + Settings->bDynamicFoveatedRendering = HMDSettings->bDynamicFoveatedRendering; + Settings->PixelDensityMin = HMDSettings->PixelDensityMin; + Settings->PixelDensityMax = HMDSettings->PixelDensityMax; + Settings->ColorSpace = HMDSettings->ColorSpace; + Settings->ControllerPoseAlignment = HMDSettings->ControllerPoseAlignment; + Settings->bLateLatching = HMDSettings->bLateLatching; + Settings->XrApi = HMDSettings->XrApi; + Settings->bSupportExperimentalFeatures = HMDSettings->bSupportExperimentalFeatures; + Settings->bSupportEyeTrackedFoveatedRendering = HMDSettings->bSupportEyeTrackedFoveatedRendering; + Settings->SystemSplashBackground = HMDSettings->SystemSplashBackground; + + + Settings->FaceTrackingDataSource.Empty(ovrpFaceConstants_FaceTrackingDataSourcesCount); + Settings->FaceTrackingDataSource.Append(HMDSettings->FaceTrackingDataSource); + } + + void FOculusXRHMD::CheckMultiPlayer() + { +#if WITH_EDITOR && PLATFORM_WINDOWS + ULevelEditorPlaySettings* PlayInSettings = GetMutableDefault(); + check(PlayInSettings); + int PlayNumberOfClients = 0; + PlayInSettings->GetPlayNumberOfClients(PlayNumberOfClients); + bMultiPlayer = PlayNumberOfClients > 1; +#endif + } + + /// @endcond + +} // namespace OculusXRHMD + +#endif //OCULUS_HMD_SUPPORTED_PLATFORMS diff --git a/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD.h b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD.h new file mode 100644 index 0000000..5c22aaa --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD.h @@ -0,0 +1,637 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +#pragma once +#include "OculusXRHMDModule.h" + +#if OCULUS_HMD_SUPPORTED_PLATFORMS +#include "OculusXRHMD_Settings.h" +#include "OculusXRHMD_GameFrame.h" +#include "OculusXRHMD_CustomPresent.h" +#include "OculusXRHMD_Layer.h" +#include "OculusXRHMD_Splash.h" +#include "OculusXRHMD_StressTester.h" +#include "OculusXRHMD_ConsoleCommands.h" +#include "OculusXRHMD_SpectatorScreenController.h" +#include "OculusXRHMD_DynamicResolutionState.h" +#include "OculusXRHMD_DeferredDeletionQueue.h" + +#include "OculusXRAssetManager.h" + +#include "HeadMountedDisplayBase.h" +#include "HeadMountedDisplay.h" +#include "XRRenderTargetManager.h" +#include "XRRenderBridge.h" +#include "IStereoLayers.h" +#include "Stats/Stats.h" +#include "SceneViewExtension.h" +#include "Engine/Engine.h" +#include "Engine/StaticMeshActor.h" +#include "XRThreadUtils.h" +#include "ProceduralMeshComponent.h" +#include "Shader.h" +#include "Misc/EngineVersionComparison.h" +#include "OculusXRHMD_FoveatedRendering.h" + +namespace OculusXRHMD +{ + + DECLARE_DELEGATE_TwoParams(FOculusXRHMDEventPollingDelegate, ovrpEventDataBuffer*, bool&); + + //------------------------------------------------------------------------------------------------- + // FPerformanceStats + //------------------------------------------------------------------------------------------------- + + struct FPerformanceStats + { + uint64 Frames; + double Seconds; + + FPerformanceStats(uint32 InFrames = 0, double InSeconds = 0.0) + : Frames(InFrames) + , Seconds(InSeconds) + { + } + + FPerformanceStats operator-(const FPerformanceStats& PerformanceStats) const + { + return FPerformanceStats( + Frames - PerformanceStats.Frames, + Seconds - PerformanceStats.Seconds); + } + }; + + enum FRecenterTypes + { + RecenterOrientation = 0x1, + RecenterPosition = 0x2, + RecenterOrientationAndPosition = 0x3 + }; + + //------------------------------------------------------------------------------------------------- + // FOculusXRHMD - Oculus Rift Head Mounted Display + //------------------------------------------------------------------------------------------------- + + class FOculusXRHMD : public FHeadMountedDisplayBase, public FXRRenderTargetManager, public IStereoLayers, public FHMDSceneViewExtension, public FOculusAssetManager + { + friend class UOculusXRFunctionLibrary; + friend FOculusXRHMDModule; + friend class FSplash; + friend class FConsoleCommands; + + public: + OCULUSXRHMD_API static const FName OculusSystemName; + // IXRSystemIdentifier + virtual FName GetSystemName() const override; + virtual int32 GetXRSystemFlags() const override; + + // IXRTrackingSystem + virtual FString GetVersionString() const override; + virtual bool DoesSupportPositionalTracking() const override; + virtual bool HasValidTrackingPosition() override; + virtual bool EnumerateTrackedDevices(TArray& OutDevices, EXRTrackedDeviceType Type = EXRTrackedDeviceType::Any) override; + virtual bool GetCurrentPose(int32 InDeviceId, FQuat& OutOrientation, FVector& OutPosition) override; + virtual bool GetRelativeEyePose(int32 InDeviceId, int32 ViewIndex, FQuat& OutOrientation, FVector& OutPosition) override; + virtual bool GetTrackingSensorProperties(int32 InDeviceId, FQuat& OutOrientation, FVector& OutPosition, FXRSensorProperties& OutSensorProperties) override; + virtual void SetTrackingOrigin(EHMDTrackingOrigin::Type NewOrigin) override; + virtual EHMDTrackingOrigin::Type GetTrackingOrigin() const override; + virtual bool GetFloorToEyeTrackingTransform(FTransform& OutFloorToEye) const override; + //virtual FVector GetAudioListenerOffset(int32 InDeviceId = HMDDeviceId) const override; + virtual void ResetOrientationAndPosition(float Yaw = 0.f) override; + virtual void ResetOrientation(float Yaw = 0.f) override; + virtual void ResetPosition() override; + virtual void SetBaseRotation(const FRotator& BaseRot) override; + virtual FRotator GetBaseRotation() const override; + virtual void SetBaseOrientation(const FQuat& BaseOrient) override; + virtual FQuat GetBaseOrientation() const override; + //virtual TSharedPtr GetXRCamera(int32 DeviceId = HMDDeviceId) override; + virtual class IHeadMountedDisplay* GetHMDDevice() override { return this; } + virtual class TSharedPtr GetStereoRenderingDevice() override + { + return SharedThis(this); + } + //virtual class IXRInput* GetXRInput() override; + virtual bool + IsHeadTrackingEnforced() const override; + virtual void SetHeadTrackingEnforced(bool bEnabled) override; + virtual bool IsHeadTrackingAllowed() const override; + virtual void OnBeginPlay(FWorldContext& InWorldContext) override; + virtual void OnEndPlay(FWorldContext& InWorldContext) override; + virtual bool OnStartGameFrame(FWorldContext& WorldContext) override; + virtual bool OnEndGameFrame(FWorldContext& WorldContext) override; + virtual void OnBeginRendering_RenderThread(FRHICommandListImmediate& RHICmdList, FSceneViewFamily& ViewFamily) override; + virtual void OnBeginRendering_GameThread() override; + virtual class IXRLoadingScreen* CreateLoadingScreen() override { return GetSplash(); } + virtual FVector2D GetPlayAreaBounds(EHMDTrackingOrigin::Type Origin) const override; + + // IHeadMountedDisplay + virtual bool IsHMDConnected() override { return true; } + virtual bool IsHMDEnabled() const override; + virtual EHMDWornState::Type GetHMDWornState() override; + virtual void EnableHMD(bool bEnable = true) override; + virtual bool GetHMDMonitorInfo(MonitorInfo&) override; + virtual void GetFieldOfView(float& InOutHFOVInDegrees, float& InOutVFOVInDegrees) const override; + virtual void SetInterpupillaryDistance(float NewInterpupillaryDistance) override; + virtual float GetInterpupillaryDistance() const override; + //virtual void SetClippingPlanes(float NCP, float FCP) override; + //virtual FVector GetAudioListenerOffset() const override; + virtual bool GetHMDDistortionEnabled(EShadingPath ShadingPath) const override; + //virtual void BeginRendering_RenderThread(const FTransform& NewRelativeTransform, FRHICommandListImmediate& RHICmdList, FSceneViewFamily& ViewFamily) override; + //virtual bool IsSpectatorScreenActive() const override; + //virtual class ISpectatorScreenController* GetSpectatorScreenController() override; + //virtual class ISpectatorScreenController const* GetSpectatorScreenController() const override; + //virtual float GetDistortionScalingFactor() const override; + //virtual float GetLensCenterOffset() const override; + //virtual void GetDistortionWarpValues(FVector4& K) const override; + virtual bool IsChromaAbCorrectionEnabled() const override; + //virtual bool GetChromaAbCorrectionValues(FVector4& K) const override; + virtual bool HasHiddenAreaMesh() const override; + virtual bool HasVisibleAreaMesh() const override; + virtual void DrawHiddenAreaMesh(class FRHICommandList& RHICmdList, int32 ViewIndex) const override; + virtual void DrawVisibleAreaMesh(class FRHICommandList& RHICmdList, int32 ViewIndex) const override; + //virtual void DrawDistortionMesh_RenderThread(struct FHeadMountedDisplayPassContext& Context, const FIntPoint& TextureSize) override; + //virtual void UpdateScreenSettings(const FViewport* InViewport) override; + //virtual void UpdatePostProcessSettings(FPostProcessSettings*) override; + //virtual FTexture* GetDistortionTextureLeft() const override; + //virtual FTexture* GetDistortionTextureRight() const override; + //virtual FVector2D GetTextureOffsetLeft() const override; + //virtual FVector2D GetTextureOffsetRight() const override; + //virtual FVector2D GetTextureScaleLeft() const override; + //virtual FVector2D GetTextureScaleRight() const override; + //virtual const float* GetRedDistortionParameters() const override; + //virtual const float* GetGreenDistortionParameters() const override; + //virtual const float* GetBlueDistortionParameters() const override; + //virtual bool NeedsUpscalePostProcessPass() override; + //virtual void RecordAnalytics() override; + //virtual bool DoesAppUseVRFocus() const override; + //virtual bool DoesAppHaveVRFocus() const override; + virtual float GetPixelDenity() const override; + virtual void SetPixelDensity(const float NewPixelDensity) override; + virtual FIntPoint GetIdealRenderTargetSize() const override; + virtual void GetMotionControllerData(UObject* WorldContext, const EControllerHand Hand, FXRMotionControllerData& MotionControllerData) override; + + // IStereoRendering interface + virtual bool IsStereoEnabled() const override; + virtual bool IsStereoEnabledOnNextFrame() const override; + virtual bool EnableStereo(bool stereo = true) override; + virtual void AdjustViewRect(int32 ViewIndex, int32& X, int32& Y, uint32& SizeX, uint32& SizeY) const override; + virtual void SetFinalViewRect(FRHICommandListImmediate& RHICmdList, const int32 ViewIndex, const FIntRect& FinalViewRect) override; + //virtual FVector2D GetTextSafeRegionBounds() const override; + virtual void CalculateStereoViewOffset(const int32 ViewIndex, FRotator& ViewRotation, const float WorldToMeters, FVector& ViewLocation) override; + virtual FMatrix GetStereoProjectionMatrix(const int32 ViewIndex) const override; + virtual void InitCanvasFromView(class FSceneView* InView, class UCanvas* Canvas) override; + //virtual void GetEyeRenderParams_RenderThread(const struct FRenderingCompositePassContext& Context, FVector2D& EyeToSrcUVScaleValue, FVector2D& EyeToSrcUVOffsetValue) const override; + virtual void RenderTexture_RenderThread(class FRHICommandListImmediate& RHICmdList, class FRHITexture* BackBuffer, class FRHITexture* SrcTexture, FVector2D WindowSize) const override; + //virtual void SetClippingPlanes(float NCP, float FCP) override; + virtual IStereoRenderTargetManager* GetRenderTargetManager() override { return this; } + virtual IStereoLayers* GetStereoLayers() override { return this; } + //virtual void UseImplicitHmdPosition(bool bInImplicitHmdPosition) override; + //virtual bool GetUseImplicitHmdPosition() override; + virtual bool IsStandaloneStereoOnlyDevice() const override { return bIsStandaloneStereoOnlyDevice; } + bool SupportsSpaceWarp() const; +#ifdef WITH_OCULUS_BRANCH + virtual void CalculateScissorRect(const int32 ViewIndex, const FIntRect& ViewRect, FIntRect& OutRect) override; +#endif // WITH_OCULUS_BRANCH + + // FHeadMountedDisplayBase interface + virtual FVector2D GetEyeCenterPoint_RenderThread(int32 ViewIndex) const override; + virtual FIntRect GetFullFlatEyeRect_RenderThread(FTexture2DRHIRef EyeTexture) const override; + virtual void CopyTexture_RenderThread(FRHICommandListImmediate& RHICmdList, FRHITexture2D* SrcTexture, FIntRect SrcRect, FRHITexture2D* DstTexture, FIntRect DstRect, bool bClearBlack, bool bNoAlpha) const override; + virtual bool PopulateAnalyticsAttributes(TArray& EventAttributes) override; + + // FXRRenderTargetManager interface + virtual bool ShouldUseSeparateRenderTarget() const override; + virtual void CalculateRenderTargetSize(const FViewport& Viewport, uint32& InOutSizeX, uint32& InOutSizeY) override; + virtual bool NeedReAllocateViewportRenderTarget(const class FViewport& Viewport) override; + virtual bool NeedReAllocateDepthTexture(const TRefCountPtr& DepthTarget) override; + virtual bool NeedReAllocateShadingRateTexture(const TRefCountPtr& FoveationTarget) override; +#ifdef WITH_OCULUS_BRANCH + virtual bool NeedReAllocateMotionVectorTexture(const TRefCountPtr& MotionVectorTarget, const TRefCountPtr& MotionVectorDepthTarget) override; +#endif // WITH_OCULUS_BRANCH + virtual bool AllocateRenderTargetTexture(uint32 Index, uint32 SizeX, uint32 SizeY, uint8 Format, uint32 NumMips, ETextureCreateFlags InTexFlags, ETextureCreateFlags InTargetableTextureFlags, FTexture2DRHIRef& OutTargetableTexture, FTexture2DRHIRef& OutShaderResourceTexture, uint32 NumSamples = 1) override; + virtual bool AllocateDepthTexture(uint32 Index, uint32 SizeX, uint32 SizeY, uint8 Format, uint32 NumMips, ETextureCreateFlags InTexFlags, ETextureCreateFlags TargetableTextureFlags, FTexture2DRHIRef& OutTargetableTexture, FTexture2DRHIRef& OutShaderResourceTexture, uint32 NumSamples = 1) override; + virtual bool AllocateShadingRateTexture(uint32 Index, uint32 RenderSizeX, uint32 RenderSizeY, uint8 Format, uint32 NumMips, ETextureCreateFlags InTexFlags, ETextureCreateFlags InTargetableTextureFlags, FTexture2DRHIRef& OutTexture, FIntPoint& OutTextureSize) override; +#ifdef WITH_OCULUS_BRANCH + virtual bool AllocateMotionVectorTexture(uint32 Index, uint8 Format, uint32 NumMips, ETextureCreateFlags InTexFlags, ETextureCreateFlags InTargetableTextureFlags, FTexture2DRHIRef& OutTexture, FIntPoint& OutTextureSize, FTexture2DRHIRef& OutDepthTexture, FIntPoint& OutDepthTextureSize) override; + virtual bool FindEnvironmentDepthTexture_RenderThread(FTextureRHIRef& OutTexture, FVector2f& OutDepthFactors, FMatrix44f OutScreenToDepthMatrices[2], FMatrix44f OutDepthViewProjMatrices[2]) override; +#endif // WITH_OCULUS_BRANCH + virtual EPixelFormat GetActualColorSwapchainFormat() const override; + + virtual void UpdateViewportWidget(bool bUseSeparateRenderTarget, const class FViewport& Viewport, class SViewport* ViewportWidget) override; + virtual FXRRenderBridge* GetActiveRenderBridge_GameThread(bool bUseSeparateRenderTarget); + void AllocateEyeBuffer(); + + // IStereoLayers interface + virtual uint32 CreateLayer(const IStereoLayers::FLayerDesc& InLayerDesc) override; + virtual void DestroyLayer(uint32 LayerId) override; + virtual void SetLayerDesc(uint32 LayerId, const IStereoLayers::FLayerDesc& InLayerDesc) override; + virtual bool GetLayerDesc(uint32 LayerId, IStereoLayers::FLayerDesc& OutLayerDesc) override; + virtual void MarkTextureForUpdate(uint32 LayerId) override; + virtual IStereoLayers::FLayerDesc GetDebugCanvasLayerDesc(FTextureRHIRef Texture) override; + virtual void GetAllocatedTexture(uint32 LayerId, FTextureRHIRef& Texture, FTextureRHIRef& LeftTexture) override; + virtual bool ShouldCopyDebugLayersToSpectatorScreen() const override { return true; } + virtual void PushLayerState(bool) override + { /* Todo */ + } + virtual void PopLayerState() override + { /* Todo */ + } + + // ISceneViewExtension + virtual void SetupViewFamily(FSceneViewFamily& InViewFamily) override; + virtual void SetupView(FSceneViewFamily& InViewFamily, FSceneView& InView) override; + virtual void BeginRenderViewFamily(FSceneViewFamily& InViewFamily) override; + virtual void PreRenderViewFamily_RenderThread(FRDGBuilder& GraphBuilder, FSceneViewFamily& InViewFamily) override; + virtual void PreRenderView_RenderThread(FRDGBuilder& GraphBuilder, FSceneView& InView) override; + virtual void PostRenderViewFamily_RenderThread(FRDGBuilder& GraphBuilder, FSceneViewFamily& InViewFamily) override; +#if UE_VERSION_OLDER_THAN(5, 3, 0) + virtual void PostRenderBasePassMobile_RenderThread(FRHICommandListImmediate& RHICmdList, FSceneView& InView) override; +#ifdef WITH_OCULUS_BRANCH + virtual void PostSceneColorRenderingMobile_RenderThread(FRHICommandListImmediate& RHICmdList, FSceneView& InView) override; +#endif +#else + virtual void PostRenderBasePassMobile_RenderThread(FRHICommandList& RHICmdList, FSceneView& InView) override; +#ifdef WITH_OCULUS_BRANCH + virtual void PostSceneColorRenderingMobile_RenderThread(FRHICommandList& RHICmdList, FSceneView& InView) override; +#endif +#endif + virtual void PostRenderBasePassDeferred_RenderThread(FRDGBuilder& GraphBuilder, FSceneView& InView, const FRenderTargetBindingSlots& RenderTargets, TRDGUniformBufferRef SceneTextures) override; + virtual int32 GetPriority() const override; +#ifdef WITH_OCULUS_BRANCH + virtual bool LateLatchingEnabled() const override; + virtual void PreLateLatchingViewFamily_RenderThread(FRHICommandListImmediate& RHICmdList, FSceneViewFamily& InViewFamily) override; +#endif + + public: + FOculusXRHMD(const FAutoRegister&); + ~FOculusXRHMD(); + + protected: + bool Startup(); + void PreShutdown(); + void Shutdown(); + bool InitializeSession(); + void ShutdownSession(); + bool InitDevice(); + void ReleaseDevice(); + void ApplicationPauseDelegate(); + void ApplicationResumeDelegate(); + bool CheckEyeTrackingPermission(EOculusXRFoveatedRenderingMethod FoveatedRenderingMethod); + void SetupOcclusionMeshes(); + void UpdateStereoRenderingParams(); + void UpdateHmdRenderInfo(); + void InitializeEyeLayer_RenderThread(FRHICommandListImmediate& RHICmdList); + void ApplySystemOverridesOnStereo(bool force = false); + bool OnOculusStateChange(bool bIsEnabledNow); + bool ShouldDisableHiddenAndVisibileAreaMeshForSpectatorScreen_RenderThread() const; + void Recenter(FRecenterTypes RecenterType, float Yaw); + FIntRect GetAsymmetricViewRect(const int32 ViewIndex, const FIntRect& ViewRect); +#if !UE_BUILD_SHIPPING + void DrawDebug(UCanvas* InCanvas, APlayerController* InPlayerController); +#endif + + class FSceneViewport* FindSceneViewport(); + FOculusXRSplashDesc GetUESplashScreenDesc(); + void EyeTrackedFoveatedRenderingFallback(); + + public: + OCULUSXRHMD_API static FOculusXRHMD* GetOculusXRHMD(); + + bool IsHMDActive() const; + + FSplash* GetSplash() const { return Splash.Get(); } + FCustomPresent* GetCustomPresent_Internal() const { return CustomPresent; } + + float GetWorldToMetersScale() const; + + ESpectatorScreenMode GetSpectatorScreenMode_RenderThread() const; + + FVector GetNeckPosition(const FQuat& HeadOrientation, const FVector& HeadPosition); + + /** + * Sets base position offset (in meters). The base position offset is the distance from the physical (0, 0, 0) position + * to current HMD position (bringing the (0, 0, 0) point to the current HMD position) + * Note, this vector is set by ResetPosition call; use this method with care. + * The axis of the vector are the same as in Unreal: X - forward, Y - right, Z - up. + * + * @param BaseOffset (in) the vector to be set as base offset, in meters. + */ + void SetBaseOffsetInMeters(const FVector& BaseOffset); + + /** + * Returns the currently used base position offset, previously set by the + * ResetPosition or SetBasePositionOffset calls. It represents a vector that translates the HMD's position + * into (0,0,0) point, in meters. + * The axis of the vector are the same as in Unreal: X - forward, Y - right, Z - up. + * + * @return Base position offset, in meters. + */ + FVector GetBaseOffsetInMeters() const; + + OCULUSXRHMD_API bool ConvertPose(const ovrpPosef& InPose, FPose& OutPose) const; + OCULUSXRHMD_API bool ConvertPose(const FPose& InPose, ovrpPosef& OutPose) const; + OCULUSXRHMD_API bool ConvertPose_RenderThread(const ovrpPosef& InPose, FPose& OutPose) const; + OCULUSXRHMD_API static bool ConvertPose_Internal(const ovrpPosef& InPose, FPose& OutPose, const FSettings* Settings, float WorldToMetersScale = 100.0f); + OCULUSXRHMD_API static bool ConvertPose_Internal(const FPose& InPose, ovrpPosef& OutPose, const FSettings* Settings, float WorldToMetersScale = 100.0f); + + /** Turns ovrVector3f in Unreal World space to a scaled FVector and applies translation and rotation corresponding to player movement */ + FVector ScaleAndMovePointWithPlayer(ovrpVector3f& OculusXRHMDPoint); + + /** The inverse of ScaleAndMovePointWithPlayer */ + ovrpVector3f WorldLocationToOculusPoint(const FVector& InUnrealPosition); + + /** Convert dimension of a float (e.g., a distance) from meters to Unreal Units */ + float ConvertFloat_M2U(float OculusFloat) const; + FVector ConvertVector_M2U(ovrpVector3f OculusPoint) const; + + struct UserProfile + { + float IPD; + float EyeDepth; + float EyeHeight; + }; + + bool GetUserProfile(UserProfile& OutProfile); + float GetVsyncToNextVsync() const; + FPerformanceStats GetPerformanceStats() const; + bool DoEnableStereo(bool bStereo); + void ResetControlRotation() const; + void UpdateFoveationOffsets_RenderThread(); + bool ComputeEnvironmentDepthParameters_RenderThread(FVector2f& DepthFactors, FMatrix44f ScreenToDepth[ovrpEye_Count], FMatrix44f DepthViewProj[ovrpEye_Count], int& SwapchainIndex); +#if UE_VERSION_OLDER_THAN(5, 3, 0) + void RenderHardOcclusions_RenderThread(FRHICommandListImmediate& RHICmdList, const FSceneView& InView); +#else + void RenderHardOcclusions_RenderThread(FRHICommandList& RHICmdList, const FSceneView& InView); +#endif + + FSettingsPtr CreateNewSettings() const; + FGameFramePtr CreateNewGameFrame() const; + + FGameFrame* GetFrame() + { + CheckInGameThread(); + return Frame.Get(); + } + const FGameFrame* GetFrame() const + { + CheckInGameThread(); + return Frame.Get(); + } + FGameFrame* GetFrame_RenderThread() + { + CheckInRenderThread(); + return Frame_RenderThread.Get(); + } + const FGameFrame* GetFrame_RenderThread() const + { + CheckInRenderThread(); + return Frame_RenderThread.Get(); + } + FGameFrame* GetFrame_RHIThread() + { + CheckInRHIThread(); + return Frame_RHIThread.Get(); + } + const FGameFrame* GetFrame_RHIThread() const + { + CheckInRHIThread(); + return Frame_RHIThread.Get(); + } + FGameFrame* GetNextFrameToRender() + { + CheckInGameThread(); + return NextFrameToRender.Get(); + } + const FGameFrame* GetNextFrameToRender() const + { + CheckInGameThread(); + return NextFrameToRender.Get(); + } + + FSettings* GetSettings() + { + CheckInGameThread(); + return Settings.Get(); + } + const FSettings* GetSettings() const + { + CheckInGameThread(); + return Settings.Get(); + } + FSettings* GetSettings_RenderThread() + { + CheckInRenderThread(); + return Settings_RenderThread.Get(); + } + const FSettings* GetSettings_RenderThread() const + { + CheckInRenderThread(); + return Settings_RenderThread.Get(); + } + FSettings* GetSettings_RHIThread() + { + CheckInRHIThread(); + return Settings_RHIThread.Get(); + } + const FSettings* GetSettings_RHIThread() const + { + CheckInRHIThread(); + return Settings_RHIThread.Get(); + } + + const int GetNextFrameNumber() const { return NextFrameNumber; } + + const FRotator GetSplashRotation() const { return SplashRotation; } + void SetSplashRotationToForward(); + + OCULUSXRHMD_API void StartGameFrame_GameThread(); // Called from OnStartGameFrame or from FOculusXRInput::SendControllerEvents (first actual call of the frame) + void FinishGameFrame_GameThread(); // Called from OnEndGameFrame + void StartRenderFrame_GameThread(); // Called from BeginRenderViewFamily + void FinishRenderFrame_RenderThread(FRDGBuilder& GraphBuilder); // Called from PostRenderViewFamily_RenderThread + void StartRHIFrame_RenderThread(); // Called from PreRenderViewFamily_RenderThread + void FinishRHIFrame_RHIThread(); // Called from FinishRendering_RHIThread + + void GetSuggestedCpuAndGpuPerformanceLevels(EOculusXRProcessorPerformanceLevel& CpuPerfLevel, EOculusXRProcessorPerformanceLevel& GpuPerfLevel); + void SetSuggestedCpuAndGpuPerformanceLevels(EOculusXRProcessorPerformanceLevel CpuPerfLevel, EOculusXRProcessorPerformanceLevel GpuPerfLevel); + void SetFoveatedRenderingMethod(EOculusXRFoveatedRenderingMethod InFoveationMethod); + void SetFoveatedRenderingLevel(EOculusXRFoveatedRenderingLevel InFoveationLevel, bool isDynamic); + void SetColorScaleAndOffset(FLinearColor ColorScale, FLinearColor ColorOffset, bool bApplyToAllLayers); + void SetEnvironmentDepthHandRemoval(bool RemoveHands); + void StartEnvironmentDepth(int CreateFlags); + void StopEnvironmentDepth(); + bool IsEnvironmentDepthStarted(); + + void EnableHardOcclusions(bool bEnable); + + OCULUSXRHMD_API void UpdateRTPoses(); + + FTransform GetLastTrackingToWorld() const { return LastTrackingToWorld; } + OCULUSXRHMD_API void AddEventPollingDelegate(const FOculusXRHMDEventPollingDelegate& NewDelegate); + + protected: + FConsoleCommands ConsoleCommands; + void UpdateOnRenderThreadCommandHandler(const TArray& Args, UWorld* World, FOutputDevice& Ar); + void PixelDensityMinCommandHandler(const TArray& Args, UWorld* World, FOutputDevice& Ar); + void PixelDensityMaxCommandHandler(const TArray& Args, UWorld* World, FOutputDevice& Ar); + void HQBufferCommandHandler(const TArray& Args, UWorld*, FOutputDevice& Ar); + void HQDistortionCommandHandler(const TArray& Args, UWorld*, FOutputDevice& Ar); + void ShowGlobalMenuCommandHandler(const TArray& Args, UWorld* World, FOutputDevice& Ar); + void ShowQuitMenuCommandHandler(const TArray& Args, UWorld* World, FOutputDevice& Ar); +#if !UE_BUILD_SHIPPING + void StatsCommandHandler(const TArray& Args, UWorld* World, FOutputDevice& Ar); + void ShowSettingsCommandHandler(const TArray& Args, UWorld* World, FOutputDevice& Ar); + void IPDCommandHandler(const TArray& Args, UWorld* World, FOutputDevice& Ar); +#endif + + void LoadFromSettings(); + void CheckMultiPlayer(); + void DoSessionShutdown(); + + protected: + void UpdateHMDWornState(); + EHMDWornState::Type HMDWornState = EHMDWornState::Unknown; + + void UpdateHMDEvents(); + + void EnableInsightPassthrough_RenderThread(bool bEnablePassthrough); + + void DrawHmdViewMesh( + FRHICommandList& RHICmdList, + float X, + float Y, + float SizeX, + float SizeY, + float U, + float V, + float SizeU, + float SizeV, + FIntPoint TargetSize, + FIntPoint TextureSize, + int32 StereoView, + const TShaderRef& VertexShader); + + union + { + struct + { + uint64 bApplySystemOverridesOnStereo : 1; + + uint64 bNeedEnableStereo : 1; + uint64 bNeedDisableStereo : 1; + }; + uint64 Raw; + } Flags; + + union + { + struct + { + // set to true when origin was set while OvrSession == null; the origin will be set ASA OvrSession != null + uint64 NeedSetTrackingOrigin : 1; + // enforces exit; used mostly for testing + uint64 EnforceExit : 1; + // set if a game is paused by the plug-in + uint64 AppIsPaused : 1; + // set to indicate that DisplayLost was detected by game thread. + uint64 DisplayLostDetected : 1; + // set to true once new session is created; being handled and reset as soon as session->IsVisible. + uint64 NeedSetFocusToGameViewport : 1; + }; + uint64 Raw; + } OCFlags; + + TRefCountPtr CustomPresent; + FSplashPtr Splash; + IRendererModule* RendererModule; + + FDeferredDeletionQueue DeferredDeletion; + + EHMDTrackingOrigin::Type TrackingOrigin; + // Stores difference between ViewRotation and EyeOrientation from previous frame + FQuat LastPlayerOrientation; + // Stores GetFrame()->PlayerLocation (i.e., ViewLocation) from the previous frame + FVector LastPlayerLocation; + FRotator DeltaControlRotation; // used from ApplyHmdRotation + TWeakPtr CachedViewportWidget; + TWeakPtr CachedWindow; + FIntPoint CachedWindowSize; + float CachedWorldToMetersScale; + bool bIsStandaloneStereoOnlyDevice; + // Stores TrackingToWorld from previous frame + FTransform LastTrackingToWorld; + std::atomic bHardOcclusionsEnabled; + std::atomic bEnvironmentDepthHandRemovalEnabled; + + // These three properties indicate the current state of foveated rendering, which may differ from what's in Settings + // due to cases such as falling back to FFR when eye tracked foveated rendering isn't enabled. Will allow us to resume + // ETFR from situations such as when ET gets paused. + std::atomic FoveatedRenderingMethod; + std::atomic FoveatedRenderingLevel; + std::atomic bDynamicFoveatedRendering; + + // Game thread + FSettingsPtr Settings; + uint32 NextFrameNumber; + uint32 WaitFrameNumber; + FGameFramePtr Frame; // Valid from OnStartGameFrame to OnEndGameFrame + FGameFramePtr NextFrameToRender; // Valid from OnStartGameFrame to BeginRenderViewFamily + FGameFramePtr LastFrameToRender; // Valid from OnStartGameFrame to BeginRenderViewFamily + uint32 NextLayerId; + TMap LayerMap; + bool bNeedReAllocateViewportRenderTarget; + + // Render thread + FSettingsPtr Settings_RenderThread; + FGameFramePtr Frame_RenderThread; // Valid from BeginRenderViewFamily to PostRenderViewFamily_RenderThread + TArray Layers_RenderThread; + FLayerPtr EyeLayer_RenderThread; // Valid to be accessed from game thread, since updated only when game thread is waiting + bool bNeedReAllocateDepthTexture_RenderThread; + bool bNeedReAllocateFoveationTexture_RenderThread; + bool bNeedReAllocateMotionVectorTexture_RenderThread; +#if !UE_VERSION_OLDER_THAN(5, 3, 0) + TSharedPtr FoveationImageGenerator; +#endif // !UE_VERSION_OLDER_THAN(5, 3, 0) + + // RHI thread + FSettingsPtr Settings_RHIThread; + FGameFramePtr Frame_RHIThread; // Valid from PreRenderViewFamily_RenderThread to FinishRendering_RHIThread + TArray Layers_RHIThread; + + FHMDViewMesh HiddenAreaMeshes[2]; + FHMDViewMesh VisibleAreaMeshes[2]; + + FPerformanceStats PerformanceStats; + + FRotator SplashRotation; // rotation applied to all splash screens (dependent on HMD orientation as the splash is shown) + + TArray EnvironmentDepthSwapchain; + +#if !UE_BUILD_SHIPPING + FDelegateHandle DrawDebugDelegateHandle; +#endif + + enum class FInsightInitStatus + { + NotInitialized, + Initialized, + Failed, + }; + + FInsightInitStatus InsightInitStatus; + + bool bShutdownRequestQueued; + bool bEyeTrackedFoveatedRenderingSupported; + + TArray EventPollingDelegates; + + // MultiPlayer + bool bMultiPlayer; + bool bShouldWait_GameThread; + bool bIsRendering_RenderThread; + }; + + typedef TSharedPtr FOculusXRHMDPtr; + +} // namespace OculusXRHMD + +#endif //OCULUS_HMD_SUPPORTED_PLATFORMS diff --git a/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMDModule.cpp b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMDModule.cpp new file mode 100644 index 0000000..c19f324 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMDModule.cpp @@ -0,0 +1,509 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +#include "OculusXRHMDModule.h" +#include "OculusXRHMD.h" +#include "OculusXRHMDPrivateRHI.h" +#include "OculusXRHMDRuntimeSettings.h" +#include "Containers/StringConv.h" +#include "Misc/EngineVersion.h" +#include "Misc/Paths.h" +#if PLATFORM_ANDROID +#include "Android/AndroidApplication.h" +#include "Android/AndroidPlatformMisc.h" +#endif +#include "Interfaces/IPluginManager.h" +#include "ShaderCore.h" +#include "OculusXRTelemetry.h" +#if PLATFORM_WINDOWS +#include "OculusXRSimulator.h" +#include "OculusXRSyntheticEnvironmentServer.h" +#endif + +#if !PLATFORM_ANDROID +#if !UE_BUILD_SHIPPING +namespace +{ + void __cdecl OvrpLogCallback2(ovrpLogLevel InLevel, const char* Message, int Length) + { + ELogVerbosity::Type OutLevel; + switch (InLevel) + { + case ovrpLogLevel_Debug: + OutLevel = ELogVerbosity::Log; + break; + case ovrpLogLevel_Info: + OutLevel = ELogVerbosity::Display; + break; + case ovrpLogLevel_Error: + OutLevel = ELogVerbosity::Error; + break; + default: + OutLevel = ELogVerbosity::NoLogging; + } + const FString MessageStr(Length, Message); + GLog->CategorizedLogf(TEXT("LogOVRPlugin"), OutLevel, TEXT("%s"), *MessageStr); + } +} // namespace +#endif // !UE_BUILD_SHIPPING +#endif // !PLATFORM_ANDROID + +//------------------------------------------------------------------------------------------------- +// FOculusXRHMDModule +//------------------------------------------------------------------------------------------------- + +OculusPluginWrapper FOculusXRHMDModule::PluginWrapper{}; + +#if OCULUS_HMD_SUPPORTED_PLATFORMS +OculusPluginWrapper& FOculusXRHMDModule::GetPluginWrapper() +{ + return PluginWrapper; +} +#endif // OCULUS_HMD_SUPPORTED_PLATFORMS + +FOculusXRHMDModule::FOculusXRHMDModule() +{ +#if OCULUS_HMD_SUPPORTED_PLATFORMS + bPreInit = false; + bPreInitCalled = false; + OVRPluginHandle = nullptr; + GraphicsAdapterLuid = 0; +#endif +} + +void FOculusXRHMDModule::StartupModule() +{ + IHeadMountedDisplayModule::StartupModule(); + FString PluginShaderDir = FPaths::Combine(IPluginManager::Get().FindPlugin(TEXT("OculusXR"))->GetBaseDir(), TEXT("Shaders")); + AddShaderSourceDirectoryMapping(TEXT("/Plugin/OculusXR"), PluginShaderDir); +} + +void FOculusXRHMDModule::ShutdownModule() +{ +#if OCULUS_HMD_SUPPORTED_PLATFORMS + if (PluginWrapper.IsInitialized()) + { + OculusXRTelemetry::FTelemetryBackend::OnEditorShutdown(); + PluginWrapper.Shutdown2(); + OculusPluginWrapper::DestroyOculusPluginWrapper(&PluginWrapper); + } + + if (OVRPluginHandle) + { + FPlatformProcess::FreeDllHandle(OVRPluginHandle); + OVRPluginHandle = nullptr; + } +#endif +} + +#if PLATFORM_ANDROID +extern bool AndroidThunkCpp_IsOculusMobileApplication(); +#endif + +FString FOculusXRHMDModule::GetModuleKeyName() const +{ + return FString(TEXT("OculusXRHMD")); +} + +void FOculusXRHMDModule::GetModuleAliases(TArray& AliasesOut) const +{ + // Pre-OculusXR rename (5.0.3 v44) + AliasesOut.Add(TEXT("OculusHMD")); +} + +bool FOculusXRHMDModule::PreInit() +{ +#if OCULUS_HMD_SUPPORTED_PLATFORMS + if (!bPreInitCalled) + { + bPreInit = false; + +#if PLATFORM_ANDROID + bPreInitCalled = true; + if (!AndroidThunkCpp_IsOculusMobileApplication()) + { + UE_LOG(LogHMD, Log, TEXT("App is not packaged for Oculus Mobile")); + return false; + } +#endif + + // Init module if app can render + if (FApp::CanEverRender()) + { + // Load OVRPlugin + OVRPluginHandle = GetOVRPluginHandle(); + + if (!OVRPluginHandle) + { + UE_LOG(LogHMD, Log, TEXT("Failed loading OVRPlugin %s"), TEXT(OVRP_VERSION_STR)); + return false; + } + + if (!OculusPluginWrapper::InitializeOculusPluginWrapper(&PluginWrapper)) + { + UE_LOG(LogHMD, Log, TEXT("Failed InitializeOculusPluginWrapper")); + return false; + } + + // Initialize OVRPlugin + ovrpRenderAPIType PreinitApiType = ovrpRenderAPI_None; +#if PLATFORM_ANDROID + void* Activity = (void*)FAndroidApplication::GetGameActivityThis(); + PreinitApiType = ovrpRenderAPI_Vulkan; +#else + void* Activity = nullptr; +#endif + +#if !PLATFORM_ANDROID +#if !UE_BUILD_SHIPPING + PluginWrapper.SetLogCallback2(OvrpLogCallback2); +#endif // !UE_BUILD_SHIPPING +#endif // !PLATFORM_ANDROID + + if (OVRP_FAILURE(PluginWrapper.PreInitialize5(Activity, PreinitApiType, ovrpPreinitializeFlags::ovrpPreinitializeFlag_None))) + { + UE_LOG(LogHMD, Log, TEXT("Failed initializing OVRPlugin %s"), TEXT(OVRP_VERSION_STR)); +#if WITH_EDITOR && PLATFORM_WINDOWS + // In the editor, we want to allow the headset to connect after the editor has booted. + // To do this, we must have PreInit() return true, to prevent the HMD module from being unloaded. + return GIsEditor; +#else + return false; +#endif + } + +#if PLATFORM_WINDOWS + bPreInitCalled = true; + const LUID* DisplayAdapterId; + if (OVRP_SUCCESS(PluginWrapper.GetDisplayAdapterId2((const void**)&DisplayAdapterId)) && DisplayAdapterId) + { + SetGraphicsAdapterLuid(*(const uint64*)DisplayAdapterId); + } + else + { + UE_LOG(LogHMD, Log, TEXT("Could not determine HMD display adapter")); + } + + const WCHAR* AudioInDeviceId; + if (OVRP_SUCCESS(PluginWrapper.GetAudioInDeviceId2((const void**)&AudioInDeviceId)) && AudioInDeviceId) + { + GConfig->SetString(TEXT("Oculus.Settings"), TEXT("AudioInputDevice"), AudioInDeviceId, GEngineIni); + } + else + { + UE_LOG(LogHMD, Log, TEXT("Could not determine HMD audio input device")); + } + + const WCHAR* AudioOutDeviceId; + if (OVRP_SUCCESS(PluginWrapper.GetAudioOutDeviceId2((const void**)&AudioOutDeviceId)) && AudioOutDeviceId) + { + GConfig->SetString(TEXT("Oculus.Settings"), TEXT("AudioOutputDevice"), AudioOutDeviceId, GEngineIni); + } + else + { + UE_LOG(LogHMD, Log, TEXT("Could not determine HMD audio output device")); + } +#endif + + float ModulePriority; + if (!GConfig->GetFloat(TEXT("HMDPluginPriority"), *GetModuleKeyName(), ModulePriority, GEngineIni)) + { + // if user doesn't set priority set it for them to allow this hmd to be used if enabled + ModulePriority = 45.0f; + GConfig->SetFloat(TEXT("HMDPluginPriority"), *GetModuleKeyName(), ModulePriority, GEngineIni); + } + + UE_LOG(LogHMD, Log, TEXT("FOculusXRHMDModule PreInit successfully")); + + bPreInit = true; + } + } + + return bPreInit; +#else + return false; +#endif // OCULUS_HMD_SUPPORTED_PLATFORMS +} + +bool FOculusXRHMDModule::IsHMDConnected() +{ +#if OCULUS_HMD_SUPPORTED_PLATFORMS + UOculusXRHMDRuntimeSettings* HMDSettings = GetMutableDefault(); + if (FApp::CanEverRender() && HMDSettings->XrApi != EOculusXRXrApi::NativeOpenXR) + { + return true; + } +#endif // OCULUS_HMD_SUPPORTED_PLATFORMS + return false; +} + +uint64 FOculusXRHMDModule::GetGraphicsAdapterLuid() +{ +#if OCULUS_HMD_SUPPORTED_PLATFORMS_D3D11 || OCULUS_HMD_SUPPORTED_PLATFORMS_D3D12 + if (!GraphicsAdapterLuid) + { + int GraphicsAdapter; + + if (GConfig->GetInt(TEXT("Oculus.Settings"), TEXT("GraphicsAdapter"), GraphicsAdapter, GEngineIni) && GraphicsAdapter >= 0) + { + TRefCountPtr DXGIFactory; + TRefCountPtr DXGIAdapter; + DXGI_ADAPTER_DESC DXGIAdapterDesc; + + if (SUCCEEDED(CreateDXGIFactory(__uuidof(IDXGIFactory), (void**)DXGIFactory.GetInitReference())) && SUCCEEDED(DXGIFactory->EnumAdapters(GraphicsAdapter, DXGIAdapter.GetInitReference())) && SUCCEEDED(DXGIAdapter->GetDesc(&DXGIAdapterDesc))) + { + FMemory::Memcpy(&GraphicsAdapterLuid, &DXGIAdapterDesc.AdapterLuid, sizeof(GraphicsAdapterLuid)); + } + } + } +#endif + +#if OCULUS_HMD_SUPPORTED_PLATFORMS + return GraphicsAdapterLuid; +#else + return 0; +#endif +} + +FString FOculusXRHMDModule::GetAudioInputDevice() +{ + FString AudioInputDevice; +#if OCULUS_HMD_SUPPORTED_PLATFORMS + GConfig->GetString(TEXT("Oculus.Settings"), TEXT("AudioInputDevice"), AudioInputDevice, GEngineIni); +#endif + return AudioInputDevice; +} + +FString FOculusXRHMDModule::GetAudioOutputDevice() +{ + FString AudioOutputDevice; +#if OCULUS_HMD_SUPPORTED_PLATFORMS +#if PLATFORM_WINDOWS + if (bPreInit) + { + if (FApp::CanEverRender()) + { + const WCHAR* audioOutDeviceId; + if (OVRP_SUCCESS(PluginWrapper.GetAudioOutDeviceId2((const void**)&audioOutDeviceId)) && audioOutDeviceId) + { + AudioOutputDevice = audioOutDeviceId; + } + } + } +#else + GConfig->GetString(TEXT("Oculus.Settings"), TEXT("AudioOutputDevice"), AudioOutputDevice, GEngineIni); +#endif +#endif + return AudioOutputDevice; +} + +TSharedPtr FOculusXRHMDModule::CreateTrackingSystem() +{ +#if OCULUS_HMD_SUPPORTED_PLATFORMS + if (bPreInit || (GIsEditor && PLATFORM_WINDOWS)) + { + //If -HMDSimulator is used as the command option to launch UE, use simulator runtime instead of the physical HMD runtime (like PC-Link). + if (FParse::Param(FCommandLine::Get(), TEXT("HMDSimulator")) && GetMutableDefault()->MetaXRJsonPath.FilePath.Len()) + { + if (!IsSimulatorActivated()) + { + ToggleOpenXRRuntime(); + } + } + + OculusXRHMD::FOculusXRHMDPtr OculusXRHMD = FSceneViewExtensions::NewExtension(); + + if (OculusXRHMD->Startup()) + { + HeadMountedDisplay = OculusXRHMD; + return OculusXRHMD; + } + } + HeadMountedDisplay = nullptr; +#endif + return nullptr; +} + +TSharedPtr FOculusXRHMDModule::GetVulkanExtensions() +{ +#if OCULUS_HMD_SUPPORTED_PLATFORMS + if (bPreInit) + { + if (!VulkanExtensions.IsValid()) + { + VulkanExtensions = MakeShareable(new OculusXRHMD::FVulkanExtensions); + } + } +#if WITH_EDITOR && PLATFORM_WINDOWS + else if (GIsEditor) + { + // OpenXR has no ability to query for possible vulkan extensions without connecting a HMD. + // This is a problem, because we need to create our VkInstance and VkDevice to render in 2D and there's no HMD. + // For now, as a workaround, we hardcode the extensions that Oculus's OpenXR implementation needs. + // Eventually, one of three things has to happen for a proper fix: + // + // 1. OculusXRHMD (or, better, OVRPlugin) maintains a separate VkInstance that has the right extensions, + // and uses the vk_external extensions to transfer data between them when needed. + // 2. OpenXR changes to allow querying instance and device extensions without an active HMD. + // It may still require a physical device handle to list device extensions. + // 3. Oculus's Link implementation for OpenXR changes to allow an XrSystemId to be created before a headset + // is connected (possibly as an opt-in OpenXR extension for backwards compatibility). + // + // (2) or (3) are preferable, but if OpenXR is held constant we will have to do (1). + if (!VulkanExtensions.IsValid()) + { + VulkanExtensions = MakeShareable(new OculusXRHMD::FEditorVulkanExtensions); + } + } +#endif + return VulkanExtensions; +#endif + return nullptr; +} + +FString FOculusXRHMDModule::GetDeviceSystemName() +{ +#if OCULUS_HMD_SUPPORTED_PLATFORMS + ovrpSystemHeadset SystemHeadset; + if (PluginWrapper.IsInitialized() && OVRP_SUCCESS(PluginWrapper.GetSystemHeadsetType2(&SystemHeadset))) + { + switch (SystemHeadset) + { + case ovrpSystemHeadset_Oculus_Quest: + return FString("Oculus Quest"); + + case ovrpSystemHeadset_Oculus_Quest_2: + default: + return FString("Oculus Quest2"); + +#ifdef WITH_OCULUS_BRANCH + case ovrpSystemHeadset_Meta_Quest_Pro: + return FString("Meta Quest Pro"); + + case ovrpSystemHeadset_Meta_Quest_3: + return FString("Meta Quest 3"); +#endif // WITH_OCULUS_BRANCH + } + } + return FString(); +#else + return FString(); +#endif +} + +bool FOculusXRHMDModule::IsStandaloneStereoOnlyDevice() +{ +#if PLATFORM_ANDROID + return FAndroidMisc::GetDeviceMake() == FString("Oculus"); +#else + return false; +#endif +} + +bool FOculusXRHMDModule::IsSimulatorActivated() +{ +#if PLATFORM_WINDOWS + return FMetaXRSimulator::IsSimulatorActivated(); +#else + return false; +#endif +} + +void FOculusXRHMDModule::ToggleOpenXRRuntime() +{ +#if PLATFORM_WINDOWS + FMetaXRSimulator::ToggleOpenXRRuntime(); +#endif +} + +void FOculusXRHMDModule::LaunchEnvironment(FString EnvironmentName) +{ +#if PLATFORM_WINDOWS + FMetaXRSES::LaunchEnvironment(EnvironmentName); +#endif +} + +void FOculusXRHMDModule::StopServer() +{ +#if PLATFORM_WINDOWS + FMetaXRSES::StopServer(); +#endif +} + +#if OCULUS_HMD_SUPPORTED_PLATFORMS +void* FOculusXRHMDModule::GetOVRPluginHandle() +{ + void* OVRPluginHandle = nullptr; + +#if PLATFORM_WINDOWS + FString XrApi; + if (!FModuleManager::Get().IsModuleLoaded("OpenXRHMD") || !GConfig->GetString(TEXT("/Script/OculusXRHMD.OculusXRHMDRuntimeSettings"), TEXT("XrApi"), XrApi, GEngineIni) || XrApi.Equals(FString("OVRPluginOpenXR"))) + { + FString BinariesPath = FPaths::Combine(IPluginManager::Get().FindPlugin(TEXT("OculusXR"))->GetBaseDir(), TEXT("/Source/ThirdParty/OVRPlugin/OVRPlugin/Lib/Win64")); + FPlatformProcess::PushDllDirectory(*BinariesPath); + OVRPluginHandle = FPlatformProcess::GetDllHandle(*(BinariesPath / "OpenXR/OVRPlugin.dll")); + FPlatformProcess::PopDllDirectory(*BinariesPath); + } +#elif PLATFORM_ANDROID + OVRPluginHandle = FPlatformProcess::GetDllHandle(TEXT("libOVRPlugin.so")); +#endif // PLATFORM_ANDROID + + return OVRPluginHandle; +} + +bool FOculusXRHMDModule::PoseToOrientationAndPosition(const FQuat& InOrientation, const FVector& InPosition, FQuat& OutOrientation, FVector& OutPosition) const +{ + OculusXRHMD::CheckInGameThread(); + + OculusXRHMD::FOculusXRHMD* OculusXRHMD = static_cast(HeadMountedDisplay.Pin().Get()); + + if (OculusXRHMD) + { + ovrpPosef InPose; + InPose.Orientation = OculusXRHMD::ToOvrpQuatf(InOrientation); + InPose.Position = OculusXRHMD::ToOvrpVector3f(InPosition); + OculusXRHMD::FPose OutPose; + + if (OculusXRHMD->ConvertPose(InPose, OutPose)) + { + OutOrientation = OutPose.Orientation; + OutPosition = OutPose.Position; + return true; + } + } + + return false; +} + +void FOculusXRHMDModule::SetGraphicsAdapterLuid(uint64 InLuid) +{ + GraphicsAdapterLuid = InLuid; + +#if OCULUS_HMD_SUPPORTED_PLATFORMS_D3D11 || OCULUS_HMD_SUPPORTED_PLATFORMS_D3D12 + TRefCountPtr DXGIFactory; + + if (SUCCEEDED(CreateDXGIFactory(__uuidof(IDXGIFactory), (void**)DXGIFactory.GetInitReference()))) + { + for (int32 adapterIndex = 0;; adapterIndex++) + { + TRefCountPtr DXGIAdapter; + DXGI_ADAPTER_DESC DXGIAdapterDesc; + + if (FAILED(DXGIFactory->EnumAdapters(adapterIndex, DXGIAdapter.GetInitReference())) || FAILED(DXGIAdapter->GetDesc(&DXGIAdapterDesc))) + { + break; + } + + if (!FMemory::Memcmp(&GraphicsAdapterLuid, &DXGIAdapterDesc.AdapterLuid, sizeof(GraphicsAdapterLuid))) + { + // Remember this adapterIndex so we use the right adapter, even when we startup without HMD connected + GConfig->SetInt(TEXT("Oculus.Settings"), TEXT("GraphicsAdapter"), adapterIndex, GEngineIni); + break; + } + } + } +#endif // OCULUS_HMD_SUPPORTED_PLATFORMS_D3D11 || OCULUS_HMD_SUPPORTED_PLATFORMS_D3D12 +} +#endif // OCULUS_HMD_SUPPORTED_PLATFORMS + +IMPLEMENT_MODULE(FOculusXRHMDModule, OculusXRHMD) diff --git a/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMDModule.h b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMDModule.h new file mode 100644 index 0000000..db313bc --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMDModule.h @@ -0,0 +1,121 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +#pragma once +#include "OculusXRHMDPrivate.h" +#include "IHeadMountedDisplay.h" +#include "OculusXRFunctionLibrary.h" +#include "OculusXRHMD_VulkanExtensions.h" +#include "OculusXRPluginWrapper.h" + +//------------------------------------------------------------------------------------------------- +// FOculusXRHMDModule +//------------------------------------------------------------------------------------------------- + +class FOculusXRHMDModule : public IOculusXRHMDModule +{ +public: + FOculusXRHMDModule(); + + static inline FOculusXRHMDModule& Get() + { + return FModuleManager::LoadModuleChecked("OculusXRHMD"); + } + + // IModuleInterface + virtual void StartupModule() override; + virtual void ShutdownModule() override; + + // IHeadMountedDisplayModule + virtual FString GetModuleKeyName() const override; + virtual void GetModuleAliases(TArray& AliasesOut) const override; + virtual bool PreInit() override; + virtual bool IsHMDConnected() override; + virtual uint64 GetGraphicsAdapterLuid() override; + virtual FString GetAudioInputDevice() override; + virtual FString GetAudioOutputDevice() override; + virtual FString GetDeviceSystemName() override; + + virtual TSharedPtr CreateTrackingSystem() override; + virtual TSharedPtr GetVulkanExtensions() override; + virtual bool IsStandaloneStereoOnlyDevice() override; + + // IOculusXRHMDModule + virtual void GetPose(FRotator& DeviceRotation, FVector& DevicePosition, FVector& NeckPosition, bool bUseOrienationForPlayerCamera = false, bool bUsePositionForPlayerCamera = false, const FVector PositionScale = FVector::ZeroVector) override + { + UOculusXRFunctionLibrary::GetPose(DeviceRotation, DevicePosition, NeckPosition, bUseOrienationForPlayerCamera, bUsePositionForPlayerCamera, PositionScale); + } + + virtual void GetRawSensorData(FVector& AngularAcceleration, FVector& LinearAcceleration, FVector& AngularVelocity, FVector& LinearVelocity, float& TimeInSeconds) override + { + UOculusXRFunctionLibrary::GetRawSensorData(AngularAcceleration, LinearAcceleration, AngularVelocity, LinearVelocity, TimeInSeconds, EOculusXRTrackedDeviceType::HMD); + } + + virtual bool GetUserProfile(struct FOculusXRHmdUserProfile& Profile) override + { + return UOculusXRFunctionLibrary::GetUserProfile(Profile); + } + + virtual void SetBaseRotationAndBaseOffsetInMeters(FRotator Rotation, FVector BaseOffsetInMeters, EOrientPositionSelector::Type Options) override + { + UOculusXRFunctionLibrary::SetBaseRotationAndBaseOffsetInMeters(Rotation, BaseOffsetInMeters, Options); + } + + virtual void GetBaseRotationAndBaseOffsetInMeters(FRotator& OutRotation, FVector& OutBaseOffsetInMeters) override + { + UOculusXRFunctionLibrary::GetBaseRotationAndBaseOffsetInMeters(OutRotation, OutBaseOffsetInMeters); + } + + virtual void SetBaseRotationAndPositionOffset(FRotator BaseRot, FVector PosOffset, EOrientPositionSelector::Type Options) override + { + UOculusXRFunctionLibrary::SetBaseRotationAndPositionOffset(BaseRot, PosOffset, Options); + } + + virtual void GetBaseRotationAndPositionOffset(FRotator& OutRot, FVector& OutPosOffset) override + { + UOculusXRFunctionLibrary::GetBaseRotationAndPositionOffset(OutRot, OutPosOffset); + } + + virtual class IStereoLayers* GetStereoLayers() override + { + return UOculusXRFunctionLibrary::GetStereoLayers(); + } + + bool IsOVRPluginAvailable() const + { +#if OCULUS_HMD_SUPPORTED_PLATFORMS + return OVRPluginHandle != nullptr; +#else + return false; +#endif + } + + // FMetaXRSimulator + OCULUSXRHMD_API static bool IsSimulatorActivated(); + OCULUSXRHMD_API static void ToggleOpenXRRuntime(); + + // FMetaXRSES + OCULUSXRHMD_API static void LaunchEnvironment(FString EnvironmentName); + OCULUSXRHMD_API static void StopServer(); + +#if OCULUS_HMD_SUPPORTED_PLATFORMS + OCULUSXRHMD_API static void* GetOVRPluginHandle(); + OCULUSXRHMD_API static OculusPluginWrapper& GetPluginWrapper(); + virtual bool PoseToOrientationAndPosition(const FQuat& InOrientation, const FVector& InPosition, FQuat& OutOrientation, FVector& OutPosition) const override; + +protected: + void SetGraphicsAdapterLuid(uint64 InLuid); + + static OculusPluginWrapper PluginWrapper; + + bool bPreInit; + bool bPreInitCalled; + void* OVRPluginHandle; + uint64 GraphicsAdapterLuid; + TWeakPtr HeadMountedDisplay; + TSharedPtr VulkanExtensions; + + friend class ::OculusXRHMD::FOculusXRHMD; + +#endif // OCULUS_HMD_SUPPORTED_PLATFORMS +}; diff --git a/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMDPrivate.cpp b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMDPrivate.cpp new file mode 100644 index 0000000..9566d0a --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMDPrivate.cpp @@ -0,0 +1,95 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +#include "OculusXRHMDPrivate.h" +#include "RHICommandList.h" +#include "RenderingThread.h" + +namespace OculusXRHMD +{ + + //------------------------------------------------------------------------------------------------- + // Utility functions + //------------------------------------------------------------------------------------------------- + + // TODO: Change in case of parallel game threads + bool InGameThread() + { + if (GIsGameThreadIdInitialized) + { + return FPlatformTLS::GetCurrentThreadId() == GGameThreadId; + } + else + { + return true; + } + } + + bool InRenderThread() + { + if (GIsThreadedRendering && !GIsRenderingThreadSuspended.Load(EMemoryOrder::Relaxed)) + { + return IsInParallelRenderingThread(); + } + else + { + return InGameThread(); + } + } + + // TODO: Change in case of parallel RHI threads + bool InRHIThread() + { + if (GIsThreadedRendering && !GIsRenderingThreadSuspended.Load(EMemoryOrder::Relaxed)) + { + if (IsRHIThreadRunning()) + { + if (IsInRHIThread()) + { + return true; + } + + if (IsInParallelRenderingThread()) + { + return GetImmediateCommandList_ForRenderCommand().Bypass(); + } + + return false; + } + else + { + return IsInParallelRenderingThread(); + } + } + else + { + return InGameThread(); + } + } + + bool ConvertPose_Internal(const FPose& InPose, FPose& OutPose, const FQuat BaseOrientation, const FVector BaseOffset, float WorldToMetersScale) + { + // apply base orientation correction + OutPose.Orientation = BaseOrientation.Inverse() * InPose.Orientation; + OutPose.Orientation.Normalize(); + + // correct position according to BaseOrientation and BaseOffset. + OutPose.Position = (InPose.Position - BaseOffset) * WorldToMetersScale; + OutPose.Position = BaseOrientation.Inverse().RotateVector(OutPose.Position); + + return true; + } + + bool ConvertPose_Internal(const ovrpPosef& InPose, FPose& OutPose, const FQuat BaseOrientation, const FVector BaseOffset, float WorldToMetersScale) + { + return ConvertPose_Internal(FPose(ToFQuat(InPose.Orientation), ToFVector(InPose.Position)), OutPose, BaseOrientation, BaseOffset, WorldToMetersScale); + } + + bool ConvertPose_Internal(const FPose& InPose, ovrpPosef& OutPose, const FQuat BaseOrientation, const FVector BaseOffset, float WorldToMetersScale) + { + OutPose.Orientation = ToOvrpQuatf(BaseOrientation * InPose.Orientation); + OutPose.Position = ToOvrpVector3f(BaseOrientation.RotateVector(InPose.Position) / WorldToMetersScale + BaseOffset); + return true; + } + +} // namespace OculusXRHMD diff --git a/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMDPrivate.h b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMDPrivate.h new file mode 100644 index 0000000..8628130 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMDPrivate.h @@ -0,0 +1,311 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +#pragma once +#include "GameFramework/WorldSettings.h" +#include "IOculusXRHMDModule.h" +#include "OculusXRFunctionLibrary.h" +#include "OculusXRPassthroughLayerShapes.h" +#include "StereoRendering.h" +#include "HAL/RunnableThread.h" +#include "RHI.h" +#include + +#if OCULUS_HMD_SUPPORTED_PLATFORMS +#define OCULUS_HMD_SUPPORTED_PLATFORMS_D3D11 PLATFORM_WINDOWS +#define OCULUS_HMD_SUPPORTED_PLATFORMS_D3D12 PLATFORM_WINDOWS +#define OCULUS_HMD_SUPPORTED_PLATFORMS_VULKAN (PLATFORM_WINDOWS || PLATFORM_ANDROID) +#else +#define OCULUS_HMD_SUPPORTED_PLATFORMS_D3D11 0 +#define OCULUS_HMD_SUPPORTED_PLATFORMS_D3D12 0 +#define OCULUS_HMD_SUPPORTED_PLATFORMS_VULKAN 0 +#endif // OCULUS_HMD_SUPPORTED_PLATFORMS + +//------------------------------------------------------------------------------------------------- +// OVRPlugin +//------------------------------------------------------------------------------------------------- + +#if OCULUS_HMD_SUPPORTED_PLATFORMS +#include "OculusXRPluginWrapper.h" +#endif // OCULUS_HMD_SUPPORTED_PLATFORMS + +//------------------------------------------------------------------------------------------------- +// Utility functions +//------------------------------------------------------------------------------------------------- + +namespace OculusXRHMD +{ +#if OCULUS_HMD_SUPPORTED_PLATFORMS + struct FPose + { + FQuat Orientation; + FVector Position; + + FPose() + : Orientation(EForceInit::ForceInit) + , Position(EForceInit::ForceInit) + { + } + + FPose(const FQuat& InOrientation, const FVector& InPosition) + : Orientation(InOrientation), Position(InPosition) {} + + FPose Inverse() const + { + FQuat InvOrientation = Orientation.Inverse(); + FVector InvPosition = InvOrientation.RotateVector(-Position); + return FPose(InvOrientation, InvPosition); + } + + FPose operator*(const FPose& other) const + { + return FPose(Orientation * other.Orientation, Orientation.RotateVector(other.Position) + Position); + } + }; + + /** Converts ovrpQuatf to FQuat */ + FORCEINLINE FQuat ToFQuat(const ovrpQuatf& InQuat) + { + return FQuat(-InQuat.z, InQuat.x, InQuat.y, -InQuat.w); + } + + /** Converts FQuat to ovrpQuatf */ + FORCEINLINE ovrpQuatf ToOvrpQuatf(const FQuat& InQuat) + { + return ovrpQuatf{ static_cast(InQuat.Y), static_cast(InQuat.Z), static_cast(-InQuat.X), static_cast(-InQuat.W) }; + } + + /** Converts vector from Oculus to Unreal */ + FORCEINLINE FVector ToFVector(const ovrpVector3f& InVec) + { + return FVector(-InVec.z, InVec.x, InVec.y); + } + + /** Converts vector from Unreal to Oculus. */ + FORCEINLINE ovrpVector3f ToOvrpVector3f(const FVector& InVec) + { + return ovrpVector3f{ static_cast(InVec.Y), static_cast(InVec.Z), static_cast(-InVec.X) }; + } + + FORCEINLINE FMatrix ToFMatrix(const ovrpMatrix4f& vtm) + { + // Rows and columns are swapped between ovrpMatrix4f and FMatrix + return FMatrix( + FPlane(vtm.M[0][0], vtm.M[1][0], vtm.M[2][0], vtm.M[3][0]), + FPlane(vtm.M[0][1], vtm.M[1][1], vtm.M[2][1], vtm.M[3][1]), + FPlane(vtm.M[0][2], vtm.M[1][2], vtm.M[2][2], vtm.M[3][2]), + FPlane(vtm.M[0][3], vtm.M[1][3], vtm.M[2][3], vtm.M[3][3])); + } + + FORCEINLINE ovrpVector4f LinearColorToOvrpVector4f(const FLinearColor& InColor) + { + return ovrpVector4f{ InColor.R, InColor.G, InColor.B, InColor.A }; + } + + FORCEINLINE ovrpRecti ToOvrpRecti(const FIntRect& rect) + { + return ovrpRecti{ { rect.Min.X, rect.Min.Y }, { rect.Size().X, rect.Size().Y } }; + } + + FORCEINLINE ovrpColorf ToOvrpColorf(const FLinearColor LinearColor) + { + return ovrpColorf{ LinearColor.R, LinearColor.G, LinearColor.B, LinearColor.A }; + } + + FORCEINLINE ovrpMatrix4f ToOvrpMatrix(FMatrix Matrix) + { + ovrpMatrix4f Result; + + Result.M[0][0] = Matrix.M[0][0]; + Result.M[0][1] = Matrix.M[0][1]; + Result.M[0][2] = Matrix.M[0][2]; + Result.M[0][3] = Matrix.M[0][3]; + + Result.M[1][0] = Matrix.M[1][0]; + Result.M[1][1] = Matrix.M[1][1]; + Result.M[1][2] = Matrix.M[1][2]; + Result.M[1][3] = Matrix.M[1][3]; + + Result.M[2][0] = Matrix.M[2][0]; + Result.M[2][1] = Matrix.M[2][1]; + Result.M[2][2] = Matrix.M[2][2]; + Result.M[2][3] = Matrix.M[2][3]; + + Result.M[3][0] = Matrix.M[3][0]; + Result.M[3][1] = Matrix.M[3][1]; + Result.M[3][2] = Matrix.M[3][2]; + Result.M[3][3] = Matrix.M[3][3]; + + return Result; + } + + /** Helper that converts ovrTrackedDeviceType to EOculusXRTrackedDeviceType */ + FORCEINLINE EOculusXRTrackedDeviceType ToEOculusXRTrackedDeviceType(ovrpNode Source) + { + EOculusXRTrackedDeviceType Destination = EOculusXRTrackedDeviceType::All; // Best attempt at initialization + + switch (Source) + { + case ovrpNode_None: + Destination = EOculusXRTrackedDeviceType::None; + break; + case ovrpNode_Head: + Destination = EOculusXRTrackedDeviceType::HMD; + break; + case ovrpNode_HandLeft: + Destination = EOculusXRTrackedDeviceType::LTouch; + break; + case ovrpNode_HandRight: + Destination = EOculusXRTrackedDeviceType::RTouch; + break; + case ovrpNode_DeviceObjectZero: + Destination = EOculusXRTrackedDeviceType::DeviceObjectZero; + break; + default: + break; + } + return Destination; + } + + /** Helper that converts EOculusXRTrackedDeviceType to ovrTrackedDeviceType */ + FORCEINLINE ovrpNode ToOvrpNode(EOculusXRTrackedDeviceType Source) + { + ovrpNode Destination = ovrpNode_None; // Best attempt at initialization + + switch (Source) + { + case EOculusXRTrackedDeviceType::None: + Destination = ovrpNode_None; + break; + case EOculusXRTrackedDeviceType::HMD: + Destination = ovrpNode_Head; + break; + case EOculusXRTrackedDeviceType::LTouch: + Destination = ovrpNode_HandLeft; + break; + case EOculusXRTrackedDeviceType::RTouch: + Destination = ovrpNode_HandRight; + break; + case EOculusXRTrackedDeviceType::DeviceObjectZero: + Destination = ovrpNode_DeviceObjectZero; + break; + default: + break; + } + return Destination; + } + + FORCEINLINE int32 ToExternalDeviceId(const ovrpNode Source) + { + int32 ExternalDeviceId = INDEX_NONE; + switch (Source) + { + case ovrpNode_Head: + // required to be zero (see IXRTrackingSystem::HMDDeviceId) + ExternalDeviceId = 0; + break; + case ovrpNode_None: + case ovrpNode_Count: + case ovrpNode_EnumSize: + // ExternalDeviceId = INDEX_NONE; + break; + default: + // add one, in case the enum value is zero (conflicting with the HMD) + ExternalDeviceId = 1 + (int32)Source; + break; + } + return ExternalDeviceId; + } + + FORCEINLINE ovrpNode ToOvrpNode(const int32 ExternalDeviceId) + { + ovrpNode Destination = ovrpNode_None; + switch (ExternalDeviceId) + { + case 0: + // zero implies HMD (see ToExternalDeviceId/IXRTrackingSystem::HMDDeviceId) + Destination = ovrpNode_Head; + break; + case -1: + // Destination = ovrpNode_None; + break; + default: + // we added one to avoid collision with the HMD's ID (see ToExternalDeviceId) + Destination = ovrpNode(ExternalDeviceId - 1); + break; + } + return Destination; + } + + bool ConvertPose_Internal(const FPose& InPose, FPose& OutPose, const FQuat BaseOrientation, const FVector BaseOffset, float WorldToMetersScale); + + bool ConvertPose_Internal(const ovrpPosef& InPose, FPose& OutPose, const FQuat BaseOrientation, const FVector BaseOffset, float WorldToMetersScale); + + bool ConvertPose_Internal(const FPose& InPose, ovrpPosef& OutPose, const FQuat BaseOrientation, const FVector BaseOffset, float WorldToMetersScale); + + FORCEINLINE ovrpInsightPassthroughColorMapType ToOVRPColorMapType(EOculusXRColorMapType InColorMapType) + { + switch (InColorMapType) + { + case ColorMapType_GrayscaleToColor: + return ovrpInsightPassthroughColorMapType_MonoToRgba; + case ColorMapType_Grayscale: + return ovrpInsightPassthroughColorMapType_MonoToMono; + case ColorMapType_ColorAdjustment: + return ovrpInsightPassthroughColorMapType_BrightnessContrastSaturation; + case ColorMapType_ColorLut: + return ovrpInsightPassthroughColorMapType_ColorLut; + case ColorMapType_ColorLut_Interpolated: + return ovrpInsightPassthroughColorMapType_InterpolatedColorLut; + default: + return ovrpInsightPassthroughColorMapType_None; + } + } + +#endif // OCULUS_HMD_SUPPORTED_PLATFORMS + + /** Check currently executing from Game thread */ + OCULUSXRHMD_API bool InGameThread(); + + FORCEINLINE void CheckInGameThread() + { +#if DO_CHECK + check(InGameThread()); +#endif + } + + /** Check currently executing from Render thread */ + OCULUSXRHMD_API bool InRenderThread(); + + FORCEINLINE void CheckInRenderThread() + { +#if DO_CHECK + check(InRenderThread()); +#endif + } + + /** Check currently executing from RHI thread */ + OCULUSXRHMD_API bool InRHIThread(); + + FORCEINLINE void CheckInRHIThread() + { +#if DO_CHECK + check(InRHIThread()); +#endif + } + + FORCEINLINE bool GetUnitScaleFactorFromSettings(UWorld* World, float& outWorldToMeters) + { + if (IsValid(World)) + { + const auto* WorldSettings = World->GetWorldSettings(); + if (IsValid(WorldSettings)) + { + outWorldToMeters = WorldSettings->WorldToMeters; + return true; + } + } + return false; + } + +} // namespace OculusXRHMD diff --git a/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMDPrivateRHI.h b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMDPrivateRHI.h new file mode 100644 index 0000000..2d35c17 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMDPrivateRHI.h @@ -0,0 +1,64 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +#pragma once + +#if OCULUS_HMD_SUPPORTED_PLATFORMS + +//------------------------------------------------------------------------------------------------- +// D3D11 +//------------------------------------------------------------------------------------------------- + +#if OCULUS_HMD_SUPPORTED_PLATFORMS_D3D11 +#include "ID3D11DynamicRHI.h" +#endif // OCULUS_HMD_SUPPORTED_PLATFORMS_D3D11 + +//------------------------------------------------------------------------------------------------- +// D3D12 +//------------------------------------------------------------------------------------------------- + +#if OCULUS_HMD_SUPPORTED_PLATFORMS_D3D12 +#define GetD3D11CubeFace GetD3D12CubeFace +#define VerifyD3D11Result VerifyD3D12Result +#define GetD3D11TextureFromRHITexture GetD3D12TextureFromRHITexture +#define FRingAllocation FRingAllocation_D3D12 +#define GetRenderTargetFormat GetRenderTargetFormat_D3D12 +#define ED3D11ShaderOffsetBuffer ED3D12ShaderOffsetBuffer +#define FindShaderResourceDXGIFormat FindShaderResourceDXGIFormat_D3D12 +#define FindUnorderedAccessDXGIFormat FindUnorderedAccessDXGIFormat_D3D12 +#define FindDepthStencilDXGIFormat FindDepthStencilDXGIFormat_D3D12 +#define HasStencilBits HasStencilBits_D3D12 +#define FVector4VertexDeclaration FVector4VertexDeclaration_D3D12 +#define GLOBAL_CONSTANT_BUFFER_INDEX GLOBAL_CONSTANT_BUFFER_INDEX_D3D12 +#define MAX_CONSTANT_BUFFER_SLOTS MAX_CONSTANT_BUFFER_SLOTS_D3D12 +#define FD3DGPUProfiler FD3D12GPUProfiler +#define FRangeAllocator FRangeAllocator_D3D12 + +#include "ID3D12DynamicRHI.h" + +#undef GetD3D11CubeFace +#undef VerifyD3D11Result +#undef GetD3D11TextureFromRHITexture +#undef FRingAllocation +#undef GetRenderTargetFormat +#undef ED3D11ShaderOffsetBuffer +#undef FindShaderResourceDXGIFormat +#undef FindUnorderedAccessDXGIFormat +#undef FindDepthStencilDXGIFormat +#undef HasStencilBits +#undef FVector4VertexDeclaration +#undef GLOBAL_CONSTANT_BUFFER_INDEX +#undef MAX_CONSTANT_BUFFER_SLOTS +#undef FD3DGPUProfiler +#undef FRangeAllocator +#endif // OCULUS_HMD_SUPPORTED_PLATFORMS_D3D12 + +//------------------------------------------------------------------------------------------------- +// Vulkan +//------------------------------------------------------------------------------------------------- + +#if OCULUS_HMD_SUPPORTED_PLATFORMS_VULKAN +#include "IVulkanDynamicRHI.h" +#endif // OCULUS_HMD_SUPPORTED_PLATFORMS_VULKAN + +#endif // OCULUS_HMD_SUPPORTED_PLATFORMS diff --git a/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMDRuntimeSettings.cpp b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMDRuntimeSettings.cpp new file mode 100644 index 0000000..8bf12e5 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMDRuntimeSettings.cpp @@ -0,0 +1,299 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +#include "OculusXRHMDRuntimeSettings.h" + +////////////////////////////////////////////////////////////////////////// +// UOculusXRHMDRuntimeSettings + +#include "OculusXRHMD_Settings.h" + +UOculusXRHMDRuntimeSettings::UOculusXRHMDRuntimeSettings(const FObjectInitializer& ObjectInitializer) + : Super(ObjectInitializer) + , bAutoEnabled(false) +{ +#if OCULUS_HMD_SUPPORTED_PLATFORMS + // FSettings is the sole source of truth for Oculus default settings + OculusXRHMD::FSettings DefaultSettings; + SystemSplashBackground = DefaultSettings.SystemSplashBackground; + bSupportsDash = DefaultSettings.Flags.bSupportsDash; + bCompositesDepth = DefaultSettings.Flags.bCompositeDepth; + bHQDistortion = DefaultSettings.Flags.bHQDistortion; + SuggestedCpuPerfLevel = DefaultSettings.SuggestedCpuPerfLevel; + SuggestedGpuPerfLevel = DefaultSettings.SuggestedGpuPerfLevel; + FoveatedRenderingMethod = DefaultSettings.FoveatedRenderingMethod; + FoveatedRenderingLevel = DefaultSettings.FoveatedRenderingLevel; + bDynamicFoveatedRendering = DefaultSettings.bDynamicFoveatedRendering; + bSupportEyeTrackedFoveatedRendering = DefaultSettings.bSupportEyeTrackedFoveatedRendering; + PixelDensityMin = DefaultSettings.PixelDensityMin; + PixelDensityMax = DefaultSettings.PixelDensityMax; + bFocusAware = DefaultSettings.Flags.bFocusAware; + bDynamicResolution = DefaultSettings.Flags.bPixelDensityAdaptive; + XrApi = DefaultSettings.XrApi; + ColorSpace = DefaultSettings.ColorSpace; + ControllerPoseAlignment = DefaultSettings.ControllerPoseAlignment; + bRequiresSystemKeyboard = DefaultSettings.Flags.bRequiresSystemKeyboard; + HandTrackingSupport = DefaultSettings.HandTrackingSupport; + HandTrackingFrequency = DefaultSettings.HandTrackingFrequency; + HandTrackingVersion = DefaultSettings.HandTrackingVersion; + bInsightPassthroughEnabled = DefaultSettings.Flags.bInsightPassthroughEnabled; + bBodyTrackingEnabled = DefaultSettings.Flags.bBodyTrackingEnabled; + bEyeTrackingEnabled = DefaultSettings.Flags.bEyeTrackingEnabled; + bFaceTrackingEnabled = DefaultSettings.Flags.bFaceTrackingEnabled; + bSupportExperimentalFeatures = DefaultSettings.bSupportExperimentalFeatures; + bAnchorSupportEnabled = DefaultSettings.Flags.bAnchorSupportEnabled; + bAnchorSharingEnabled = DefaultSettings.Flags.bAnchorSharingEnabled; + bSceneSupportEnabled = DefaultSettings.Flags.bSceneSupportEnabled; + ProcessorFavor = DefaultSettings.ProcessorFavor; + bTileTurnOffEnabled = DefaultSettings.Flags.bTileTurnOffEnabled; + + + FaceTrackingDataSource.Empty(static_cast(EFaceTrackingDataSourceConfig::MAX)); + FaceTrackingDataSource.Append(DefaultSettings.FaceTrackingDataSource); + + // Default this to false, FSettings doesn't have a separate composite depth flag for mobile + bCompositeDepthMobile = false; + +#else + // Some set of reasonable defaults, since blueprints are still available on non-Oculus platforms. + SystemSplashBackground = ESystemSplashBackgroundType::Black; + bSupportsDash = false; + bCompositesDepth = false; + bHQDistortion = false; + SuggestedCpuPerfLevel = EOculusXRProcessorPerformanceLevel::SustainedLow; + SuggestedGpuPerfLevel = EOculusXRProcessorPerformanceLevel::SustainedHigh; + FoveatedRenderingMethod = EOculusXRFoveatedRenderingMethod::FixedFoveatedRendering; + FoveatedRenderingLevel = EOculusXRFoveatedRenderingLevel::Off; + bDynamicFoveatedRendering = false; + bSupportEyeTrackedFoveatedRendering = false; + PixelDensityMin = 0.8f; + PixelDensityMax = 1.2f; + bDynamicResolution = false; + bCompositeDepthMobile = false; + bFocusAware = true; + XrApi = EOculusXRXrApi::OVRPluginOpenXR; + bLateLatching = false; + ColorSpace = EOculusXRColorSpace::P3; + ControllerPoseAlignment = EOculusXRControllerPoseAlignment::Default; + bRequiresSystemKeyboard = false; + HandTrackingSupport = EOculusXRHandTrackingSupport::ControllersOnly; + HandTrackingFrequency = EOculusXRHandTrackingFrequency::Low; + HandTrackingVersion = EOculusXRHandTrackingVersion::Default; + bInsightPassthroughEnabled = false; + bSupportExperimentalFeatures = false; + bBodyTrackingEnabled = false; + bEyeTrackingEnabled = false; + bFaceTrackingEnabled = false; + bAnchorSupportEnabled = false; + bAnchorSharingEnabled = false; + bSceneSupportEnabled = false; + ProcessorFavor = EProcessorFavor::FavorEqually; + bTileTurnOffEnabled = false; +#endif + + LoadFromIni(); +} + +#if WITH_EDITOR +bool UOculusXRHMDRuntimeSettings::CanEditChange(const FProperty* InProperty) const +{ + bool bIsEditable = Super::CanEditChange(InProperty); + + if (bIsEditable && InProperty) + { + const FName PropertyName = InProperty->GetFName(); + + if (PropertyName == GET_MEMBER_NAME_CHECKED(UOculusXRHMDRuntimeSettings, XrApi) && !FModuleManager::Get().IsModuleLoaded("OpenXRHMD")) + { + bIsEditable = false; + } + +// Disable settings for marketplace release that are only compatible with the Oculus engine fork +#ifndef WITH_OCULUS_BRANCH + if (PropertyName == GET_MEMBER_NAME_CHECKED(UOculusXRHMDRuntimeSettings, FoveatedRenderingMethod) || PropertyName == GET_MEMBER_NAME_CHECKED(UOculusXRHMDRuntimeSettings, bSupportEyeTrackedFoveatedRendering) || PropertyName == GET_MEMBER_NAME_CHECKED(UOculusXRHMDRuntimeSettings, bDynamicResolution)) + + { + bIsEditable = false; + } +#endif // WITH_OCULUS_BRANCH + } + + return bIsEditable; +} + +void UOculusXRHMDRuntimeSettings::PostEditChangeProperty(struct FPropertyChangedEvent& PropertyChangedEvent) +{ + Super::PostEditChangeProperty(PropertyChangedEvent); + + if (PropertyChangedEvent.Property != nullptr) + { + // Automatically switch to Fixed Foveated Rendering when removing Eye Tracked Foveated rendering support + if (PropertyChangedEvent.Property->GetFName() == GET_MEMBER_NAME_CHECKED(UOculusXRHMDRuntimeSettings, bSupportEyeTrackedFoveatedRendering) && !bSupportEyeTrackedFoveatedRendering) + { + FoveatedRenderingMethod = EOculusXRFoveatedRenderingMethod::FixedFoveatedRendering; + UpdateSinglePropertyInConfigFile(GetClass()->FindPropertyByName(GET_MEMBER_NAME_CHECKED(UOculusXRHMDRuntimeSettings, FoveatedRenderingMethod)), GetDefaultConfigFilename()); + } + // Automatically enable support for eye tracked foveated rendering when selecting the Eye Tracked Foveated Rendering method + if (PropertyChangedEvent.Property->GetFName() == GET_MEMBER_NAME_CHECKED(UOculusXRHMDRuntimeSettings, FoveatedRenderingMethod) && FoveatedRenderingMethod == EOculusXRFoveatedRenderingMethod::EyeTrackedFoveatedRendering) + { + bSupportEyeTrackedFoveatedRendering = true; + UpdateSinglePropertyInConfigFile(GetClass()->FindPropertyByName(GET_MEMBER_NAME_CHECKED(UOculusXRHMDRuntimeSettings, bSupportEyeTrackedFoveatedRendering)), GetDefaultConfigFilename()); + } + + if (PropertyChangedEvent.Property->GetFName() == GET_MEMBER_NAME_CHECKED(UOculusXRHMDRuntimeSettings, SupportedDevices)) + { + if (PropertyChangedEvent.ChangeType == EPropertyChangeType::ArrayAdd) + { + // Get a list of all available devices + TArray deviceList; +#define OCULUS_DEVICE_LOOP(device) deviceList.Add(device); + FOREACH_ENUM_EOCULUSXRSUPPORTEDDEVICES(OCULUS_DEVICE_LOOP); +#undef OCULUS_DEVICE_LOOP + // Add last device that isn't already in the list + for (int i = deviceList.Num() - 1; i >= 0; --i) + { + if (!SupportedDevices.Contains(deviceList[i])) + { + SupportedDevices.Last() = deviceList[i]; + break; + } + // Just add another copy of the first device if nothing was available + SupportedDevices.Last() = deviceList[deviceList.Num() - 1]; + } + } + } + } +} +#endif // WITH_EDITOR + +void UOculusXRHMDRuntimeSettings::PostInitProperties() +{ + Super::PostInitProperties(); + RenameProperties(); + + const TCHAR* OculusSettings = TEXT("/Script/OculusXRHMD.OculusXRHMDRuntimeSettings"); + if (!FModuleManager::Get().IsModuleLoaded("OpenXRHMD")) + { + XrApi = EOculusXRXrApi::OVRPluginOpenXR; + UpdateSinglePropertyInConfigFile(GetClass()->FindPropertyByName(GET_MEMBER_NAME_CHECKED(UOculusXRHMDRuntimeSettings, XrApi)), GetDefaultConfigFilename()); + } +} + +void UOculusXRHMDRuntimeSettings::LoadFromIni() +{ + const TCHAR* OculusSettings = TEXT("Oculus.Settings"); + bool v; + float f; + FVector vec; + + if (GConfig->GetFloat(OculusSettings, TEXT("PixelDensityMax"), f, GEngineIni)) + { + check(!FMath::IsNaN(f)); + PixelDensityMax = f; + } + if (GConfig->GetFloat(OculusSettings, TEXT("PixelDensityMin"), f, GEngineIni)) + { + check(!FMath::IsNaN(f)); + PixelDensityMin = f; + } + if (GConfig->GetBool(OculusSettings, TEXT("bHQDistortion"), v, GEngineIni)) + { + bHQDistortion = v; + } + if (GConfig->GetBool(OculusSettings, TEXT("bCompositeDepth"), v, GEngineIni)) + { + bCompositesDepth = v; + } +} + +/** This essentially acts like redirects for plugin settings saved in the engine config. + Anything added here should check for the current setting in the config so that if the dev changes the setting manually, we don't overwrite it with the old setting. + Note: Do not use UpdateSinglePropertyInConfigFile() here, since that uses a temp config to save the single property, + it'll get overwritten when GConfig->RemoveKey() marks the main config as dirty and it gets saved again **/ +void UOculusXRHMDRuntimeSettings::RenameProperties() +{ + const TCHAR* OculusSettings = TEXT("/Script/OculusXRHMD.OculusXRHMDRuntimeSettings"); + bool v = false; + FString str; + + // FFRLevel was renamed to FoveatedRenderingLevel + if (!GConfig->GetString(OculusSettings, GET_MEMBER_NAME_STRING_CHECKED(UOculusXRHMDRuntimeSettings, FoveatedRenderingLevel), str, GetDefaultConfigFilename()) && GConfig->GetString(OculusSettings, TEXT("FFRLevel"), str, GetDefaultConfigFilename())) + { + if (str.Equals(TEXT("FFR_Off"))) + { + FoveatedRenderingLevel = EOculusXRFoveatedRenderingLevel::Off; + } + else if (str.Equals(TEXT("FFR_Low"))) + { + FoveatedRenderingLevel = EOculusXRFoveatedRenderingLevel::Low; + } + else if (str.Equals(TEXT("FFR_Medium"))) + { + FoveatedRenderingLevel = EOculusXRFoveatedRenderingLevel::Medium; + } + else if (str.Equals(TEXT("FFR_High"))) + { + FoveatedRenderingLevel = EOculusXRFoveatedRenderingLevel::High; + } + else if (str.Equals(TEXT("FFR_HighTop"))) + { + FoveatedRenderingLevel = EOculusXRFoveatedRenderingLevel::HighTop; + } + // Use GetNameStringByValue() here because GetValueAsString() includes the type name as well + GConfig->SetString(OculusSettings, GET_MEMBER_NAME_STRING_CHECKED(UOculusXRHMDRuntimeSettings, FoveatedRenderingLevel), *StaticEnum()->GetNameStringByValue((int64)FoveatedRenderingLevel), GetDefaultConfigFilename()); + GConfig->RemoveKey(OculusSettings, TEXT("FFRLevel"), GetDefaultConfigFilename()); + } + + // FFRDynamic was renamed to bDynamicFoveatedRendering + if (!GConfig->GetString(OculusSettings, GET_MEMBER_NAME_STRING_CHECKED(UOculusXRHMDRuntimeSettings, bDynamicFoveatedRendering), str, GetDefaultConfigFilename()) && GConfig->GetBool(OculusSettings, TEXT("FFRDynamic"), v, GetDefaultConfigFilename())) + { + bDynamicFoveatedRendering = v; + GConfig->SetBool(OculusSettings, GET_MEMBER_NAME_STRING_CHECKED(UOculusXRHMDRuntimeSettings, bDynamicFoveatedRendering), bDynamicFoveatedRendering, GetDefaultConfigFilename()); + GConfig->RemoveKey(OculusSettings, TEXT("FFRDynamic"), GetDefaultConfigFilename()); + } + + const FString Quest = TEXT("Quest"); + +#ifndef WITH_OCULUS_BRANCH + const TCHAR* AndroidSettings = TEXT("/Script/AndroidRuntimeSettings.AndroidRuntimeSettings"); + TArray PackageList; + const TCHAR* PackageForMobileKey = TEXT("+PackageForOculusMobile"); + if (GConfig->GetArray(AndroidSettings, PackageForMobileKey, PackageList, GetDefaultConfigFilename())) + { + const FString Quest2 = TEXT("Quest2"); + if (PackageList.Contains(Quest)) + { + PackageList.Remove(Quest); + if (!PackageList.Contains(Quest2)) + { + PackageList.Add(Quest2); + } + GConfig->SetArray(AndroidSettings, PackageForMobileKey, PackageList, GetDefaultConfigFilename()); + } + } +#endif // WITH_OCULUS_BRANCH + + TArray DeviceList; + const TCHAR* SupportedDevicesKey = *FString("+").Append(GET_MEMBER_NAME_STRING_CHECKED(UOculusXRHMDRuntimeSettings, SupportedDevices)); + if (GConfig->GetArray(OculusSettings, SupportedDevicesKey, DeviceList, GetDefaultConfigFilename())) + { + const EOculusXRSupportedDevices LastSupportedDevice = EOculusXRSupportedDevices::Quest2; + const FString LastSupportedDeviceString = StaticEnum()->GetNameStringByValue((int64)LastSupportedDevice); + if (DeviceList.Contains(Quest)) + { + DeviceList.Remove(Quest); + if (!DeviceList.Contains(LastSupportedDeviceString)) + { + DeviceList.Add(LastSupportedDeviceString); + } + GConfig->SetArray(OculusSettings, SupportedDevicesKey, DeviceList, GetDefaultConfigFilename()); + + // Reflect the config changes in the Project Settings UI + SupportedDevices.Remove((EOculusXRSupportedDevices)0); // Enums that don't exist just have a value of 0 + if (!SupportedDevices.Contains(LastSupportedDevice)) + { + SupportedDevices.Add(LastSupportedDevice); + } + } + } +} diff --git a/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_ConsoleCommands.cpp b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_ConsoleCommands.cpp new file mode 100644 index 0000000..6368027 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_ConsoleCommands.cpp @@ -0,0 +1,90 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. +#include "OculusXRHMD_ConsoleCommands.h" + +#if OCULUS_HMD_SUPPORTED_PLATFORMS +#include "OculusXRHMD.h" +#include "OculusXRSceneCaptureCubemap.h" + +namespace OculusXRHMD +{ + + //------------------------------------------------------------------------------------------------- + // FConsoleCommands + //------------------------------------------------------------------------------------------------- + + /// @cond DOXYGEN_WARNINGS + + FConsoleCommands::FConsoleCommands(class FOculusXRHMD* InHMDPtr) + : UpdateOnRenderThreadCommand(TEXT("vr.oculus.bUpdateOnRenderThread"), + *NSLOCTEXT("OculusRift", "CCommandText_UpdateRT", "Oculus Rift specific extension.\nEnables or disables updating on the render thread.").ToString(), + FConsoleCommandWithWorldArgsAndOutputDeviceDelegate::CreateRaw(InHMDPtr, &FOculusXRHMD::UpdateOnRenderThreadCommandHandler)) + , PixelDensityMinCommand(TEXT("vr.oculus.PixelDensity.min"), + *NSLOCTEXT("OculusRift", "CCommandText_PixelDensityMin", "Oculus Rift specific extension.\nMinimum pixel density when adaptive pixel density is enabled").ToString(), + FConsoleCommandWithWorldArgsAndOutputDeviceDelegate::CreateRaw(InHMDPtr, &FOculusXRHMD::PixelDensityMinCommandHandler)) + , PixelDensityMaxCommand(TEXT("vr.oculus.PixelDensity.max"), + *NSLOCTEXT("OculusRift", "CCommandText_PixelDensityMax", "Oculus Rift specific extension.\nMaximum pixel density when adaptive pixel density is enabled").ToString(), + FConsoleCommandWithWorldArgsAndOutputDeviceDelegate::CreateRaw(InHMDPtr, &FOculusXRHMD::PixelDensityMaxCommandHandler)) + , HQBufferCommand(TEXT("vr.oculus.bHQBuffer"), + *NSLOCTEXT("OculusRift", "CCommandText_HQBuffer", "Oculus Rift specific extension.\nEnable or disable using floating point texture format for the eye layer.").ToString(), + FConsoleCommandWithWorldArgsAndOutputDeviceDelegate::CreateRaw(InHMDPtr, &FOculusXRHMD::HQBufferCommandHandler)) + , HQDistortionCommand(TEXT("vr.oculus.bHQDistortion"), + *NSLOCTEXT("OculusRift", "CCommandText_HQDistortion", "Oculus Rift specific extension.\nEnable or disable using multiple mipmap levels for the eye layer.").ToString(), + FConsoleCommandWithWorldArgsAndOutputDeviceDelegate::CreateRaw(InHMDPtr, &FOculusXRHMD::HQDistortionCommandHandler)) + , ShowGlobalMenuCommand(TEXT("vr.oculus.ShowGlobalMenu"), + *NSLOCTEXT("OculusRift", "CCommandText_GlobalMenu", "Oculus Rift specific extension.\nOpens the global menu.").ToString(), + FConsoleCommandWithWorldArgsAndOutputDeviceDelegate::CreateRaw(InHMDPtr, &FOculusXRHMD::ShowGlobalMenuCommandHandler)) + , ShowQuitMenuCommand(TEXT("vr.oculus.ShowQuitMenu"), + *NSLOCTEXT("OculusRift", "CCommandText_QuitMenu", "Oculus Rift specific extension.\nOpens the quit menu.").ToString(), + FConsoleCommandWithWorldArgsAndOutputDeviceDelegate::CreateRaw(InHMDPtr, &FOculusXRHMD::ShowQuitMenuCommandHandler)) + +#if !UE_BUILD_SHIPPING + , StatsCommand(TEXT("vr.oculus.Debug.bShowStats"), + *NSLOCTEXT("OculusRift", "CCommandText_Stats", "Oculus Rift specific extension.\nEnable or disable rendering of stats.").ToString(), + FConsoleCommandWithWorldArgsAndOutputDeviceDelegate::CreateRaw(InHMDPtr, &FOculusXRHMD::StatsCommandHandler)) + , CubemapCommand(TEXT("vr.oculus.Debug.CaptureCubemap"), + *NSLOCTEXT("OculusRift", "CCommandText_Cubemap", "Oculus Rift specific extension.\nCaptures a cubemap for Oculus Home.\nOptional arguments (default is zero for all numeric arguments):\n xoff= -- X axis offset from the origin\n yoff= -- Y axis offset\n zoff= -- Z axis offset\n yaw= -- the direction to look into (roll and pitch is fixed to zero)\n mobile -- Generate a Mobile format cubemap\n (height of the captured cubemap will be 1024 instead of 2048 pixels)\n").ToString(), + FConsoleCommandWithWorldArgsAndOutputDeviceDelegate::CreateStatic(&UOculusXRSceneCaptureCubemap::CaptureCubemapCommandHandler)) + , ShowSettingsCommand(TEXT("vr.oculus.Debug.Show"), + *NSLOCTEXT("OculusRift", "CCommandText_Show", "Oculus Rift specific extension.\nShows the current value of various stereo rendering params.").ToString(), + FConsoleCommandWithWorldArgsAndOutputDeviceDelegate::CreateRaw(InHMDPtr, &FOculusXRHMD::ShowSettingsCommandHandler)) + , IPDCommand(TEXT("vr.oculus.Debug.IPD"), + *NSLOCTEXT("OculusRift", "CCommandText_IPD", "Oculus Rift specific extension.\nShows or changes the current interpupillary distance in meters.").ToString(), + FConsoleCommandWithWorldArgsAndOutputDeviceDelegate::CreateRaw(InHMDPtr, &FOculusXRHMD::IPDCommandHandler)) +#endif // !UE_BUILD_SHIPPING + { + } + + bool FConsoleCommands::Exec(UWorld* InWorld, const TCHAR* Cmd, FOutputDevice& Ar) + { + const TCHAR* OrigCmd = Cmd; + FString AliasedCommand; + + if (FParse::Command(&Cmd, TEXT("OVRGLOBALMENU"))) + { + AliasedCommand = TEXT("vr.oculus.ShowGlobalMenu"); + } + else if (FParse::Command(&Cmd, TEXT("OVRQUITMENU"))) + { + AliasedCommand = TEXT("vr.oculus.ShowQuitMenu"); + } +#if !UE_BUILD_SHIPPING + else if (FParse::Command(&Cmd, TEXT("vr.oculus.Debug.EnforceHeadTracking"))) + { + AliasedCommand = TEXT("vr.HeadTracking.bEnforced"); + } +#endif // !UE_BUILD_SHIPPING + + if (!AliasedCommand.IsEmpty()) + { + Ar.Logf(ELogVerbosity::Warning, TEXT("%s is deprecated. Use %s instead"), OrigCmd, *AliasedCommand); + return IConsoleManager::Get().ProcessUserConsoleInput(*AliasedCommand, Ar, InWorld); + } + return false; + } + + /// @endcond + +} // namespace OculusXRHMD + +#endif // OCULUS_HMD_SUPPORTED_PLATFORMS diff --git a/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_ConsoleCommands.h b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_ConsoleCommands.h new file mode 100644 index 0000000..f78799d --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_ConsoleCommands.h @@ -0,0 +1,45 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +#pragma once +#include "OculusXRHMDPrivate.h" + +#if OCULUS_HMD_SUPPORTED_PLATFORMS +#include "HAL/IConsoleManager.h" + +namespace OculusXRHMD +{ + + //------------------------------------------------------------------------------------------------- + // FConsoleCommands + //------------------------------------------------------------------------------------------------- + + class FConsoleCommands : private FSelfRegisteringExec + { + public: + FConsoleCommands(class FOculusXRHMD* InHMDPtr); + + // FSelfRegisteringExec interface + virtual bool Exec(UWorld* InWorld, const TCHAR* Cmd, FOutputDevice& Ar) override; + + private: + FAutoConsoleCommand UpdateOnRenderThreadCommand; + FAutoConsoleCommand PixelDensityMinCommand; + FAutoConsoleCommand PixelDensityMaxCommand; + FAutoConsoleCommand HQBufferCommand; + FAutoConsoleCommand HQDistortionCommand; + FAutoConsoleCommand ShowGlobalMenuCommand; + FAutoConsoleCommand ShowQuitMenuCommand; + +#if !UE_BUILD_SHIPPING + // Debug console commands + FAutoConsoleCommand StatsCommand; + FAutoConsoleCommand CubemapCommand; + FAutoConsoleCommand ShowSettingsCommand; + FAutoConsoleCommand IPDCommand; +#endif // !UE_BUILD_SHIPPING + }; + +} // namespace OculusXRHMD + +#endif //OCULUS_HMD_SUPPORTED_PLATFORMS diff --git a/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_CustomPresent.cpp b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_CustomPresent.cpp new file mode 100644 index 0000000..73ebaee --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_CustomPresent.cpp @@ -0,0 +1,657 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +#include "OculusXRHMD_CustomPresent.h" + +#if OCULUS_HMD_SUPPORTED_PLATFORMS +#include "OculusXRHMD.h" +#include "ScreenRendering.h" +#include "PipelineStateCache.h" +#include "ClearQuad.h" +#include "OculusShaders.h" +#include "CommonRenderResources.h" +#include "RHIStaticStates.h" + +#if PLATFORM_ANDROID +#include "Android/AndroidJNI.h" +#include "Android/AndroidEGL.h" +#include "Android/AndroidApplication.h" +#include "Android/AndroidPlatformMisc.h" +#endif + +#define VULKAN_CUBEMAP_POSITIVE_Y 2 +#define VULKAN_CUBEMAP_NEGATIVE_Y 3 + +namespace OculusXRHMD +{ + /** + * A pixel shader for rendering a textured screen element with mip maps and array slice. + */ + class FScreenPSMipLevelArray : public FGlobalShader + { + DECLARE_SHADER_TYPE(FScreenPSMipLevelArray, Global); + + public: + static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters) { return true; } + + FScreenPSMipLevelArray(const ShaderMetaType::CompiledShaderInitializerType& Initializer) + : FGlobalShader(Initializer) + { + InTexture.Bind(Initializer.ParameterMap, TEXT("InTexture"), SPF_Mandatory); + InTextureSampler.Bind(Initializer.ParameterMap, TEXT("InTextureSampler")); + InMipLevelParameter.Bind(Initializer.ParameterMap, TEXT("MipLevel")); + InArraySliceParameter.Bind(Initializer.ParameterMap, TEXT("ArraySlice")); + } + FScreenPSMipLevelArray() {} + + void SetParameters(FRHIBatchedShaderParameters& BatchedParameters, const FTexture* Texture, int ArraySlice, int MipLevel) + { + SetTextureParameter(BatchedParameters, InTexture, InTextureSampler, Texture); + SetShaderValue(BatchedParameters, InMipLevelParameter, MipLevel); + SetShaderValue(BatchedParameters, InArraySliceParameter, ArraySlice); + } + + void SetParameters(FRHIBatchedShaderParameters& BatchedParameters, FRHISamplerState* SamplerStateRHI, FRHITexture* TextureRHI, int ArraySlice, int MipLevel) + { + SetTextureParameter(BatchedParameters, InTexture, InTextureSampler, SamplerStateRHI, TextureRHI); + SetShaderValue(BatchedParameters, InMipLevelParameter, MipLevel); + SetShaderValue(BatchedParameters, InArraySliceParameter, ArraySlice); + } + + private: + LAYOUT_FIELD(FShaderResourceParameter, InTexture); + LAYOUT_FIELD(FShaderResourceParameter, InTextureSampler); + LAYOUT_FIELD(FShaderParameter, InMipLevelParameter); + LAYOUT_FIELD(FShaderParameter, InArraySliceParameter); + }; + IMPLEMENT_SHADER_TYPE(, FScreenPSMipLevelArray, TEXT("/Plugin/OculusXR/Private/ScreenPixelShaderArraySlice.usf"), TEXT("MainMipLevel"), SF_Pixel); + + /** + * A pixel shader for rendering a textured screen element with mip maps and array slice. + */ + class FScreenPSsRGBSourceMipLevelArray : public FGlobalShader + { + DECLARE_SHADER_TYPE(FScreenPSsRGBSourceMipLevelArray, Global); + + public: + static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters) { return true; } + + FScreenPSsRGBSourceMipLevelArray(const ShaderMetaType::CompiledShaderInitializerType& Initializer) + : FGlobalShader(Initializer) + { + InTexture.Bind(Initializer.ParameterMap, TEXT("InTexture"), SPF_Mandatory); + InTextureSampler.Bind(Initializer.ParameterMap, TEXT("InTextureSampler")); + InMipLevelParameter.Bind(Initializer.ParameterMap, TEXT("MipLevel")); + InArraySliceParameter.Bind(Initializer.ParameterMap, TEXT("ArraySlice")); + } + FScreenPSsRGBSourceMipLevelArray() {} + + void SetParameters(FRHIBatchedShaderParameters& BatchedParameters, const FTexture* Texture, int ArraySlice, int MipLevel) + { + SetTextureParameter(BatchedParameters, InTexture, InTextureSampler, Texture); + SetShaderValue(BatchedParameters, InMipLevelParameter, MipLevel); + SetShaderValue(BatchedParameters, InArraySliceParameter, ArraySlice); + } + + void SetParameters(FRHIBatchedShaderParameters& BatchedParameters, FRHISamplerState* SamplerStateRHI, FRHITexture* TextureRHI, int ArraySlice, int MipLevel) + { + SetTextureParameter(BatchedParameters, InTexture, InTextureSampler, SamplerStateRHI, TextureRHI); + SetShaderValue(BatchedParameters, InMipLevelParameter, MipLevel); + SetShaderValue(BatchedParameters, InArraySliceParameter, ArraySlice); + } + + private: + LAYOUT_FIELD(FShaderResourceParameter, InTexture); + LAYOUT_FIELD(FShaderResourceParameter, InTextureSampler); + LAYOUT_FIELD(FShaderParameter, InMipLevelParameter); + LAYOUT_FIELD(FShaderParameter, InArraySliceParameter); + }; + IMPLEMENT_SHADER_TYPE(, FScreenPSsRGBSourceMipLevelArray, TEXT("/Plugin/OculusXR/Private/ScreenPixelShaderArraySlice.usf"), TEXT("MainsRGBSourceMipLevel"), SF_Pixel); + + //------------------------------------------------------------------------------------------------- + // FCustomPresent + //------------------------------------------------------------------------------------------------- + + FCustomPresent::FCustomPresent(class FOculusXRHMD* InOculusXRHMD, ovrpRenderAPIType InRenderAPI, EPixelFormat InDefaultPixelFormat, bool bInSupportsSRGB) + : OculusXRHMD(InOculusXRHMD) + , RenderAPI(InRenderAPI) + , DefaultPixelFormat(InDefaultPixelFormat) + , bSupportsSRGB(bInSupportsSRGB) + , bSupportsSubsampled(false) + , bIsStandaloneStereoDevice(false) + { + CheckInGameThread(); + + DefaultOvrpTextureFormat = GetOvrpTextureFormat(GetDefaultPixelFormat()); + DefaultDepthOvrpTextureFormat = ovrpTextureFormat_None; + +#if PLATFORM_ANDROID + bIsStandaloneStereoDevice = FAndroidMisc::GetDeviceMake() == FString("Oculus"); +#endif + + // grab a pointer to the renderer module for displaying our mirror window + static const FName RendererModuleName("Renderer"); + RendererModule = FModuleManager::GetModulePtr(RendererModuleName); + } + + void FCustomPresent::ReleaseResources_RHIThread() + { + CheckInRHIThread(); + + if (MirrorTextureRHI.IsValid()) + { + FOculusXRHMDModule::GetPluginWrapper().DestroyMirrorTexture2(); + MirrorTextureRHI = nullptr; + } + } + + void FCustomPresent::Shutdown() + { + CheckInGameThread(); + + // OculusXRHMD is going away, but this object can live on until viewport is destroyed + ExecuteOnRenderThread([this]() { + ExecuteOnRHIThread([this]() { + OculusXRHMD = nullptr; + }); + }); + } + + bool FCustomPresent::NeedsNativePresent() + { + return !bIsStandaloneStereoDevice; + } + + bool FCustomPresent::Present(int32& SyncInterval) + { + CheckInRHIThread(); + + if (OculusXRHMD) + { + FGameFrame* Frame_RHIThread = OculusXRHMD->GetFrame_RHIThread(); + if (Frame_RHIThread) + { + FinishRendering_RHIThread(); + } + } + + SyncInterval = 0; // VSync off + + return NeedsNativePresent(); + } + + void FCustomPresent::UpdateMirrorTexture_RenderThread() + { + SCOPE_CYCLE_COUNTER(STAT_BeginRendering); + + CheckInRenderThread(); + + const ESpectatorScreenMode MirrorWindowMode = OculusXRHMD->GetSpectatorScreenMode_RenderThread(); + const FIntPoint MirrorWindowSize = OculusXRHMD->GetFrame_RenderThread()->WindowSize; + + if (FOculusXRHMDModule::GetPluginWrapper().GetInitialized()) + { + // Need to destroy mirror texture? + if (MirrorTextureRHI.IsValid()) + { + const auto MirrorTextureSize = FIntPoint(MirrorTextureRHI->GetDesc().Extent.X, MirrorTextureRHI->GetDesc().Extent.Y); + if (MirrorWindowMode != ESpectatorScreenMode::Distorted || MirrorWindowSize != MirrorTextureSize) + { + ExecuteOnRHIThread([]() { + FOculusXRHMDModule::GetPluginWrapper().DestroyMirrorTexture2(); + }); + + MirrorTextureRHI = nullptr; + } + } + + // Need to create mirror texture? + if (!MirrorTextureRHI.IsValid() && MirrorWindowMode == ESpectatorScreenMode::Distorted && MirrorWindowSize.X != 0 && MirrorWindowSize.Y != 0) + { + const int Width = MirrorWindowSize.X; + const int Height = MirrorWindowSize.Y; + ovrpTextureHandle TextureHandle; + + ExecuteOnRHIThread([&]() { + FOculusXRHMDModule::GetPluginWrapper().SetupMirrorTexture2(GetOvrpDevice(), Height, Width, GetDefaultOvrpTextureFormat(), &TextureHandle); + }); + + UE_LOG(LogHMD, Log, TEXT("Allocated a new mirror texture (size %d x %d)"), Width, Height); + + ETextureCreateFlags TexCreateFlags = TexCreate_ShaderResource | TexCreate_RenderTargetable; + + MirrorTextureRHI = CreateTexture_RenderThread(Width, Height, GetDefaultPixelFormat(), FClearValueBinding::None, 1, 1, 1, RRT_Texture2D, TextureHandle, TexCreateFlags)->GetTexture2D(); + } + } + } + + void FCustomPresent::FinishRendering_RHIThread() + { + SCOPE_CYCLE_COUNTER(STAT_FinishRendering); + CheckInRHIThread(); + +#if STATS + if (OculusXRHMD->GetFrame_RHIThread()->ShowFlags.Rendering) + { + ovrpAppLatencyTimings AppLatencyTimings; + if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetAppLatencyTimings2(&AppLatencyTimings))) + { + SET_FLOAT_STAT(STAT_LatencyRender, AppLatencyTimings.LatencyRender * 1000.0f); + SET_FLOAT_STAT(STAT_LatencyTimewarp, AppLatencyTimings.LatencyTimewarp * 1000.0f); + SET_FLOAT_STAT(STAT_LatencyPostPresent, AppLatencyTimings.LatencyPostPresent * 1000.0f); + SET_FLOAT_STAT(STAT_ErrorRender, AppLatencyTimings.ErrorRender * 1000.0f); + SET_FLOAT_STAT(STAT_ErrorTimewarp, AppLatencyTimings.ErrorTimewarp * 1000.0f); + } + } +#endif + + OculusXRHMD->FinishRHIFrame_RHIThread(); + +#if PLATFORM_ANDROID + float GPUFrameTime = 0.0f; + if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetGPUFrameTime(&GPUFrameTime))) + { + SubmitGPUFrameTime(GPUFrameTime); + } +#endif + } + + EPixelFormat FCustomPresent::GetPixelFormat(EPixelFormat Format) const + { + switch (Format) + { + // case PF_B8G8R8A8: + case PF_FloatRGBA: + case PF_FloatR11G11B10: + // case PF_R8G8B8A8: + case PF_G16: + case PF_R16F: + case PF_R32_FLOAT: + case PF_ShadowDepth: + case PF_D24: + return Format; + } + + return GetDefaultPixelFormat(); + } + + EPixelFormat FCustomPresent::GetPixelFormat(ovrpTextureFormat Format) const + { + switch (Format) + { + // case ovrpTextureFormat_R8G8B8A8_sRGB: + // case ovrpTextureFormat_R8G8B8A8: + // return PF_R8G8B8A8; + case ovrpTextureFormat_R16G16B16A16_FP: + return PF_FloatRGBA; + case ovrpTextureFormat_R11G11B10_FP: + return PF_FloatR11G11B10; + // case ovrpTextureFormat_B8G8R8A8_sRGB: + // case ovrpTextureFormat_B8G8R8A8: + // return PF_B8G8R8A8; + case ovrpTextureFormat_R16: + return PF_G16; // G stands for grey here, not green, and is actually R16 in RHI + case ovrpTextureFormat_R16_FP: + return PF_R16F; + case ovrpTextureFormat_R32_FP: + return PF_R32_FLOAT; + case ovrpTextureFormat_D16: + return PF_ShadowDepth; // ShadowDepth maps to D16 in Vulkan + case ovrpTextureFormat_D24_S8: + return PF_D24; + } + + return GetDefaultPixelFormat(); + } + + ovrpTextureFormat FCustomPresent::GetOvrpTextureFormat(EPixelFormat Format, bool usesRGB) const + { + switch (GetPixelFormat(Format)) + { + case PF_B8G8R8A8: + return bSupportsSRGB && usesRGB ? ovrpTextureFormat_B8G8R8A8_sRGB : ovrpTextureFormat_B8G8R8A8; + case PF_FloatRGBA: + return ovrpTextureFormat_R16G16B16A16_FP; + case PF_FloatR11G11B10: + return ovrpTextureFormat_R11G11B10_FP; + case PF_R8G8B8A8: + return bSupportsSRGB && usesRGB ? ovrpTextureFormat_R8G8B8A8_sRGB : ovrpTextureFormat_R8G8B8A8; + case PF_G16: + return ovrpTextureFormat_R16; + case PF_R16F: + return ovrpTextureFormat_R16_FP; + case PF_R32_FLOAT: + return ovrpTextureFormat_R32_FP; + case PF_ShadowDepth: + return ovrpTextureFormat_D16; + case PF_D24: + return ovrpTextureFormat_D24_S8; + } + + return ovrpTextureFormat_None; + } + + bool FCustomPresent::IsSRGB(ovrpTextureFormat InFormat) + { + switch (InFormat) + { + case ovrpTextureFormat_B8G8R8A8_sRGB: + case ovrpTextureFormat_R8G8B8A8_sRGB: + return true; + } + + return false; + } + + int FCustomPresent::GetSystemRecommendedMSAALevel() const + { + int SystemRecommendedMSAALevel = 1; + FOculusXRHMDModule::GetPluginWrapper().GetSystemRecommendedMSAALevel2(&SystemRecommendedMSAALevel); + return SystemRecommendedMSAALevel; + } + + FXRSwapChainPtr FCustomPresent::CreateSwapChain_RenderThread(uint32 InSizeX, uint32 InSizeY, EPixelFormat InFormat, FClearValueBinding InBinding, uint32 InNumMips, uint32 InNumSamples, uint32 InNumSamplesTileMem, ERHIResourceType InResourceType, const TArray& InTextures, ETextureCreateFlags InTexCreateFlags, const TCHAR* DebugName) + { + TArray RHITextureSwapChain = CreateSwapChainTextures_RenderThread(InSizeX, InSizeY, InFormat, InBinding, InNumMips, InNumSamples, InNumSamplesTileMem, InResourceType, InTextures, InTexCreateFlags, DebugName); + + FTextureRHIRef RHITexture = GDynamicRHI->RHICreateAliasedTexture(RHITextureSwapChain[0]); + + return CreateXRSwapChain(MoveTemp(RHITextureSwapChain), RHITexture); + } + + TArray FCustomPresent::CreateSwapChainTextures_RenderThread(uint32 InSizeX, uint32 InSizeY, EPixelFormat InFormat, FClearValueBinding InBinding, uint32 InNumMips, uint32 InNumSamples, uint32 InNumSamplesTileMem, ERHIResourceType InResourceType, const TArray& InTextures, ETextureCreateFlags InTexCreateFlags, const TCHAR* DebugName) + { + CheckInRenderThread(); + + TArray RHITextureSwapChain; + { + for (int32 TextureIndex = 0; TextureIndex < InTextures.Num(); ++TextureIndex) + { + FTextureRHIRef TexRef = CreateTexture_RenderThread(InSizeX, InSizeY, InFormat, InBinding, InNumMips, InNumSamples, InNumSamplesTileMem, InResourceType, InTextures[TextureIndex], InTexCreateFlags); + + FString TexName = FString::Printf(TEXT("%s (%d/%d)"), DebugName, TextureIndex, InTextures.Num()); + TexRef->SetName(*TexName); + RHIBindDebugLabelName(TexRef, *TexName); + + RHITextureSwapChain.Add(TexRef); + } + } + + return RHITextureSwapChain; + } + + void FCustomPresent::CopyTexture_RenderThread(FRHICommandListImmediate& RHICmdList, FRHITexture* DstTexture, FRHITexture* SrcTexture, + FIntRect DstRect, FIntRect SrcRect, bool bAlphaPremultiply, bool bNoAlphaWrite, bool bInvertY, bool sRGBSource, bool bInvertAlpha) const + { + CheckInRenderThread(); + + FIntPoint DstSize; + FIntPoint SrcSize; + + if (DstTexture->GetDesc().IsTexture2D() && SrcTexture->GetDesc().IsTexture2D()) + { + DstSize = FIntPoint(DstTexture->GetSizeX(), DstTexture->GetSizeY()); + SrcSize = FIntPoint(SrcTexture->GetSizeX(), SrcTexture->GetSizeY()); + } + else if (DstTexture->GetDesc().IsTextureCube() && SrcTexture->GetDesc().IsTextureCube()) + { + DstSize = FIntPoint(DstTexture->GetSize(), DstTexture->GetSize()); + SrcSize = FIntPoint(SrcTexture->GetSize(), SrcTexture->GetSize()); + } + else + { + return; + } + + if (DstRect.IsEmpty()) + { + DstRect = FIntRect(FIntPoint::ZeroValue, DstSize); + } + + if (SrcRect.IsEmpty()) + { + SrcRect = FIntRect(FIntPoint::ZeroValue, SrcSize); + } + + const uint32 ViewportWidth = DstRect.Width(); + const uint32 ViewportHeight = DstRect.Height(); + const FIntPoint TargetSize(ViewportWidth, ViewportHeight); + float U = SrcRect.Min.X / (float)SrcSize.X; + float V = SrcRect.Min.Y / (float)SrcSize.Y; + float USize = SrcRect.Width() / (float)SrcSize.X; + float VSize = SrcRect.Height() / (float)SrcSize.Y; + +#if PLATFORM_ANDROID // on android, top-left isn't 0/0 but 1/0. + if (bInvertY) + { + V = 1.0f - V; + VSize = -VSize; + } +#endif + + FRHITexture* SrcTextureRHI = SrcTexture; + RHICmdList.Transition(FRHITransitionInfo(SrcTextureRHI, ERHIAccess::Unknown, ERHIAccess::SRVGraphics)); + FGraphicsPipelineStateInitializer GraphicsPSOInit; + + if (bInvertAlpha) + { + // write RGBA, RGB = src.rgb * 1 + dst.rgb * 0, A = src.a * 0 + dst.a * (1 - src.a) + GraphicsPSOInit.BlendState = TStaticBlendState::GetRHI(); + } + else if (bAlphaPremultiply) + { + if (bNoAlphaWrite) + { + // for quads, write RGB, RGB = src.rgb * 1 + dst.rgb * 0 + GraphicsPSOInit.BlendState = TStaticBlendState::GetRHI(); + } + else + { + // for quads, write RGBA, RGB = src.rgb * src.a + dst.rgb * 0, A = src.a + dst.a * 0 + GraphicsPSOInit.BlendState = TStaticBlendState::GetRHI(); + } + } + else + { + if (bNoAlphaWrite) + { + GraphicsPSOInit.BlendState = TStaticBlendState::GetRHI(); + } + else + { + // for mirror window, write RGBA, RGB = src.rgb * src.a + dst.rgb * (1 - src.a), A = src.a * 1 + dst.a * (1 - src a) + GraphicsPSOInit.BlendState = TStaticBlendState::GetRHI(); + } + } + + GraphicsPSOInit.RasterizerState = TStaticRasterizerState<>::GetRHI(); + GraphicsPSOInit.DepthStencilState = TStaticDepthStencilState::GetRHI(); + GraphicsPSOInit.PrimitiveType = PT_TriangleList; + + const auto FeatureLevel = OculusXRHMD->GetSettings_RenderThread()->CurrentFeatureLevel; + auto ShaderMap = GetGlobalShaderMap(FeatureLevel); + TShaderMapRef VertexShader(ShaderMap); + GraphicsPSOInit.BoundShaderState.VertexDeclarationRHI = GFilterVertexDeclaration.VertexDeclarationRHI; + GraphicsPSOInit.BoundShaderState.VertexShaderRHI = VertexShader.GetVertexShader(); + + if (DstTexture->GetDesc().IsTexture2D()) + { + sRGBSource &= EnumHasAnyFlags(SrcTexture->GetFlags(), TexCreate_SRGB); + + // Need to copy over mip maps on Android since they are not generated like they are on PC +#if PLATFORM_ANDROID + uint32 NumMips = SrcTexture->GetNumMips(); +#else + uint32 NumMips = 1; +#endif + + const bool bUseTexArrayShader = SrcTexture->GetDesc().IsTextureArray() && DstTexture->GetDesc().IsTextureArray(); + const int32 SliceCount = bUseTexArrayShader ? FMath::Min(SrcTexture->GetDesc().ArraySize, DstTexture->GetDesc().ArraySize) : 1; + + for (uint32 MipIndex = 0; MipIndex < NumMips; MipIndex++) + { + FRHIRenderPassInfo RPInfo(DstTexture, ERenderTargetActions::Load_Store); + RPInfo.ColorRenderTargets[0].MipIndex = MipIndex; + + for (int32 SliceIndex = 0; SliceIndex < SliceCount; ++SliceIndex) + { + RPInfo.ColorRenderTargets[0].ArraySlice = SliceIndex; + + RHICmdList.BeginRenderPass(RPInfo, TEXT("CopyTexture")); + { + const uint32 MipViewportWidth = ViewportWidth >> MipIndex; + const uint32 MipViewportHeight = ViewportHeight >> MipIndex; + const FIntPoint MipTargetSize(MipViewportWidth, MipViewportHeight); + + if (bNoAlphaWrite || bInvertAlpha) + { + RHICmdList.SetViewport(DstRect.Min.X, DstRect.Min.Y, 0.0f, DstRect.Max.X, DstRect.Max.Y, 1.0f); + DrawClearQuad(RHICmdList, bAlphaPremultiply ? FLinearColor::Black : FLinearColor::White); + } + + RHICmdList.ApplyCachedRenderTargets(GraphicsPSOInit); + FRHISamplerState* SamplerState = DstRect.Size() == SrcRect.Size() ? TStaticSamplerState::GetRHI() : TStaticSamplerState::GetRHI(); + + if (!sRGBSource) + { + if (bUseTexArrayShader) + { + TShaderMapRef PixelShader(ShaderMap); + GraphicsPSOInit.BoundShaderState.PixelShaderRHI = PixelShader.GetPixelShader(); + SetGraphicsPipelineState(RHICmdList, GraphicsPSOInit, 0); + FRHIBatchedShaderParameters& BatchedParameters = RHICmdList.GetScratchShaderParameters(); + PixelShader->SetParameters(BatchedParameters, SamplerState, SrcTextureRHI, SliceIndex, MipIndex); + RHICmdList.SetBatchedShaderParameters(RHICmdList.GetBoundPixelShader(), BatchedParameters); + } + else + { + + TShaderMapRef PixelShader(ShaderMap); + GraphicsPSOInit.BoundShaderState.PixelShaderRHI = PixelShader.GetPixelShader(); + SetGraphicsPipelineState(RHICmdList, GraphicsPSOInit, 0); +#if UE_VERSION_OLDER_THAN(5, 3, 0) + PixelShader->SetParameters(RHICmdList, SamplerState, SrcTextureRHI, MipIndex); +#else + FRHIBatchedShaderParameters& BatchedParameters = RHICmdList.GetScratchShaderParameters(); + PixelShader->SetParameters(BatchedParameters, SamplerState, SrcTextureRHI, MipIndex); + RHICmdList.SetBatchedShaderParameters(RHICmdList.GetBoundPixelShader(), BatchedParameters); +#endif + } + } + else + { + if (bUseTexArrayShader) + { + TShaderMapRef PixelShader(ShaderMap); + GraphicsPSOInit.BoundShaderState.PixelShaderRHI = PixelShader.GetPixelShader(); + SetGraphicsPipelineState(RHICmdList, GraphicsPSOInit, 0); + FRHIBatchedShaderParameters& BatchedParameters = RHICmdList.GetScratchShaderParameters(); + PixelShader->SetParameters(BatchedParameters, SamplerState, SrcTextureRHI, SliceIndex, MipIndex); + RHICmdList.SetBatchedShaderParameters(RHICmdList.GetBoundPixelShader(), BatchedParameters); + } + else + { + TShaderMapRef PixelShader(ShaderMap); + GraphicsPSOInit.BoundShaderState.PixelShaderRHI = PixelShader.GetPixelShader(); + SetGraphicsPipelineState(RHICmdList, GraphicsPSOInit, 0); +#if UE_VERSION_OLDER_THAN(5, 3, 0) + PixelShader->SetParameters(RHICmdList, SamplerState, SrcTextureRHI, MipIndex); +#else + FRHIBatchedShaderParameters& BatchedParameters = RHICmdList.GetScratchShaderParameters(); + PixelShader->SetParameters(BatchedParameters, SamplerState, SrcTextureRHI, MipIndex); + RHICmdList.SetBatchedShaderParameters(RHICmdList.GetBoundPixelShader(), BatchedParameters); +#endif + } + } + + RHICmdList.SetViewport(DstRect.Min.X, DstRect.Min.Y, 0.0f, DstRect.Min.X + MipViewportWidth, DstRect.Min.Y + MipViewportHeight, 1.0f); + + RendererModule->DrawRectangle( + RHICmdList, + 0, 0, MipViewportWidth, MipViewportHeight, + U, V, USize, VSize, + MipTargetSize, + FIntPoint(1, 1), + VertexShader, + EDRF_Default); + } + RHICmdList.EndRenderPass(); + } + } + } + else + { + for (int FaceIndex = 0; FaceIndex < 6; FaceIndex++) + { + FRHIRenderPassInfo RPInfo(DstTexture, ERenderTargetActions::Load_Store); + + // On Vulkan the positive and negative Y faces of the cubemap need to be flipped + if (RenderAPI == ovrpRenderAPI_Vulkan) + { + int NewFaceIndex = 0; + + if (FaceIndex == VULKAN_CUBEMAP_POSITIVE_Y) + NewFaceIndex = VULKAN_CUBEMAP_NEGATIVE_Y; + else if (FaceIndex == VULKAN_CUBEMAP_NEGATIVE_Y) + NewFaceIndex = VULKAN_CUBEMAP_POSITIVE_Y; + else + NewFaceIndex = FaceIndex; + + RPInfo.ColorRenderTargets[0].ArraySlice = NewFaceIndex; + } + else + { + RPInfo.ColorRenderTargets[0].ArraySlice = FaceIndex; + } + + RHICmdList.BeginRenderPass(RPInfo, TEXT("CopyTextureFace")); + { + if (bNoAlphaWrite) + { + DrawClearQuad(RHICmdList, bAlphaPremultiply ? FLinearColor::Black : FLinearColor::White); + } + + RHICmdList.ApplyCachedRenderTargets(GraphicsPSOInit); + + TShaderMapRef PixelShader(ShaderMap); + GraphicsPSOInit.BoundShaderState.PixelShaderRHI = PixelShader.GetPixelShader(); + SetGraphicsPipelineState(RHICmdList, GraphicsPSOInit, 0); + FRHISamplerState* SamplerState = DstRect.Size() == SrcRect.Size() ? TStaticSamplerState::GetRHI() : TStaticSamplerState::GetRHI(); +#if UE_VERSION_OLDER_THAN(5, 3, 0) + PixelShader->SetParameters(RHICmdList, SamplerState, SrcTextureRHI, FaceIndex); +#else + FRHIBatchedShaderParameters& BatchedParameters = RHICmdList.GetScratchShaderParameters(); + PixelShader->SetParameters(BatchedParameters, SamplerState, SrcTextureRHI, FaceIndex); + RHICmdList.SetBatchedShaderParameters(RHICmdList.GetBoundPixelShader(), BatchedParameters); +#endif + + RHICmdList.SetViewport(DstRect.Min.X, DstRect.Min.Y, 0.0f, DstRect.Max.X, DstRect.Max.Y, 1.0f); + + RendererModule->DrawRectangle( + RHICmdList, + 0, 0, ViewportWidth, ViewportHeight, +#if PLATFORM_ANDROID + U, V, USize, VSize, +#else + U, 1.0 - V, USize, -VSize, +#endif + TargetSize, + FIntPoint(1, 1), + VertexShader, + EDRF_Default); + } + RHICmdList.EndRenderPass(); + } + } + } + + void FCustomPresent::SubmitGPUCommands_RenderThread(FRHICommandListImmediate& RHICmdList) + { + CheckInRenderThread(); + + RHICmdList.SubmitCommandsHint(); + } + +} // namespace OculusXRHMD + +#endif //OCULUS_HMD_SUPPORTED_PLATFORMS diff --git a/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_CustomPresent.h b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_CustomPresent.h new file mode 100644 index 0000000..206ccc6 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_CustomPresent.h @@ -0,0 +1,117 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +#pragma once +#include "OculusXRHMDPrivate.h" + +#if OCULUS_HMD_SUPPORTED_PLATFORMS +#include "OculusXRHMD_Settings.h" +#include "OculusXRHMD_GameFrame.h" +#include "XRSwapChain.h" +#include "RHI.h" +#include "RendererInterface.h" +#include "IStereoLayers.h" +#include "XRRenderBridge.h" + +#if PLATFORM_WINDOWS +#include "Windows/WindowsHWrapper.h" +#endif + +DECLARE_STATS_GROUP(TEXT("OculusXRHMD"), STATGROUP_OculusXRHMD, STATCAT_Advanced); +DECLARE_CYCLE_STAT(TEXT("BeginRendering"), STAT_BeginRendering, STATGROUP_OculusXRHMD); +DECLARE_CYCLE_STAT(TEXT("FinishRendering"), STAT_FinishRendering, STATGROUP_OculusXRHMD); +DECLARE_FLOAT_COUNTER_STAT(TEXT("LatencyRender"), STAT_LatencyRender, STATGROUP_OculusXRHMD); +DECLARE_FLOAT_COUNTER_STAT(TEXT("LatencyTimewarp"), STAT_LatencyTimewarp, STATGROUP_OculusXRHMD); +DECLARE_FLOAT_COUNTER_STAT(TEXT("LatencyPostPresent"), STAT_LatencyPostPresent, STATGROUP_OculusXRHMD); +DECLARE_FLOAT_COUNTER_STAT(TEXT("ErrorRender"), STAT_ErrorRender, STATGROUP_OculusXRHMD); +DECLARE_FLOAT_COUNTER_STAT(TEXT("ErrorTimewarp"), STAT_ErrorTimewarp, STATGROUP_OculusXRHMD); + +namespace OculusXRHMD +{ + + //------------------------------------------------------------------------------------------------- + // FCustomPresent + //------------------------------------------------------------------------------------------------- + + class FCustomPresent : public FXRRenderBridge + { + public: + FCustomPresent(class FOculusXRHMD* InOculusXRHMD, ovrpRenderAPIType InRenderAPI, EPixelFormat InDefaultPixelFormat, bool InSupportsSRGB); + + // FXRRenderBridge/FRHICustomPresent + virtual bool NeedsNativePresent() override; + virtual bool Present(int32& SyncInterval) override; + virtual void FinishRendering_RHIThread(); + + ovrpRenderAPIType GetRenderAPI() const { return RenderAPI; } + virtual bool IsUsingCorrectDisplayAdapter() const { return true; } + + void UpdateMirrorTexture_RenderThread(); + void ReleaseResources_RHIThread(); + void Shutdown(); + + FTexture2DRHIRef GetMirrorTexture() { return MirrorTextureRHI; } + + virtual void* GetOvrpInstance() const { return nullptr; } + virtual void* GetOvrpPhysicalDevice() const { return nullptr; } + virtual void* GetOvrpDevice() const { return nullptr; } + virtual void* GetOvrpCommandQueue() const { return nullptr; } + EPixelFormat GetPixelFormat(EPixelFormat InFormat) const; + EPixelFormat GetPixelFormat(ovrpTextureFormat InFormat) const; + EPixelFormat GetDefaultPixelFormat() const { return DefaultPixelFormat; } + ovrpTextureFormat GetOvrpTextureFormat(EPixelFormat InFormat, bool usesRGB = true) const; + ovrpTextureFormat GetDefaultOvrpTextureFormat() const { return DefaultOvrpTextureFormat; } + ovrpTextureFormat GetDefaultDepthOvrpTextureFormat() const { return DefaultDepthOvrpTextureFormat; } + static bool IsSRGB(ovrpTextureFormat InFormat); + virtual int GetSystemRecommendedMSAALevel() const; + virtual int GetLayerFlags() const { return 0; } + + virtual FTextureRHIRef CreateTexture_RenderThread(uint32 InSizeX, uint32 InSizeY, EPixelFormat InFormat, FClearValueBinding InBinding, uint32 InNumMips, uint32 InNumSamples, uint32 InNumSamplesTileMem, ERHIResourceType InResourceType, ovrpTextureHandle InTexture, ETextureCreateFlags TexCreateFlags) = 0; + FXRSwapChainPtr CreateSwapChain_RenderThread(uint32 InSizeX, uint32 InSizeY, EPixelFormat InFormat, FClearValueBinding InBinding, uint32 InNumMips, uint32 InNumSamples, uint32 InNumSamplesTileMem, ERHIResourceType InResourceType, const TArray& InTextures, ETextureCreateFlags InTexCreateFlags, const TCHAR* DebugName); + TArray CreateSwapChainTextures_RenderThread(uint32 InSizeX, uint32 InSizeY, EPixelFormat InFormat, FClearValueBinding InBinding, uint32 InNumMips, uint32 InNumSamples, uint32 InNumSamplesTileMem, ERHIResourceType InResourceType, const TArray& InTextures, ETextureCreateFlags InTexCreateFlags, const TCHAR* DebugName); + void CopyTexture_RenderThread(FRHICommandListImmediate& RHICmdList, FRHITexture* DstTexture, FRHITexture* SrcTexture, FIntRect DstRect = FIntRect(), FIntRect SrcRect = FIntRect(), bool bAlphaPremultiply = false, bool bNoAlphaWrite = false, bool bInvertY = true, bool sRGBSource = false, bool bInvertAlpha = false) const; + void SubmitGPUCommands_RenderThread(FRHICommandListImmediate& RHICmdList); + virtual void SubmitGPUFrameTime(float GPUFrameTime) {} + // This is a hack to turn force FSR off when we allocate our FDM to avoid a crash on Quest 3 + // TODO: Remove this for UE 5.3 after there's an engine-side fix + virtual void UseFragmentDensityMapOverShadingRate_RHIThread(){}; +#ifdef WITH_OCULUS_BRANCH + virtual void UpdateFoveationOffsets_RHIThread(bool bUseOffsets, FIntPoint Offsets[2]){}; +#endif // WITH_OCULUS_BRANCH + + bool SupportsSRGB() + { + return bSupportsSRGB; + } + bool SupportsSubsampled() { return bSupportsSubsampled; } + + protected: + FOculusXRHMD* OculusXRHMD; + ovrpRenderAPIType RenderAPI; + EPixelFormat DefaultPixelFormat; + bool bSupportsSRGB; + bool bSupportsSubsampled; + ovrpTextureFormat DefaultOvrpTextureFormat; + ovrpTextureFormat DefaultDepthOvrpTextureFormat; + IRendererModule* RendererModule; + FTexture2DRHIRef MirrorTextureRHI; + bool bIsStandaloneStereoDevice; + }; + + //------------------------------------------------------------------------------------------------- + // APIs + //------------------------------------------------------------------------------------------------- + +#if OCULUS_HMD_SUPPORTED_PLATFORMS_D3D11 + FCustomPresent* CreateCustomPresent_D3D11(FOculusXRHMD* InOculusXRHMD); +#endif +#if OCULUS_HMD_SUPPORTED_PLATFORMS_D3D12 + FCustomPresent* CreateCustomPresent_D3D12(FOculusXRHMD* InOculusXRHMD); +#endif +#if OCULUS_HMD_SUPPORTED_PLATFORMS_VULKAN + FCustomPresent* CreateCustomPresent_Vulkan(FOculusXRHMD* InOculusXRHMD); +#endif + +} // namespace OculusXRHMD + +#endif //OCULUS_HMD_SUPPORTED_PLATFORMS diff --git a/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_CustomPresent_D3D11.cpp b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_CustomPresent_D3D11.cpp new file mode 100644 index 0000000..e28915c --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_CustomPresent_D3D11.cpp @@ -0,0 +1,118 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +#include "OculusXRHMD_CustomPresent.h" +#include "OculusXRHMDPrivateRHI.h" + +#if OCULUS_HMD_SUPPORTED_PLATFORMS_D3D11 +#include "OculusXRHMD.h" + +#ifndef WINDOWS_PLATFORM_TYPES_GUARD +#include "Windows/AllowWindowsPlatformTypes.h" +#endif + +namespace OculusXRHMD +{ + + //------------------------------------------------------------------------------------------------- + // FD3D11CustomPresent + //------------------------------------------------------------------------------------------------- + + class FD3D11CustomPresent : public FCustomPresent + { + public: + FD3D11CustomPresent(FOculusXRHMD* InOculusXRHMD); + + // Implementation of FCustomPresent, called by Plugin itself + virtual bool IsUsingCorrectDisplayAdapter() const override; + virtual void* GetOvrpDevice() const override; + virtual FTextureRHIRef CreateTexture_RenderThread(uint32 InSizeX, uint32 InSizeY, EPixelFormat InFormat, FClearValueBinding InBinding, uint32 InNumMips, uint32 InNumSamples, uint32 InNumSamplesTileMem, ERHIResourceType InResourceType, ovrpTextureHandle InTexture, ETextureCreateFlags InTexCreateFlags) override; + }; + + FD3D11CustomPresent::FD3D11CustomPresent(FOculusXRHMD* InOculusXRHMD) + : FCustomPresent(InOculusXRHMD, ovrpRenderAPI_D3D11, PF_B8G8R8A8, true) + { + switch (GPixelFormats[PF_DepthStencil].PlatformFormat) + { + case DXGI_FORMAT_R24G8_TYPELESS: + DefaultDepthOvrpTextureFormat = ovrpTextureFormat_D24_S8; + break; + case DXGI_FORMAT_R32G8X24_TYPELESS: + DefaultDepthOvrpTextureFormat = ovrpTextureFormat_D32_FP_S8; + break; + default: + UE_LOG(LogHMD, Error, TEXT("Unrecognized depth buffer format")); + break; + } + } + + bool FD3D11CustomPresent::IsUsingCorrectDisplayAdapter() const + { + const void* luid; + + if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetDisplayAdapterId2(&luid)) && luid) + { + TRefCountPtr D3D11Device; + + ExecuteOnRenderThread([&D3D11Device]() { + D3D11Device = (ID3D11Device*)RHIGetNativeDevice(); + }); + + if (D3D11Device) + { + TRefCountPtr DXGIDevice; + TRefCountPtr DXGIAdapter; + DXGI_ADAPTER_DESC DXGIAdapterDesc; + + if (SUCCEEDED(D3D11Device->QueryInterface(__uuidof(IDXGIDevice), (void**)DXGIDevice.GetInitReference())) && SUCCEEDED(DXGIDevice->GetAdapter(DXGIAdapter.GetInitReference())) && SUCCEEDED(DXGIAdapter->GetDesc(&DXGIAdapterDesc))) + { + return !FMemory::Memcmp(luid, &DXGIAdapterDesc.AdapterLuid, sizeof(LUID)); + } + } + } + + // Not enough information. Assume that we are using the correct adapter. + return true; + } + + void* FD3D11CustomPresent::GetOvrpDevice() const + { + return GetID3D11DynamicRHI()->RHIGetDevice(); + } + + FTextureRHIRef FD3D11CustomPresent::CreateTexture_RenderThread(uint32 InSizeX, uint32 InSizeY, EPixelFormat InFormat, FClearValueBinding InBinding, uint32 InNumMips, uint32 InNumSamples, uint32 InNumSamplesTileMem, ERHIResourceType InResourceType, ovrpTextureHandle InTexture, ETextureCreateFlags InTexCreateFlags) + { + CheckInRenderThread(); + + switch (InResourceType) + { + case RRT_Texture2D: + return GetID3D11DynamicRHI()->RHICreateTexture2DFromResource(InFormat, InTexCreateFlags, InBinding, (ID3D11Texture2D*)InTexture).GetReference(); + + case RRT_Texture2DArray: + return GetID3D11DynamicRHI()->RHICreateTexture2DArrayFromResource(InFormat, InTexCreateFlags, InBinding, (ID3D11Texture2D*)InTexture).GetReference(); + + case RRT_TextureCube: + return GetID3D11DynamicRHI()->RHICreateTextureCubeFromResource(InFormat, InTexCreateFlags | TexCreate_TargetArraySlicesIndependently, InBinding, (ID3D11Texture2D*)InTexture).GetReference(); + + default: + return nullptr; + } + } + + //------------------------------------------------------------------------------------------------- + // APIs + //------------------------------------------------------------------------------------------------- + + FCustomPresent* CreateCustomPresent_D3D11(FOculusXRHMD* InOculusXRHMD) + { + return new FD3D11CustomPresent(InOculusXRHMD); + } + +} // namespace OculusXRHMD + +#if PLATFORM_WINDOWS +#undef WINDOWS_PLATFORM_TYPES_GUARD +#endif + +#endif // OCULUS_HMD_SUPPORTED_PLATFORMS_D3D11 diff --git a/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_CustomPresent_D3D12.cpp b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_CustomPresent_D3D12.cpp new file mode 100644 index 0000000..870defa --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_CustomPresent_D3D12.cpp @@ -0,0 +1,114 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +#include "OculusXRHMD_CustomPresent.h" +#include "OculusXRHMDPrivateRHI.h" + +#if OCULUS_HMD_SUPPORTED_PLATFORMS_D3D12 +#include "OculusXRHMD.h" + +#ifndef WINDOWS_PLATFORM_TYPES_GUARD +#include "Windows/AllowWindowsPlatformTypes.h" +#endif + +namespace OculusXRHMD +{ + + //------------------------------------------------------------------------------------------------- + // FCustomPresentD3D12 + //------------------------------------------------------------------------------------------------- + + class FD3D12CustomPresent : public FCustomPresent + { + public: + FD3D12CustomPresent(FOculusXRHMD* InOculusXRHMD); + + // Implementation of FCustomPresent, called by Plugin itself + virtual bool IsUsingCorrectDisplayAdapter() const override; + virtual void* GetOvrpDevice() const override; + virtual FTextureRHIRef CreateTexture_RenderThread(uint32 InSizeX, uint32 InSizeY, EPixelFormat InFormat, FClearValueBinding InBinding, uint32 InNumMips, uint32 InNumSamples, uint32 InNumSamplesTileMem, ERHIResourceType InResourceType, ovrpTextureHandle InTexture, ETextureCreateFlags InTexCreateFlags) override; + }; + + FD3D12CustomPresent::FD3D12CustomPresent(FOculusXRHMD* InOculusXRHMD) + : FCustomPresent(InOculusXRHMD, ovrpRenderAPI_D3D12, PF_B8G8R8A8, true) + { + switch (GPixelFormats[PF_DepthStencil].PlatformFormat) + { + case DXGI_FORMAT_R24G8_TYPELESS: + DefaultDepthOvrpTextureFormat = ovrpTextureFormat_D24_S8; + break; + case DXGI_FORMAT_R32G8X24_TYPELESS: + DefaultDepthOvrpTextureFormat = ovrpTextureFormat_D32_FP_S8; + break; + default: + UE_LOG(LogHMD, Error, TEXT("Unrecognized depth buffer format")); + break; + } + } + + bool FD3D12CustomPresent::IsUsingCorrectDisplayAdapter() const + { + const void* luid; + + if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetDisplayAdapterId2(&luid)) && luid) + { + TRefCountPtr D3DDevice; + + ExecuteOnRenderThread([&D3DDevice]() { + D3DDevice = (ID3D12Device*)RHIGetNativeDevice(); + }); + + if (D3DDevice) + { + LUID AdapterLuid = D3DDevice->GetAdapterLuid(); + return !FMemory::Memcmp(luid, &AdapterLuid, sizeof(LUID)); + } + } + + // Not enough information. Assume that we are using the correct adapter. + return true; + } + + void* FD3D12CustomPresent::GetOvrpDevice() const + { + return GetID3D12DynamicRHI()->RHIGetCommandQueue(); + } + + FTextureRHIRef FD3D12CustomPresent::CreateTexture_RenderThread(uint32 InSizeX, uint32 InSizeY, EPixelFormat InFormat, FClearValueBinding InBinding, uint32 InNumMips, uint32 InNumSamples, uint32 InNumSamplesTileMem, ERHIResourceType InResourceType, ovrpTextureHandle InTexture, ETextureCreateFlags InTexCreateFlags) + { + CheckInRenderThread(); + + ID3D12DynamicRHI* DynamicRHI = GetID3D12DynamicRHI(); + + switch (InResourceType) + { + case RRT_Texture2D: + return DynamicRHI->RHICreateTexture2DFromResource(InFormat, InTexCreateFlags, InBinding, (ID3D12Resource*)InTexture).GetReference(); + + case RRT_Texture2DArray: + return DynamicRHI->RHICreateTexture2DArrayFromResource(InFormat, InTexCreateFlags, InBinding, (ID3D12Resource*)InTexture).GetReference(); + + case RRT_TextureCube: + return DynamicRHI->RHICreateTextureCubeFromResource(InFormat, InTexCreateFlags, InBinding, (ID3D12Resource*)InTexture).GetReference(); + + default: + return nullptr; + } + } + + //------------------------------------------------------------------------------------------------- + // APIs + //------------------------------------------------------------------------------------------------- + + FCustomPresent* CreateCustomPresent_D3D12(FOculusXRHMD* InOculusXRHMD) + { + return new FD3D12CustomPresent(InOculusXRHMD); + } + +} // namespace OculusXRHMD + +#if PLATFORM_WINDOWS +#undef WINDOWS_PLATFORM_TYPES_GUARD +#endif + +#endif // OCULUS_HMD_SUPPORTED_PLATFORMS_D3D12 diff --git a/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_CustomPresent_Vulkan.cpp b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_CustomPresent_Vulkan.cpp new file mode 100644 index 0000000..70fe10d --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_CustomPresent_Vulkan.cpp @@ -0,0 +1,171 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +#include "OculusXRHMD_CustomPresent.h" +#include "OculusXRHMDPrivateRHI.h" + +#if OCULUS_HMD_SUPPORTED_PLATFORMS_VULKAN +#include "OculusXRHMD.h" +#include "IVulkanDynamicRHI.h" + +#if PLATFORM_WINDOWS +#ifndef WINDOWS_PLATFORM_TYPES_GUARD +#include "Windows/AllowWindowsPlatformTypes.h" +#endif +#endif + +namespace OculusXRHMD +{ + + //------------------------------------------------------------------------------------------------- + // FCustomPresentVulkan + //------------------------------------------------------------------------------------------------- + + class FVulkanCustomPresent : public FCustomPresent + { + public: + FVulkanCustomPresent(FOculusXRHMD* InOculusXRHMD); + + // Implementation of FCustomPresent, called by Plugin itself + virtual bool IsUsingCorrectDisplayAdapter() const override; + virtual void* GetOvrpInstance() const override; + virtual void* GetOvrpPhysicalDevice() const override; + virtual void* GetOvrpDevice() const override; + virtual void* GetOvrpCommandQueue() const override; + virtual FTextureRHIRef CreateTexture_RenderThread(uint32 InSizeX, uint32 InSizeY, EPixelFormat InFormat, FClearValueBinding InBinding, uint32 InNumMips, uint32 InNumSamples, uint32 InNumSamplesTileMem, ERHIResourceType InResourceType, ovrpTextureHandle InTexture, ETextureCreateFlags InTexCreateFlags) override; + // This is a hack to turn force FSR off when we allocate our FDM to avoid a crash on Quest 3 + // TODO: Remove this for UE 5.3 after there's an engine-side fix + virtual void UseFragmentDensityMapOverShadingRate_RHIThread() override; +#ifdef WITH_OCULUS_BRANCH + virtual void UpdateFoveationOffsets_RHIThread(bool bUseTileOffsets, FIntPoint TileOffsets[2]) override; +#endif // WITH_OCULUS_BRANCH + }; + + FVulkanCustomPresent::FVulkanCustomPresent(FOculusXRHMD* InOculusXRHMD) + : FCustomPresent(InOculusXRHMD, ovrpRenderAPI_Vulkan, PF_R8G8B8A8, true) + { +#if PLATFORM_ANDROID + if (GRHISupportsRHIThread && GIsThreadedRendering && GUseRHIThread_InternalUseOnly) + { + SetRHIThreadEnabled(false, false); + } +#endif + + switch (GPixelFormats[PF_DepthStencil].PlatformFormat) + { + case VK_FORMAT_D24_UNORM_S8_UINT: + DefaultDepthOvrpTextureFormat = ovrpTextureFormat_D24_S8; + break; + case VK_FORMAT_D32_SFLOAT_S8_UINT: + DefaultDepthOvrpTextureFormat = ovrpTextureFormat_D32_FP_S8; + break; + default: + UE_LOG(LogHMD, Error, TEXT("Unrecognized depth buffer format")); + break; + } + bSupportsSubsampled = GetIVulkanDynamicRHI()->RHISupportsEXTFragmentDensityMap2(); + } + + bool FVulkanCustomPresent::IsUsingCorrectDisplayAdapter() const + { +#if PLATFORM_WINDOWS + const void* AdapterId = nullptr; + if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetDisplayAdapterId2(&AdapterId)) && AdapterId) + { + return GetIVulkanDynamicRHI()->RHIDoesAdapterMatchDevice(AdapterId); + } +#endif + + // Not enough information. Assume that we are using the correct adapter. + return true; + } + + void* FVulkanCustomPresent::GetOvrpInstance() const + { + return GetIVulkanDynamicRHI()->RHIGetVkInstance(); + } + + void* FVulkanCustomPresent::GetOvrpPhysicalDevice() const + { + return GetIVulkanDynamicRHI()->RHIGetVkPhysicalDevice(); + } + + void* FVulkanCustomPresent::GetOvrpDevice() const + { + return GetIVulkanDynamicRHI()->RHIGetVkDevice(); + } + + void* FVulkanCustomPresent::GetOvrpCommandQueue() const + { + return GetIVulkanDynamicRHI()->RHIGetGraphicsVkQueue(); + } + + FTextureRHIRef FVulkanCustomPresent::CreateTexture_RenderThread(uint32 InSizeX, uint32 InSizeY, EPixelFormat InFormat, FClearValueBinding InBinding, uint32 InNumMips, uint32 InNumSamples, uint32 InNumSamplesTileMem, ERHIResourceType InResourceType, ovrpTextureHandle InTexture, ETextureCreateFlags InTexCreateFlags) + { + CheckInRenderThread(); + + IVulkanDynamicRHI* VulkanRHI = GetIVulkanDynamicRHI(); + const VkImageSubresourceRange SubresourceRangeAll = { VK_IMAGE_ASPECT_COLOR_BIT, 0, VK_REMAINING_MIP_LEVELS, 0, VK_REMAINING_ARRAY_LAYERS }; + + if (EnumHasAnyFlags(InTexCreateFlags, TexCreate_RenderTargetable)) + { + VulkanRHI->RHISetImageLayout((VkImage)InTexture, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, SubresourceRangeAll); + } + else if (EnumHasAnyFlags(InTexCreateFlags, TexCreate_Foveation)) + { + VulkanRHI->RHISetImageLayout((VkImage)InTexture, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_FRAGMENT_DENSITY_MAP_OPTIMAL_EXT, SubresourceRangeAll); + } + + switch (InResourceType) + { + case RRT_Texture2D: + return VulkanRHI->RHICreateTexture2DFromResource(InFormat, InSizeX, InSizeY, InNumMips, InNumSamples, (VkImage)InTexture, InTexCreateFlags, InBinding).GetReference(); + + case RRT_Texture2DArray: + return VulkanRHI->RHICreateTexture2DArrayFromResource(InFormat, InSizeX, InSizeY, 2, InNumMips, InNumSamples, (VkImage)InTexture, InTexCreateFlags, InBinding).GetReference(); + + case RRT_TextureCube: + return VulkanRHI->RHICreateTextureCubeFromResource(InFormat, InSizeX, false, 1, InNumMips, (VkImage)InTexture, InTexCreateFlags, InBinding).GetReference(); + + default: + return nullptr; + } + } + + // This is a hack to turn force FSR off when we allocate our FDM to avoid a crash on Quest 3 + // TODO: Remove this for UE 5.3 after there's an engine-side fix + void FVulkanCustomPresent::UseFragmentDensityMapOverShadingRate_RHIThread() + { + CheckInRHIThread(); + SCOPED_NAMED_EVENT(UseFragmentDensityMapOverShadingRate_RHIThread, FColor::Red); + + GRHIVariableRateShadingImageDataType = VRSImage_Fractional; + GRHIVariableRateShadingImageFormat = PF_R8G8; + } + +#ifdef WITH_OCULUS_BRANCH + void FVulkanCustomPresent::UpdateFoveationOffsets_RHIThread(bool bUseOffsets, FIntPoint Offsets[2]) + { + CheckInRHIThread(); + + SCOPED_NAMED_EVENT(UpdateFoveationOffsets_RHIThread, FColor::Red); + GetIVulkanDynamicRHI()->RHISetQcomFragmentDensityMapOffsets(bUseOffsets, Offsets); + } +#endif // WITH_OCULUS_BRANCH + + //------------------------------------------------------------------------------------------------- + // APIs + //------------------------------------------------------------------------------------------------- + + FCustomPresent* CreateCustomPresent_Vulkan(FOculusXRHMD* InOculusXRHMD) + { + return new FVulkanCustomPresent(InOculusXRHMD); + } + +} // namespace OculusXRHMD + +#if PLATFORM_WINDOWS +#undef WINDOWS_PLATFORM_TYPES_GUARD +#endif + +#endif // OCULUS_HMD_SUPPORTED_PLATFORMS_VULKAN diff --git a/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_DeferredDeletionQueue.cpp b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_DeferredDeletionQueue.cpp new file mode 100644 index 0000000..5d5ef46 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_DeferredDeletionQueue.cpp @@ -0,0 +1,71 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +#include "OculusXRHMD_DeferredDeletionQueue.h" + +#if OCULUS_HMD_SUPPORTED_PLATFORMS +#include "OculusXRHMDPrivate.h" +#include "XRThreadUtils.h" +#include "OculusXRHMDModule.h" + +namespace OculusXRHMD +{ + + //------------------------------------------------------------------------------------------------- + // FDeferredDeletionQueue + //------------------------------------------------------------------------------------------------- + uint32 GOculusXRHMDLayerDeletionFrameNumber = 0; + const uint32 NUM_FRAMES_TO_WAIT_FOR_LAYER_DELETE = 3; + const uint32 NUM_FRAMES_TO_WAIT_FOR_OVRP_LAYER_DELETE = 7; + + void FDeferredDeletionQueue::AddLayerToDeferredDeletionQueue(const FLayerPtr& ptr) + { + DeferredDeletionEntry Entry; + Entry.Layer = ptr; + Entry.FrameEnqueued = GOculusXRHMDLayerDeletionFrameNumber; + Entry.EntryType = DeferredDeletionEntry::DeferredDeletionEntryType::Layer; + DeferredDeletionArray.Add(Entry); + } + + void FDeferredDeletionQueue::AddOVRPLayerToDeferredDeletionQueue(const uint32 layerID) + { + DeferredDeletionEntry Entry; + Entry.OvrpLayerId = layerID; + Entry.FrameEnqueued = GOculusXRHMDLayerDeletionFrameNumber; + Entry.EntryType = DeferredDeletionEntry::DeferredDeletionEntryType::OvrpLayer; + DeferredDeletionArray.Add(Entry); + } + + void FDeferredDeletionQueue::HandleLayerDeferredDeletionQueue_RenderThread(bool bDeleteImmediately) + { + // Traverse list backwards so the swap switches to elements already tested + for (int32 Index = DeferredDeletionArray.Num() - 1; Index >= 0; --Index) + { + DeferredDeletionEntry* Entry = &DeferredDeletionArray[Index]; + if (Entry->EntryType == DeferredDeletionEntry::DeferredDeletionEntryType::Layer) + { + if (bDeleteImmediately || GOculusXRHMDLayerDeletionFrameNumber > Entry->FrameEnqueued + NUM_FRAMES_TO_WAIT_FOR_LAYER_DELETE) + { + DeferredDeletionArray.RemoveAtSwap(Index, 1, false); + } + } + else if (Entry->EntryType == DeferredDeletionEntry::DeferredDeletionEntryType::OvrpLayer) + { + if (bDeleteImmediately || GOculusXRHMDLayerDeletionFrameNumber > Entry->FrameEnqueued + NUM_FRAMES_TO_WAIT_FOR_OVRP_LAYER_DELETE) + { + ExecuteOnRHIThread_DoNotWait([OvrpLayerId = Entry->OvrpLayerId]() { + UE_LOG(LogHMD, Warning, TEXT("Destroying layer %d"), OvrpLayerId); + FOculusXRHMDModule::GetPluginWrapper().DestroyLayer(OvrpLayerId); + }); + DeferredDeletionArray.RemoveAtSwap(Index, 1, false); + } + } + } + + // if the function is to be called multiple times, move this increment somewhere unique! + ++GOculusXRHMDLayerDeletionFrameNumber; + } + +} // namespace OculusXRHMD + +#endif //OCULUS_HMD_SUPPORTED_PLATFORMS diff --git a/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_DeferredDeletionQueue.h b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_DeferredDeletionQueue.h new file mode 100644 index 0000000..420b032 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_DeferredDeletionQueue.h @@ -0,0 +1,45 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +#pragma once +#include "OculusXRHMDPrivate.h" + +#if OCULUS_HMD_SUPPORTED_PLATFORMS +#include "OculusXRHMD_Layer.h" + +namespace OculusXRHMD +{ + + //------------------------------------------------------------------------------------------------- + // FDeferredDeletionQueue + //------------------------------------------------------------------------------------------------- + + class FDeferredDeletionQueue + { + public: + void AddLayerToDeferredDeletionQueue(const FLayerPtr& ptr); + void AddOVRPLayerToDeferredDeletionQueue(const uint32 layerID); + void HandleLayerDeferredDeletionQueue_RenderThread(bool bDeleteImmediately = false); + + private: + struct DeferredDeletionEntry + { + enum class DeferredDeletionEntryType + { + Layer, + OvrpLayer + }; + + FLayerPtr Layer; + uint32 OvrpLayerId; + + uint32 FrameEnqueued; + DeferredDeletionEntryType EntryType; + }; + + TArray DeferredDeletionArray; + }; + +} // namespace OculusXRHMD + +#endif //OCULUS_HMD_SUPPORTED_PLATFORMS diff --git a/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_DynamicResolutionState.cpp b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_DynamicResolutionState.cpp new file mode 100644 index 0000000..8bcb812 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_DynamicResolutionState.cpp @@ -0,0 +1,90 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +#include "OculusXRHMD_DynamicResolutionState.h" +#include "LegacyScreenPercentageDriver.h" + +#if OCULUS_HMD_SUPPORTED_PLATFORMS +#include "SceneView.h" + +namespace OculusXRHMD +{ + + //------------------------------------------------------------------------------------------------- + // FDynamicResolutionState implementation + //------------------------------------------------------------------------------------------------- + + FDynamicResolutionState::FDynamicResolutionState(const OculusXRHMD::FSettingsPtr InSettings) + : Settings(InSettings) + , ResolutionFraction(-1.0f) + , ResolutionFractionUpperBound(-1.0f) + { + check(Settings.IsValid()); + } + + void FDynamicResolutionState::ResetHistory(){ + // Empty - Oculus drives resolution fraction externally + }; + + bool FDynamicResolutionState::IsSupported() const + { + return true; + } + + void FDynamicResolutionState::SetupMainViewFamily(class FSceneViewFamily& ViewFamily) + { + check(IsInGameThread()); + check(ViewFamily.EngineShowFlags.ScreenPercentage == true); + + if (IsEnabled()) + { + // Compute desired resolution fraction range + float MinResolutionFraction = Settings->PixelDensityMin; + float MaxResolutionFraction = Settings->PixelDensityMax; + + // Clamp resolution fraction to what the renderer can do. + MinResolutionFraction = FMath::Max(MinResolutionFraction, ISceneViewFamilyScreenPercentage::kMinResolutionFraction); + MaxResolutionFraction = FMath::Min(MaxResolutionFraction, ISceneViewFamilyScreenPercentage::kMaxResolutionFraction); + + ResolutionFraction = FMath::Clamp(Settings->PixelDensity, MinResolutionFraction, MaxResolutionFraction); + ResolutionFractionUpperBound = MaxResolutionFraction; + + ViewFamily.SetScreenPercentageInterface(new FLegacyScreenPercentageDriver(ViewFamily, ResolutionFraction, ResolutionFractionUpperBound)); + } + } + + DynamicRenderScaling::TMap FDynamicResolutionState::GetResolutionFractionsApproximation() const + { + DynamicRenderScaling::TMap ResolutionFractions; + ResolutionFractions.SetAll(1.0f); + ResolutionFractions[GDynamicPrimaryResolutionFraction] = ResolutionFraction; + return ResolutionFractions; + } + + DynamicRenderScaling::TMap FDynamicResolutionState::GetResolutionFractionsUpperBound() const + { + DynamicRenderScaling::TMap ResolutionFractions; + ResolutionFractions.SetAll(1.0f); + ResolutionFractions[GDynamicPrimaryResolutionFraction] = ResolutionFractionUpperBound; + return ResolutionFractionUpperBound; + } + + void FDynamicResolutionState::SetEnabled(bool bEnable) + { + check(IsInGameThread()); + Settings->Flags.bPixelDensityAdaptive = bEnable; + } + + bool FDynamicResolutionState::IsEnabled() const + { + check(IsInGameThread()); + return Settings->Flags.bPixelDensityAdaptive; + } + + void FDynamicResolutionState::ProcessEvent(EDynamicResolutionStateEvent Event){ + // Empty - Oculus drives resolution fraction externally + }; + +} // namespace OculusXRHMD + +#endif //OCULUS_HMD_SUPPORTED_PLATFORMS diff --git a/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_DynamicResolutionState.h b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_DynamicResolutionState.h new file mode 100644 index 0000000..6484392 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_DynamicResolutionState.h @@ -0,0 +1,43 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +#pragma once +#include "OculusXRHMDPrivate.h" + +#if OCULUS_HMD_SUPPORTED_PLATFORMS +#include "OculusXRHMD_Settings.h" +#include "DynamicResolutionState.h" + +namespace OculusXRHMD +{ + + //------------------------------------------------------------------------------------------------- + // FDynamicResolutionState + //------------------------------------------------------------------------------------------------- + + class FDynamicResolutionState : public IDynamicResolutionState + { + public: + FDynamicResolutionState(const OculusXRHMD::FSettingsPtr InSettings); + + // ISceneViewFamilyScreenPercentage + virtual void ResetHistory() override; + virtual bool IsSupported() const override; + virtual void SetupMainViewFamily(class FSceneViewFamily& ViewFamily) override; + + protected: + virtual DynamicRenderScaling::TMap GetResolutionFractionsApproximation() const override; + virtual DynamicRenderScaling::TMap GetResolutionFractionsUpperBound() const override; + virtual void SetEnabled(bool bEnable) override; + virtual bool IsEnabled() const override; + virtual void ProcessEvent(EDynamicResolutionStateEvent Event) override; + + private: + const OculusXRHMD::FSettingsPtr Settings; + float ResolutionFraction; + float ResolutionFractionUpperBound; + }; + +} // namespace OculusXRHMD + +#endif //OCULUS_HMD_SUPPORTED_PLATFORMS diff --git a/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_FoveatedRendering.cpp b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_FoveatedRendering.cpp new file mode 100644 index 0000000..de152bb --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_FoveatedRendering.cpp @@ -0,0 +1,53 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +#include "OculusXRHMD_FoveatedRendering.h" + +#if !UE_VERSION_OLDER_THAN(5, 3, 0) +#include "RenderGraphBuilder.h" +#include "HeadMountedDisplayTypes.h" // For the LogHMD log category + +FOculusXRFoveatedRenderingImageGenerator::FOculusXRFoveatedRenderingImageGenerator(const FXRSwapChainPtr& Swapchain) + : FoveationSwapchain(Swapchain) +{ + GVRSImageManager.RegisterExternalImageGenerator(this); +} + +FOculusXRFoveatedRenderingImageGenerator::~FOculusXRFoveatedRenderingImageGenerator() +{ + GVRSImageManager.UnregisterExternalImageGenerator(this); +} + +FRDGTextureRef FOculusXRFoveatedRenderingImageGenerator::GetImage(FRDGBuilder& GraphBuilder, const FViewInfo& ViewInfo, FVariableRateShadingImageManager::EVRSImageType ImageType) +{ + if (!FoveationSwapchain.IsValid()) + { + return nullptr; + } + + FTexture2DRHIRef SwapchainTexture = FoveationSwapchain->GetTexture2DArray() ? FoveationSwapchain->GetTexture2DArray() : FoveationSwapchain->GetTexture2D(); + FIntPoint TexSize = SwapchainTexture->GetSizeXY(); + // Only set texture and return true if we have a valid texture of compatible size + if (SwapchainTexture->IsValid() && TexSize.X > 0 && TexSize.Y > 0) + { + TRefCountPtr PooledRenderTarget = CreateRenderTarget(SwapchainTexture, *SwapchainTexture->GetName().ToString()); + return GraphBuilder.RegisterExternalTexture(PooledRenderTarget, *SwapchainTexture->GetName().ToString(), ERDGTextureFlags::SkipTracking); + } + return nullptr; +} + +void FOculusXRFoveatedRenderingImageGenerator::PrepareImages(FRDGBuilder& GraphBuilder, const FSceneViewFamily& ViewFamily, const FMinimalSceneTextures& SceneTextures) +{ + return; +} + +bool FOculusXRFoveatedRenderingImageGenerator::IsEnabledForView(const FSceneView& View) const +{ + return View.StereoPass != EStereoscopicPass::eSSP_FULL; +} + +FRDGTextureRef FOculusXRFoveatedRenderingImageGenerator::GetDebugImage(FRDGBuilder& GraphBuilder, const FViewInfo& ViewInfo, FVariableRateShadingImageManager::EVRSImageType ImageType) +{ + return nullptr; +} +#endif // !UE_VERSION_OLDER_THAN(5, 3, 0) diff --git a/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_FoveatedRendering.h b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_FoveatedRendering.h new file mode 100644 index 0000000..10cf3e9 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_FoveatedRendering.h @@ -0,0 +1,31 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "Misc/EngineVersionComparison.h" + +#if !UE_VERSION_OLDER_THAN(5, 3, 0) +#include "VariableRateShadingImageManager.h" +#include "XRSwapchain.h" + +class FOculusXRFoveatedRenderingImageGenerator : public IVariableRateShadingImageGenerator +{ +public: + FOculusXRFoveatedRenderingImageGenerator(const FXRSwapChainPtr& Swapchain); + virtual ~FOculusXRFoveatedRenderingImageGenerator() override; + + // IVariableRateShadingImageGenerator interface + virtual FRDGTextureRef GetImage(FRDGBuilder& GraphBuilder, const FViewInfo& ViewInfo, FVariableRateShadingImageManager::EVRSImageType ImageType) override; + virtual void PrepareImages(FRDGBuilder& GraphBuilder, const FSceneViewFamily& ViewFamily, const FMinimalSceneTextures& SceneTextures) override; + virtual bool IsEnabledForView(const FSceneView& View) const override; + virtual FRDGTextureRef GetDebugImage(FRDGBuilder& GraphBuilder, const FViewInfo& ViewInfo, FVariableRateShadingImageManager::EVRSImageType ImageType) override; + virtual FVariableRateShadingImageManager::EVRSSourceType GetType() const override + { + return FVariableRateShadingImageManager::EVRSSourceType::FixedFoveation; + } + +private: + const FXRSwapChainPtr& FoveationSwapchain; +}; +#endif // !UE_VERSION_OLDER_THAN(5, 3, 0) diff --git a/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_GameFrame.cpp b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_GameFrame.cpp new file mode 100644 index 0000000..05e3b96 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_GameFrame.cpp @@ -0,0 +1,33 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +#include "OculusXRHMD_GameFrame.h" + +#if OCULUS_HMD_SUPPORTED_PLATFORMS +#include "GameFramework/WorldSettings.h" +#include "Engine/Engine.h" +#include "Engine/World.h" + +namespace OculusXRHMD +{ + + //------------------------------------------------------------------------------------------------- + // FGameFrame + //------------------------------------------------------------------------------------------------- + + FGameFrame::FGameFrame() + : FrameNumber(0), WorldToMetersScale(100.f), ShowFlags(ESFIM_All0), PlayerOrientation(FQuat::Identity), PlayerLocation(FVector::ZeroVector), FoveatedRenderingMethod(EOculusXRFoveatedRenderingMethod::FixedFoveatedRendering), FoveatedRenderingLevel(EOculusXRFoveatedRenderingLevel::Off), bDynamicFoveatedRendering(false) + { + Flags.Raw = 0; + Fov[0] = Fov[1] = SymmetricFov[0] = SymmetricFov[1] = ovrpFovf{ 0, 0, 0, 0 }; + } + + TSharedPtr FGameFrame::Clone() const + { + TSharedPtr NewFrame = MakeShareable(new FGameFrame(*this)); + return NewFrame; + } + +} // namespace OculusXRHMD + +#endif //OCULUS_HMD_SUPPORTED_PLATFORMS diff --git a/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_GameFrame.h b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_GameFrame.h new file mode 100644 index 0000000..40c099d --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_GameFrame.h @@ -0,0 +1,65 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +#pragma once +#include "OculusXRHMDPrivate.h" + +#if OCULUS_HMD_SUPPORTED_PLATFORMS +#include "OculusXRHMD_Settings.h" +#include "ShowFlags.h" + +namespace OculusXRHMD +{ + + //------------------------------------------------------------------------------------------------- + // FGameFrame + //------------------------------------------------------------------------------------------------- + + class FGameFrame : public TSharedFromThis + { + public: + uint32 FrameNumber; // current frame number. (StartGameFrame_GameThread) + float WorldToMetersScale; // World units (UU) to Meters scale. (OnStartGameFrame) + FIntPoint WindowSize; // actual window size (StartGameFrame_GameThread) + FEngineShowFlags ShowFlags; // (PreRenderViewFamily_RenderThread) + + FQuat HeadOrientation; // (CalculateStereoViewOffset) + FQuat PlayerOrientation; // (CalculateStereoViewOffset) + FVector PlayerLocation; // (CalculateStereoViewOffset) + float NearClippingPlane; // (GetStereoProjectionMatrix) + + FTransform TrackingToWorld; // (OnEndGameFrame) + FTransform LastTrackingToWorld; // (OnEndGameFrame) + + EOculusXRFoveatedRenderingMethod FoveatedRenderingMethod; // OnStartGameFrame + EOculusXRFoveatedRenderingLevel FoveatedRenderingLevel; // OnStartGameFrame + bool bDynamicFoveatedRendering; // OnStartGameFrame + + ovrpFovf Fov[ovrpEye_Count]; // UpdateStereoRenderingParams + ovrpFovf SymmetricFov[ovrpEye_Count]; // UpdateStereoRenderingParams, symmetric FOV if frame is using symmetricFOV. + + union + { + struct + { + /** True, if splash is shown */ + uint64 bSplashIsShown : 1; + /** True, if spectator screen is active */ + uint64 bSpectatorScreenActive : 1; + /** True if the frame's positions have been updated on the render thread */ + uint64 bRTLateUpdateDone : 1; + }; + uint64 Raw; + } Flags; + + public: + FGameFrame(); + + TSharedPtr Clone() const; + }; + + typedef TSharedPtr FGameFramePtr; + +} // namespace OculusXRHMD + +#endif //OCULUS_HMD_SUPPORTED_PLATFORMS diff --git a/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_Layer.cpp b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_Layer.cpp new file mode 100644 index 0000000..2ac6ece --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_Layer.cpp @@ -0,0 +1,1484 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +#include "OculusXRHMD_Layer.h" + +#if OCULUS_HMD_SUPPORTED_PLATFORMS +//#include "MediaTexture.h" +//#include "ScreenRendering.h" +//#include "ScenePrivate.h" +//#include "PostProcess/SceneFilterRendering.h" +#include "PostProcess/SceneRenderTargets.h" +#include "HeadMountedDisplayTypes.h" // for LogHMD +#include "OculusXRHMD.h" +#include "XRThreadUtils.h" +#include "Engine/RendererSettings.h" +#include "Engine/Texture2D.h" +#include "UObject/ConstructorHelpers.h" +#include "Materials/Material.h" +#include "Materials/MaterialInterface.h" +#include "Materials/MaterialInstanceDynamic.h" +#include "Engine/GameEngine.h" +#include "SceneUtils.h" +#include "OculusXRHMDPrivate.h" +#include "OculusXRHMDModule.h" +#include "OculusXRHMD_DeferredDeletionQueue.h" + +namespace OculusXRHMD +{ + + //------------------------------------------------------------------------------------------------- + // FOvrpLayer + //------------------------------------------------------------------------------------------------- + + FOvrpLayer::FOvrpLayer(uint32 InOvrpLayerId, FDeferredDeletionQueue* InDeferredDeletion) + : OvrpLayerId(InOvrpLayerId), DeferredDeletion(InDeferredDeletion) + { + } + + FOvrpLayer::~FOvrpLayer() + { + if (IsInGameThread()) + { + ExecuteOnRenderThread([OvrpLayerId = this->OvrpLayerId, DeferredDeletion = this->DeferredDeletion]() { + DeferredDeletion->AddOVRPLayerToDeferredDeletionQueue(OvrpLayerId); + }); + } + else + { + DeferredDeletion->AddOVRPLayerToDeferredDeletionQueue(OvrpLayerId); + } + } + + //------------------------------------------------------------------------------------------------- + // FLayer + //------------------------------------------------------------------------------------------------- + + FLayer::FLayer(uint32 InId) + : bNeedsTexSrgbCreate(false) + , Id(InId) + , OvrpLayerId(0) + , bUpdateTexture(false) + , bInvertY(false) + , bHasDepth(false) + , bSupportDepthComposite(false) + , PokeAHoleComponentPtr(nullptr) + , PokeAHoleActor(nullptr) + { + FMemory::Memzero(OvrpLayerDesc); + FMemory::Memzero(OvrpLayerSubmit); + } + + FLayer::FLayer(const FLayer& Layer) + : bNeedsTexSrgbCreate(Layer.bNeedsTexSrgbCreate) + , Id(Layer.Id) + , Desc(Layer.Desc) + , OvrpLayerId(Layer.OvrpLayerId) + , OvrpLayer(Layer.OvrpLayer) + , SwapChain(Layer.SwapChain) + , DepthSwapChain(Layer.DepthSwapChain) + , FoveationSwapChain(Layer.FoveationSwapChain) + , RightSwapChain(Layer.RightSwapChain) + , RightDepthSwapChain(Layer.RightDepthSwapChain) + , MotionVectorSwapChain(Layer.MotionVectorSwapChain) + , MotionVectorDepthSwapChain(Layer.MotionVectorDepthSwapChain) + , InvAlphaTexture(Layer.InvAlphaTexture) + , bUpdateTexture(Layer.bUpdateTexture) + , bInvertY(Layer.bInvertY) + , bHasDepth(Layer.bHasDepth) + , bSupportDepthComposite(Layer.bSupportDepthComposite) + , PokeAHoleComponentPtr(Layer.PokeAHoleComponentPtr) + , PokeAHoleActor(Layer.PokeAHoleActor) + , UserDefinedGeometryMap(Layer.UserDefinedGeometryMap) + , PassthroughPokeActorMap(Layer.PassthroughPokeActorMap) + { + FMemory::Memcpy(&OvrpLayerDesc, &Layer.OvrpLayerDesc, sizeof(OvrpLayerDesc)); + FMemory::Memcpy(&OvrpLayerSubmit, &Layer.OvrpLayerSubmit, sizeof(OvrpLayerSubmit)); + } + + FLayer::~FLayer() + { + } + + void FLayer::SetDesc(const IStereoLayers::FLayerDesc& InDesc) + { + if (Desc.Texture != InDesc.Texture || Desc.LeftTexture != InDesc.LeftTexture) + { + bUpdateTexture = true; + } + + Desc = InDesc; + + if (!UserDefinedGeometryMap) + { + UserDefinedGeometryMap = MakeShared, ESPMode::ThreadSafe>(); + } + + if (!PassthroughPokeActorMap) + { + PassthroughPokeActorMap = MakeShared, ESPMode::ThreadSafe>(); + } + + HandlePokeAHoleComponent(); + +#if !PLATFORM_ANDROID + if (!(Desc.HasShape() || Desc.HasShape())) //If not Passthrough Shape + { + // Mark all layers as supporting depth for now, due to artifacts with ovrpLayerSubmitFlag_NoDepth + Desc.Flags |= IStereoLayers::LAYER_FLAG_SUPPORT_DEPTH; + } +#endif + + UpdatePassthroughPokeActors_GameThread(); + } + + void FLayer::SetDesc(const FSettings* Settings, const IStereoLayers::FLayerDesc& InDesc) + { + bSupportDepthComposite = Settings->Flags.bCompositeDepth; + + SetDesc(InDesc); + } + + static UWorld* GetWorld() + { + UWorld* World = nullptr; + for (const FWorldContext& Context : GEngine->GetWorldContexts()) + { + if (Context.WorldType == EWorldType::Game || Context.WorldType == EWorldType::PIE) + { + World = Context.World(); + } + } + return World; + } + + bool FLayer::NeedsPassthroughPokeAHole() + { + return ((Desc.Flags & IStereoLayers::LAYER_FLAG_SUPPORT_DEPTH) != 0) && Desc.HasShape(); + } + + bool FLayer::NeedsPokeAHole() + { +#if PLATFORM_ANDROID + bool bIsPassthroughShape = (Desc.HasShape() || Desc.HasShape()); + return !bIsPassthroughShape && !bSupportDepthComposite && ((Desc.Flags & IStereoLayers::LAYER_FLAG_SUPPORT_DEPTH) != 0); +#else + return false; +#endif + } + + void FLayer::HandlePokeAHoleComponent() + { + if (NeedsPokeAHole()) + { + const FString BaseComponentName = FString::Printf(TEXT("OculusPokeAHole_%d"), Id); + const FName ComponentName(*BaseComponentName); + + if (!PokeAHoleComponentPtr) + { + UWorld* World = GetWorld(); + + if (!World) + { + return; + } + + PokeAHoleActor = World->SpawnActor(); + + PokeAHoleComponentPtr = NewObject(PokeAHoleActor, ComponentName); + PokeAHoleComponentPtr->RegisterComponent(); + + TArray Vertices; + TArray Triangles; + TArray Normals; + TArray UV0; + TArray VertexColors; + TArray Tangents; + + BuildPokeAHoleMesh(Vertices, Triangles, UV0); + PokeAHoleComponentPtr->CreateMeshSection_LinearColor(0, Vertices, Triangles, Normals, UV0, VertexColors, Tangents, false); + + FOculusXRHMD* OculusXRHMD = static_cast(GEngine->XRSystem->GetHMDDevice()); + UMaterial* PokeAHoleMaterial = OculusXRHMD->GetResourceHolder()->PokeAHoleMaterial; + UMaterialInstanceDynamic* DynamicMaterial = UMaterialInstanceDynamic::Create(PokeAHoleMaterial, nullptr); + PokeAHoleComponentPtr->SetMaterial(0, DynamicMaterial); + } + PokeAHoleComponentPtr->SetWorldTransform(Desc.Transform); + } + + return; + } + + static void AppendFaceIndices(const int v0, const int v1, const int v2, const int v3, TArray& Triangles, bool inverse) + { + if (inverse) + { + Triangles.Add(v0); + Triangles.Add(v2); + Triangles.Add(v1); + Triangles.Add(v0); + Triangles.Add(v3); + Triangles.Add(v2); + } + else + { + Triangles.Add(v0); + Triangles.Add(v1); + Triangles.Add(v2); + Triangles.Add(v0); + Triangles.Add(v2); + Triangles.Add(v3); + } + } + + void FLayer::BuildPokeAHoleMesh(TArray& Vertices, TArray& Triangles, TArray& UV0) + { + if (Desc.HasShape()) + { + const float QuadScale = 0.99; + + FIntPoint TexSize = Desc.Texture.IsValid() ? Desc.Texture->GetTexture2D()->GetSizeXY() : Desc.LayerSize; + float AspectRatio = TexSize.X ? (float)TexSize.Y / (float)TexSize.X : 3.0f / 4.0f; + + float QuadSizeX = Desc.QuadSize.X; + float QuadSizeY = (Desc.Flags & IStereoLayers::LAYER_FLAG_QUAD_PRESERVE_TEX_RATIO) ? Desc.QuadSize.X * AspectRatio : Desc.QuadSize.Y; + + Vertices.Init(FVector::ZeroVector, 4); + Vertices[0] = FVector(0.0, -QuadSizeX / 2, -QuadSizeY / 2) * QuadScale; + Vertices[1] = FVector(0.0, QuadSizeX / 2, -QuadSizeY / 2) * QuadScale; + Vertices[2] = FVector(0.0, QuadSizeX / 2, QuadSizeY / 2) * QuadScale; + Vertices[3] = FVector(0.0, -QuadSizeX / 2, QuadSizeY / 2) * QuadScale; + + UV0.Init(FVector2D::ZeroVector, 4); + UV0[0] = FVector2D(1, 0); + UV0[1] = FVector2D(1, 1); + UV0[2] = FVector2D(0, 0); + UV0[3] = FVector2D(0, 1); + + Triangles.Reserve(6); + AppendFaceIndices(0, 1, 2, 3, Triangles, false); + } + else if (Desc.HasShape()) + { + const FCylinderLayer& CylinderProps = Desc.GetShape(); + const float CylinderScale = 0.99; + + FIntPoint TexSize = Desc.Texture.IsValid() ? Desc.Texture->GetTexture2D()->GetSizeXY() : Desc.LayerSize; + float AspectRatio = TexSize.X ? (float)TexSize.Y / (float)TexSize.X : 3.0f / 4.0f; + + float CylinderHeight = (Desc.Flags & IStereoLayers::LAYER_FLAG_QUAD_PRESERVE_TEX_RATIO) ? CylinderProps.OverlayArc * AspectRatio : CylinderProps.Height; + + const FVector XAxis = FVector(1, 0, 0); + const FVector YAxis = FVector(0, 1, 0); + const FVector HalfHeight = FVector(0, 0, CylinderHeight / 2); + + const float ArcAngle = CylinderProps.OverlayArc / CylinderProps.Radius; + const int Sides = (int)((ArcAngle * 180) / (PI * 5)); // one triangle every 10 degrees of cylinder for a good-cheap approximation + Vertices.Init(FVector::ZeroVector, 2 * (Sides + 1)); + UV0.Init(FVector2D::ZeroVector, 2 * (Sides + 1)); + Triangles.Init(0, Sides * 6); + + float CurrentAngle = -ArcAngle / 2; + const float AngleStep = ArcAngle / Sides; + + for (int Side = 0; Side < Sides + 1; Side++) + { + FVector MidVertex = CylinderProps.Radius * (FMath::Cos(CurrentAngle) * XAxis + FMath::Sin(CurrentAngle) * YAxis); + Vertices[2 * Side] = (MidVertex - HalfHeight) * CylinderScale; + Vertices[(2 * Side) + 1] = (MidVertex + HalfHeight) * CylinderScale; + + UV0[2 * Side] = FVector2D(1 - (Side / (float)Sides), 0); + UV0[(2 * Side) + 1] = FVector2D(1 - (Side / (float)Sides), 1); + + CurrentAngle += AngleStep; + + if (Side < Sides) + { + Triangles[6 * Side + 0] = 2 * Side; + Triangles[6 * Side + 2] = 2 * Side + 1; + Triangles[6 * Side + 1] = 2 * (Side + 1) + 1; + Triangles[6 * Side + 3] = 2 * Side; + Triangles[6 * Side + 5] = 2 * (Side + 1) + 1; + Triangles[6 * Side + 4] = 2 * (Side + 1); + } + } + } + else if (Desc.HasShape()) + { + const float CubemapScale = 1000; + Vertices.Init(FVector::ZeroVector, 8); + Vertices[0] = FVector(-1.0, -1.0, -1.0) * CubemapScale; + Vertices[1] = FVector(-1.0, -1.0, 1.0) * CubemapScale; + Vertices[2] = FVector(-1.0, 1.0, -1.0) * CubemapScale; + Vertices[3] = FVector(-1.0, 1.0, 1.0) * CubemapScale; + Vertices[4] = FVector(1.0, -1.0, -1.0) * CubemapScale; + Vertices[5] = FVector(1.0, -1.0, 1.0) * CubemapScale; + Vertices[6] = FVector(1.0, 1.0, -1.0) * CubemapScale; + Vertices[7] = FVector(1.0, 1.0, 1.0) * CubemapScale; + + Triangles.Reserve(24); + AppendFaceIndices(0, 1, 3, 2, Triangles, false); + AppendFaceIndices(4, 5, 7, 6, Triangles, true); + AppendFaceIndices(0, 1, 5, 4, Triangles, true); + AppendFaceIndices(2, 3, 7, 6, Triangles, false); + AppendFaceIndices(0, 2, 6, 4, Triangles, false); + AppendFaceIndices(1, 3, 7, 5, Triangles, true); + } + } + + bool FLayer::BuildPassthroughPokeActor(FOculusPassthroughMeshRef PassthroughMesh, FPassthroughPokeActor& OutPassthroughPokeActor) + { + UWorld* World = GetWorld(); + + if (!World) + { + return false; + } + + const FString BaseComponentName = FString::Printf(TEXT("OculusPassthroughPoke_%d"), Id); + const FName ComponentName(*BaseComponentName); + AActor* PassthoughPokeActor = World->SpawnActor(); + UProceduralMeshComponent* PassthoughPokeComponentPtr = NewObject(PassthoughPokeActor, ComponentName); + PassthoughPokeComponentPtr->RegisterComponent(); + + const TArray& Triangles = PassthroughMesh->GetTriangles(); + const TArray& Vertices = PassthroughMesh->GetVertices(); + TArray Normals; + TArray UV0; + TArray VertexColors; + TArray Tangents; + + PassthoughPokeComponentPtr->CreateMeshSection_LinearColor(0, Vertices, Triangles, Normals, UV0, VertexColors, Tangents, false); + + FOculusXRHMD* OculusXRHMD = static_cast(GEngine->XRSystem->GetHMDDevice()); + UMaterial* PokeAHoleMaterial = OculusXRHMD->GetResourceHolder()->PokeAHoleMaterial; + + UMaterialInstanceDynamic* DynamicMaterial = UMaterialInstanceDynamic::Create(PokeAHoleMaterial, nullptr); + PassthoughPokeComponentPtr->SetMaterial(0, DynamicMaterial); + + OutPassthroughPokeActor.PokeAHoleActor = PassthoughPokeActor; + OutPassthroughPokeActor.PokeAHoleComponentPtr = PassthoughPokeComponentPtr; + + return true; + } + + void FLayer::UpdatePassthroughPokeActors_GameThread() + { + if (Desc.HasShape()) + { + const FUserDefinedLayer& UserDefinedLayerProps = Desc.GetShape(); + const TArray& UserGeometryList = UserDefinedLayerProps.UserGeometryList; + TSet UsedSet = {}; + + if (NeedsPassthroughPokeAHole()) + { + for (const FUserDefinedGeometryDesc& GeometryDesc : UserGeometryList) + { + const FString MeshName = GeometryDesc.MeshName; + UsedSet.Add(MeshName); + + FPassthroughPokeActor* FoundPassthroughPokeActor = PassthroughPokeActorMap->Find(MeshName); + if (!FoundPassthroughPokeActor) + { + OculusXRHMD::FOculusPassthroughMeshRef GeomPassthroughMesh = GeometryDesc.PassthroughMesh; + if (GeomPassthroughMesh) + { + FPassthroughPokeActor PassthroughPokeActor; + if (BuildPassthroughPokeActor(GeomPassthroughMesh, PassthroughPokeActor)) + { + PassthroughPokeActor.PokeAHoleComponentPtr->SetWorldTransform(GeometryDesc.Transform); + PassthroughPokeActorMap->Add(MeshName, PassthroughPokeActor); + } + } + } + else if (GeometryDesc.bUpdateTransform) + { + (*FoundPassthroughPokeActor).PokeAHoleComponentPtr->SetWorldTransform(GeometryDesc.Transform); + } + } + } + + // find actors that no longer exist + TArray ItemsToRemove; + for (auto& Entry : *UserDefinedGeometryMap) + { + if (!UsedSet.Contains(Entry.Key)) + { + ItemsToRemove.Add(Entry.Key); + } + } + + for (FString Entry : ItemsToRemove) + { + FPassthroughPokeActor* PassthroughPokeActor = PassthroughPokeActorMap->Find(Entry); + if (PassthroughPokeActor) + { + UWorld* World = GetWorld(); + if (World) + { + World->DestroyActor(PassthroughPokeActor->PokeAHoleActor); + } + } + PassthroughPokeActorMap->Remove(Entry); + } + } + } + + bool FLayer::ShapeNeedsTextures(ovrpShape shape) + { + return ((shape != ovrpShape_ReconstructionPassthrough) && (shape != ovrpShape_SurfaceProjectedPassthrough)); + } + + void FLayer::SetEyeLayerDesc(const ovrpLayerDesc_EyeFov& InEyeLayerDesc) + { + OvrpLayerDesc.EyeFov = InEyeLayerDesc; + + bHasDepth = InEyeLayerDesc.DepthFormat != ovrpTextureFormat_None; + } + + TSharedPtr FLayer::Clone() const + { + return MakeShareable(new FLayer(*this)); + } + + bool FLayer::CanReuseResources(const FLayer* InLayer) const + { + if (!InLayer || !InLayer->OvrpLayer.IsValid()) + { + return false; + } + + if (OvrpLayerDesc.Shape != InLayer->OvrpLayerDesc.Shape || OvrpLayerDesc.Layout != InLayer->OvrpLayerDesc.Layout || OvrpLayerDesc.TextureSize.w != InLayer->OvrpLayerDesc.TextureSize.w || OvrpLayerDesc.TextureSize.h != InLayer->OvrpLayerDesc.TextureSize.h || OvrpLayerDesc.MipLevels != InLayer->OvrpLayerDesc.MipLevels || OvrpLayerDesc.SampleCount != InLayer->OvrpLayerDesc.SampleCount || OvrpLayerDesc.Format != InLayer->OvrpLayerDesc.Format || OvrpLayerDesc.LayerFlags != InLayer->OvrpLayerDesc.LayerFlags || bNeedsTexSrgbCreate != InLayer->bNeedsTexSrgbCreate) + { + return false; + } + + if (OvrpLayerDesc.Shape == ovrpShape_EyeFov) + { + if (OvrpLayerDesc.EyeFov.DepthFormat != InLayer->OvrpLayerDesc.EyeFov.DepthFormat || OvrpLayerDesc.EyeFov.MotionVectorDepthFormat != InLayer->OvrpLayerDesc.EyeFov.MotionVectorDepthFormat || OvrpLayerDesc.EyeFov.MotionVectorFormat != InLayer->OvrpLayerDesc.EyeFov.MotionVectorFormat || OvrpLayerDesc.EyeFov.MotionVectorTextureSize.w != InLayer->OvrpLayerDesc.EyeFov.MotionVectorTextureSize.w || OvrpLayerDesc.EyeFov.MotionVectorTextureSize.h != InLayer->OvrpLayerDesc.EyeFov.MotionVectorTextureSize.h) + { + return false; + } + } + + return true; + } + + bool FLayer::Initialize_RenderThread(const FSettings* Settings, FCustomPresent* CustomPresent, FDeferredDeletionQueue* DeferredDeletion, FRHICommandListImmediate& RHICmdList, const FLayer* InLayer) + { + CheckInRenderThread(); + + if (Id == 0) + { + // OvrpLayerDesc and OvrpViewportRects already initialized, as this is the eyeFOV layer. The only necessary modification is to take into account MSAA level, that can only be accurately determined on the RT. + } + else + { + bInvertY = (CustomPresent->GetLayerFlags() & ovrpLayerFlag_TextureOriginAtBottomLeft) != 0; + + uint32 SizeX = 0, SizeY = 0; + + if (Desc.Texture.IsValid()) + { + FRHITexture2D* Texture2D = Desc.Texture->GetTexture2D(); + FRHITextureCube* TextureCube = Desc.Texture->GetTextureCube(); + + if (Texture2D) + { + SizeX = Texture2D->GetSizeX(); + SizeY = Texture2D->GetSizeY(); + } + else if (TextureCube) + { + SizeX = SizeY = TextureCube->GetSize(); + } + } + else + { + SizeX = Desc.LayerSize.X; + SizeY = Desc.LayerSize.Y; + } + + ovrpShape Shape; + + if (Desc.HasShape()) + { + Shape = ovrpShape_Quad; + } + else if (Desc.HasShape()) + { + Shape = ovrpShape_Cylinder; + } + else if (Desc.HasShape()) + { + Shape = ovrpShape_Cubemap; + } + else if (Desc.HasShape()) + { + Shape = ovrpShape_Equirect; + } + else if (Desc.HasShape()) + { + Shape = ovrpShape_ReconstructionPassthrough; + } + else if (Desc.HasShape()) + { + Shape = ovrpShape_SurfaceProjectedPassthrough; + } + else + { + return false; + } + + if (ShapeNeedsTextures(Shape) && (SizeX == 0 || SizeY == 0)) + { + return false; + } + + EPixelFormat Format = Desc.Texture.IsValid() ? CustomPresent->GetPixelFormat(Desc.Texture->GetFormat()) : CustomPresent->GetDefaultPixelFormat(); +#if PLATFORM_ANDROID + uint32 NumMips = Desc.Texture.IsValid() ? Desc.Texture->GetNumMips() : 1; +#else + uint32 NumMips = 0; +#endif + uint32 NumSamples = 1; + int LayerFlags = CustomPresent->GetLayerFlags(); + + if (!(Desc.Flags & IStereoLayers::LAYER_FLAG_TEX_CONTINUOUS_UPDATE)) + { + LayerFlags |= ovrpLayerFlag_Static; + } +#ifdef WITH_OCULUS_BRANCH + if (Desc.Flags & IStereoLayers::LAYER_FLAG_BICUBIC_FILTERING) + { + LayerFlags |= ovrpLayerFlag_BicubicFiltering; + } +#endif + // Calculate layer desc + FOculusXRHMDModule::GetPluginWrapper().CalculateLayerDesc( + Shape, + !Desc.LeftTexture.IsValid() ? ovrpLayout_Mono : ovrpLayout_Stereo, + ovrpSizei{ (int)SizeX, (int)SizeY }, + NumMips, + NumSamples, + CustomPresent->GetOvrpTextureFormat(Format), + LayerFlags, + &OvrpLayerDesc); + + // Calculate viewport rect + for (uint32 EyeIndex = 0; EyeIndex < ovrpEye_Count; EyeIndex++) + { + ovrpRecti& ViewportRect = OvrpLayerSubmit.ViewportRect[EyeIndex]; + ViewportRect.Pos.x = (int)(Desc.UVRect.Min.X * SizeX + 0.5f); + ViewportRect.Pos.y = (int)(Desc.UVRect.Min.Y * SizeY + 0.5f); + ViewportRect.Size.w = (int)(Desc.UVRect.Max.X * SizeX + 0.5f) - ViewportRect.Pos.x; + ViewportRect.Size.h = (int)(Desc.UVRect.Max.Y * SizeY + 0.5f) - ViewportRect.Pos.y; + } + } + + // Reuse/Create texture set + if (CanReuseResources(InLayer)) + { + OvrpLayerId = InLayer->OvrpLayerId; + OvrpLayer = InLayer->OvrpLayer; + SwapChain = InLayer->SwapChain; + DepthSwapChain = InLayer->DepthSwapChain; + FoveationSwapChain = InLayer->FoveationSwapChain; + RightSwapChain = InLayer->RightSwapChain; + RightDepthSwapChain = InLayer->RightDepthSwapChain; + MotionVectorSwapChain = InLayer->MotionVectorSwapChain; + MotionVectorDepthSwapChain = InLayer->MotionVectorDepthSwapChain; + InvAlphaTexture = InLayer->InvAlphaTexture; + bUpdateTexture = InLayer->bUpdateTexture; + bNeedsTexSrgbCreate = InLayer->bNeedsTexSrgbCreate; + UserDefinedGeometryMap = InLayer->UserDefinedGeometryMap; + } + else + { + bool bLayerCreated = false; + bool bValidFoveationTextures = true; + TArray ColorTextures; + TArray DepthTextures; + TArray FoveationTextures; + TArray RightColorTextures; + TArray RightDepthTextures; + ovrpSizei FoveationTextureSize; + + bool bValidMotionVectorTextures = false; + TArray MotionVectorTextures; + ovrpSizei MotionVectorTextureSize; + TArray MotionVectorDepthTextures; + ovrpSizei MotionVectorDepthTextureSize; + + ExecuteOnRHIThread([&]() { + // UNDONE Do this in RenderThread once OVRPlugin allows FOculusXRHMDModule::GetPluginWrapper().SetupLayer to be called asynchronously + int32 TextureCount; + if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().SetupLayer(CustomPresent->GetOvrpDevice(), OvrpLayerDesc.Base, (int*)&OvrpLayerId)) && OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetLayerTextureStageCount(OvrpLayerId, &TextureCount))) + { + if (ShapeNeedsTextures(OvrpLayerDesc.Shape)) + { + // Left + { + ColorTextures.SetNum(TextureCount); + if (bHasDepth) + { + DepthTextures.SetNum(TextureCount); + } + + FoveationTextures.SetNum(TextureCount); + FoveationTextureSize.w = 0; + FoveationTextureSize.h = 0; + + MotionVectorTextures.SetNum(TextureCount); + MotionVectorTextureSize.w = 0; + MotionVectorTextureSize.h = 0; + MotionVectorDepthTextures.SetNum(TextureCount); + MotionVectorDepthTextureSize.w = 0; + MotionVectorDepthTextureSize.h = 0; + + bValidMotionVectorTextures = ((OvrpLayerDesc.LayerFlags & ovrpLayerFlag_SpaceWarpDataAllocation) > 0) && (OvrpLayerDesc.Shape == ovrpShape_EyeFov); + for (int32 TextureIndex = 0; TextureIndex < TextureCount; TextureIndex++) + { + ovrpTextureHandle* DepthTexHdlPtr = bHasDepth ? &DepthTextures[TextureIndex] : nullptr; + if (OVRP_FAILURE(FOculusXRHMDModule::GetPluginWrapper().GetLayerTexture2(OvrpLayerId, TextureIndex, ovrpEye_Left, &ColorTextures[TextureIndex], DepthTexHdlPtr))) + { + UE_LOG(LogHMD, Error, TEXT("Failed to create Oculus layer texture. NOTE: This causes a leak of %d other texture(s), which will go unused."), TextureIndex); + // skip setting bLayerCreated and allocating any other textures + return; + } + if (bValidFoveationTextures) + { + // Call fails on unsupported platforms and returns null textures for no foveation texture + // Since this texture is not required for rendering, don't return on failure + if (OVRP_FAILURE(FOculusXRHMDModule::GetPluginWrapper().GetLayerTextureFoveation(OvrpLayerId, TextureIndex, ovrpEye_Left, &FoveationTextures[TextureIndex], &FoveationTextureSize)) || FoveationTextures[TextureIndex] == (unsigned long long)nullptr) + { + bValidFoveationTextures = false; + } + } + + if (bValidMotionVectorTextures) + { + // Call fails on unsupported platforms and returns null textures for no motion vector texture + // Since this texture is not required for rendering, don't return on failure + + if (OVRP_FAILURE(FOculusXRHMDModule::GetPluginWrapper().GetLayerTextureSpaceWarp(OvrpLayerId, TextureIndex, ovrpEye_Left, &MotionVectorTextures[TextureIndex], &MotionVectorTextureSize, &MotionVectorDepthTextures[TextureIndex], &MotionVectorDepthTextureSize)) || MotionVectorTextures[TextureIndex] == (unsigned long long)nullptr) + { + bValidMotionVectorTextures = false; + UE_LOG(LogHMD, Error, TEXT("[Mobile SpaceWarp] Space Warpovrp_GetLayerTextureMotionVector failed")); + } + } + } + } + + // Right + if (OvrpLayerDesc.Layout == ovrpLayout_Stereo) + { + RightColorTextures.SetNum(TextureCount); + if (bHasDepth) + { + RightDepthTextures.SetNum(TextureCount); + } + + for (int32 TextureIndex = 0; TextureIndex < TextureCount; TextureIndex++) + { + ovrpTextureHandle* DepthTexHdlPtr = bHasDepth ? &RightDepthTextures[TextureIndex] : nullptr; + if (OVRP_FAILURE(FOculusXRHMDModule::GetPluginWrapper().GetLayerTexture2(OvrpLayerId, TextureIndex, ovrpEye_Right, &RightColorTextures[TextureIndex], DepthTexHdlPtr))) + { + UE_LOG(LogHMD, Error, TEXT("Failed to create Oculus layer texture. NOTE: This causes a leak of %d other texture(s), which will go unused."), TextureCount + TextureIndex); + // skip setting bLayerCreated and allocating any other textures + return; + } + } + } + } + else + { + bValidFoveationTextures = false; + } + + bLayerCreated = true; + } + }); + + if (bLayerCreated) + { + OvrpLayer = MakeShareable(new FOvrpLayer(OvrpLayerId, DeferredDeletion)); + + if (ShapeNeedsTextures(OvrpLayerDesc.Shape)) + { + uint32 SizeX = OvrpLayerDesc.TextureSize.w; + uint32 SizeY = OvrpLayerDesc.TextureSize.h; + EPixelFormat ColorFormat = CustomPresent->GetPixelFormat(OvrpLayerDesc.Format); + EPixelFormat DepthFormat = PF_DepthStencil; + uint32 NumMips = OvrpLayerDesc.MipLevels; + uint32 NumSamples = OvrpLayerDesc.SampleCount; + uint32 NumSamplesTileMem = 1; + if (OvrpLayerDesc.Shape == ovrpShape_EyeFov) + { + static const auto CVarMobileMSAA = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.MobileMSAA")); + NumSamplesTileMem = (CVarMobileMSAA ? CVarMobileMSAA->GetValueOnAnyThread() : 1); + } + + ERHIResourceType ResourceType; + if (OvrpLayerDesc.Shape == ovrpShape_Cubemap || OvrpLayerDesc.Shape == ovrpShape_OffcenterCubemap) + { + ResourceType = RRT_TextureCube; + } + else if (OvrpLayerDesc.Layout == ovrpLayout_Array) + { + ResourceType = RRT_Texture2DArray; + } + else + { + ResourceType = RRT_Texture2D; + } + + const bool bNeedsSRGBFlag = bNeedsTexSrgbCreate || CustomPresent->IsSRGB(OvrpLayerDesc.Format); + + ETextureCreateFlags ColorTexCreateFlags = TexCreate_ShaderResource | TexCreate_RenderTargetable | TexCreate_ResolveTargetable | (bNeedsSRGBFlag ? TexCreate_SRGB : TexCreate_None); + ETextureCreateFlags DepthTexCreateFlags = TexCreate_ShaderResource | TexCreate_DepthStencilTargetable | TexCreate_InputAttachmentRead | (bSupportDepthComposite ? TexCreate_ResolveTargetable : TexCreate_None); + + if (Desc.Texture.IsValid()) + { + ColorTexCreateFlags |= (Desc.Texture->GetFlags() & TexCreate_SRGB); + } + + FClearValueBinding ColorTextureBinding; + FClearValueBinding DepthTextureBinding = FClearValueBinding::DepthFar; + if (OvrpLayerDesc.Shape == ovrpShape_EyeFov) + { + ColorTextureBinding = FClearValueBinding::Black; + } + + SwapChain = CustomPresent->CreateSwapChain_RenderThread(SizeX, SizeY, ColorFormat, ColorTextureBinding, NumMips, NumSamples, NumSamplesTileMem, ResourceType, ColorTextures, ColorTexCreateFlags, *FString::Printf(TEXT("Oculus Color Swapchain %d"), OvrpLayerId)); + +#if PLATFORM_WINDOWS + static const auto CVarPropagateAlpha = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.PostProcessing.PropagateAlpha")); + const EAlphaChannelMode::Type PropagateAlpha = EAlphaChannelMode::FromInt(CVarPropagateAlpha->GetValueOnRenderThread()); + if (PropagateAlpha == EAlphaChannelMode::AllowThroughTonemapper) + { + const ETextureCreateFlags InvTextureCreateFlags = TexCreate_ShaderResource | TexCreate_RenderTargetable; + FRHITextureCreateDesc InvTextureDesc{}; + if (OvrpLayerDesc.Layout == ovrpLayout_Array) + { + InvTextureDesc = FRHITextureCreateDesc::Create2DArray(TEXT("InvAlphaTexture")) + .SetArraySize(2) + .SetExtent(SizeX, SizeY) + .SetFormat(ColorFormat) + .SetNumMips(NumMips) + .SetNumSamples(NumSamples) + .SetFlags(InvTextureCreateFlags | TexCreate_TargetArraySlicesIndependently) + .SetClearValue(ColorTextureBinding); + } + else + { + InvTextureDesc = FRHITextureCreateDesc::Create2D(TEXT("InvAlphaTexture")) + .SetExtent(SizeX, SizeY) + .SetFormat(ColorFormat) + .SetNumMips(NumMips) + .SetNumSamples(NumSamples) + .SetFlags(InvTextureCreateFlags) + .SetClearValue(ColorTextureBinding); + } + InvAlphaTexture = RHICreateTexture(InvTextureDesc); + } +#endif + + if (bHasDepth) + { + DepthSwapChain = CustomPresent->CreateSwapChain_RenderThread(SizeX, SizeY, DepthFormat, DepthTextureBinding, 1, NumSamples, NumSamplesTileMem, ResourceType, DepthTextures, DepthTexCreateFlags, *FString::Printf(TEXT("Oculus Depth Swapchain %d"), OvrpLayerId)); + } + if (bValidFoveationTextures) + { + FoveationSwapChain = CustomPresent->CreateSwapChain_RenderThread(FoveationTextureSize.w, FoveationTextureSize.h, PF_R8G8, FClearValueBinding::White, 1, 1, 1, ResourceType, FoveationTextures, TexCreate_Foveation, *FString::Printf(TEXT("Oculus Foveation Swapchain %d"), OvrpLayerId)); + } + else + { + FoveationSwapChain.Reset(); + } + + if (bValidMotionVectorTextures) + { + EPixelFormat MvPixelFormat = PF_FloatRGBA; + ETextureCreateFlags MVTexCreateFlags = TexCreate_ShaderResource | TexCreate_RenderTargetable; + MotionVectorSwapChain = CustomPresent->CreateSwapChain_RenderThread(MotionVectorTextureSize.w, MotionVectorTextureSize.h, MvPixelFormat, FClearValueBinding::Black, 1, 1, 1, ResourceType, MotionVectorTextures, MVTexCreateFlags, *FString::Printf(TEXT("Oculus MV Swapchain %d"), OvrpLayerId)); + if (MotionVectorDepthTextures.Num() && MotionVectorDepthTextures[0] != (unsigned long long)nullptr) + { + ETextureCreateFlags MVDepthTexCreateFlags = TexCreate_ShaderResource | TexCreate_DepthStencilTargetable; + MotionVectorDepthSwapChain = CustomPresent->CreateSwapChain_RenderThread(MotionVectorDepthTextureSize.w, MotionVectorDepthTextureSize.h, PF_DepthStencil, FClearValueBinding::Black, 1, 1, 1, ResourceType, MotionVectorDepthTextures, MVDepthTexCreateFlags, *FString::Printf(TEXT("Oculus MV Depth Swapchain %d"), OvrpLayerId)); + } + else + { + MotionVectorDepthSwapChain = nullptr; + } + } + else + { + MotionVectorSwapChain.Reset(); + MotionVectorDepthSwapChain.Reset(); + } + + if (OvrpLayerDesc.Layout == ovrpLayout_Stereo) + { + RightSwapChain = CustomPresent->CreateSwapChain_RenderThread(SizeX, SizeY, ColorFormat, ColorTextureBinding, NumMips, NumSamples, NumSamplesTileMem, ResourceType, RightColorTextures, ColorTexCreateFlags, *FString::Printf(TEXT("Oculus Right Color Swapchain %d"), OvrpLayerId)); + + if (bHasDepth) + { + RightDepthSwapChain = CustomPresent->CreateSwapChain_RenderThread(SizeX, SizeY, DepthFormat, DepthTextureBinding, 1, NumSamples, NumSamplesTileMem, ResourceType, RightDepthTextures, DepthTexCreateFlags, *FString::Printf(TEXT("Oculus Right Depth Swapchain %d"), OvrpLayerId)); + } + } + + bUpdateTexture = true; + } + else + { + SwapChain.Reset(); + DepthSwapChain.Reset(); + FoveationSwapChain.Reset(); + RightSwapChain.Reset(); + RightDepthSwapChain.Reset(); + if (UserDefinedGeometryMap) + { + UserDefinedGeometryMap->Reset(); + } + } + } + else + { + return false; + } + } + + if ((Desc.Flags & IStereoLayers::LAYER_FLAG_TEX_CONTINUOUS_UPDATE) && Desc.Texture.IsValid() && IsVisible()) + { + bUpdateTexture = true; + } + + return true; + } + + void FLayer::UpdatePassthroughStyle_RenderThread(const FEdgeStyleParameters& EdgeStyleParameters) + { + ovrpInsightPassthroughStyle Style; + Style.EdgeColor = ovrpColorf{ 0, 0, 0, 0 }; + Style.TextureOpacityFactor = EdgeStyleParameters.TextureOpacityFactor; + Style.Flags = (ovrpInsightPassthroughStyleFlags)(ovrpInsightPassthroughStyleFlags_HasTextureOpacityFactor + | ovrpInsightPassthroughStyleFlags_HasEdgeColor + | ovrpInsightPassthroughStyleFlags_HasTextureColorMap); + Style.TextureColorMapType = ovrpInsightPassthroughColorMapType_None; + Style.TextureColorMapData = nullptr; + Style.TextureColorMapDataSize = 0; + Style.LutWeight = 0; + Style.LutSource = 0; + Style.LutTarget = 0; + + if (EdgeStyleParameters.bEnableEdgeColor) + { + Style.EdgeColor = ToOvrpColorf(EdgeStyleParameters.EdgeColor); + } + + if (EdgeStyleParameters.bEnableColorMap) + { + Style.TextureColorMapType = ToOVRPColorMapType(EdgeStyleParameters.ColorMapType); + Style.TextureColorMapData = (uint8*)EdgeStyleParameters.ColorMapData.GetData(); + Style.TextureColorMapDataSize = EdgeStyleParameters.ColorMapData.Num(); + } + + if (EdgeStyleParameters.bUseColorLuts) + { + Style.LutWeight = EdgeStyleParameters.ColorLutDesc.Weight; + Style.TextureColorMapType = ToOVRPColorMapType(EdgeStyleParameters.ColorMapType); + + if (EdgeStyleParameters.ColorLutDesc.ColorLuts.Num() == 1) + { + check(Style.TextureColorMapType == ovrpInsightPassthroughColorMapType_ColorLut); + Style.LutSource = EdgeStyleParameters.ColorLutDesc.ColorLuts[0]; + } + + if (EdgeStyleParameters.ColorLutDesc.ColorLuts.Num() == 2) + { + check(Style.TextureColorMapType == ovrpInsightPassthroughColorMapType_InterpolatedColorLut); + Style.LutSource = EdgeStyleParameters.ColorLutDesc.ColorLuts[0]; + Style.LutTarget = EdgeStyleParameters.ColorLutDesc.ColorLuts[1]; + } + } + + if (OVRP_FAILURE(FOculusXRHMDModule::GetPluginWrapper().SetInsightPassthroughStyle2(OvrpLayerId, &Style))) + { + UE_LOG(LogTemp, Error, TEXT("Failed setting passthrough style")); + return; + } + } + + static FMatrix TransformToPassthroughSpace(FTransform Transform, const FGameFrame* Frame) + { + const FVector WorldToMetersScaleInv = FVector(Frame->WorldToMetersScale).Reciprocal(); + FTransform TransformWorld = Transform * Frame->TrackingToWorld.Inverse(); + TransformWorld.MultiplyScale3D(WorldToMetersScaleInv); + TransformWorld.ScaleTranslation(WorldToMetersScaleInv); + const FMatrix TransformWorldScaled = TransformWorld.ToMatrixWithScale(); + + const FMatrix SwapAxisMatrix( + FPlane(0.0f, 0.0f, -1.0f, 0.0f), + FPlane(1.0f, 0.0f, 0.0f, 0.0f), + FPlane(0.0f, 1.0f, 0.0f, 0.0f), + FPlane(0.0f, 0.0f, 0.0f, 1.0f)); + + return TransformWorldScaled * SwapAxisMatrix; + } + + void FLayer::UpdatePassthrough_RenderThread(FCustomPresent* CustomPresent, FRHICommandListImmediate& RHICmdList, const FGameFrame* Frame) + { + CheckInRenderThread(); + if (Desc.HasShape()) + { + const FReconstructedLayer& ReconstructedLayerProps = Desc.GetShape(); + UpdatePassthroughStyle_RenderThread(ReconstructedLayerProps.EdgeStyleParameters); + } + else if (Desc.HasShape()) + { + const FUserDefinedLayer& UserDefinedLayerProps = Desc.GetShape(); + UpdatePassthroughStyle_RenderThread(UserDefinedLayerProps.EdgeStyleParameters); + } + + if (Desc.HasShape()) + { + const FUserDefinedLayer& UserDefinedLayerProps = Desc.GetShape(); + const TArray& UserGeometryList = UserDefinedLayerProps.UserGeometryList; + TSet UsedSet; + + for (const FUserDefinedGeometryDesc& GeometryDesc : UserGeometryList) + { + const FString MeshName = GeometryDesc.MeshName; + UsedSet.Add(MeshName); + + FPassthroughMesh* LayerPassthroughMesh = UserDefinedGeometryMap->Find(MeshName); + if (!LayerPassthroughMesh) + { + OculusXRHMD::FOculusPassthroughMeshRef GeomPassthroughMesh = GeometryDesc.PassthroughMesh; + if (GeomPassthroughMesh) + { + const FMatrix Transform = TransformToPassthroughSpace(GeometryDesc.Transform, Frame); + uint64_t MeshHandle = 0; + uint64_t InstanceHandle = 0; + AddPassthroughMesh_RenderThread(GeomPassthroughMesh->GetVertices(), GeomPassthroughMesh->GetTriangles(), Transform, MeshHandle, InstanceHandle); + UserDefinedGeometryMap->Add(MeshName, FPassthroughMesh(MeshHandle, InstanceHandle)); + } + } + else + { + const FMatrix Transform = TransformToPassthroughSpace(GeometryDesc.Transform, Frame); + UpdatePassthroughMeshTransform_RenderThread(LayerPassthroughMesh->InstanceHandle, Transform); + } + } + + // find meshes that no longer exist + TArray ItemsToRemove; + for (auto& Entry : *UserDefinedGeometryMap) + { + if (!UsedSet.Contains(Entry.Key)) + { + ItemsToRemove.Add(Entry.Key); + } + } + + for (FString Entry : ItemsToRemove) + { + FPassthroughMesh* PassthroughMesh = UserDefinedGeometryMap->Find(Entry); + if (PassthroughMesh) + { + const uint64_t MeshHandle = PassthroughMesh->MeshHandle; + const uint64_t InstanceHandle = PassthroughMesh->InstanceHandle; + RemovePassthroughMesh_RenderThread(MeshHandle, InstanceHandle); + } + else + { + UE_LOG(LogTemp, Error, TEXT("PassthroughMesh: %s doesn't exist."), *Entry); + return; + } + + UserDefinedGeometryMap->Remove(Entry); + } + } + } + + static void InvertTextureAlpha_RenderThread(FCustomPresent* CustomPresent, FRHICommandListImmediate& RHICmdList, FRHITexture* Texture, FRHITexture* TempTexture, const FIntRect& ViewportRect) + { + { + FRHITexture* SrcTexture = Texture; + FRHITexture* DstTexture = TempTexture; + const FIntRect SrcRect(ViewportRect); + const FIntRect DstRect(0, 0, ViewportRect.Size().X, ViewportRect.Size().Y); + + const bool bAlphaPremultiply = false; + const bool bNoAlphaWrite = false; + const bool bInvertSrcY = false; + const bool sRGBSource = false; + const bool bInvertAlpha = true; + + CustomPresent->CopyTexture_RenderThread(RHICmdList, DstTexture, SrcTexture, DstRect, SrcRect, bAlphaPremultiply, bNoAlphaWrite, bInvertSrcY, sRGBSource, bInvertAlpha); + } + + { + FRHICopyTextureInfo CopyInfo; + CopyInfo.Size = FIntVector(ViewportRect.Size().X, ViewportRect.Size().Y, 1); + CopyInfo.SourcePosition = FIntVector::ZeroValue; + CopyInfo.DestPosition = FIntVector(ViewportRect.Min.X, ViewportRect.Min.Y, 0); + CopyInfo.SourceSliceIndex = 0; + CopyInfo.DestSliceIndex = 0; + + if (Texture->GetDesc().IsTextureArray() && TempTexture->GetDesc().IsTextureArray()) + { + CopyInfo.NumSlices = FMath::Min(Texture->GetDesc().ArraySize, TempTexture->GetDesc().ArraySize); + } + + FRHITexture* SrcTexture = TempTexture; + FRHITexture* DstTexture = Texture; + RHICmdList.Transition(FRHITransitionInfo(SrcTexture, ERHIAccess::Unknown, ERHIAccess::CopySrc)); + RHICmdList.Transition(FRHITransitionInfo(DstTexture, ERHIAccess::Unknown, ERHIAccess::CopyDest)); + RHICmdList.CopyTexture(SrcTexture, DstTexture, CopyInfo); + RHICmdList.Transition(FRHITransitionInfo(DstTexture, ERHIAccess::CopyDest, ERHIAccess::SRVMask)); + RHICmdList.Transition(FRHITransitionInfo(SrcTexture, ERHIAccess::CopySrc, ERHIAccess::SRVMask)); + } + } + + void FLayer::UpdateTexture_RenderThread(const FSettings* Settings, FCustomPresent* CustomPresent, FRHICommandListImmediate& RHICmdList) + { + CheckInRenderThread(); + + if (bUpdateTexture && SwapChain.IsValid()) + { + // Copy textures + if (Desc.Texture.IsValid()) + { + bool bAlphaPremultiply = true; + bool bNoAlphaWrite = (Desc.Flags & IStereoLayers::LAYER_FLAG_TEX_NO_ALPHA_CHANNEL) != 0; + + // Left + { + FRHITexture* SrcTexture = Desc.LeftTexture.IsValid() ? Desc.LeftTexture : Desc.Texture; + FRHITexture* DstTexture = SwapChain->GetTexture(); + + const ovrpRecti& OvrpViewportRect = OvrpLayerSubmit.ViewportRect[ovrpEye_Left]; + FIntRect DstRect(OvrpViewportRect.Pos.x, OvrpViewportRect.Pos.y, OvrpViewportRect.Pos.x + OvrpViewportRect.Size.w, OvrpViewportRect.Pos.y + OvrpViewportRect.Size.h); + + CustomPresent->CopyTexture_RenderThread(RHICmdList, DstTexture, SrcTexture, DstRect, FIntRect(), bAlphaPremultiply, bNoAlphaWrite, bInvertY); + } + + // Right + if (OvrpLayerDesc.Layout != ovrpLayout_Mono) + { + FRHITexture* SrcTexture = Desc.Texture; + FRHITexture* DstTexture = RightSwapChain.IsValid() ? RightSwapChain->GetTexture() : SwapChain->GetTexture(); + + const ovrpRecti& OvrpViewportRect = OvrpLayerSubmit.ViewportRect[ovrpEye_Right]; + FIntRect DstRect(OvrpViewportRect.Pos.x, OvrpViewportRect.Pos.y, OvrpViewportRect.Pos.x + OvrpViewportRect.Size.w, OvrpViewportRect.Pos.y + OvrpViewportRect.Size.h); + + CustomPresent->CopyTexture_RenderThread(RHICmdList, DstTexture, SrcTexture, DstRect, FIntRect(), bAlphaPremultiply, bNoAlphaWrite, bInvertY); + } + + bUpdateTexture = false; + } + + // Generate mips + SwapChain->GenerateMips_RenderThread(RHICmdList); + + if (RightSwapChain.IsValid()) + { + RightSwapChain->GenerateMips_RenderThread(RHICmdList); + } + } + + if (Id == 0 && SwapChain.IsValid() && InvAlphaTexture) + { + // Left + { + FRHITexture* EyeTexture = SwapChain->GetTexture(); + InvertTextureAlpha_RenderThread(CustomPresent, RHICmdList, EyeTexture, InvAlphaTexture, Settings->EyeRenderViewport[ovrpEye_Left]); + } + + // Right + if (OvrpLayerDesc.Layout != ovrpLayout_Mono && OvrpLayerDesc.Layout != ovrpLayout_Array) + { + FRHITexture* EyeTexture = RightSwapChain.IsValid() ? RightSwapChain->GetTexture() : SwapChain->GetTexture(); + InvertTextureAlpha_RenderThread(CustomPresent, RHICmdList, EyeTexture, InvAlphaTexture, Settings->EyeRenderViewport[ovrpEye_Right]); + } + } + } + + // Returned how much the tracking space moved from previous frame to current frame. + // Note: FTransform is following the order of C = A * B, Apply C means, apply A then Apply B. + void GetTrackingSpaceDeltaPose(const FSettings* Settings, const FGameFrame* Frame, FTransform& TrackingSpaceDeltaPose) + { + // TrackingSpaceDeltaPose: describe the tracking space movement in current tracking space + TrackingSpaceDeltaPose = Frame->TrackingToWorld * Frame->LastTrackingToWorld.Inverse(); + + // However There is a intermediete layer from SettingBasePose, which is acting as a bridge between OVRPlugin Device Space and UE4 Device Space + // Define: OVRPlugin-Device-FPose: same space with the OvrPlugin returned Pose ( In FPose, not ovrpPose ). FOculusXRHMDModule::GetPluginWrapper().GetNodePoseState3() returned value in this space + // Define: UE4-Device-FPose: the space UE4 seeing as device pose space. GetCurrentPose() returned result in this space + FTransform SettingBasePose = FTransform(Settings->BaseOrientation, Settings->BaseOffset); + + // According context of GetCurrentPose, all OVRPlugin-Device-FPose will be inversed by Settings->BaseOrientation & Settings->BaseOffset + // before exposing to UE4 as UE4-Device-FPose. which means UE4-Device-FPose = OVRPlugin-Device-FPose * FPose(BaseOrientation, BaseOffset ).Inverse() + // FPose(BaseOrientation, BaseOffset ) is the UE4 device reference frame defined in OVRPlugin Device Space ( In FPose, not ovrpPose ). + // OVRPlugin-Device-FPose_To_UE4-Device-FPose = FPose(BaseOrientation, BaseOffset ).Inverse() + // UE4-Device-FPose_To_OVRPlugin-Device-FPose = FPose(BaseOrientation, BaseOffset ) + + // Eventually we want a transform in OvrPlugin space (both the input and output data are in OvrPlugin Device Space) + TrackingSpaceDeltaPose = SettingBasePose.Inverse() * TrackingSpaceDeltaPose * SettingBasePose; + } + + const ovrpLayerSubmit* FLayer::UpdateLayer_RHIThread(const FSettings* Settings, const FGameFrame* Frame, const int LayerIndex) + { + OvrpLayerSubmit.LayerId = OvrpLayerId; + OvrpLayerSubmit.TextureStage = SwapChain.IsValid() ? SwapChain->GetSwapChainIndex_RHIThread() : 0; + + bool injectColorScale = Id == 0 || Settings->bApplyColorScaleAndOffsetToAllLayers; + OvrpLayerSubmit.ColorOffset = injectColorScale ? Settings->ColorOffset : ovrpVector4f{ 0, 0, 0, 0 }; + OvrpLayerSubmit.ColorScale = injectColorScale ? Settings->ColorScale : ovrpVector4f{ 1, 1, 1, 1 }; + + if (OvrpLayerDesc.Shape == ovrpShape_Equirect) + { + const FEquirectLayer& EquirectProps = Desc.GetShape(); + + ovrpTextureRectMatrixf& RectMatrix = OvrpLayerSubmit.TextureRectMatrix; + ovrpRectf& LeftUVRect = RectMatrix.LeftRect; + ovrpRectf& RightUVRect = RectMatrix.RightRect; + LeftUVRect.Pos.x = EquirectProps.LeftUVRect.Min.X; + LeftUVRect.Pos.y = EquirectProps.LeftUVRect.Min.Y; + LeftUVRect.Size.w = EquirectProps.LeftUVRect.Max.X - EquirectProps.LeftUVRect.Min.X; + LeftUVRect.Size.h = EquirectProps.LeftUVRect.Max.Y - EquirectProps.LeftUVRect.Min.Y; + RightUVRect.Pos.x = EquirectProps.RightUVRect.Min.X; + RightUVRect.Pos.y = EquirectProps.RightUVRect.Min.Y; + RightUVRect.Size.w = EquirectProps.RightUVRect.Max.X - EquirectProps.RightUVRect.Min.X; + RightUVRect.Size.h = EquirectProps.RightUVRect.Max.Y - EquirectProps.RightUVRect.Min.Y; + + ovrpVector4f& LeftScaleBias = RectMatrix.LeftScaleBias; + LeftScaleBias.x = EquirectProps.LeftScale.X; + LeftScaleBias.y = EquirectProps.LeftScale.Y; + LeftScaleBias.z = EquirectProps.LeftBias.X; + LeftScaleBias.w = EquirectProps.LeftBias.Y; + ovrpVector4f& RightScaleBias = RectMatrix.RightScaleBias; + RightScaleBias.x = EquirectProps.RightScale.X; + RightScaleBias.y = EquirectProps.RightScale.Y; + RightScaleBias.z = EquirectProps.RightBias.X; + RightScaleBias.w = EquirectProps.RightBias.Y; + + OvrpLayerSubmit.OverrideTextureRectMatrix = ovrpBool_True; + } + + if (Id != 0) + { + int SizeX = OvrpLayerDesc.TextureSize.w; + int SizeY = OvrpLayerDesc.TextureSize.h; + + float AspectRatio = SizeX ? (float)SizeY / (float)SizeX : 3.0f / 4.0f; + FVector LocationScaleInv(Frame->WorldToMetersScale); + FVector LocationScale = LocationScaleInv.Reciprocal(); + ovrpVector3f Scale = ToOvrpVector3f(Desc.Transform.GetScale3D() * LocationScale); + + switch (OvrpLayerDesc.Shape) + { + case ovrpShape_ReconstructionPassthrough: + { + float QuadSizeY = (Desc.Flags & IStereoLayers::LAYER_FLAG_QUAD_PRESERVE_TEX_RATIO) ? Desc.QuadSize.X * AspectRatio : Desc.QuadSize.Y; + OvrpLayerSubmit.Quad.Size = ovrpSizef{ static_cast(Desc.QuadSize.X * Scale.x), static_cast(QuadSizeY * Scale.y) }; + } + break; + + case ovrpShape_Quad: + { + float QuadSizeY = (Desc.Flags & IStereoLayers::LAYER_FLAG_QUAD_PRESERVE_TEX_RATIO) ? Desc.QuadSize.X * AspectRatio : Desc.QuadSize.Y; + OvrpLayerSubmit.Quad.Size = ovrpSizef{ static_cast(Desc.QuadSize.X * Scale.x), static_cast(QuadSizeY * Scale.y) }; + } + break; + case ovrpShape_Cylinder: + { + const FCylinderLayer& CylinderProps = Desc.GetShape(); + float CylinderHeight = (Desc.Flags & IStereoLayers::LAYER_FLAG_QUAD_PRESERVE_TEX_RATIO) ? CylinderProps.OverlayArc * AspectRatio : CylinderProps.Height; + OvrpLayerSubmit.Cylinder.ArcWidth = CylinderProps.OverlayArc * Scale.x; + OvrpLayerSubmit.Cylinder.Height = CylinderHeight * Scale.x; + OvrpLayerSubmit.Cylinder.Radius = CylinderProps.Radius * Scale.x; + } + break; + } + + FQuat BaseOrientation; + FVector BaseLocation; + + switch (Desc.PositionType) + { + case IStereoLayers::WorldLocked: + BaseOrientation = Frame->TrackingToWorld.GetRotation(); + BaseLocation = Frame->TrackingToWorld.GetTranslation(); + break; + + case IStereoLayers::TrackerLocked: + BaseOrientation = FQuat::Identity; + BaseLocation = FVector::ZeroVector; + break; + + case IStereoLayers::FaceLocked: + BaseOrientation = FQuat::Identity; + BaseLocation = FVector::ZeroVector; + break; + } + + FTransform PlayerTransform(BaseOrientation, BaseLocation); + + FQuat Orientation = BaseOrientation.Inverse() * Desc.Transform.Rotator().Quaternion(); + FVector Location = PlayerTransform.InverseTransformPosition(Desc.Transform.GetLocation()); + FPose OutLayerPose = FPose(Orientation, Location); + if (Desc.PositionType != IStereoLayers::FaceLocked) + ConvertPose_Internal(FPose(Orientation, Location), OutLayerPose, Settings->BaseOrientation.Inverse(), Settings->BaseOrientation.Inverse().RotateVector(-Settings->BaseOffset * LocationScaleInv), 1.0); + + OvrpLayerSubmit.Pose.Orientation = ToOvrpQuatf(OutLayerPose.Orientation); + OvrpLayerSubmit.Pose.Position = ToOvrpVector3f(OutLayerPose.Position * LocationScale); + OvrpLayerSubmit.LayerSubmitFlags = 0; + + if (Desc.PositionType == IStereoLayers::FaceLocked) + { + OvrpLayerSubmit.LayerSubmitFlags |= ovrpLayerSubmitFlag_HeadLocked; + } + + if (!(Desc.Flags & IStereoLayers::LAYER_FLAG_SUPPORT_DEPTH)) + { + OvrpLayerSubmit.LayerSubmitFlags |= ovrpLayerSubmitFlag_NoDepth; + } + +#ifdef WITH_OCULUS_BRANCH + if (Desc.Flags & IStereoLayers::LAYER_FLAG_AUTO_FILTERING) + { + OvrpLayerSubmit.LayerSubmitFlags |= ovrpLayerSubmitFlag_AutoLayerFilter; + } + if (Desc.Flags & IStereoLayers::LAYER_FLAG_NORMAL_SUPERSAMPLE) + { + OvrpLayerSubmit.LayerSubmitFlags |= ovrpLayerSubmitFlag_EfficientSuperSample; + } + if (Desc.Flags & IStereoLayers::LAYER_FLAG_QUALITY_SUPERSAMPLE) + { + OvrpLayerSubmit.LayerSubmitFlags |= ovrpLayerSubmitFlag_ExpensiveSuperSample; + } + if (Desc.Flags & IStereoLayers::LAYER_FLAG_NORMAL_SHARPEN) + { + OvrpLayerSubmit.LayerSubmitFlags |= ovrpLayerSubmitFlag_EfficientSharpen; + } + if (Desc.Flags & IStereoLayers::LAYER_FLAG_QUALITY_SHARPEN) + { + OvrpLayerSubmit.LayerSubmitFlags |= ovrpLayerSubmitFlag_QualitySharpen; + } +#endif + } + else + { + OvrpLayerSubmit.EyeFov.DepthFar = 0; + OvrpLayerSubmit.EyeFov.DepthNear = Frame->NearClippingPlane / 100.f; //physical scale is 100UU/meter + OvrpLayerSubmit.LayerSubmitFlags = ovrpLayerSubmitFlag_ReverseZ; + OvrpLayerSubmit.ViewportRect[0] = ToOvrpRecti(Settings->EyeRenderViewport[0]); + OvrpLayerSubmit.ViewportRect[1] = ToOvrpRecti(Settings->EyeRenderViewport[1]); + OvrpLayerSubmit.EyeFov.Fov[0] = Frame->Fov[0]; + OvrpLayerSubmit.EyeFov.Fov[1] = Frame->Fov[1]; + + static const auto CVarOculusEnableSpaceWarpInternal = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.Mobile.Oculus.SpaceWarp.EnableInternal")); + if (CVarOculusEnableSpaceWarpInternal->GetValueOnAnyThread() != 0) + { + OvrpLayerSubmit.LayerSubmitFlags |= ovrpLayerSubmitFlag_SpaceWarp; + OvrpLayerSubmit.EyeFov.MotionVectorDepthFar = Frame->NearClippingPlane / 100.f; + OvrpLayerSubmit.EyeFov.MotionVectorDepthNear = INFINITY; + OvrpLayerSubmit.EyeFov.MotionVectorOffset = ovrpVector4f{ 0.0f, 0.0f, 0.0f, 0.0f }; + OvrpLayerSubmit.EyeFov.MotionVectorScale = ovrpVector4f{ 1.0f, 1.0f, 1.0f, 1.0f }; + + FTransform TrackingSpaceDeltaPose; + GetTrackingSpaceDeltaPose(Settings, Frame, TrackingSpaceDeltaPose); + OvrpLayerSubmit.EyeFov.AppSpaceDeltaPose.Orientation = ToOvrpQuatf(TrackingSpaceDeltaPose.GetRotation()); + OvrpLayerSubmit.EyeFov.AppSpaceDeltaPose.Position = ToOvrpVector3f(TrackingSpaceDeltaPose.GetLocation() / Frame->WorldToMetersScale); + } + + ovrpXrApi NativeXrApi; + if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetNativeXrApiType(&NativeXrApi)) && (NativeXrApi == ovrpXrApi_OpenXR)) + { + + const bool bShouldIgnoreSrcAlpha = (LayerIndex == 0 && Settings->SystemSplashBackground == ESystemSplashBackgroundType::Black); + + if (bShouldIgnoreSrcAlpha) + { + OvrpLayerSubmit.LayerSubmitFlags |= ovrpLayerSubmitFlag_IgnoreSourceAlpha; + } + else if (InvAlphaTexture == nullptr) + { + OvrpLayerSubmit.HasBlendFactors = true; + OvrpLayerSubmit.SrcBlendFactor = ovrpBlendFactorOneMinusSrcAlpha; + OvrpLayerSubmit.DstBlendFactor = ovrpBlendFactorSrcAlpha; + } + } + else + { +#if PLATFORM_WINDOWS + OvrpLayerSubmit.LayerSubmitFlags |= ovrpLayerSubmitFlag_IgnoreSourceAlpha; +#else + OvrpLayerSubmit.LayerSubmitFlags |= ovrpLayerSubmitFlag_InverseAlpha; +#endif + } + } + + return &OvrpLayerSubmit.Base; + } + + void FLayer::IncrementSwapChainIndex_RHIThread(FCustomPresent* CustomPresent) + { + CheckInRHIThread(); + + if (SwapChain.IsValid()) + { + SwapChain->IncrementSwapChainIndex_RHIThread(); + } + + if (DepthSwapChain.IsValid()) + { + DepthSwapChain->IncrementSwapChainIndex_RHIThread(); + } + + if (FoveationSwapChain.IsValid()) + { + FoveationSwapChain->IncrementSwapChainIndex_RHIThread(); + } + + if (RightSwapChain.IsValid()) + { + RightSwapChain->IncrementSwapChainIndex_RHIThread(); + } + + if (RightDepthSwapChain.IsValid()) + { + RightDepthSwapChain->IncrementSwapChainIndex_RHIThread(); + } + + if (MotionVectorSwapChain.IsValid()) + { + MotionVectorSwapChain->IncrementSwapChainIndex_RHIThread(); + } + + if (MotionVectorDepthSwapChain.IsValid()) + { + MotionVectorDepthSwapChain->IncrementSwapChainIndex_RHIThread(); + } + } + + void FLayer::ReleaseResources_RHIThread() + { + CheckInRHIThread(); + + OvrpLayerId = 0; + OvrpLayer.Reset(); + SwapChain.Reset(); + DepthSwapChain.Reset(); + FoveationSwapChain.Reset(); + RightSwapChain.Reset(); + RightDepthSwapChain.Reset(); + MotionVectorSwapChain.Reset(); + MotionVectorDepthSwapChain.Reset(); + bUpdateTexture = false; + } + + void FLayer::AddPassthroughMesh_RenderThread(const TArray& Vertices, const TArray& Triangles, FMatrix Transformation, uint64_t& OutMeshHandle, uint64_t& OutInstanceHandle) + { + CheckInRenderThread(); + + uint64_t MeshHandle = 0; + uint64_t InstanceHandle = 0; + + // Explicit conversion is needed since FVector contains double elements. + // Converting Vertices.Data() to float* causes issues when memory is parsed. + TArray VertexData; + VertexData.SetNumUninitialized(Vertices.Num() * 3); + + size_t i = 0; + for (const FVector& vertex : Vertices) + { + VertexData[i++] = vertex.X; + VertexData[i++] = vertex.Y; + VertexData[i++] = vertex.Z; + } + + if (OVRP_FAILURE(FOculusXRHMDModule::GetPluginWrapper().CreateInsightTriangleMesh( + OvrpLayerId, + VertexData.GetData(), + Vertices.Num(), + (int*)Triangles.GetData(), + Triangles.Num() / 3, + &MeshHandle))) + { + UE_LOG(LogTemp, Error, TEXT("Failed creating passthrough mesh surface.")); + return; + } + + const ovrpMatrix4f OvrTransformation = ToOvrpMatrix(Transformation); + + if (OVRP_FAILURE(FOculusXRHMDModule::GetPluginWrapper().AddInsightPassthroughSurfaceGeometry( + OvrpLayerId, + MeshHandle, + OvrTransformation, + &InstanceHandle))) + { + UE_LOG(LogTemp, Error, TEXT("Failed adding passthrough mesh surface to scene.")); + return; + } + OutMeshHandle = MeshHandle; + OutInstanceHandle = InstanceHandle; + } + + void FLayer::UpdatePassthroughMeshTransform_RenderThread(uint64_t InstanceHandle, FMatrix Transformation) + { + CheckInRenderThread(); + + const ovrpMatrix4f OvrTransformation = ToOvrpMatrix(Transformation); + + if (OVRP_FAILURE(FOculusXRHMDModule::GetPluginWrapper().UpdateInsightPassthroughGeometryTransform( + InstanceHandle, + OvrTransformation))) + { + UE_LOG(LogTemp, Error, TEXT("Failed updating passthrough mesh surface transform.")); + return; + } + } + + void FLayer::RemovePassthroughMesh_RenderThread(uint64_t MeshHandle, uint64_t InstanceHandle) + { + CheckInRenderThread(); + + if (OVRP_FAILURE(FOculusXRHMDModule::GetPluginWrapper().DestroyInsightPassthroughGeometryInstance(InstanceHandle))) + { + UE_LOG(LogTemp, Error, TEXT("Failed removing passthrough surface from scene.")); + return; + } + + if (OVRP_FAILURE(FOculusXRHMDModule::GetPluginWrapper().DestroyInsightTriangleMesh(MeshHandle))) + { + UE_LOG(LogTemp, Error, TEXT("Failed destroying passthrough surface mesh.")); + return; + } + } + + void FLayer::DestroyLayer() + { + CheckInGameThread(); + + if (PassthroughPokeActorMap) + { + UWorld* World = GetWorld(); + if (!World) + { + return; + } + + for (auto& Entry : *PassthroughPokeActorMap) + { + World->DestroyActor(Entry.Value.PokeAHoleActor); + } + PassthroughPokeActorMap.Reset(); + } + } + +} // namespace OculusXRHMD + +#endif //OCULUS_HMD_SUPPORTED_PLATFORMS diff --git a/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_Layer.h b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_Layer.h new file mode 100644 index 0000000..c4917d2 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_Layer.h @@ -0,0 +1,233 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +#pragma once +#include "OculusXRHMDPrivate.h" +#include "ProceduralMeshComponent.h" + +#if OCULUS_HMD_SUPPORTED_PLATFORMS +#include "OculusXRHMD_CustomPresent.h" +#include "XRSwapChain.h" +#include "OculusXRPassthroughLayerShapes.h" + +namespace OculusXRHMD +{ + + //------------------------------------------------------------------------------------------------- + // FOvrpLayer + //------------------------------------------------------------------------------------------------- + class FDeferredDeletionQueue; + + class FOvrpLayer : public TSharedFromThis + { + public: + FOvrpLayer(uint32 InOvrpLayerId, FDeferredDeletionQueue* InDeferredDeletion); + ~FOvrpLayer(); + + protected: + uint32 OvrpLayerId; + + private: + FDeferredDeletionQueue* DeferredDeletion; // necessary for deferred deletion queue of the actual OvrpLayer + }; + + typedef TSharedPtr FOvrpLayerPtr; + + //------------------------------------------------------------------------------------------------- + // FLayer + //------------------------------------------------------------------------------------------------- + + class FLayer : public TSharedFromThis + { + public: + FLayer(uint32 InId); + FLayer(const FLayer& InLayer); + ~FLayer(); + + uint32 GetId() const { return Id; } + int GetOvrpId() const { return OvrpLayerId; } + void SetDesc(const IStereoLayers::FLayerDesc& InDesc); + void SetDesc(const FSettings* Settings, const IStereoLayers::FLayerDesc& InDesc); + const IStereoLayers::FLayerDesc& GetDesc() const { return Desc; } + void SetEyeLayerDesc(const ovrpLayerDesc_EyeFov& InEyeLayerDesc); + const FXRSwapChainPtr& GetSwapChain() const { return SwapChain; } + const FXRSwapChainPtr& GetRightSwapChain() const { return RightSwapChain; } + const FXRSwapChainPtr& GetDepthSwapChain() const { return DepthSwapChain; } + const FXRSwapChainPtr& GetFoveationSwapChain() const { return FoveationSwapChain; } + const FXRSwapChainPtr& GetMotionVectorSwapChain() const { return MotionVectorSwapChain; } + const FXRSwapChainPtr& GetMotionVectorDepthSwapChain() const { return MotionVectorDepthSwapChain; } + void MarkTextureForUpdate() { bUpdateTexture = true; } + bool NeedsPokeAHole(); + void HandlePokeAHoleComponent(); + void BuildPokeAHoleMesh(TArray& Vertices, TArray& Triangles, TArray& UV0); + bool NeedsPassthroughPokeAHole(); + + bool ShapeNeedsTextures(ovrpShape shape); + + FTextureRHIRef GetTexture() { return Desc.Texture; } + + TSharedPtr Clone() const; + + bool CanReuseResources(const FLayer* InLayer) const; + bool Initialize_RenderThread(const FSettings* Settings, FCustomPresent* CustomPresent, FDeferredDeletionQueue* DeferredDeletion, FRHICommandListImmediate& RHICmdList, const FLayer* InLayer = nullptr); + void UpdateTexture_RenderThread(const FSettings* Settings, FCustomPresent* CustomPresent, FRHICommandListImmediate& RHICmdList); + void UpdatePassthrough_RenderThread(FCustomPresent* CustomPresent, FRHICommandListImmediate& RHICmdList, const FGameFrame* Frame); + + const ovrpLayerSubmit* UpdateLayer_RHIThread(const FSettings* Settings, const FGameFrame* Frame, const int LayerIndex); + void IncrementSwapChainIndex_RHIThread(FCustomPresent* CustomPresent); + void ReleaseResources_RHIThread(); + bool IsVisible() { return (Desc.Flags & IStereoLayers::LAYER_FLAG_HIDDEN) == 0; } + + bool bNeedsTexSrgbCreate; + + void AddPassthroughMesh_RenderThread(const TArray& Vertices, const TArray& Triangles, FMatrix Transformation, uint64_t& OutMeshHandle, uint64_t& OutInstanceHandle); + void UpdatePassthroughMeshTransform_RenderThread(uint64_t InstanceHandle, FMatrix Transformation); + void RemovePassthroughMesh_RenderThread(uint64_t MeshHandle, uint64_t InstanceHandle); + + void DestroyLayer(); + + protected: + struct FPassthroughMesh + { + FPassthroughMesh(uint64_t MeshHandle, uint64_t InstanceHandle) + : MeshHandle(MeshHandle) + , InstanceHandle(InstanceHandle) + { + } + uint64_t MeshHandle; + uint64_t InstanceHandle; + }; + + typedef TSharedPtr, ESPMode::ThreadSafe> FUserDefinedGeometryMapPtr; + + void UpdatePassthroughStyle_RenderThread(const FEdgeStyleParameters& EdgeStyleParameters); + + struct FPassthroughPokeActor + { + FPassthroughPokeActor(){}; + FPassthroughPokeActor(UProceduralMeshComponent* PokeAHoleComponentPtr, AActor* PokeAHoleActor) + : PokeAHoleComponentPtr(PokeAHoleComponentPtr) + , PokeAHoleActor(PokeAHoleActor){}; + UProceduralMeshComponent* PokeAHoleComponentPtr; + AActor* PokeAHoleActor; + }; + + typedef TSharedPtr, ESPMode::ThreadSafe> FPassthroughPokeActorMapPtr; + + bool BuildPassthroughPokeActor(FOculusPassthroughMeshRef PassthroughMesh, FPassthroughPokeActor& OutPassthroughPokeActor); + void UpdatePassthroughPokeActors_GameThread(); + + uint32 Id; + IStereoLayers::FLayerDesc Desc; + int OvrpLayerId; + ovrpLayerDescUnion OvrpLayerDesc; + ovrpLayerSubmitUnion OvrpLayerSubmit; + FOvrpLayerPtr OvrpLayer; + FXRSwapChainPtr SwapChain; + FXRSwapChainPtr DepthSwapChain; + FXRSwapChainPtr FoveationSwapChain; + FXRSwapChainPtr RightSwapChain; + FXRSwapChainPtr RightDepthSwapChain; + FXRSwapChainPtr MotionVectorSwapChain; + FXRSwapChainPtr MotionVectorDepthSwapChain; + FTextureRHIRef InvAlphaTexture; + bool bUpdateTexture; + bool bInvertY; + bool bHasDepth; + bool bSupportDepthComposite; + + UProceduralMeshComponent* PokeAHoleComponentPtr; + AActor* PokeAHoleActor; + + FUserDefinedGeometryMapPtr UserDefinedGeometryMap; + FPassthroughPokeActorMapPtr PassthroughPokeActorMap; + }; + + typedef TSharedPtr FLayerPtr; + + //------------------------------------------------------------------------------------------------- + // FLayerPtr_CompareId + //------------------------------------------------------------------------------------------------- + + struct FLayerPtr_CompareId + { + FORCEINLINE bool operator()(const FLayerPtr& A, const FLayerPtr& B) const + { + return A->GetId() < B->GetId(); + } + }; + + //------------------------------------------------------------------------------------------------- + // FLayerPtr_ComparePriority + //------------------------------------------------------------------------------------------------- + + struct FLayerPtr_ComparePriority + { + FORCEINLINE bool operator()(const FLayerPtr& A, const FLayerPtr& B) const + { + if (A->GetDesc().Priority < B->GetDesc().Priority) + return true; + if (A->GetDesc().Priority > B->GetDesc().Priority) + return false; + + return A->GetId() < B->GetId(); + } + }; + + struct FLayerPtr_CompareTotal + { + FORCEINLINE int32 GetLayerTypePriority(const FLayerPtr& A) const + { + // Draw FReconstructedLayer, PoleAHole layers (Android only), EyeFov layer, followed by other layers + const bool IsEyeFov = (A->GetId() == 0); + const bool IsPokeAHole = A->NeedsPokeAHole() || A->NeedsPassthroughPokeAHole(); + bool IsUnderlay = false; + + if (A->GetDesc().HasShape()) + { + const FReconstructedLayer& ReconstructedLayerProps = A->GetDesc().GetShape(); + IsUnderlay = (ReconstructedLayerProps.PassthroughLayerOrder == PassthroughLayerOrder_Underlay); + } + else if (A->GetDesc().HasShape()) + { + const FUserDefinedLayer& UserDefinedLayerProps = A->GetDesc().GetShape(); + IsUnderlay = (UserDefinedLayerProps.PassthroughLayerOrder == PassthroughLayerOrder_Underlay); + } + + const int32 Priority = IsUnderlay ? -2 : IsPokeAHole ? -1 + : IsEyeFov ? 0 + : 1; + return Priority; + } + + FORCEINLINE bool operator()(const FLayerPtr& A, const FLayerPtr& B) const + { + // First order layers by type + int32 PassA = GetLayerTypePriority(A); + int32 PassB = GetLayerTypePriority(B); + + if (PassA != PassB) + return PassA < PassB; + + // Draw non-FaceLocked layers first + const IStereoLayers::FLayerDesc& DescA = A->GetDesc(); + const IStereoLayers::FLayerDesc& DescB = B->GetDesc(); + + bool bFaceLockedA = (DescA.PositionType == IStereoLayers::ELayerType::FaceLocked); + bool bFaceLockedB = (DescB.PositionType == IStereoLayers::ELayerType::FaceLocked); + + if (bFaceLockedA != bFaceLockedB) + return !bFaceLockedA; + + // Draw layers by ascending priority + if (DescA.Priority != DescB.Priority) + return DescA.Priority < DescB.Priority; + + // Draw layers by ascending id + return A->GetId() < B->GetId(); + } + }; + +} // namespace OculusXRHMD + +#endif //OCULUS_HMD_SUPPORTED_PLATFORMS diff --git a/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_Settings.cpp b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_Settings.cpp new file mode 100644 index 0000000..d44d286 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_Settings.cpp @@ -0,0 +1,135 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +#include "OculusXRHMD_Settings.h" +#include "Engine/Engine.h" + +#if OCULUS_HMD_SUPPORTED_PLATFORMS + +namespace OculusXRHMD +{ + + //------------------------------------------------------------------------------------------------- + // FSettings + //------------------------------------------------------------------------------------------------- + + FSettings::FSettings() + : BaseOffset(0, 0, 0) + , BaseOrientation(FQuat::Identity) + , PixelDensity(1.0f) + , PixelDensityMin(0.8f) + , PixelDensityMax(1.2f) + , SystemHeadset(ovrpSystemHeadset_None) + , SuggestedCpuPerfLevel(EOculusXRProcessorPerformanceLevel::SustainedLow) + , SuggestedGpuPerfLevel(EOculusXRProcessorPerformanceLevel::SustainedHigh) + , FoveatedRenderingMethod(EOculusXRFoveatedRenderingMethod::FixedFoveatedRendering) + , FoveatedRenderingLevel(EOculusXRFoveatedRenderingLevel::Off) + , bDynamicFoveatedRendering(true) + , bSupportEyeTrackedFoveatedRendering(false) + , SystemSplashBackground(ESystemSplashBackgroundType::Black) + , XrApi(EOculusXRXrApi::OVRPluginOpenXR) + , ColorSpace(EOculusXRColorSpace::P3) + , ControllerPoseAlignment(EOculusXRControllerPoseAlignment::Default) + , HandTrackingSupport(EOculusXRHandTrackingSupport::ControllersOnly) + , HandTrackingFrequency(EOculusXRHandTrackingFrequency::LOW) + , HandTrackingVersion(EOculusXRHandTrackingVersion::Default) + , ColorScale(ovrpVector4f{ 1, 1, 1, 1 }) + , ColorOffset(ovrpVector4f{ 0, 0, 0, 0 }) + , bApplyColorScaleAndOffsetToAllLayers(false) + , CurrentFeatureLevel(GMaxRHIFeatureLevel) + , bLateLatching(false) + , bSupportExperimentalFeatures(false) + , ProcessorFavor(EProcessorFavor::FavorEqually) + , BodyTrackingFidelity(EOculusXRHMDBodyTrackingFidelity::Low) + , BodyTrackingJointSet(EOculusXRHMDBodyJointSet::UpperBody) + { + Flags.Raw = 0; + Flags.bHMDEnabled = true; + Flags.bUpdateOnRT = true; + Flags.bHQBuffer = false; + Flags.bCompositeDepth = true; +#if PLATFORM_ANDROID + Flags.bsRGBEyeBuffer = true; + //oculus mobile is always-on stereo, no need for enableStereo codepaths + Flags.bStereoEnabled = true; +#else + Flags.bsRGBEyeBuffer = false; + Flags.bStereoEnabled = false; +#endif + CurrentFeatureLevel = GEngine ? GEngine->GetDefaultWorldFeatureLevel() : GMaxRHIFeatureLevel; + CurrentShaderPlatform = GShaderPlatformForFeatureLevel[CurrentFeatureLevel]; + + Flags.bSupportsDash = true; + Flags.bFocusAware = true; + Flags.bRequiresSystemKeyboard = false; + Flags.bInsightPassthroughEnabled = false; + Flags.bAnchorSupportEnabled = false; + Flags.bAnchorSharingEnabled = false; + Flags.bSceneSupportEnabled = false; + Flags.bBodyTrackingEnabled = false; + Flags.bEyeTrackingEnabled = false; + Flags.bFaceTrackingEnabled = false; + EyeRenderViewport[0] = EyeRenderViewport[1] = FIntRect(0, 0, 0, 0); + + RenderTargetSize = FIntPoint(0, 0); + +#ifdef WITH_OCULUS_BRANCH + Flags.bTileTurnOffEnabled = false; +#else + Flags.bTileTurnOffEnabled = true; +#endif + } + + TSharedPtr FSettings::Clone() const + { + TSharedPtr NewSettings = MakeShareable(new FSettings(*this)); + return NewSettings; + } + + void FSettings::SetPixelDensity(float NewPixelDensity) + { + if (Flags.bPixelDensityAdaptive) + { + PixelDensity = FMath::Clamp(NewPixelDensity, PixelDensityMin, PixelDensityMax); + } + else + { + PixelDensity = FMath::Clamp(NewPixelDensity, ClampPixelDensityMin, ClampPixelDensityMax); + } + } + + void FSettings::SetPixelDensitySmooth(float NewPixelDensity) + { + // Pixel Density changes need to be smooth both for artifacts with FFR/TTO (FFR/tile-turnoff is one frame late so shouldn't change too fast) + // but also so that if the developer uses the CVar and not the runtime (which is already smooth) there is no jump artifacts. + constexpr float MaxPerFrameIncrease = 0.010; + constexpr float MaxPerFrameDecrease = 0.045; + + float NewClampedPixelDensity = FMath::Clamp(NewPixelDensity, PixelDensity - MaxPerFrameDecrease, PixelDensity + MaxPerFrameIncrease); + if (Flags.bPixelDensityAdaptive) + { + PixelDensity = FMath::Clamp(NewClampedPixelDensity, PixelDensityMin, PixelDensityMax); + } + else + { + PixelDensity = FMath::Clamp(NewClampedPixelDensity, ClampPixelDensityMin, ClampPixelDensityMax); + } + } + + void FSettings::SetPixelDensityMin(float NewPixelDensityMin) + { + PixelDensityMin = FMath::Clamp(NewPixelDensityMin, ClampPixelDensityMin, ClampPixelDensityMax); + PixelDensityMax = FMath::Max(PixelDensityMin, PixelDensityMax); + SetPixelDensity(PixelDensity); + } + + void FSettings::SetPixelDensityMax(float NewPixelDensityMax) + { + PixelDensityMax = FMath::Clamp(NewPixelDensityMax, ClampPixelDensityMin, ClampPixelDensityMax); + PixelDensityMin = FMath::Min(PixelDensityMin, PixelDensityMax); + SetPixelDensity(PixelDensity); + } + +} // namespace OculusXRHMD + +#endif //OCULUS_HMD_SUPPORTED_PLATFORMS diff --git a/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_Settings.h b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_Settings.h new file mode 100644 index 0000000..6caab15 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_Settings.h @@ -0,0 +1,174 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +#pragma once +#include "OculusXRHMDPrivate.h" + +#if OCULUS_HMD_SUPPORTED_PLATFORMS + +namespace OculusXRHMD +{ + + static const float ClampPixelDensityMin = 0.5f; + static const float ClampPixelDensityMax = 2.0f; + + //------------------------------------------------------------------------------------------------- + // FSettings + //------------------------------------------------------------------------------------------------- + + class FSettings : public TSharedFromThis + { + public: + union + { + struct + { + /** Whether stereo is currently on or off. */ + uint64 bStereoEnabled : 1; + + /** Whether or not switching to stereo is allowed */ + uint64 bHMDEnabled : 1; + + /** Turns on/off updating view's orientation/position on a RenderThread. When it is on, + latency should be significantly lower. + See 'HMD UPDATEONRT ON|OFF' console command. + */ + uint64 bUpdateOnRT : 1; + + /** Enforces headtracking to work even in non-stereo mode (for debugging or screenshots). + See 'MOTION ENFORCE' console command. */ + uint64 bHeadTrackingEnforced : 1; + + /** Allocate an high quality OVR_FORMAT_R11G11B10_FLOAT buffer for Rift */ + uint64 bHQBuffer : 1; + + /** Rendering should be (could be) paused */ + uint64 bPauseRendering : 1; + + /** HQ Distortion */ + uint64 bHQDistortion : 1; + + /** Send the depth buffer to the compositor */ + uint64 bCompositeDepth : 1; + + /** Supports Dash in-game compositing */ + uint64 bSupportsDash : 1; +#if !UE_BUILD_SHIPPING + /** Show status / statistics on screen. See 'hmd stats' cmd */ + uint64 bShowStats : 1; +#endif + /** Dynamically update pixel density to maintain framerate */ + uint64 bPixelDensityAdaptive : 1; + + /** All future eye buffers will need to be created with TexSRGB_Create flag due to the current feature level (ES31) */ + uint64 bsRGBEyeBuffer : 1; + + /** Supports Focus Aware state on Quest */ + uint64 bFocusAware : 1; + + /** Requires the Oculus system keyboard */ + uint64 bRequiresSystemKeyboard : 1; + + /** Whether passthrough functionality can be used with the app */ + uint64 bInsightPassthroughEnabled : 1; + + /** Whether Anchors can be used with the app */ + uint64 bAnchorSupportEnabled : 1; + + /** Whether Anchor Sharing can be used with the app */ + uint64 bAnchorSharingEnabled : 1; + + /** Whether Scene can be used with the app */ + uint64 bSceneSupportEnabled : 1; + + + + /** Whether body tracking functionality can be used with the app */ + uint64 bBodyTrackingEnabled : 1; + + /** Whether eye tracking functionality can be used with the app */ + uint64 bEyeTrackingEnabled : 1; + + /** Whether face tracking functionality can be used with the app */ + uint64 bFaceTrackingEnabled : 1; + + /** Whether tile turn off can be used with the app */ + uint64 bTileTurnOffEnabled : 1; + }; + uint64 Raw; + } Flags; + + /** HMD base values, specify forward orientation and zero pos offset */ + FVector BaseOffset; // base position, in meters, relatively to the sensor //@todo hmd: clients need to stop using oculus space + FQuat BaseOrientation; // base orientation + + /** Viewports for each eye, in render target texture coordinates */ + FIntRect EyeRenderViewport[ovrpEye_Count]; + /** Viewports for each eye, without DynamicResolution scaling applied */ + FIntRect EyeUnscaledRenderViewport[ovrpEye_Count]; + + ovrpMatrix4f EyeProjectionMatrices[ovrpEye_Count]; // 0 - left, 1 - right same as Views + ovrpMatrix4f MonoProjectionMatrix; + + FIntPoint RenderTargetSize; + float PixelDensity; + float PixelDensityMin; + float PixelDensityMax; + + ovrpSystemHeadset SystemHeadset; + + float VsyncToNextVsync; + + EOculusXRProcessorPerformanceLevel SuggestedCpuPerfLevel; + EOculusXRProcessorPerformanceLevel SuggestedGpuPerfLevel; + + EOculusXRFoveatedRenderingMethod FoveatedRenderingMethod; + EOculusXRFoveatedRenderingLevel FoveatedRenderingLevel; + bool bDynamicFoveatedRendering; + bool bSupportEyeTrackedFoveatedRendering; + + ESystemSplashBackgroundType SystemSplashBackground; + + EOculusXRXrApi XrApi; + EOculusXRColorSpace ColorSpace; + EOculusXRControllerPoseAlignment ControllerPoseAlignment; + + EOculusXRHandTrackingSupport HandTrackingSupport; + EOculusXRHandTrackingFrequency HandTrackingFrequency; + EOculusXRHandTrackingVersion HandTrackingVersion; + + ovrpVector4f ColorScale, ColorOffset; + bool bApplyColorScaleAndOffsetToAllLayers; + + FStaticFeatureLevel CurrentFeatureLevel; + EShaderPlatform CurrentShaderPlatform; + + bool bLateLatching; + bool bSupportExperimentalFeatures; + + EProcessorFavor ProcessorFavor; + + EOculusXRHMDBodyTrackingFidelity BodyTrackingFidelity; + EOculusXRHMDBodyJointSet BodyTrackingJointSet; + + TSet FaceTrackingDataSource; + + public: + FSettings(); + virtual ~FSettings() {} + + bool IsStereoEnabled() const { return Flags.bStereoEnabled && Flags.bHMDEnabled; } + + void SetPixelDensity(float NewPixelDensity); + void SetPixelDensitySmooth(float NewPixelDensity); + void SetPixelDensityMin(float NewPixelDensityMin); + void SetPixelDensityMax(float NewPixelDensityMax); + + TSharedPtr Clone() const; + }; + + typedef TSharedPtr FSettingsPtr; + +} // namespace OculusXRHMD + +#endif //OCULUS_HMD_SUPPORTED_PLATFORMS diff --git a/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_SpectatorScreenController.cpp b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_SpectatorScreenController.cpp new file mode 100644 index 0000000..8effa9c --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_SpectatorScreenController.cpp @@ -0,0 +1,121 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +#include "OculusXRHMD_SpectatorScreenController.h" + +#if OCULUS_HMD_SUPPORTED_PLATFORMS +#include "OculusXRHMD.h" +#include "TextureResource.h" +#include "Engine/TextureRenderTarget2D.h" + +namespace OculusXRHMD +{ + + //------------------------------------------------------------------------------------------------- + // FSpectatorScreenController + //------------------------------------------------------------------------------------------------- + + FSpectatorScreenController::FSpectatorScreenController(FOculusXRHMD* InOculusXRHMD) + : FDefaultSpectatorScreenController(InOculusXRHMD) + , OculusXRHMD(InOculusXRHMD) + , SpectatorMode(EMRSpectatorScreenMode::Default) + , ForegroundRenderTexture(nullptr) + , BackgroundRenderTexture(nullptr) + { + } + + void FSpectatorScreenController::RenderSpectatorScreen_RenderThread(FRHICommandListImmediate& RHICmdList, FRHITexture2D* BackBuffer, FTexture2DRHIRef RenderTexture, FVector2D WindowSize) + { + CheckInRenderThread(); + if (OculusXRHMD->GetCustomPresent_Internal()) + { + if (SpectatorMode == EMRSpectatorScreenMode::ExternalComposition) + { + auto ForegroundResource = ForegroundRenderTexture->GetRenderTargetResource(); + auto BackgroundResource = BackgroundRenderTexture->GetRenderTargetResource(); + if (ForegroundResource && BackgroundResource) + { + RenderSpectatorModeExternalComposition( + RHICmdList, + FTexture2DRHIRef(BackBuffer), + ForegroundResource->GetRenderTargetTexture(), + BackgroundResource->GetRenderTargetTexture()); + return; + } + } + else if (SpectatorMode == EMRSpectatorScreenMode::DirectComposition) + { + auto BackgroundResource = BackgroundRenderTexture->GetRenderTargetResource(); + if (BackgroundResource) + { + RenderSpectatorModeDirectComposition( + RHICmdList, + FTexture2DRHIRef(BackBuffer), + BackgroundRenderTexture->GetRenderTargetResource()->GetRenderTargetTexture()); + return; + } + } + FDefaultSpectatorScreenController::RenderSpectatorScreen_RenderThread(RHICmdList, BackBuffer, RenderTexture, WindowSize); + } + } + + void FSpectatorScreenController::RenderSpectatorModeUndistorted(FRHICommandListImmediate& RHICmdList, FTexture2DRHIRef TargetTexture, FTexture2DRHIRef EyeTexture, FTexture2DRHIRef OtherTexture, FVector2D WindowSize) + { + CheckInRenderThread(); + FSettings* Settings = OculusXRHMD->GetSettings_RenderThread(); + FIntRect DestRect(0, 0, TargetTexture->GetSizeX() / 2, TargetTexture->GetSizeY()); + for (int i = 0; i < 2; ++i) + { + OculusXRHMD->CopyTexture_RenderThread(RHICmdList, EyeTexture, Settings->EyeRenderViewport[i], TargetTexture, DestRect, false, true); + DestRect.Min.X += TargetTexture->GetSizeX() / 2; + DestRect.Max.X += TargetTexture->GetSizeX() / 2; + } + } + + void FSpectatorScreenController::RenderSpectatorModeDistorted(FRHICommandListImmediate& RHICmdList, FTexture2DRHIRef TargetTexture, FTexture2DRHIRef EyeTexture, FTexture2DRHIRef OtherTexture, FVector2D WindowSize) + { + CheckInRenderThread(); + FCustomPresent* CustomPresent = OculusXRHMD->GetCustomPresent_Internal(); + FTexture2DRHIRef MirrorTexture = CustomPresent->GetMirrorTexture(); + if (MirrorTexture) + { + FIntRect SrcRect(0, 0, MirrorTexture->GetSizeX(), MirrorTexture->GetSizeY()); + FIntRect DestRect(0, 0, TargetTexture->GetSizeX(), TargetTexture->GetSizeY()); + OculusXRHMD->CopyTexture_RenderThread(RHICmdList, MirrorTexture, SrcRect, TargetTexture, DestRect, false, true); + } + } + + void FSpectatorScreenController::RenderSpectatorModeSingleEye(FRHICommandListImmediate& RHICmdList, FTexture2DRHIRef TargetTexture, FTexture2DRHIRef EyeTexture, FTexture2DRHIRef OtherTexture, FVector2D WindowSize) + { + CheckInRenderThread(); + FSettings* Settings = OculusXRHMD->GetSettings_RenderThread(); + const FIntRect SrcRect = Settings->EyeRenderViewport[0]; + const FIntRect DstRect(0, 0, TargetTexture->GetSizeX(), TargetTexture->GetSizeY()); + + OculusXRHMD->CopyTexture_RenderThread(RHICmdList, EyeTexture, SrcRect, TargetTexture, DstRect, false, true); + } + + void FSpectatorScreenController::RenderSpectatorModeDirectComposition(FRHICommandListImmediate& RHICmdList, FTexture2DRHIRef TargetTexture, const FTexture2DRHIRef SrcTexture) const + { + CheckInRenderThread(); + const FIntRect SrcRect(0, 0, SrcTexture->GetSizeX(), SrcTexture->GetSizeY()); + const FIntRect DstRect(0, 0, TargetTexture->GetSizeX(), TargetTexture->GetSizeY()); + + OculusXRHMD->CopyTexture_RenderThread(RHICmdList, SrcTexture, SrcRect, TargetTexture, DstRect, false, true); + } + + void FSpectatorScreenController::RenderSpectatorModeExternalComposition(FRHICommandListImmediate& RHICmdList, FTexture2DRHIRef TargetTexture, const FTexture2DRHIRef FrontTexture, const FTexture2DRHIRef BackTexture) const + { + CheckInRenderThread(); + const FIntRect FrontSrcRect(0, 0, FrontTexture->GetSizeX(), FrontTexture->GetSizeY()); + const FIntRect FrontDstRect(0, 0, TargetTexture->GetSizeX() / 2, TargetTexture->GetSizeY()); + const FIntRect BackSrcRect(0, 0, BackTexture->GetSizeX(), BackTexture->GetSizeY()); + const FIntRect BackDstRect(TargetTexture->GetSizeX() / 2, 0, TargetTexture->GetSizeX(), TargetTexture->GetSizeY()); + + OculusXRHMD->CopyTexture_RenderThread(RHICmdList, FrontTexture, FrontSrcRect, TargetTexture, FrontDstRect, false, true); + OculusXRHMD->CopyTexture_RenderThread(RHICmdList, BackTexture, BackSrcRect, TargetTexture, BackDstRect, false, true); + } + +} // namespace OculusXRHMD + +#endif // OCULUS_HMD_SUPPORTED_PLATFORMS diff --git a/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_SpectatorScreenController.h b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_SpectatorScreenController.h new file mode 100644 index 0000000..1eaf981 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_SpectatorScreenController.h @@ -0,0 +1,53 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +#pragma once +#include "OculusXRHMDPrivate.h" + +#if OCULUS_HMD_SUPPORTED_PLATFORMS +#include "DefaultSpectatorScreenController.h" + +class UTextureRenderTarget2D; + +namespace OculusXRHMD +{ + + // Oculus specific spectator screen modes that override the regular VR spectator screens + enum class EMRSpectatorScreenMode : uint8 + { + Default, + ExternalComposition, + DirectComposition + }; + + //------------------------------------------------------------------------------------------------- + // FSpectatorScreenController + //------------------------------------------------------------------------------------------------- + + class FSpectatorScreenController : public FDefaultSpectatorScreenController + { + public: + FSpectatorScreenController(class FOculusXRHMD* InOculusXRHMD); + + void SetMRSpectatorScreenMode(EMRSpectatorScreenMode Mode) { SpectatorMode = Mode; } + void SetMRForeground(UTextureRenderTarget2D* Texture) { ForegroundRenderTexture = Texture; } + void SetMRBackground(UTextureRenderTarget2D* Texture) { BackgroundRenderTexture = Texture; } + + virtual void RenderSpectatorScreen_RenderThread(FRHICommandListImmediate& RHICmdList, FRHITexture2D* BackBuffer, FTexture2DRHIRef RenderTarget, FVector2D WindowSize) override; + virtual void RenderSpectatorModeUndistorted(FRHICommandListImmediate& RHICmdList, FTexture2DRHIRef TargetTexture, FTexture2DRHIRef EyeTexture, FTexture2DRHIRef OtherTexture, FVector2D WindowSize) override; + virtual void RenderSpectatorModeDistorted(FRHICommandListImmediate& RHICmdList, FTexture2DRHIRef TargetTexture, FTexture2DRHIRef EyeTexture, FTexture2DRHIRef OtherTexture, FVector2D WindowSize) override; + virtual void RenderSpectatorModeSingleEye(FRHICommandListImmediate& RHICmdList, FTexture2DRHIRef TargetTexture, FTexture2DRHIRef EyeTexture, FTexture2DRHIRef OtherTexture, FVector2D WindowSize) override; + + private: + FOculusXRHMD* OculusXRHMD; + EMRSpectatorScreenMode SpectatorMode; + UTextureRenderTarget2D* ForegroundRenderTexture; + UTextureRenderTarget2D* BackgroundRenderTexture; + + void RenderSpectatorModeDirectComposition(FRHICommandListImmediate& RHICmdList, FTexture2DRHIRef TargetTexture, const FTexture2DRHIRef SrcTexture) const; + void RenderSpectatorModeExternalComposition(FRHICommandListImmediate& RHICmdList, FTexture2DRHIRef TargetTexture, const FTexture2DRHIRef FrontTexture, const FTexture2DRHIRef BackTexture) const; + }; + +} // namespace OculusXRHMD + +#endif // OCULUS_HMD_SUPPORTED_PLATFORMS diff --git a/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_Splash.cpp b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_Splash.cpp new file mode 100644 index 0000000..c2ceec8 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_Splash.cpp @@ -0,0 +1,666 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +#include "OculusXRHMD_Splash.h" + +#if OCULUS_HMD_SUPPORTED_PLATFORMS +#include "OculusXRHMD.h" +#include "RenderingThread.h" +#include "Misc/ScopeLock.h" +#include "OculusXRHMDRuntimeSettings.h" +#include "StereoLayerFunctionLibrary.h" +#include "TextureResource.h" + +#if PLATFORM_ANDROID +#include "Android/AndroidJNI.h" +#include "Android/AndroidEGL.h" +#include "Android/AndroidApplication.h" +#include "OculusXRHMDTypes.h" +#endif + +namespace OculusXRHMD +{ + + //------------------------------------------------------------------------------------------------- + // FSplash + //------------------------------------------------------------------------------------------------- + + FSplash::FSplash(FOculusXRHMD* InOculusXRHMD) + : OculusXRHMD(InOculusXRHMD), CustomPresent(InOculusXRHMD->GetCustomPresent_Internal()), FramesOutstanding(0), NextLayerId(1), bInitialized(false), bIsShown(false), bNeedSplashUpdate(false), bShouldShowSplash(false), SystemDisplayInterval(1 / 90.0f) + { + // Create empty quad layer for UE layer + { + IStereoLayers::FLayerDesc LayerDesc; + LayerDesc.QuadSize = FVector2D(0.01f, 0.01f); + LayerDesc.Priority = 0; + LayerDesc.PositionType = IStereoLayers::TrackerLocked; + LayerDesc.Texture = nullptr; + UELayer = MakeShareable(new FLayer(NextLayerId++)); + UELayer->SetDesc(LayerDesc); + } + } + + FSplash::~FSplash() + { + // Make sure RenTicker is freed in Shutdown + check(!Ticker.IsValid()) + } + + void FSplash::Tick_RenderThread(float DeltaTime) + { + CheckInRenderThread(); + + if (FramesOutstanding > 0) + { + UE_LOG(LogHMD, VeryVerbose, TEXT("Splash skipping frame; too many frames outstanding")); + return; + } + + const double TimeInSeconds = FPlatformTime::Seconds(); + const double DeltaTimeInSeconds = TimeInSeconds - LastTimeInSeconds; + + if (DeltaTimeInSeconds > 2.f * SystemDisplayInterval && Layers_RenderThread_DeltaRotation.Num() > 0) + { + FScopeLock ScopeLock(&RenderThreadLock); + for (TTuple& Info : Layers_RenderThread_DeltaRotation) + { + FLayerPtr Layer = Info.Key; + const FQuat& DeltaRotation = Info.Value; + check(Layer.IsValid()); + check(!DeltaRotation.Equals(FQuat::Identity)); // Only layers with non-zero delta rotation should be in the DeltaRotation array. + + IStereoLayers::FLayerDesc LayerDesc = Layer->GetDesc(); + LayerDesc.Transform.SetRotation(LayerDesc.Transform.GetRotation() * DeltaRotation); + LayerDesc.Transform.NormalizeRotation(); + Layer->SetDesc(LayerDesc); + } + LastTimeInSeconds = TimeInSeconds; + } + + RenderFrame_RenderThread(FRHICommandListExecutor::GetImmediateCommandList()); + } + + void FSplash::LoadSettings() + { + UOculusXRHMDRuntimeSettings* HMDSettings = GetMutableDefault(); + check(HMDSettings); + ClearSplashes(); + for (const FOculusXRSplashDesc& SplashDesc : HMDSettings->SplashDescs) + { + AddSplash(SplashDesc); + } + + if (HMDSettings->bAutoEnabled) + { + if (!PreLoadLevelDelegate.IsValid()) + { + PreLoadLevelDelegate = FCoreUObjectDelegates::PreLoadMap.AddSP(this, &FSplash::OnPreLoadMap); + } + if (!PostLoadLevelDelegate.IsValid()) + { + PostLoadLevelDelegate = FCoreUObjectDelegates::PostLoadMapWithWorld.AddSP(this, &FSplash::OnPostLoadMap); + } + } + else + { + if (PreLoadLevelDelegate.IsValid()) + { + FCoreUObjectDelegates::PreLoadMap.Remove(PreLoadLevelDelegate); + PreLoadLevelDelegate.Reset(); + } + if (PostLoadLevelDelegate.IsValid()) + { + FCoreUObjectDelegates::PostLoadMapWithWorld.Remove(PostLoadLevelDelegate); + PostLoadLevelDelegate.Reset(); + } + } + } + + void FSplash::OnPreLoadMap(const FString&) + { + DoShow(); + } + + void FSplash::OnPostLoadMap(UWorld* LoadedWorld) + { + // Don't auto-hide splash if show loading screen is called explicitly + if (!bShouldShowSplash) + { + UE_LOG(LogHMD, Log, TEXT("FSplash::OnPostLoadMap Hide Auto Splash")); + HideLoadingScreen(); + } + } + +#if WITH_EDITOR + void FSplash::OnPieBegin(bool bIsSimulating) + { + LoadSettings(); + } +#endif + + void FSplash::Startup() + { + CheckInGameThread(); + + if (!bInitialized) + { + Settings = OculusXRHMD->CreateNewSettings(); + Frame = OculusXRHMD->CreateNewGameFrame(); + // keep units in meters rather than UU (because UU make not much sense). + Frame->WorldToMetersScale = 1.0f; + + float SystemDisplayFrequency; + if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetSystemDisplayFrequency2(&SystemDisplayFrequency))) + { + SystemDisplayInterval = 1.0f / SystemDisplayFrequency; + } + + LoadSettings(); + + OculusXRHMD->InitDevice(); + +#if WITH_EDITOR + PieBeginDelegateHandle = FEditorDelegates::BeginPIE.AddRaw(this, &FSplash::OnPieBegin); +#else + UOculusXRHMDRuntimeSettings* HMDSettings = GetMutableDefault(); + check(HMDSettings); + if (HMDSettings->bAutoEnabled) + { + UE_LOG(LogHMD, Log, TEXT("FSplash::Startup Show Splash on Startup")); + DoShow(); + } +#endif + + OculusXRHMD->Settings_RenderThread = OculusXRHMD->Settings->Clone(); + + bInitialized = true; + } + } + + void FSplash::StopTicker() + { + CheckInGameThread(); + + if (!bIsShown) + { + ExecuteOnRenderThread([this]() { + if (Ticker.IsValid()) + { + Ticker->Unregister(); + Ticker = nullptr; + } + }); + UnloadTextures(); + } + } + + void FSplash::StartTicker() + { + CheckInGameThread(); + + if (!Ticker.IsValid()) + { + Ticker = MakeShareable(new FTicker(this)); + + ExecuteOnRenderThread([this]() { + LastTimeInSeconds = FPlatformTime::Seconds(); + Ticker->Register(); + }); + } + } + + void FSplash::RenderFrame_RenderThread(FRHICommandListImmediate& RHICmdList) + { + CheckInRenderThread(); + + FScopeLock ScopeLock(&RenderThreadLock); + + // RenderFrame + FSettingsPtr XSettings = Settings->Clone(); + FGameFramePtr XFrame = Frame->Clone(); + XFrame->FrameNumber = OculusXRHMD->NextFrameNumber; + XFrame->ShowFlags.Rendering = true; + TArray XLayers = Layers_RenderThread_Input; + + ensure(XLayers.Num() != 0); + + ovrpResult Result; + if (FOculusXRHMDModule::GetPluginWrapper().GetInitialized() && OculusXRHMD->WaitFrameNumber != XFrame->FrameNumber) + { + UE_LOG(LogHMD, Verbose, TEXT("Splash FOculusXRHMDModule::GetPluginWrapper().WaitToBeginFrame %u"), XFrame->FrameNumber); + if (OVRP_FAILURE(Result = FOculusXRHMDModule::GetPluginWrapper().WaitToBeginFrame(XFrame->FrameNumber))) + { + UE_LOG(LogHMD, Error, TEXT("Splash FOculusXRHMDModule::GetPluginWrapper().WaitToBeginFrame %u failed (%d)"), XFrame->FrameNumber, Result); + XFrame->ShowFlags.Rendering = false; + } + else + { + OculusXRHMD->WaitFrameNumber = XFrame->FrameNumber; + OculusXRHMD->NextFrameNumber = XFrame->FrameNumber + 1; + FPlatformAtomics::InterlockedIncrement(&FramesOutstanding); + } + } + else + { + XFrame->ShowFlags.Rendering = false; + } + + if (XFrame->ShowFlags.Rendering) + { + if (OVRP_FAILURE(Result = FOculusXRHMDModule::GetPluginWrapper().Update3(ovrpStep_Render, XFrame->FrameNumber, 0.0))) + { + UE_LOG(LogHMD, Error, TEXT("Splash FOculusXRHMDModule::GetPluginWrapper().Update3 %u failed (%d)"), XFrame->FrameNumber, Result); + } + } + + { + int32 LayerIndex = 0; + int32 LayerIndex_RenderThread = 0; + + while (LayerIndex < XLayers.Num() && LayerIndex_RenderThread < Layers_RenderThread.Num()) + { + uint32 LayerIdA = XLayers[LayerIndex]->GetId(); + uint32 LayerIdB = Layers_RenderThread[LayerIndex_RenderThread]->GetId(); + + if (LayerIdA < LayerIdB) + { + XLayers[LayerIndex++]->Initialize_RenderThread(XSettings.Get(), CustomPresent, &OculusXRHMD->DeferredDeletion, RHICmdList); + } + else if (LayerIdA > LayerIdB) + { + OculusXRHMD->DeferredDeletion.AddLayerToDeferredDeletionQueue(Layers_RenderThread[LayerIndex_RenderThread++]); + } + else + { + XLayers[LayerIndex++]->Initialize_RenderThread(XSettings.Get(), CustomPresent, &OculusXRHMD->DeferredDeletion, RHICmdList, Layers_RenderThread[LayerIndex_RenderThread++].Get()); + } + } + + while (LayerIndex < XLayers.Num()) + { + XLayers[LayerIndex++]->Initialize_RenderThread(XSettings.Get(), CustomPresent, &OculusXRHMD->DeferredDeletion, RHICmdList); + } + + while (LayerIndex_RenderThread < Layers_RenderThread.Num()) + { + OculusXRHMD->DeferredDeletion.AddLayerToDeferredDeletionQueue(Layers_RenderThread[LayerIndex_RenderThread++]); + } + } + + Layers_RenderThread = XLayers; + + for (int32 LayerIndex = 0; LayerIndex < Layers_RenderThread.Num(); LayerIndex++) + { + Layers_RenderThread[LayerIndex]->UpdateTexture_RenderThread(XSettings.Get(), CustomPresent, RHICmdList); + } + + // This submit is required since splash happens before the game is rendering, so layers won't be submitted with game render commands + CustomPresent->SubmitGPUCommands_RenderThread(RHICmdList); + + // RHIFrame + for (int32 LayerIndex = 0; LayerIndex < XLayers.Num(); LayerIndex++) + { + XLayers[LayerIndex] = XLayers[LayerIndex]->Clone(); + } + + ExecuteOnRHIThread_DoNotWait([this, XSettings, XFrame, XLayers]() { + ovrpResult ResultT; + + if (XFrame->ShowFlags.Rendering) + { + UE_LOG(LogHMD, Verbose, TEXT("Splash FOculusXRHMDModule::GetPluginWrapper().BeginFrame4 %u"), XFrame->FrameNumber); + if (OVRP_FAILURE(ResultT = FOculusXRHMDModule::GetPluginWrapper().BeginFrame4(XFrame->FrameNumber, CustomPresent->GetOvrpCommandQueue()))) + { + UE_LOG(LogHMD, Error, TEXT("Splash FOculusXRHMDModule::GetPluginWrapper().BeginFrame4 %u failed (%d)"), XFrame->FrameNumber, ResultT); + XFrame->ShowFlags.Rendering = false; + } + } + + FPlatformAtomics::InterlockedDecrement(&FramesOutstanding); + + Layers_RHIThread = XLayers; + Layers_RHIThread.Sort(FLayerPtr_ComparePriority()); + + if (XFrame->ShowFlags.Rendering) + { + TArray LayerSubmitPtr; + LayerSubmitPtr.SetNum(Layers_RHIThread.Num()); + + for (int32 LayerIndex = 0; LayerIndex < Layers_RHIThread.Num(); LayerIndex++) + { + LayerSubmitPtr[LayerIndex] = Layers_RHIThread[LayerIndex]->UpdateLayer_RHIThread(XSettings.Get(), XFrame.Get(), LayerIndex); + } + + UE_LOG(LogHMD, Verbose, TEXT("Splash FOculusXRHMDModule::GetPluginWrapper().EndFrame4 %u"), XFrame->FrameNumber); + if (OVRP_FAILURE(ResultT = FOculusXRHMDModule::GetPluginWrapper().EndFrame4(XFrame->FrameNumber, LayerSubmitPtr.GetData(), LayerSubmitPtr.Num(), CustomPresent->GetOvrpCommandQueue()))) + { + UE_LOG(LogHMD, Error, TEXT("Splash FOculusXRHMDModule::GetPluginWrapper().EndFrame4 %u failed (%d)"), XFrame->FrameNumber, ResultT); + } + else + { + for (int32 LayerIndex = 0; LayerIndex < Layers_RHIThread.Num(); LayerIndex++) + { + Layers_RHIThread[LayerIndex]->IncrementSwapChainIndex_RHIThread(CustomPresent); + } + } + } + }); + } + + void FSplash::ReleaseResources_RHIThread() + { + for (int32 LayerIndex = 0; LayerIndex < Layers_RenderThread.Num(); LayerIndex++) + { + Layers_RenderThread[LayerIndex]->ReleaseResources_RHIThread(); + } + + for (int32 LayerIndex = 0; LayerIndex < Layers_RHIThread.Num(); LayerIndex++) + { + Layers_RHIThread[LayerIndex]->ReleaseResources_RHIThread(); + } + + Layers_RenderThread.Reset(); + Layers_RHIThread.Reset(); + } + + void FSplash::PreShutdown() + { + CheckInGameThread(); + } + + void FSplash::Shutdown() + { + CheckInGameThread(); + +#if WITH_EDITOR + if (PieBeginDelegateHandle.IsValid()) + { + FEditorDelegates::BeginPIE.Remove(PieBeginDelegateHandle); + PieBeginDelegateHandle.Reset(); + } +#endif + + if (PreLoadLevelDelegate.IsValid()) + { + FCoreUObjectDelegates::PreLoadMap.Remove(PreLoadLevelDelegate); + PreLoadLevelDelegate.Reset(); + } + if (PostLoadLevelDelegate.IsValid()) + { + FCoreUObjectDelegates::PostLoadMapWithWorld.Remove(PostLoadLevelDelegate); + PostLoadLevelDelegate.Reset(); + } + + if (bInitialized) + { + ExecuteOnRenderThread([this]() { + if (Ticker) + { + Ticker->Unregister(); + Ticker = nullptr; + } + + ExecuteOnRHIThread([this]() { + SplashLayers.Reset(); + Layers_RenderThread.Reset(); + Layers_RenderThread_Input.Reset(); + Layers_RHIThread.Reset(); + }); + }); + + bInitialized = false; + } + } + + int FSplash::AddSplash(const FOculusXRSplashDesc& Desc) + { + CheckInGameThread(); + + FScopeLock ScopeLock(&RenderThreadLock); + return SplashLayers.Add(FSplashLayer(Desc)); + } + + void FSplash::AddSplash(const FSplashDesc& Splash) + { + FOculusXRSplashDesc OculusDesc; + OculusDesc.TransformInMeters = Splash.Transform; + OculusDesc.QuadSizeInMeters = Splash.QuadSize; + OculusDesc.DeltaRotation = Splash.DeltaRotation; + OculusDesc.bNoAlphaChannel = Splash.bIgnoreAlpha; + OculusDesc.bIsDynamic = Splash.bIsDynamic || Splash.bIsExternal; + OculusDesc.TextureOffset = Splash.UVRect.Min; + OculusDesc.TextureScale = Splash.UVRect.Max; + OculusDesc.LoadedTexture = Splash.Texture; + + AddSplash(OculusDesc); + } + + void FSplash::ClearSplashes() + { + CheckInGameThread(); + + FScopeLock ScopeLock(&RenderThreadLock); + SplashLayers.Reset(); + } + + bool FSplash::GetSplash(unsigned InSplashLayerIndex, FOculusXRSplashDesc& OutDesc) + { + CheckInGameThread(); + + FScopeLock ScopeLock(&RenderThreadLock); + if (InSplashLayerIndex < unsigned(SplashLayers.Num())) + { + OutDesc = SplashLayers[int32(InSplashLayerIndex)].Desc; + return true; + } + return false; + } + + IStereoLayers::FLayerDesc FSplash::StereoLayerDescFromOculusSplashDesc(FOculusXRSplashDesc OculusDesc) + { + IStereoLayers::FLayerDesc LayerDesc; + if (OculusDesc.LoadedTexture->GetTextureCube() != nullptr) + { + LayerDesc.SetShape(); + } + // else LayerDesc.Shape defaults to FQuadLayer + + LayerDesc.Transform = OculusDesc.TransformInMeters * FTransform(OculusXRHMD->GetSplashRotation().Quaternion()); + LayerDesc.QuadSize = OculusDesc.QuadSizeInMeters; + LayerDesc.UVRect = FBox2D(OculusDesc.TextureOffset, OculusDesc.TextureOffset + OculusDesc.TextureScale); + LayerDesc.Priority = INT32_MAX - (int32)(OculusDesc.TransformInMeters.GetTranslation().X * 1000.f); + LayerDesc.PositionType = IStereoLayers::TrackerLocked; + LayerDesc.Texture = OculusDesc.LoadedTexture; + LayerDesc.Flags = IStereoLayers::LAYER_FLAG_QUAD_PRESERVE_TEX_RATIO | (OculusDesc.bNoAlphaChannel ? IStereoLayers::LAYER_FLAG_TEX_NO_ALPHA_CHANNEL : 0) | (OculusDesc.bIsDynamic ? IStereoLayers::LAYER_FLAG_TEX_CONTINUOUS_UPDATE : 0); + + return LayerDesc; + } + + void FSplash::DoShow() + { + CheckInGameThread(); + + OculusXRHMD->SetSplashRotationToForward(); + + // Create new textures + UnloadTextures(); + + // Make sure all UTextures are loaded and contain Resource->TextureRHI + bool bWaitForRT = false; + + for (int32 SplashLayerIndex = 0; SplashLayerIndex < SplashLayers.Num(); ++SplashLayerIndex) + { + FSplashLayer& SplashLayer = SplashLayers[SplashLayerIndex]; + + if (SplashLayer.Desc.TexturePath.IsValid()) + { + // load temporary texture (if TexturePath was specified) + LoadTexture(SplashLayer); + } + if (SplashLayer.Desc.LoadingTexture && SplashLayer.Desc.LoadingTexture->IsValidLowLevel()) + { + SplashLayer.Desc.LoadingTexture->UpdateResource(); + bWaitForRT = true; + } + } + + FlushRenderingCommands(); + + for (int32 SplashLayerIndex = 0; SplashLayerIndex < SplashLayers.Num(); ++SplashLayerIndex) + { + FSplashLayer& SplashLayer = SplashLayers[SplashLayerIndex]; + + //@DBG BEGIN + if (SplashLayer.Desc.LoadingTexture->IsValidLowLevel()) + { + if (SplashLayer.Desc.LoadingTexture->GetResource() && SplashLayer.Desc.LoadingTexture->GetResource()->TextureRHI) + { + SplashLayer.Desc.LoadedTexture = SplashLayer.Desc.LoadingTexture->GetResource()->TextureRHI; + } + else + { + UE_LOG(LogHMD, Warning, TEXT("Splash, %s - no Resource"), *SplashLayer.Desc.LoadingTexture->GetDesc()); + } + } + //@DBG END + + if (SplashLayer.Desc.LoadedTexture) + { + SplashLayer.Layer = MakeShareable(new FLayer(NextLayerId++)); + SplashLayer.Layer->SetDesc(StereoLayerDescFromOculusSplashDesc(SplashLayer.Desc)); + } + } + + { + //add oculus-generated layers through the OculusVR settings area + FScopeLock ScopeLock(&RenderThreadLock); + Layers_RenderThread_DeltaRotation.Reset(); + Layers_RenderThread_Input.Reset(); + for (int32 SplashLayerIndex = 0; SplashLayerIndex < SplashLayers.Num(); SplashLayerIndex++) + { + const FSplashLayer& SplashLayer = SplashLayers[SplashLayerIndex]; + + if (SplashLayer.Layer.IsValid()) + { + FLayerPtr ClonedLayer = SplashLayer.Layer->Clone(); + Layers_RenderThread_Input.Add(ClonedLayer); + + // Register layers that need to be rotated every n ticks + if (!SplashLayer.Desc.DeltaRotation.Equals(FQuat::Identity)) + { + Layers_RenderThread_DeltaRotation.Emplace(ClonedLayer, SplashLayer.Desc.DeltaRotation); + } + } + } + + //add UE VR splash screen + FOculusXRSplashDesc UESplashDesc = OculusXRHMD->GetUESplashScreenDesc(); + if (UESplashDesc.LoadedTexture != nullptr) + { + UELayer.Reset(); + UELayer = MakeShareable(new FLayer(NextLayerId++)); + UELayer->SetDesc(StereoLayerDescFromOculusSplashDesc(UESplashDesc)); + Layers_RenderThread_Input.Add(UELayer->Clone()); + } + + Layers_RenderThread_Input.Sort(FLayerPtr_CompareId()); + } + + if (Layers_RenderThread_Input.Num() > 0) + { + // If no textures are loaded, this will push black frame + StartTicker(); + bIsShown = true; + UE_LOG(LogHMD, Log, TEXT("FSplash::DoShow")); + } + else + { + UE_LOG(LogHMD, Log, TEXT("No splash layers in FSplash::DoShow")); + } + } + + void FSplash::DoHide() + { + CheckInGameThread(); + + UE_LOG(LogHMD, Log, TEXT("FSplash::DoHide")); + bIsShown = false; + + StopTicker(); + } + + void FSplash::UpdateLoadingScreen_GameThread() + { + if (bNeedSplashUpdate) + { + if (bShouldShowSplash) + { + DoShow(); + } + else + { + DoHide(); + } + + bNeedSplashUpdate = false; + } + } + + void FSplash::ShowLoadingScreen() + { + bShouldShowSplash = true; + + // DoShow will be called from UpdateSplashScreen_Gamethread(). + // This can can happen if the splashes are already being shown, as it will reset the relative positions and delta rotations of the layers. + bNeedSplashUpdate = true; + } + + void FSplash::HideLoadingScreen() + { + bShouldShowSplash = false; + bNeedSplashUpdate = bIsShown; // no need to call DoHide when the splash is already hidden + } + + void FSplash::UnloadTextures() + { + CheckInGameThread(); + + // unload temporary loaded textures + FScopeLock ScopeLock(&RenderThreadLock); + for (int32 SplashLayerIndex = 0; SplashLayerIndex < SplashLayers.Num(); ++SplashLayerIndex) + { + if (SplashLayers[SplashLayerIndex].Desc.TexturePath.IsValid()) + { + UnloadTexture(SplashLayers[SplashLayerIndex]); + } + } + } + + void FSplash::LoadTexture(FSplashLayer& InSplashLayer) + { + CheckInGameThread(); + + UnloadTexture(InSplashLayer); + + UE_LOG(LogLoadingSplash, Log, TEXT("Loading texture for splash %s..."), *InSplashLayer.Desc.TexturePath.GetAssetName()); + InSplashLayer.Desc.LoadingTexture = Cast(InSplashLayer.Desc.TexturePath.TryLoad()); + if (InSplashLayer.Desc.LoadingTexture != nullptr) + { + UE_LOG(LogLoadingSplash, Log, TEXT("...Success. ")); + } + InSplashLayer.Desc.LoadedTexture = nullptr; + InSplashLayer.Layer.Reset(); + } + + void FSplash::UnloadTexture(FSplashLayer& InSplashLayer) + { + CheckInGameThread(); + + InSplashLayer.Desc.LoadingTexture = nullptr; + InSplashLayer.Desc.LoadedTexture = nullptr; + InSplashLayer.Layer.Reset(); + } + +} // namespace OculusXRHMD + +#endif // OCULUS_HMD_SUPPORTED_PLATFORMS diff --git a/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_Splash.h b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_Splash.h new file mode 100644 index 0000000..3d61d84 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_Splash.h @@ -0,0 +1,146 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +#pragma once +#include "OculusXRHMDPrivate.h" +#include "IXRLoadingScreen.h" + +#if WITH_EDITOR +#include "Editor.h" +#endif + +#if OCULUS_HMD_SUPPORTED_PLATFORMS +#include "OculusXRHMD_GameFrame.h" +#include "OculusXRHMD_Layer.h" +#include "TickableObjectRenderThread.h" +#include "OculusXRHMDTypes.h" + +namespace OculusXRHMD +{ + + class FOculusXRHMD; + + //------------------------------------------------------------------------------------------------- + // FSplashLayer + //------------------------------------------------------------------------------------------------- + + struct FSplashLayer + { + FOculusXRSplashDesc Desc; + FLayerPtr Layer; + + public: + FSplashLayer(const FOculusXRSplashDesc& InDesc) + : Desc(InDesc) {} + FSplashLayer(const FSplashLayer& InSplashLayer) + : Desc(InSplashLayer.Desc), Layer(InSplashLayer.Layer) {} + }; + + //------------------------------------------------------------------------------------------------- + // FSplash + //------------------------------------------------------------------------------------------------- + + class FSplash : public IXRLoadingScreen, public TSharedFromThis + { + protected: + class FTicker : public FTickableObjectRenderThread, public TSharedFromThis + { + public: + FTicker(FSplash* InSplash) + : FTickableObjectRenderThread(false, true), pSplash(InSplash) {} + + virtual void Tick(float DeltaTime) override { pSplash->Tick_RenderThread(DeltaTime); } + virtual TStatId GetStatId() const override { RETURN_QUICK_DECLARE_CYCLE_STAT(FSplash, STATGROUP_Tickables); } + virtual bool IsTickable() const override { return true; } + + protected: + FSplash* pSplash; + }; + + public: + FSplash(FOculusXRHMD* InPlugin); + virtual ~FSplash(); + + void Tick_RenderThread(float DeltaTime); + + void Startup(); + void LoadSettings(); + void ReleaseResources_RHIThread(); + void PreShutdown(); + void Shutdown(); + + void OnPreLoadMap(const FString&); + void OnPostLoadMap(UWorld* LoadedWorld); +#if WITH_EDITOR + void OnPieBegin(bool bIsSimulating); +#endif + + // Called from FOculusXRHMD + void UpdateLoadingScreen_GameThread(); + + // Internal extended API + int AddSplash(const FOculusXRSplashDesc&); + bool GetSplash(unsigned index, FOculusXRSplashDesc& OutDesc); + void StopTicker(); + void StartTicker(); + + // The standard IXRLoadingScreen interface + virtual void ShowLoadingScreen() override; + virtual void HideLoadingScreen() override; + virtual void ClearSplashes() override; + virtual void AddSplash(const FSplashDesc& Splash) override; + virtual bool IsShown() const override { return bIsShown; } +#if !UE_VERSION_OLDER_THAN(5, 3, 0) + virtual bool IsPlayingLoadingMovie() const override + { + return false; + } +#endif + + protected: + void DoShow(); + void DoHide(); + void UnloadTextures(); + void LoadTexture(FSplashLayer& InSplashLayer); + void UnloadTexture(FSplashLayer& InSplashLayer); + + void RenderFrame_RenderThread(FRHICommandListImmediate& RHICmdList); + IStereoLayers::FLayerDesc StereoLayerDescFromOculusSplashDesc(FOculusXRSplashDesc OculusDesc); + + protected: + FOculusXRHMD* OculusXRHMD; + FCustomPresent* CustomPresent; + TSharedPtr Ticker; + int32 FramesOutstanding; + FCriticalSection RenderThreadLock; + FSettingsPtr Settings; + FGameFramePtr Frame; + TArray SplashLayers; + uint32 NextLayerId; + FLayerPtr BlackLayer; + FLayerPtr UELayer; + TArray> Layers_RenderThread_DeltaRotation; + TArray Layers_RenderThread_Input; + TArray Layers_RenderThread; + TArray Layers_RHIThread; + + // All these flags are only modified from the Game thread + bool bInitialized; + bool bIsShown; + bool bNeedSplashUpdate; + bool bShouldShowSplash; + + float SystemDisplayInterval; + double LastTimeInSeconds; + FDelegateHandle PreLoadLevelDelegate; + FDelegateHandle PostLoadLevelDelegate; +#if WITH_EDITOR + FDelegateHandle PieBeginDelegateHandle; +#endif + }; + + typedef TSharedPtr FSplashPtr; + +} // namespace OculusXRHMD + +#endif // OCULUS_HMD_SUPPORTED_PLATFORMS diff --git a/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_StressTester.cpp b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_StressTester.cpp new file mode 100644 index 0000000..8678438 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_StressTester.cpp @@ -0,0 +1,309 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +#include "OculusXRHMD_StressTester.h" + +#if OCULUS_STRESS_TESTS_ENABLED +#include "OculusXRHMD.h" +#include "GlobalShader.h" +#include "UniformBuffer.h" +#include "RHICommandList.h" +#include "ShaderParameterUtils.h" +#include "RHIStaticStates.h" +#include "PipelineStateCache.h" +#include "OculusShaders.h" +#include "SceneUtils.h" // for SCOPED_DRAW_EVENT() + +DECLARE_STATS_GROUP(TEXT("Oculus"), STATGROUP_Oculus, STATCAT_Advanced); +DECLARE_CYCLE_STAT(TEXT("GPUStressRendering"), STAT_GPUStressRendering, STATGROUP_Oculus); + +//------------------------------------------------------------------------------------------------- +// Uniform buffers +//------------------------------------------------------------------------------------------------- + +//This buffer should contain variables that never, or rarely change +BEGIN_GLOBAL_SHADER_PARAMETER_STRUCT(FOculusPixelShaderConstantParameters, ) +//SHADER_PARAMETER(FVector4, Name) +END_GLOBAL_SHADER_PARAMETER_STRUCT() + +IMPLEMENT_GLOBAL_SHADER_PARAMETER_STRUCT(FOculusPixelShaderConstantParameters, "PSConstants"); + +typedef TUniformBufferRef FOculusPixelShaderConstantParametersRef; + +//This buffer is for variables that change very often (each frame for example) +BEGIN_GLOBAL_SHADER_PARAMETER_STRUCT(FOculusPixelShaderVariableParameters, ) +SHADER_PARAMETER(int, IterationsMultiplier) +END_GLOBAL_SHADER_PARAMETER_STRUCT() + +IMPLEMENT_GLOBAL_SHADER_PARAMETER_STRUCT(FOculusPixelShaderVariableParameters, "PSVariables"); + +typedef TUniformBufferRef FOculusPixelShaderVariableParametersRef; + +namespace OculusXRHMD +{ + + //------------------------------------------------------------------------------------------------- + // FTextureVertexDeclaration + //------------------------------------------------------------------------------------------------- + + struct FTextureVertex + { + FVector4 Position; + FVector2f UV; + }; + + class FTextureVertexDeclaration : public FRenderResource + { + public: + FVertexDeclarationRHIRef VertexDeclarationRHI; + +#if UE_VERSION_OLDER_THAN(5, 3, 0) + virtual void InitRHI() override +#else + virtual void InitRHI(FRHICommandListBase& RHICmdList) override +#endif + { + FVertexDeclarationElementList Elements; + uint32 Stride = sizeof(FTextureVertex); + Elements.Add(FVertexElement(0, STRUCT_OFFSET(FTextureVertex, Position), VET_Float4, 0, Stride)); + Elements.Add(FVertexElement(0, STRUCT_OFFSET(FTextureVertex, UV), VET_Float2, 1, Stride)); + VertexDeclarationRHI = PipelineStateCache::GetOrCreateVertexDeclaration(Elements); + } + + virtual void ReleaseRHI() override + { + VertexDeclarationRHI.SafeRelease(); + } + }; + + static TGlobalResource GOculusTextureVertexDeclaration; + + //------------------------------------------------------------------------------------------------- + // FStressTester + //------------------------------------------------------------------------------------------------- + + TSharedPtr FStressTester::SharedInstance; + + TSharedRef FStressTester::Get() + { + CheckInGameThread(); + if (!SharedInstance.IsValid()) + { + SharedInstance = TSharedPtr(new FStressTester()); + check(SharedInstance.IsValid()); + } + return SharedInstance.ToSharedRef(); + } + + FStressTester::FStressTester() + : Mode(STM_None) + , CPUSpinOffInSeconds(0.011 / 3.) // one third of the frame (default value) + , PDsTimeLimitInSeconds(10.) // 10 secs + , CPUsTimeLimitInSeconds(10.) // 10 secs + , GPUsTimeLimitInSeconds(10.) // 10 secs + , GPUIterationsMultiplier(0.) + , CPUStartTimeInSeconds(0.) + , GPUStartTimeInSeconds(0.) + , PDStartTimeInSeconds(0.) + { + } + + // multiple masks could be set, see EStressTestMode + void FStressTester::SetStressMode(uint32 InStressMask) + { + check((InStressMask & (~STM__All)) == 0); + Mode = InStressMask; + + for (uint32 m = 1; m < STM__All; m <<= 1) + { + if (InStressMask & m) + { + switch (m) + { + case STM_EyeBufferRealloc: + UE_LOG(LogHMD, Log, TEXT("PD of EyeBuffer stress test is started")); + break; + case STM_CPUSpin: + UE_LOG(LogHMD, Log, TEXT("CPU stress test is started")); + break; + case STM_GPU: + UE_LOG(LogHMD, Log, TEXT("GPU stress test is started")); + break; + } + } + } + } + + void FStressTester::DoTickCPU_GameThread(FOculusXRHMD* pPlugin) + { + CheckInGameThread(); + + if (Mode & STM_EyeBufferRealloc) + { + // Change PixelDensity every frame within MinPixelDensity..MaxPixelDensity range + if (PDStartTimeInSeconds == 0.) + { + PDStartTimeInSeconds = FPlatformTime::Seconds(); + } + else + { + const double Now = FPlatformTime::Seconds(); + if (Now - PDStartTimeInSeconds >= PDsTimeLimitInSeconds) + { + PDStartTimeInSeconds = 0.; + Mode &= ~STM_EyeBufferRealloc; + UE_LOG(LogHMD, Log, TEXT("PD of EyeBuffer stress test is finished")); + } + } + + const int divisor = int((MaxPixelDensity - MinPixelDensity) * 10.f); + float NewPD = float(uint64(FPlatformTime::Seconds() * 1000) % divisor) / 10.f + MinPixelDensity; + + pPlugin->SetPixelDensity(NewPD); + } + + if (Mode & STM_CPUSpin) + { + // Simulate heavy CPU load within specified time limits + + if (CPUStartTimeInSeconds == 0.) + { + CPUStartTimeInSeconds = FPlatformTime::Seconds(); + } + else + { + const double Now = FPlatformTime::Seconds(); + if (Now - CPUStartTimeInSeconds >= CPUsTimeLimitInSeconds) + { + CPUStartTimeInSeconds = 0.; + Mode &= ~STM_CPUSpin; + UE_LOG(LogHMD, Log, TEXT("CPU stress test is finished")); + } + } + + const double StartSeconds = FPlatformTime::Seconds(); + int i, num = 1, primes = 0; + + bool bFinish = false; + while (!bFinish) + { + i = 2; + while (i <= num) + { + if (num % i == 0) + { + break; + } + i++; + const double NowSeconds = FPlatformTime::Seconds(); + if (NowSeconds - StartSeconds >= CPUSpinOffInSeconds) + { + bFinish = true; + } + } + if (i == num) + { + ++primes; + } + + ++num; + } + } + + if (Mode & STM_GPU) + { + // Simulate heavy CPU load within specified time limits + + if (GPUStartTimeInSeconds == 0.) + { + GPUStartTimeInSeconds = FPlatformTime::Seconds(); + } + else + { + const double Now = FPlatformTime::Seconds(); + if (Now - GPUStartTimeInSeconds >= GPUsTimeLimitInSeconds) + { + GPUStartTimeInSeconds = 0.; + Mode &= ~STM_GPU; + UE_LOG(LogHMD, Log, TEXT("GPU stress test is finished")); + } + } + } + } + + //------------------------------------------------------------------------------------------------- + // Console commands for managing the stress tester: + //------------------------------------------------------------------------------------------------- + + static void StressGPUCmdHandler(const TArray& Args, UWorld* World, FOutputDevice& Ar) + { + auto StressTester = FStressTester::Get(); + StressTester->SetStressMode(FStressTester::STM_GPU | StressTester->GetStressMode()); + if (Args.Num() > 0) + { + const int GpuMult = FCString::Atoi(*Args[0]); + StressTester->SetGPULoadMultiplier(GpuMult); + } + if (Args.Num() > 1) + { + const float GpuTimeLimit = FCString::Atof(*Args[1]); + StressTester->SetGPUsTimeLimitInSeconds(GpuTimeLimit); + } + } + + static FAutoConsoleCommand CStressGPUCmd( + TEXT("vr.oculus.Stress.GPU"), + *NSLOCTEXT("OculusRift", "CCommandText_StressGPU", "Initiates a GPU stress test.\n Usage: vr.oculus.Stress.GPU [LoadMultiplier [TimeLimit]]").ToString(), + FConsoleCommandWithWorldArgsAndOutputDeviceDelegate::CreateStatic(StressGPUCmdHandler)); + + static void StressCPUCmdHandler(const TArray& Args, UWorld* World, FOutputDevice& Ar) + { + auto StressTester = FStressTester::Get(); + StressTester->SetStressMode(FStressTester::STM_CPUSpin | StressTester->GetStressMode()); + if (Args.Num() > 0) + { + const float CpuLimit = FCString::Atof(*Args[0]); + StressTester->SetCPUSpinOffPerFrameInSeconds(CpuLimit); + } + if (Args.Num() > 1) + { + const float CpuTimeLimit = FCString::Atof(*Args[1]); + StressTester->SetCPUsTimeLimitInSeconds(CpuTimeLimit); + } + } + + static FAutoConsoleCommand CStressCPUCmd( + TEXT("vr.oculus.Stress.CPU"), + *NSLOCTEXT("OculusRift", "CCommandText_StressCPU", "Initiates a CPU stress test.\n Usage: vr.oculus.Stress.CPU [PerFrameTime [TotalTimeLimit]]").ToString(), + FConsoleCommandWithWorldArgsAndOutputDeviceDelegate::CreateStatic(StressCPUCmdHandler)); + + static void StressPDCmdHandler(const TArray& Args, UWorld* World, FOutputDevice& Ar) + { + auto StressTester = FStressTester::Get(); + StressTester->SetStressMode(FStressTester::STM_EyeBufferRealloc | StressTester->GetStressMode()); + if (Args.Num() > 0) + { + const float TimeLimit = FCString::Atof(*Args[0]); + StressTester->SetPDsTimeLimitInSeconds(TimeLimit); + } + } + + static FAutoConsoleCommand CStressPDCmd( + TEXT("vr.oculus.Stress.PD"), + *NSLOCTEXT("OculusRift", "CCommandText_StressPD", "Initiates a pixel density stress test wher pixel density is changed every frame for TotalTimeLimit seconds.\n Usage: vr.oculus.Stress.PD [TotalTimeLimit]").ToString(), + FConsoleCommandWithWorldArgsAndOutputDeviceDelegate::CreateStatic(StressPDCmdHandler)); + + static void StressResetCmdHandler(const TArray& Args, UWorld* World, FOutputDevice& Ar) + { + auto StressTester = FStressTester::Get(); + StressTester->SetStressMode(0); + } + + static FAutoConsoleCommand CStressResetCmd( + TEXT("vr.oculus.Stress.Reset"), + *NSLOCTEXT("OculusRift", "CCommandText_StressReset", "Resets the stress tester and stops all currently running stress tests.\n Usage: vr.oculus.Stress.Reset").ToString(), + FConsoleCommandWithWorldArgsAndOutputDeviceDelegate::CreateStatic(StressResetCmdHandler)); + +} // namespace OculusXRHMD + +#endif // #if OCULUS_STRESS_TESTS_ENABLED diff --git a/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_StressTester.h b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_StressTester.h new file mode 100644 index 0000000..9726c8a --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_StressTester.h @@ -0,0 +1,91 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +#pragma once +#include "OculusXRHMDPrivate.h" + +#define OCULUS_STRESS_TESTS_ENABLED (OCULUS_HMD_SUPPORTED_PLATFORMS && !UE_BUILD_SHIPPING && !PLATFORM_ANDROID) + +#if OCULUS_STRESS_TESTS_ENABLED + +namespace OculusXRHMD +{ + + //------------------------------------------------------------------------------------------------- + // FStressTester + //------------------------------------------------------------------------------------------------- + + class FStressTester + { + + public: + const float MinPixelDensity = 0.4f; + const float MaxPixelDensity = 2.0f; + + enum EStressTestMode + { + STM_None, + STM_EyeBufferRealloc = 0x01, + STM_CPUSpin = 0x02, + STM_GPU = 0x04, + + STM__All = ((STM_GPU << 1) - 1) + }; + + // multiple masks could be set, see EStressTestMode + void SetStressMode(uint32 InStressMask); + uint32 GetStressMode() const { return Mode; } + + // sets limits for CPUSpin mode, per frame + void SetCPUSpinOffPerFrameInSeconds(double InCPUSpinOffInSeconds) { CPUSpinOffInSeconds = InCPUSpinOffInSeconds; } + + // set GPU load multiplier + // if IterationsMultiplier is 0 then the multiplier will be randomly changed in 1..20 range. + // the bigger the multiplier the longer it takes GPU to draw the quad. + void SetGPULoadMultiplier(int IterationsMultiplier) { GPUIterationsMultiplier = IterationsMultiplier; } + + // sets time limit for STM_EyeBufferRealloc mode; 0 - unlimited + void SetPDsTimeLimitInSeconds(double InSeconds) { PDsTimeLimitInSeconds = InSeconds; } + + // sets time limit for STM_CPUSpin mode; 0 - unlimited + void SetCPUsTimeLimitInSeconds(double InSeconds) { CPUsTimeLimitInSeconds = InSeconds; } + + // sets time limit for STM_GPU mode; 0 - unlimited + void SetGPUsTimeLimitInSeconds(double InSeconds) { GPUsTimeLimitInSeconds = InSeconds; } + + static TSharedRef Get(); + + static void TickCPU_GameThread(class FOculusXRHMD* pPlugin) + { + CheckInGameThread(); + + if (SharedInstance.IsValid()) + { + SharedInstance->DoTickCPU_GameThread(pPlugin); + } + } + + protected: + void DoTickCPU_GameThread(class FOculusXRHMD* pPlugin); + + FStressTester(); + + uint32 Mode; // bit mask, see EStressTestMode + double CPUSpinOffInSeconds; // limit of additional CPU load per frame, STM_CPUSpin + double PDsTimeLimitInSeconds; // time limit for STM_EyeBufferRealloc mode; 0 - unlimited + double CPUsTimeLimitInSeconds; // time limit for STM_CPUSpin mode; 0 - unlimited + double GPUsTimeLimitInSeconds; // time limit for STM_GPU mode; 0 - unlimited + + // the higher multiplier the longer it takes GPU to draw + int GPUIterationsMultiplier; // if 0 - then it is dynamically changed. + + double CPUStartTimeInSeconds; + double GPUStartTimeInSeconds; + double PDStartTimeInSeconds; + + static TSharedPtr SharedInstance; + }; + +} // namespace OculusXRHMD + +#endif // #if OCULUS_STRESS_TESTS_ENABLED diff --git a/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_VulkanExtensions.cpp b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_VulkanExtensions.cpp new file mode 100644 index 0000000..14fdf84 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_VulkanExtensions.cpp @@ -0,0 +1,120 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +#include "OculusXRHMD_VulkanExtensions.h" + +#if OCULUS_HMD_SUPPORTED_PLATFORMS +#include "OculusXRHMDPrivateRHI.h" +#include "OculusXRHMDModule.h" + +namespace OculusXRHMD +{ + + //------------------------------------------------------------------------------------------------- + // FVulkanExtensions + //------------------------------------------------------------------------------------------------- + + bool FVulkanExtensions::GetVulkanInstanceExtensionsRequired(TArray& Out) + { +#if OCULUS_HMD_SUPPORTED_PLATFORMS_VULKAN + //TArray Properties = GetIVulkanDynamicRHI()->RHIGetAllInstanceExtensions(); + + TArray Extensions; + { + int32 ExtensionCount = 0; + FOculusXRHMDModule::GetPluginWrapper().GetInstanceExtensionsVk(nullptr, &ExtensionCount); + Extensions.SetNum(ExtensionCount); + FOculusXRHMDModule::GetPluginWrapper().GetInstanceExtensionsVk(Extensions.GetData(), &ExtensionCount); + } + + // int32 ExtensionsFound = 0; + for (int32 ExtensionIndex = 0; ExtensionIndex < Extensions.Num(); ExtensionIndex++) + { + // for (int32 PropertyIndex = 0; PropertyIndex < Properties.Num(); PropertyIndex++) + { + // const char* PropertyExtensionName = Properties[PropertyIndex].extensionName; + + // if (!FCStringAnsi::Strcmp(PropertyExtensionName, Extensions[ExtensionIndex])) + { + Out.Add(Extensions[ExtensionIndex]); + // ExtensionsFound++; + // break; + } + } + } + return true; + +// return ExtensionsFound == Extensions.Num(); +#endif + return true; + } + + bool FVulkanExtensions::GetVulkanDeviceExtensionsRequired(struct VkPhysicalDevice_T* pPhysicalDevice, TArray& Out) + { +#if OCULUS_HMD_SUPPORTED_PLATFORMS_VULKAN + //TArray Properties = GetIVulkanDynamicRHI()->RHIGetAllDeviceExtensions((VkPhysicalDevice)pPhysicalDevice); + + TArray Extensions; + { + int32 ExtensionCount = 0; + FOculusXRHMDModule::GetPluginWrapper().GetDeviceExtensionsVk(nullptr, &ExtensionCount); + Extensions.SetNum(ExtensionCount); + FOculusXRHMDModule::GetPluginWrapper().GetDeviceExtensionsVk(Extensions.GetData(), &ExtensionCount); + } + + // int32 ExtensionsFound = 0; + for (int32 ExtensionIndex = 0; ExtensionIndex < Extensions.Num(); ExtensionIndex++) + { + // for (int32 PropertyIndex = 0; PropertyIndex < Properties.Num(); PropertyIndex++) + { + // const char* PropertyExtensionName = Properties[PropertyIndex].extensionName; + + // if (!FCStringAnsi::Strcmp(PropertyExtensionName, Extensions[ExtensionIndex])) + { + Out.Add(Extensions[ExtensionIndex]); + // ExtensionsFound++; + // break; + } + } + } + return true; + + // return ExtensionsFound == Extensions.Num(); +#endif + return true; + } + +#if WITH_EDITOR + bool FEditorVulkanExtensions::GetVulkanInstanceExtensionsRequired(TArray& Out) + { +#if OCULUS_HMD_SUPPORTED_PLATFORMS_VULKAN && PLATFORM_WINDOWS + Out.Append({ "VK_KHR_surface", + "VK_KHR_external_memory_capabilities", + "VK_KHR_win32_surface", + "VK_KHR_external_fence_capabilities", + "VK_KHR_external_semaphore_capabilities", + "VK_KHR_get_physical_device_properties2" }); +#endif + return true; + } + + bool FEditorVulkanExtensions::GetVulkanDeviceExtensionsRequired(struct VkPhysicalDevice_T* pPhysicalDevice, TArray& Out) + { +#if OCULUS_HMD_SUPPORTED_PLATFORMS_VULKAN && PLATFORM_WINDOWS + Out.Append({ "VK_KHR_swapchain", + "VK_KHR_external_memory", + "VK_KHR_external_memory_win32", + "VK_KHR_external_fence", + "VK_KHR_external_fence_win32", + "VK_KHR_external_semaphore", + "VK_KHR_external_semaphore_win32", + "VK_KHR_get_memory_requirements2", + "VK_KHR_dedicated_allocation" }); +#endif + return true; + } +#endif + +} // namespace OculusXRHMD + +#endif //OCULUS_HMD_SUPPORTED_PLATFORMS diff --git a/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_VulkanExtensions.h b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_VulkanExtensions.h new file mode 100644 index 0000000..e198fcb --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMD_VulkanExtensions.h @@ -0,0 +1,43 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +#pragma once +#include "OculusXRHMDPrivate.h" +#include "IHeadMountedDisplayVulkanExtensions.h" + +#if OCULUS_HMD_SUPPORTED_PLATFORMS + +namespace OculusXRHMD +{ + + //------------------------------------------------------------------------------------------------- + // FVulkanExtensions + //------------------------------------------------------------------------------------------------- + + class FVulkanExtensions : public IHeadMountedDisplayVulkanExtensions, public TSharedFromThis + { + public: + FVulkanExtensions() {} + virtual ~FVulkanExtensions() {} + + // IHeadMountedDisplayVulkanExtensions + virtual bool GetVulkanInstanceExtensionsRequired(TArray& Out) override; + virtual bool GetVulkanDeviceExtensionsRequired(struct VkPhysicalDevice_T* pPhysicalDevice, TArray& Out) override; + }; + +#if WITH_EDITOR + class FEditorVulkanExtensions : public IHeadMountedDisplayVulkanExtensions, public TSharedFromThis + { + public: + FEditorVulkanExtensions() {} + virtual ~FEditorVulkanExtensions() {} + + // IHeadMountedDisplayVulkanExtensions + virtual bool GetVulkanInstanceExtensionsRequired(TArray& Out) override; + virtual bool GetVulkanDeviceExtensionsRequired(struct VkPhysicalDevice_T* pPhysicalDevice, TArray& Out) override; + }; +#endif + +} // namespace OculusXRHMD + +#endif //OCULUS_HMD_SUPPORTED_PLATFORMS diff --git a/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRPassthroughLayerShapes.cpp b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRPassthroughLayerShapes.cpp new file mode 100644 index 0000000..81718df --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRPassthroughLayerShapes.cpp @@ -0,0 +1,152 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#include "OculusXRPassthroughLayerShapes.h" + +#include "OculusXRHMDPrivate.h" +#include "Curves/CurveLinearColor.h" +#include "OculusXRPluginWrapper.h" + +const FName FReconstructedLayer::ShapeName = FName("ReconstructedLayer"); +const FName FUserDefinedLayer::ShapeName = FName("UserDefinedLayer"); + +FColorLutDesc::FColorLutDesc() + : Weight(0) + , ColorLuts{} +{ +} + +FColorLutDesc::FColorLutDesc(const TArray& InColorLuts, float InWeight) + : Weight(InWeight) + , ColorLuts(InColorLuts) +{ +} + +FEdgeStyleParameters::FEdgeStyleParameters() + : bEnableEdgeColor(false) + , bEnableColorMap(false) + , bUseColorLuts(false) + , TextureOpacityFactor(1.0f) + , EdgeColor{} + , ColorMapType{} + , ColorMapData{} + , ColorLutDesc{} { + + }; + +FEdgeStyleParameters::FEdgeStyleParameters( + bool bEnableEdgeColor, + bool bEnableColorMap, + float TextureOpacityFactor, + float Brightness, + float Contrast, + float Posterize, + float Saturation, + FLinearColor EdgeColor, + FLinearColor ColorScale, + FLinearColor ColorOffset, + EOculusXRColorMapType InColorMapType, + const TArray& InColorMapGradient, + const FColorLutDesc& InLutDesc) + : bEnableEdgeColor(bEnableEdgeColor) + , bEnableColorMap(bEnableColorMap) + , TextureOpacityFactor(TextureOpacityFactor) + , Brightness(Brightness) + , Contrast(Contrast) + , Posterize(Posterize) + , Saturation(Saturation) + , EdgeColor(EdgeColor) + , ColorScale(ColorScale) + , ColorOffset(ColorOffset) + , ColorMapType(InColorMapType) + , ColorLutDesc(InLutDesc) +{ + bUseColorLuts = (InColorMapType == ColorMapType_ColorLut && InLutDesc.ColorLuts.Num() == 1) + || (InColorMapType == ColorMapType_ColorLut_Interpolated && InLutDesc.ColorLuts.Num() == 2); + if ((InColorMapType == ColorMapType_ColorLut || InColorMapType == ColorMapType_ColorLut_Interpolated) + && !bUseColorLuts) + { + ColorMapType = ColorMapType_None; + } + ColorMapData = GenerateColorMapData(InColorMapType, InColorMapGradient); +}; + +TArray FEdgeStyleParameters::GenerateColorMapData(EOculusXRColorMapType InColorMapType, const TArray& InColorMapGradient) +{ + switch (InColorMapType) + { + case ColorMapType_GrayscaleToColor: + { + TArray NewColorMapData = GenerateMonoBrightnessContrastPosterizeMap(); + return GenerateMonoToRGBA(InColorMapGradient, NewColorMapData); + } + case ColorMapType_Grayscale: + return GenerateMonoBrightnessContrastPosterizeMap(); + case ColorMapType_ColorAdjustment: + return GenerateBrightnessContrastSaturationColorMap(); + default: + return TArray(); + } +} + +TArray FEdgeStyleParameters::GenerateMonoToRGBA(const TArray& InColorMapGradient, const TArray& InColorMapData) +{ + TArray NewColorMapData; + FInterpCurveLinearColor InterpCurve; + const uint32 TotalEntries = 256; + + for (int32 Index = 0; Index < InColorMapGradient.Num(); ++Index) + { + InterpCurve.AddPoint(Index, (InColorMapGradient[Index] * ColorScale) + ColorOffset); + } + + NewColorMapData.SetNum(TotalEntries * sizeof(ovrpColorf)); + uint8* Dest = NewColorMapData.GetData(); + for (int32 Index = 0; Index < TotalEntries; ++Index) + { + const ovrpColorf Color = OculusXRHMD::ToOvrpColorf(InterpCurve.Eval(InColorMapData[Index])); + FMemory::Memcpy(Dest, &Color, sizeof(Color)); + Dest += sizeof(ovrpColorf); + } + return NewColorMapData; +} + +TArray FEdgeStyleParameters::GenerateMonoBrightnessContrastPosterizeMap() +{ + TArray NewColorMapData; + const int32 TotalEntries = 256; + NewColorMapData.SetNum(TotalEntries * sizeof(uint8)); + for (int32 Index = 0; Index < TotalEntries; ++Index) + { + float Alpha = ((float)Index / TotalEntries); + float ContrastFactor = Contrast + 1.0; + Alpha = (Alpha - 0.5) * ContrastFactor + 0.5 + Brightness; + + if (Posterize > 0.0f) + { + const float PosterizationBase = 50.0f; + float FinalPosterize = (FMath::Pow(PosterizationBase, Posterize) - 1.0) / (PosterizationBase - 1.0); + Alpha = FMath::RoundToFloat(Alpha / FinalPosterize) * FinalPosterize; + } + + NewColorMapData[Index] = (uint8)(FMath::Min(FMath::Max(Alpha, 0.0f), 1.0f) * 255.0f); + } + return NewColorMapData; +} + +TArray FEdgeStyleParameters::GenerateBrightnessContrastSaturationColorMap() +{ + TArray NewColorMapData; + NewColorMapData.SetNum(3 * sizeof(float)); + float newB = Brightness * 100.0f; + float newC = Contrast + 1.0f; + float newS = Saturation + 1.0f; + + uint8* Dest = NewColorMapData.GetData(); + FMemory::Memcpy(Dest, &newB, sizeof(float)); + Dest += sizeof(float); + FMemory::Memcpy(Dest, &newC, sizeof(float)); + Dest += sizeof(float); + FMemory::Memcpy(Dest, &newS, sizeof(float)); + + return NewColorMapData; +} diff --git a/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRPluginWrapper.cpp b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRPluginWrapper.cpp new file mode 100644 index 0000000..366442b --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRPluginWrapper.cpp @@ -0,0 +1,461 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +#include "OculusXRPluginWrapper.h" +#include "OculusXRHMDModule.h" + +#if PLATFORM_ANDROID +#include +#define MIN_SDK_VERSION 29 +#endif + +DEFINE_LOG_CATEGORY(LogOculusPluginWrapper); + +static void* LoadEntryPoint(void* handle, const char* EntryPointName); + +bool OculusPluginWrapper::InitializeOculusPluginWrapper(OculusPluginWrapper* wrapper) +{ + if (wrapper->IsInitialized()) + { + UE_LOG(LogOculusPluginWrapper, Warning, TEXT("wrapper already initialized")); + return true; + } + +#if OCULUS_HMD_SUPPORTED_PLATFORMS + void* LibraryHandle = nullptr; + +#if PLATFORM_ANDROID + const bool VersionValid = FAndroidMisc::GetAndroidBuildVersion() >= MIN_SDK_VERSION; +#else + const bool VersionValid = true; +#endif + + if (VersionValid) + { + LibraryHandle = FOculusXRHMDModule::GetOVRPluginHandle(); + if (LibraryHandle == nullptr) + { + UE_LOG(LogOculusPluginWrapper, Warning, TEXT("GetOVRPluginHandle() returned NULL")); + return false; + } + } + else + { + return false; + } +#else + return false; +#endif + + struct OculusEntryPoint + { + const char* EntryPointName; + void** EntryPointPtr; + }; + +#define OCULUS_BIND_ENTRY_POINT(Func) { "ovrp_" #Func, (void**)&wrapper->Func } + + OculusEntryPoint entryPointArray[] = { + // OVR_Plugin.h + + OCULUS_BIND_ENTRY_POINT(PreInitialize5), + OCULUS_BIND_ENTRY_POINT(GetInitialized), + OCULUS_BIND_ENTRY_POINT(Initialize7), + OCULUS_BIND_ENTRY_POINT(Shutdown2), + OCULUS_BIND_ENTRY_POINT(SetLogCallback2), + OCULUS_BIND_ENTRY_POINT(GetVersion2), + OCULUS_BIND_ENTRY_POINT(GetNativeSDKVersion2), + OCULUS_BIND_ENTRY_POINT(GetNativeSDKPointer2), + OCULUS_BIND_ENTRY_POINT(GetDisplayAdapterId2), + OCULUS_BIND_ENTRY_POINT(GetAudioOutId2), + OCULUS_BIND_ENTRY_POINT(GetAudioOutDeviceId2), + OCULUS_BIND_ENTRY_POINT(GetAudioInId2), + OCULUS_BIND_ENTRY_POINT(GetAudioInDeviceId2), + OCULUS_BIND_ENTRY_POINT(GetInstanceExtensionsVk), + OCULUS_BIND_ENTRY_POINT(GetDeviceExtensionsVk), + OCULUS_BIND_ENTRY_POINT(SetupDistortionWindow3), + OCULUS_BIND_ENTRY_POINT(DestroyDistortionWindow2), + OCULUS_BIND_ENTRY_POINT(GetDominantHand), + OCULUS_BIND_ENTRY_POINT(SetRemoteHandedness), + OCULUS_BIND_ENTRY_POINT(SetColorScaleAndOffset), + OCULUS_BIND_ENTRY_POINT(SetupLayer), + OCULUS_BIND_ENTRY_POINT(SetupLayerDepth), + OCULUS_BIND_ENTRY_POINT(SetEyeFovPremultipliedAlphaMode), + OCULUS_BIND_ENTRY_POINT(GetEyeFovLayerId), + OCULUS_BIND_ENTRY_POINT(GetLayerTextureStageCount), + OCULUS_BIND_ENTRY_POINT(GetLayerTexture2), + OCULUS_BIND_ENTRY_POINT(GetLayerTextureFoveation), + OCULUS_BIND_ENTRY_POINT(GetLayerOcclusionMesh), + OCULUS_BIND_ENTRY_POINT(GetLayerAndroidSurfaceObject), + OCULUS_BIND_ENTRY_POINT(GetLayerTextureSpaceWarp), + OCULUS_BIND_ENTRY_POINT(CalculateEyeLayerDesc3), + OCULUS_BIND_ENTRY_POINT(DestroyLayer), + OCULUS_BIND_ENTRY_POINT(CalculateLayerDesc), + OCULUS_BIND_ENTRY_POINT(CalculateEyeLayerDesc2), + OCULUS_BIND_ENTRY_POINT(CalculateEyePreviewRect), + OCULUS_BIND_ENTRY_POINT(SetupMirrorTexture2), + OCULUS_BIND_ENTRY_POINT(DestroyMirrorTexture2), + OCULUS_BIND_ENTRY_POINT(GetAdaptiveGpuPerformanceScale2), + OCULUS_BIND_ENTRY_POINT(GetAppCpuStartToGpuEndTime2), + OCULUS_BIND_ENTRY_POINT(GetEyePixelsPerTanAngleAtCenter2), + OCULUS_BIND_ENTRY_POINT(GetHmdToEyeOffset2), + OCULUS_BIND_ENTRY_POINT(Update3), + OCULUS_BIND_ENTRY_POINT(WaitToBeginFrame), + OCULUS_BIND_ENTRY_POINT(BeginFrame4), + OCULUS_BIND_ENTRY_POINT(UpdateFoveation), + OCULUS_BIND_ENTRY_POINT(EndFrame4), + OCULUS_BIND_ENTRY_POINT(GetTrackingOrientationSupported2), + OCULUS_BIND_ENTRY_POINT(GetTrackingOrientationEnabled2), + OCULUS_BIND_ENTRY_POINT(SetTrackingOrientationEnabled2), + OCULUS_BIND_ENTRY_POINT(GetTrackingPositionSupported2), + OCULUS_BIND_ENTRY_POINT(GetTrackingPositionEnabled2), + OCULUS_BIND_ENTRY_POINT(SetTrackingPositionEnabled2), + OCULUS_BIND_ENTRY_POINT(GetTrackingIPDEnabled2), + OCULUS_BIND_ENTRY_POINT(SetTrackingIPDEnabled2), + OCULUS_BIND_ENTRY_POINT(GetTrackingCalibratedOrigin2), + OCULUS_BIND_ENTRY_POINT(SetTrackingCalibratedOrigin2), + OCULUS_BIND_ENTRY_POINT(GetTrackingOriginType2), + OCULUS_BIND_ENTRY_POINT(SetTrackingOriginType2), + OCULUS_BIND_ENTRY_POINT(RecenterTrackingOrigin2), + OCULUS_BIND_ENTRY_POINT(GetNodePresent2), + OCULUS_BIND_ENTRY_POINT(GetNodeOrientationTracked2), + OCULUS_BIND_ENTRY_POINT(GetNodeOrientationValid), + OCULUS_BIND_ENTRY_POINT(GetNodePositionTracked2), + OCULUS_BIND_ENTRY_POINT(GetNodePositionValid), + OCULUS_BIND_ENTRY_POINT(SetNodePositionTracked2), + OCULUS_BIND_ENTRY_POINT(GetNodePoseState3), + OCULUS_BIND_ENTRY_POINT(GetNodePoseStateRaw), + OCULUS_BIND_ENTRY_POINT(GetNodeFrustum2), + OCULUS_BIND_ENTRY_POINT(SetHeadPoseModifier), + OCULUS_BIND_ENTRY_POINT(GetHeadPoseModifier), + OCULUS_BIND_ENTRY_POINT(GetControllerState4), + OCULUS_BIND_ENTRY_POINT(GetControllerState5), + OCULUS_BIND_ENTRY_POINT(GetControllerState6), + OCULUS_BIND_ENTRY_POINT(GetActiveController2), + OCULUS_BIND_ENTRY_POINT(GetConnectedControllers2), + OCULUS_BIND_ENTRY_POINT(SetControllerVibration2), + OCULUS_BIND_ENTRY_POINT(SetControllerLocalizedVibration), + OCULUS_BIND_ENTRY_POINT(SetControllerHapticsAmplitudeEnvelope), + OCULUS_BIND_ENTRY_POINT(SetControllerHapticsPcm), + OCULUS_BIND_ENTRY_POINT(GetControllerHapticsDesc2), + OCULUS_BIND_ENTRY_POINT(GetControllerHapticsState2), + OCULUS_BIND_ENTRY_POINT(GetControllerSampleRateHz), + OCULUS_BIND_ENTRY_POINT(SetControllerHaptics2), + OCULUS_BIND_ENTRY_POINT(SetSuggestedCpuPerformanceLevel), + OCULUS_BIND_ENTRY_POINT(GetSuggestedCpuPerformanceLevel), + OCULUS_BIND_ENTRY_POINT(SetSuggestedGpuPerformanceLevel), + OCULUS_BIND_ENTRY_POINT(GetSuggestedGpuPerformanceLevel), + OCULUS_BIND_ENTRY_POINT(GetAppCPUPriority2), + OCULUS_BIND_ENTRY_POINT(SetAppCPUPriority2), + OCULUS_BIND_ENTRY_POINT(GetSystemPowerSavingMode2), + OCULUS_BIND_ENTRY_POINT(GetSystemDisplayFrequency2), + OCULUS_BIND_ENTRY_POINT(GetSystemDisplayAvailableFrequencies), + OCULUS_BIND_ENTRY_POINT(SetSystemDisplayFrequency), + OCULUS_BIND_ENTRY_POINT(GetSystemVSyncCount2), + OCULUS_BIND_ENTRY_POINT(SetSystemVSyncCount2), + OCULUS_BIND_ENTRY_POINT(GetSystemProductName2), + OCULUS_BIND_ENTRY_POINT(GetSystemRegion2), + OCULUS_BIND_ENTRY_POINT(ShowSystemUI2), + OCULUS_BIND_ENTRY_POINT(GetAppHasVrFocus2), + OCULUS_BIND_ENTRY_POINT(GetAppHasInputFocus), + OCULUS_BIND_ENTRY_POINT(GetAppHasSystemOverlayPresent), + OCULUS_BIND_ENTRY_POINT(GetAppShouldQuit2), + OCULUS_BIND_ENTRY_POINT(GetAppShouldRecenter2), + OCULUS_BIND_ENTRY_POINT(GetAppShouldRecreateDistortionWindow2), + OCULUS_BIND_ENTRY_POINT(GetAppLatencyTimings2), + OCULUS_BIND_ENTRY_POINT(SetAppEngineInfo2), + OCULUS_BIND_ENTRY_POINT(GetUserPresent2), + OCULUS_BIND_ENTRY_POINT(GetUserIPD2), + OCULUS_BIND_ENTRY_POINT(SetUserIPD2), + OCULUS_BIND_ENTRY_POINT(GetUserEyeHeight2), + OCULUS_BIND_ENTRY_POINT(SetUserEyeHeight2), + OCULUS_BIND_ENTRY_POINT(GetUserNeckEyeDistance2), + OCULUS_BIND_ENTRY_POINT(SetUserNeckEyeDistance2), + OCULUS_BIND_ENTRY_POINT(SetupDisplayObjects2), + OCULUS_BIND_ENTRY_POINT(GetSystemMultiViewSupported2), + OCULUS_BIND_ENTRY_POINT(GetEyeTextureArraySupported2), + OCULUS_BIND_ENTRY_POINT(GetBoundaryConfigured2), + OCULUS_BIND_ENTRY_POINT(GetDepthCompositingSupported), + OCULUS_BIND_ENTRY_POINT(TestBoundaryNode2), + OCULUS_BIND_ENTRY_POINT(TestBoundaryPoint2), + OCULUS_BIND_ENTRY_POINT(GetBoundaryGeometry3), + OCULUS_BIND_ENTRY_POINT(GetBoundaryDimensions2), + OCULUS_BIND_ENTRY_POINT(GetBoundaryVisible2), + OCULUS_BIND_ENTRY_POINT(SetBoundaryVisible2), + OCULUS_BIND_ENTRY_POINT(GetSystemHeadsetType2), + OCULUS_BIND_ENTRY_POINT(GetAppPerfStats2), + OCULUS_BIND_ENTRY_POINT(ResetAppPerfStats2), + OCULUS_BIND_ENTRY_POINT(GetAppFramerate2), + OCULUS_BIND_ENTRY_POINT(IsPerfMetricsSupported), + OCULUS_BIND_ENTRY_POINT(GetPerfMetricsFloat), + OCULUS_BIND_ENTRY_POINT(GetPerfMetricsInt), + OCULUS_BIND_ENTRY_POINT(SetHandNodePoseStateLatency), + OCULUS_BIND_ENTRY_POINT(GetHandNodePoseStateLatency), + OCULUS_BIND_ENTRY_POINT(GetSystemRecommendedMSAALevel2), + OCULUS_BIND_ENTRY_POINT(SetInhibitSystemUX2), + OCULUS_BIND_ENTRY_POINT(GetTiledMultiResSupported), + OCULUS_BIND_ENTRY_POINT(GetTiledMultiResLevel), + OCULUS_BIND_ENTRY_POINT(SetTiledMultiResLevel), + OCULUS_BIND_ENTRY_POINT(GetTiledMultiResDynamic), + OCULUS_BIND_ENTRY_POINT(SetTiledMultiResDynamic), + OCULUS_BIND_ENTRY_POINT(GetFoveationEyeTrackedSupported), + OCULUS_BIND_ENTRY_POINT(GetFoveationEyeTracked), + OCULUS_BIND_ENTRY_POINT(SetFoveationEyeTracked), + OCULUS_BIND_ENTRY_POINT(GetFoveationEyeTrackedCenter), + OCULUS_BIND_ENTRY_POINT(GetGPUUtilSupported), + OCULUS_BIND_ENTRY_POINT(GetGPUUtilLevel), + OCULUS_BIND_ENTRY_POINT(SetThreadPerformance), + OCULUS_BIND_ENTRY_POINT(AutoThreadScheduling), + OCULUS_BIND_ENTRY_POINT(GetGPUFrameTime), + OCULUS_BIND_ENTRY_POINT(GetViewportStencil), + OCULUS_BIND_ENTRY_POINT(SetDeveloperTelemetryConsent), + OCULUS_BIND_ENTRY_POINT(SendEvent), + OCULUS_BIND_ENTRY_POINT(SendEvent2), + OCULUS_BIND_ENTRY_POINT(AddCustomMetadata), + OCULUS_BIND_ENTRY_POINT(SetDeveloperMode), + OCULUS_BIND_ENTRY_POINT(GetCurrentTrackingTransformPose), + OCULUS_BIND_ENTRY_POINT(GetTrackingTransformRawPose), + OCULUS_BIND_ENTRY_POINT(GetTrackingTransformRelativePose), + OCULUS_BIND_ENTRY_POINT(GetTimeInSeconds), + //OCULUS_BIND_ENTRY_POINT(GetPTWNear), + OCULUS_BIND_ENTRY_POINT(GetASWVelocityScale), + OCULUS_BIND_ENTRY_POINT(GetASWDepthScale), + OCULUS_BIND_ENTRY_POINT(GetASWAdaptiveMode), + OCULUS_BIND_ENTRY_POINT(SetASWAdaptiveMode), + OCULUS_BIND_ENTRY_POINT(IsRequestingASWData), + OCULUS_BIND_ENTRY_POINT(GetPredictedDisplayTime), + OCULUS_BIND_ENTRY_POINT(GetHandTrackingEnabled), + OCULUS_BIND_ENTRY_POINT(GetHandState), + OCULUS_BIND_ENTRY_POINT(GetHandState2), + OCULUS_BIND_ENTRY_POINT(GetSkeleton2), + OCULUS_BIND_ENTRY_POINT(GetMesh), + OCULUS_BIND_ENTRY_POINT(GetLocalTrackingSpaceRecenterCount), + OCULUS_BIND_ENTRY_POINT(GetSystemHmd3DofModeEnabled), + OCULUS_BIND_ENTRY_POINT(SetClientColorDesc), + OCULUS_BIND_ENTRY_POINT(GetHmdColorDesc), + OCULUS_BIND_ENTRY_POINT(PollEvent), + OCULUS_BIND_ENTRY_POINT(GetNativeXrApiType), + OCULUS_BIND_ENTRY_POINT(GetLocalDimmingSupported), + OCULUS_BIND_ENTRY_POINT(SetLocalDimming), + OCULUS_BIND_ENTRY_POINT(GetCurrentInteractionProfile), + OCULUS_BIND_ENTRY_POINT(GetLayerRecommendedResolution), + OCULUS_BIND_ENTRY_POINT(IsLayerShapeSupported), + OCULUS_BIND_ENTRY_POINT(SetEyeBufferSharpenType), + + OCULUS_BIND_ENTRY_POINT(InitializeEnvironmentDepth), + OCULUS_BIND_ENTRY_POINT(DestroyEnvironmentDepth), + OCULUS_BIND_ENTRY_POINT(GetEnvironmentDepthTextureDesc), + OCULUS_BIND_ENTRY_POINT(GetEnvironmentDepthTextureStageCount), + OCULUS_BIND_ENTRY_POINT(GetEnvironmentDepthTexture), + OCULUS_BIND_ENTRY_POINT(SetEnvironmentDepthHandRemoval), + OCULUS_BIND_ENTRY_POINT(StartEnvironmentDepth), + OCULUS_BIND_ENTRY_POINT(StopEnvironmentDepth), + OCULUS_BIND_ENTRY_POINT(GetEnvironmentDepthFrameDesc), + +#ifndef OVRPLUGIN_JNI_LIB_EXCLUDED + OCULUS_BIND_ENTRY_POINT(GetSystemVolume2), + OCULUS_BIND_ENTRY_POINT(GetSystemHeadphonesPresent2), +#endif + + // Anchors + OCULUS_BIND_ENTRY_POINT(LocateSpace), + OCULUS_BIND_ENTRY_POINT(LocateSpace2), + OCULUS_BIND_ENTRY_POINT(CreateSpatialAnchor), + OCULUS_BIND_ENTRY_POINT(DestroySpace), + OCULUS_BIND_ENTRY_POINT(SetSpaceComponentStatus), + OCULUS_BIND_ENTRY_POINT(GetSpaceComponentStatus), + OCULUS_BIND_ENTRY_POINT(EnumerateSpaceSupportedComponents), + OCULUS_BIND_ENTRY_POINT(QuerySpaces), + OCULUS_BIND_ENTRY_POINT(RetrieveSpaceQueryResults), + OCULUS_BIND_ENTRY_POINT(SaveSpace), + OCULUS_BIND_ENTRY_POINT(EraseSpace), + OCULUS_BIND_ENTRY_POINT(GetSpaceUuid), + OCULUS_BIND_ENTRY_POINT(SaveSpaceList), + OCULUS_BIND_ENTRY_POINT(ShareSpaces), + OCULUS_BIND_ENTRY_POINT(CreateSpaceUser), + OCULUS_BIND_ENTRY_POINT(DestroySpaceUser), + + + // Scene + OCULUS_BIND_ENTRY_POINT(GetSpaceContainer), + OCULUS_BIND_ENTRY_POINT(GetSpaceBoundingBox2D), + OCULUS_BIND_ENTRY_POINT(GetSpaceBoundingBox3D), + OCULUS_BIND_ENTRY_POINT(GetSpaceSemanticLabels), + OCULUS_BIND_ENTRY_POINT(GetSpaceRoomLayout), + OCULUS_BIND_ENTRY_POINT(GetSpaceBoundary2D), + OCULUS_BIND_ENTRY_POINT(RequestSceneCapture), + OCULUS_BIND_ENTRY_POINT(GetSpaceTriangleMesh), + + + + + + // MovementSDK + OCULUS_BIND_ENTRY_POINT(GetBodyTrackingEnabled), + OCULUS_BIND_ENTRY_POINT(GetBodyTrackingSupported), + OCULUS_BIND_ENTRY_POINT(StopBodyTracking), + OCULUS_BIND_ENTRY_POINT(GetBodyState4), + OCULUS_BIND_ENTRY_POINT(GetFullBodyTrackingEnabled), + OCULUS_BIND_ENTRY_POINT(StartBodyTracking2), + OCULUS_BIND_ENTRY_POINT(RequestBodyTrackingFidelity), + OCULUS_BIND_ENTRY_POINT(ResetBodyTrackingCalibration), + OCULUS_BIND_ENTRY_POINT(SuggestBodyTrackingCalibrationOverride), + + OCULUS_BIND_ENTRY_POINT(GetFaceTracking2Enabled), + OCULUS_BIND_ENTRY_POINT(GetFaceTracking2Supported), + OCULUS_BIND_ENTRY_POINT(GetFaceState2), + OCULUS_BIND_ENTRY_POINT(StartFaceTracking2), + OCULUS_BIND_ENTRY_POINT(StopFaceTracking2), + OCULUS_BIND_ENTRY_POINT(GetEyeTrackingEnabled), + OCULUS_BIND_ENTRY_POINT(GetEyeTrackingSupported), + OCULUS_BIND_ENTRY_POINT(GetEyeGazesState), + OCULUS_BIND_ENTRY_POINT(StartEyeTracking), + OCULUS_BIND_ENTRY_POINT(StopEyeTracking), + + // QPL + OCULUS_BIND_ENTRY_POINT(QplMarkerStart), + OCULUS_BIND_ENTRY_POINT(QplMarkerEnd), + OCULUS_BIND_ENTRY_POINT(QplMarkerPoint), + OCULUS_BIND_ENTRY_POINT(QplMarkerPointCached), + OCULUS_BIND_ENTRY_POINT(QplMarkerAnnotation), + OCULUS_BIND_ENTRY_POINT(QplCreateMarkerHandle), + OCULUS_BIND_ENTRY_POINT(QplDestroyMarkerHandle), + OCULUS_BIND_ENTRY_POINT(OnEditorShutdown), + OCULUS_BIND_ENTRY_POINT(QplSetConsent), + + // OVR_Plugin_Insight.h + OCULUS_BIND_ENTRY_POINT(InitializeInsightPassthrough), + OCULUS_BIND_ENTRY_POINT(ShutdownInsightPassthrough), + OCULUS_BIND_ENTRY_POINT(GetInsightPassthroughInitialized), + OCULUS_BIND_ENTRY_POINT(GetInsightPassthroughInitializationState), + OCULUS_BIND_ENTRY_POINT(CreateInsightTriangleMesh), + OCULUS_BIND_ENTRY_POINT(DestroyInsightTriangleMesh), + OCULUS_BIND_ENTRY_POINT(AddInsightPassthroughSurfaceGeometry), + OCULUS_BIND_ENTRY_POINT(DestroyInsightPassthroughGeometryInstance), + OCULUS_BIND_ENTRY_POINT(UpdateInsightPassthroughGeometryTransform), + OCULUS_BIND_ENTRY_POINT(SetInsightPassthroughStyle), + OCULUS_BIND_ENTRY_POINT(SetInsightPassthroughStyle2), + OCULUS_BIND_ENTRY_POINT(GetPassthroughCapabilityFlags), + OCULUS_BIND_ENTRY_POINT(CreatePassthroughColorLut), + OCULUS_BIND_ENTRY_POINT(DestroyPassthroughColorLut), + OCULUS_BIND_ENTRY_POINT(UpdatePassthroughColorLut), + OCULUS_BIND_ENTRY_POINT(GetPassthroughCapabilities), + OCULUS_BIND_ENTRY_POINT(GetPassthroughPreferences), + + // OVR_Plugin_MixedReality.h + + OCULUS_BIND_ENTRY_POINT(InitializeMixedReality), + OCULUS_BIND_ENTRY_POINT(ShutdownMixedReality), + OCULUS_BIND_ENTRY_POINT(GetMixedRealityInitialized), + OCULUS_BIND_ENTRY_POINT(UpdateExternalCamera), + OCULUS_BIND_ENTRY_POINT(GetExternalCameraCount), + OCULUS_BIND_ENTRY_POINT(GetExternalCameraName), + OCULUS_BIND_ENTRY_POINT(GetExternalCameraIntrinsics), + OCULUS_BIND_ENTRY_POINT(GetExternalCameraExtrinsics), + + // OVR_Plugin_Media.h + + OCULUS_BIND_ENTRY_POINT(Media_Initialize), + OCULUS_BIND_ENTRY_POINT(Media_Shutdown), + OCULUS_BIND_ENTRY_POINT(Media_GetInitialized), + OCULUS_BIND_ENTRY_POINT(Media_Update), + OCULUS_BIND_ENTRY_POINT(Media_GetMrcActivationMode), + OCULUS_BIND_ENTRY_POINT(Media_SetMrcActivationMode), + OCULUS_BIND_ENTRY_POINT(Media_IsMrcEnabled), + OCULUS_BIND_ENTRY_POINT(Media_IsMrcActivated), + OCULUS_BIND_ENTRY_POINT(Media_UseMrcDebugCamera), + OCULUS_BIND_ENTRY_POINT(Media_SetMrcInputVideoBufferType), + OCULUS_BIND_ENTRY_POINT(Media_GetMrcInputVideoBufferType), + OCULUS_BIND_ENTRY_POINT(Media_SetMrcFrameSize), + OCULUS_BIND_ENTRY_POINT(Media_GetMrcFrameSize), + OCULUS_BIND_ENTRY_POINT(Media_SetMrcAudioSampleRate), + OCULUS_BIND_ENTRY_POINT(Media_GetMrcAudioSampleRate), + OCULUS_BIND_ENTRY_POINT(Media_SetMrcFrameImageFlipped), + OCULUS_BIND_ENTRY_POINT(Media_GetMrcFrameImageFlipped), + OCULUS_BIND_ENTRY_POINT(Media_SetMrcFrameInverseAlpha), + OCULUS_BIND_ENTRY_POINT(Media_GetMrcFrameInverseAlpha), + OCULUS_BIND_ENTRY_POINT(Media_SetAvailableQueueIndexVulkan), + OCULUS_BIND_ENTRY_POINT(Media_EncodeMrcFrame), + OCULUS_BIND_ENTRY_POINT(Media_EncodeMrcFrameWithDualTextures), + OCULUS_BIND_ENTRY_POINT(Media_SyncMrcFrame), + OCULUS_BIND_ENTRY_POINT(Media_EncodeMrcFrameWithPoseTime), + OCULUS_BIND_ENTRY_POINT(Media_EncodeMrcFrameDualTexturesWithPoseTime), + OCULUS_BIND_ENTRY_POINT(Media_SetHeadsetControllerPose), + OCULUS_BIND_ENTRY_POINT(Media_EnumerateCameraAnchorHandles), + OCULUS_BIND_ENTRY_POINT(Media_GetCurrentCameraAnchorHandle), + OCULUS_BIND_ENTRY_POINT(Media_GetCameraAnchorName), + OCULUS_BIND_ENTRY_POINT(Media_GetCameraAnchorHandle), + OCULUS_BIND_ENTRY_POINT(Media_GetCameraAnchorType), + OCULUS_BIND_ENTRY_POINT(Media_CreateCustomCameraAnchor), + OCULUS_BIND_ENTRY_POINT(Media_DestroyCustomCameraAnchor), + OCULUS_BIND_ENTRY_POINT(Media_GetCustomCameraAnchorPose), + OCULUS_BIND_ENTRY_POINT(Media_SetCustomCameraAnchorPose), + OCULUS_BIND_ENTRY_POINT(Media_GetCameraMinMaxDistance), + OCULUS_BIND_ENTRY_POINT(Media_SetCameraMinMaxDistance), + + OCULUS_BIND_ENTRY_POINT(SetControllerDrivenHandPoses), + OCULUS_BIND_ENTRY_POINT(SetControllerDrivenHandPosesAreNatural), + }; + +#undef OCULUS_BIND_ENTRY_POINT + + bool result = true; + for (int i = 0; i < UE_ARRAY_COUNT(entryPointArray); ++i) + { + *(entryPointArray[i].EntryPointPtr) = LoadEntryPoint(LibraryHandle, entryPointArray[i].EntryPointName); + + if (*entryPointArray[i].EntryPointPtr == nullptr) + { + UE_LOG(LogOculusPluginWrapper, Error, TEXT("OculusPlugin EntryPoint could not be loaded: %s"), ANSI_TO_TCHAR(entryPointArray[i].EntryPointName)); + result = false; + } + } + + wrapper->Initialized = true; + + if (result) + { + UE_LOG(LogOculusPluginWrapper, Log, TEXT("OculusPlugin initialized successfully")); + } + else + { + DestroyOculusPluginWrapper(wrapper); + } + + return result; +} + +void OculusPluginWrapper::DestroyOculusPluginWrapper(OculusPluginWrapper* wrapper) +{ + if (!wrapper->Initialized) + return; + + wrapper->Reset(); + + UE_LOG(LogOculusPluginWrapper, Log, TEXT("OculusPlugin destroyed successfully")); +} + +static void* LoadEntryPoint(void* Handle, const char* EntryPointName) +{ + if (Handle == nullptr) + return nullptr; + +#if PLATFORM_WINDOWS + void* ptr = GetProcAddress((HMODULE)Handle, EntryPointName); + if (ptr == nullptr) + { + UE_LOG(LogOculusPluginWrapper, Error, TEXT("Unable to load entry point: %s"), ANSI_TO_TCHAR(EntryPointName)); + } + return ptr; +#elif PLATFORM_ANDROID + void* ptr = dlsym(Handle, EntryPointName); + if (ptr == nullptr) + { + UE_LOG(LogOculusPluginWrapper, Error, TEXT("Unable to load entry point: %s, error %s"), ANSI_TO_TCHAR(EntryPointName), ANSI_TO_TCHAR(dlerror())); + } + return ptr; +#else + UE_LOG(LogOculusPluginWrapper, Error, TEXT("LoadEntryPoint: Unsupported platform")); + return nullptr; +#endif +} diff --git a/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRPluginWrapper.h b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRPluginWrapper.h new file mode 100644 index 0000000..839611d --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRPluginWrapper.h @@ -0,0 +1,414 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CoreMinimal.h" +#include + +#if PLATFORM_SUPPORTS_PRAGMA_PACK +#pragma pack(push, 8) +#endif + +#if PLATFORM_WINDOWS +#include "Windows/AllowWindowsPlatformTypes.h" +#endif + +#pragma warning(push) +#pragma warning(disable : 4201) // nonstandard extension used: nameless struct/union +//#pragma warning(disable:4668) // 'symbol' is not defined as a preprocessor macro, replacing with '0' for 'directives' +#define OVRP_EXPORT typedef +#include "OVR_Plugin.h" +#include "OVR_Plugin_Insight.h" +#include "OVR_Plugin_MixedReality.h" +#include "OVR_Plugin_Media.h" +#undef OVRP_EXPORT +#pragma warning(pop) + +#if PLATFORM_WINDOWS +#include "Windows/HideWindowsPlatformTypes.h" +#endif + +#if PLATFORM_SUPPORTS_PRAGMA_PACK +#pragma pack(pop) +#endif + +#if PLATFORM_WINDOWS +#include "Windows/WindowsHWrapper.h" +#endif + +DECLARE_LOG_CATEGORY_EXTERN(LogOculusPluginWrapper, Log, All); + +#define OCULUS_DECLARE_ENTRY_POINT(Func) ovrp_##Func* Func + +struct OculusPluginWrapper +{ + OculusPluginWrapper() + { + Reset(); + } + + void Reset() + { + memset(this, 0, sizeof(OculusPluginWrapper)); + ovrpHeaderVersion.MajorVersion = OVRP_MAJOR_VERSION; + ovrpHeaderVersion.MinorVersion = OVRP_MINOR_VERSION; + ovrpHeaderVersion.PatchVersion = OVRP_PATCH_VERSION; + } + + bool IsInitialized() const + { + return Initialized; + } + + // OVR_Plugin.h + + OCULUS_DECLARE_ENTRY_POINT(PreInitialize5); + OCULUS_DECLARE_ENTRY_POINT(GetInitialized); + OCULUS_DECLARE_ENTRY_POINT(Initialize7); + OCULUS_DECLARE_ENTRY_POINT(Shutdown2); + OCULUS_DECLARE_ENTRY_POINT(SetLogCallback2); + OCULUS_DECLARE_ENTRY_POINT(GetVersion2); + OCULUS_DECLARE_ENTRY_POINT(GetNativeSDKVersion2); + OCULUS_DECLARE_ENTRY_POINT(GetNativeSDKPointer2); + OCULUS_DECLARE_ENTRY_POINT(GetDisplayAdapterId2); + OCULUS_DECLARE_ENTRY_POINT(GetAudioOutId2); + OCULUS_DECLARE_ENTRY_POINT(GetAudioOutDeviceId2); + OCULUS_DECLARE_ENTRY_POINT(GetAudioInId2); + OCULUS_DECLARE_ENTRY_POINT(GetAudioInDeviceId2); + OCULUS_DECLARE_ENTRY_POINT(GetInstanceExtensionsVk); + OCULUS_DECLARE_ENTRY_POINT(GetDeviceExtensionsVk); + OCULUS_DECLARE_ENTRY_POINT(SetupDistortionWindow3); + OCULUS_DECLARE_ENTRY_POINT(DestroyDistortionWindow2); + OCULUS_DECLARE_ENTRY_POINT(GetDominantHand); + OCULUS_DECLARE_ENTRY_POINT(SetRemoteHandedness); + OCULUS_DECLARE_ENTRY_POINT(SetColorScaleAndOffset); + OCULUS_DECLARE_ENTRY_POINT(SetupLayer); + OCULUS_DECLARE_ENTRY_POINT(SetupLayerDepth); + OCULUS_DECLARE_ENTRY_POINT(SetEyeFovPremultipliedAlphaMode); + OCULUS_DECLARE_ENTRY_POINT(GetEyeFovLayerId); + OCULUS_DECLARE_ENTRY_POINT(GetLayerTextureStageCount); + OCULUS_DECLARE_ENTRY_POINT(GetLayerTexture2); + OCULUS_DECLARE_ENTRY_POINT(GetLayerTextureFoveation); + OCULUS_DECLARE_ENTRY_POINT(GetLayerTextureSpaceWarp); + OCULUS_DECLARE_ENTRY_POINT(CalculateEyeLayerDesc3); + OCULUS_DECLARE_ENTRY_POINT(GetLayerAndroidSurfaceObject); + OCULUS_DECLARE_ENTRY_POINT(GetLayerOcclusionMesh); + OCULUS_DECLARE_ENTRY_POINT(DestroyLayer); + OCULUS_DECLARE_ENTRY_POINT(CalculateLayerDesc); + OCULUS_DECLARE_ENTRY_POINT(CalculateEyeLayerDesc2); + OCULUS_DECLARE_ENTRY_POINT(CalculateEyePreviewRect); + OCULUS_DECLARE_ENTRY_POINT(SetupMirrorTexture2); + OCULUS_DECLARE_ENTRY_POINT(DestroyMirrorTexture2); + OCULUS_DECLARE_ENTRY_POINT(GetAdaptiveGpuPerformanceScale2); + OCULUS_DECLARE_ENTRY_POINT(GetAppCpuStartToGpuEndTime2); + OCULUS_DECLARE_ENTRY_POINT(GetEyePixelsPerTanAngleAtCenter2); + OCULUS_DECLARE_ENTRY_POINT(GetHmdToEyeOffset2); + OCULUS_DECLARE_ENTRY_POINT(Update3); + OCULUS_DECLARE_ENTRY_POINT(WaitToBeginFrame); + OCULUS_DECLARE_ENTRY_POINT(BeginFrame4); + OCULUS_DECLARE_ENTRY_POINT(UpdateFoveation); + OCULUS_DECLARE_ENTRY_POINT(EndFrame4); + OCULUS_DECLARE_ENTRY_POINT(GetTrackingOrientationSupported2); + OCULUS_DECLARE_ENTRY_POINT(GetTrackingOrientationEnabled2); + OCULUS_DECLARE_ENTRY_POINT(SetTrackingOrientationEnabled2); + OCULUS_DECLARE_ENTRY_POINT(GetTrackingPositionSupported2); + OCULUS_DECLARE_ENTRY_POINT(GetTrackingPositionEnabled2); + OCULUS_DECLARE_ENTRY_POINT(SetTrackingPositionEnabled2); + OCULUS_DECLARE_ENTRY_POINT(GetTrackingIPDEnabled2); + OCULUS_DECLARE_ENTRY_POINT(SetTrackingIPDEnabled2); + OCULUS_DECLARE_ENTRY_POINT(GetTrackingCalibratedOrigin2); + OCULUS_DECLARE_ENTRY_POINT(SetTrackingCalibratedOrigin2); + OCULUS_DECLARE_ENTRY_POINT(GetTrackingOriginType2); + OCULUS_DECLARE_ENTRY_POINT(SetTrackingOriginType2); + OCULUS_DECLARE_ENTRY_POINT(RecenterTrackingOrigin2); + OCULUS_DECLARE_ENTRY_POINT(GetNodePresent2); + OCULUS_DECLARE_ENTRY_POINT(GetNodeOrientationTracked2); + OCULUS_DECLARE_ENTRY_POINT(GetNodeOrientationValid); + OCULUS_DECLARE_ENTRY_POINT(GetNodePositionTracked2); + OCULUS_DECLARE_ENTRY_POINT(GetNodePositionValid); + OCULUS_DECLARE_ENTRY_POINT(SetNodePositionTracked2); + OCULUS_DECLARE_ENTRY_POINT(GetNodePoseState3); + OCULUS_DECLARE_ENTRY_POINT(GetNodePoseStateRaw); + OCULUS_DECLARE_ENTRY_POINT(GetNodeFrustum2); + OCULUS_DECLARE_ENTRY_POINT(SetHeadPoseModifier); + OCULUS_DECLARE_ENTRY_POINT(GetHeadPoseModifier); + OCULUS_DECLARE_ENTRY_POINT(GetControllerState4); + OCULUS_DECLARE_ENTRY_POINT(GetControllerState5); + OCULUS_DECLARE_ENTRY_POINT(GetControllerState6); + OCULUS_DECLARE_ENTRY_POINT(GetActiveController2); + OCULUS_DECLARE_ENTRY_POINT(GetConnectedControllers2); + OCULUS_DECLARE_ENTRY_POINT(SetControllerVibration2); + OCULUS_DECLARE_ENTRY_POINT(SetControllerLocalizedVibration); + OCULUS_DECLARE_ENTRY_POINT(SetControllerHapticsAmplitudeEnvelope); + OCULUS_DECLARE_ENTRY_POINT(SetControllerHapticsPcm); + OCULUS_DECLARE_ENTRY_POINT(GetControllerHapticsDesc2); + OCULUS_DECLARE_ENTRY_POINT(GetControllerHapticsState2); + OCULUS_DECLARE_ENTRY_POINT(GetControllerSampleRateHz); + OCULUS_DECLARE_ENTRY_POINT(SetControllerHaptics2); + OCULUS_DECLARE_ENTRY_POINT(SetSuggestedCpuPerformanceLevel); + OCULUS_DECLARE_ENTRY_POINT(GetSuggestedCpuPerformanceLevel); + OCULUS_DECLARE_ENTRY_POINT(SetSuggestedGpuPerformanceLevel); + OCULUS_DECLARE_ENTRY_POINT(GetSuggestedGpuPerformanceLevel); + OCULUS_DECLARE_ENTRY_POINT(GetAppCPUPriority2); + OCULUS_DECLARE_ENTRY_POINT(SetAppCPUPriority2); + OCULUS_DECLARE_ENTRY_POINT(GetSystemPowerSavingMode2); + OCULUS_DECLARE_ENTRY_POINT(GetSystemDisplayFrequency2); + OCULUS_DECLARE_ENTRY_POINT(GetSystemDisplayAvailableFrequencies); + OCULUS_DECLARE_ENTRY_POINT(SetSystemDisplayFrequency); + OCULUS_DECLARE_ENTRY_POINT(GetSystemVSyncCount2); + OCULUS_DECLARE_ENTRY_POINT(SetSystemVSyncCount2); + OCULUS_DECLARE_ENTRY_POINT(GetSystemProductName2); + OCULUS_DECLARE_ENTRY_POINT(GetSystemRegion2); + OCULUS_DECLARE_ENTRY_POINT(ShowSystemUI2); + OCULUS_DECLARE_ENTRY_POINT(GetAppHasVrFocus2); + OCULUS_DECLARE_ENTRY_POINT(GetAppHasInputFocus); + OCULUS_DECLARE_ENTRY_POINT(GetAppHasSystemOverlayPresent); + OCULUS_DECLARE_ENTRY_POINT(GetAppShouldQuit2); + OCULUS_DECLARE_ENTRY_POINT(GetAppShouldRecenter2); + OCULUS_DECLARE_ENTRY_POINT(GetAppShouldRecreateDistortionWindow2); + OCULUS_DECLARE_ENTRY_POINT(GetAppLatencyTimings2); + OCULUS_DECLARE_ENTRY_POINT(SetAppEngineInfo2); + OCULUS_DECLARE_ENTRY_POINT(GetUserPresent2); + OCULUS_DECLARE_ENTRY_POINT(GetUserIPD2); + OCULUS_DECLARE_ENTRY_POINT(SetUserIPD2); + OCULUS_DECLARE_ENTRY_POINT(GetUserEyeHeight2); + OCULUS_DECLARE_ENTRY_POINT(SetUserEyeHeight2); + OCULUS_DECLARE_ENTRY_POINT(GetUserNeckEyeDistance2); + OCULUS_DECLARE_ENTRY_POINT(SetUserNeckEyeDistance2); + OCULUS_DECLARE_ENTRY_POINT(SetupDisplayObjects2); + OCULUS_DECLARE_ENTRY_POINT(GetSystemMultiViewSupported2); + OCULUS_DECLARE_ENTRY_POINT(GetEyeTextureArraySupported2); + OCULUS_DECLARE_ENTRY_POINT(GetBoundaryConfigured2); + OCULUS_DECLARE_ENTRY_POINT(GetDepthCompositingSupported); + OCULUS_DECLARE_ENTRY_POINT(TestBoundaryNode2); + OCULUS_DECLARE_ENTRY_POINT(TestBoundaryPoint2); + OCULUS_DECLARE_ENTRY_POINT(GetBoundaryGeometry3); + OCULUS_DECLARE_ENTRY_POINT(GetBoundaryDimensions2); + OCULUS_DECLARE_ENTRY_POINT(GetBoundaryVisible2); + OCULUS_DECLARE_ENTRY_POINT(SetBoundaryVisible2); + OCULUS_DECLARE_ENTRY_POINT(GetSystemHeadsetType2); + OCULUS_DECLARE_ENTRY_POINT(GetAppPerfStats2); + OCULUS_DECLARE_ENTRY_POINT(ResetAppPerfStats2); + OCULUS_DECLARE_ENTRY_POINT(GetAppFramerate2); + OCULUS_DECLARE_ENTRY_POINT(IsPerfMetricsSupported); + OCULUS_DECLARE_ENTRY_POINT(GetPerfMetricsFloat); + OCULUS_DECLARE_ENTRY_POINT(GetPerfMetricsInt); + OCULUS_DECLARE_ENTRY_POINT(SetHandNodePoseStateLatency); + OCULUS_DECLARE_ENTRY_POINT(GetHandNodePoseStateLatency); + OCULUS_DECLARE_ENTRY_POINT(GetSystemRecommendedMSAALevel2); + OCULUS_DECLARE_ENTRY_POINT(SetInhibitSystemUX2); + OCULUS_DECLARE_ENTRY_POINT(GetTiledMultiResSupported); + OCULUS_DECLARE_ENTRY_POINT(GetTiledMultiResLevel); + OCULUS_DECLARE_ENTRY_POINT(SetTiledMultiResLevel); + OCULUS_DECLARE_ENTRY_POINT(GetTiledMultiResDynamic); + OCULUS_DECLARE_ENTRY_POINT(SetTiledMultiResDynamic); + OCULUS_DECLARE_ENTRY_POINT(GetFoveationEyeTrackedSupported); + OCULUS_DECLARE_ENTRY_POINT(GetFoveationEyeTracked); + OCULUS_DECLARE_ENTRY_POINT(SetFoveationEyeTracked); + OCULUS_DECLARE_ENTRY_POINT(GetFoveationEyeTrackedCenter); + OCULUS_DECLARE_ENTRY_POINT(GetGPUUtilSupported); + OCULUS_DECLARE_ENTRY_POINT(GetGPUUtilLevel); + OCULUS_DECLARE_ENTRY_POINT(SetThreadPerformance); + OCULUS_DECLARE_ENTRY_POINT(AutoThreadScheduling); + OCULUS_DECLARE_ENTRY_POINT(GetGPUFrameTime); + OCULUS_DECLARE_ENTRY_POINT(GetViewportStencil); + OCULUS_DECLARE_ENTRY_POINT(SetDeveloperTelemetryConsent); + OCULUS_DECLARE_ENTRY_POINT(SendEvent); + OCULUS_DECLARE_ENTRY_POINT(SendEvent2); + OCULUS_DECLARE_ENTRY_POINT(AddCustomMetadata); + OCULUS_DECLARE_ENTRY_POINT(SetDeveloperMode); + OCULUS_DECLARE_ENTRY_POINT(GetCurrentTrackingTransformPose); + OCULUS_DECLARE_ENTRY_POINT(GetTrackingTransformRawPose); + OCULUS_DECLARE_ENTRY_POINT(GetTrackingTransformRelativePose); + OCULUS_DECLARE_ENTRY_POINT(GetTimeInSeconds); + //OCULUS_DECLARE_ENTRY_POINT(GetPTWNear); + OCULUS_DECLARE_ENTRY_POINT(GetASWVelocityScale); + OCULUS_DECLARE_ENTRY_POINT(GetASWDepthScale); + OCULUS_DECLARE_ENTRY_POINT(GetASWAdaptiveMode); + OCULUS_DECLARE_ENTRY_POINT(SetASWAdaptiveMode); + OCULUS_DECLARE_ENTRY_POINT(IsRequestingASWData); + OCULUS_DECLARE_ENTRY_POINT(GetPredictedDisplayTime); + OCULUS_DECLARE_ENTRY_POINT(GetHandTrackingEnabled); + OCULUS_DECLARE_ENTRY_POINT(GetHandState); + OCULUS_DECLARE_ENTRY_POINT(GetHandState2); + OCULUS_DECLARE_ENTRY_POINT(GetSkeleton2); + OCULUS_DECLARE_ENTRY_POINT(GetMesh); + OCULUS_DECLARE_ENTRY_POINT(GetLocalTrackingSpaceRecenterCount); + OCULUS_DECLARE_ENTRY_POINT(GetSystemHmd3DofModeEnabled); + OCULUS_DECLARE_ENTRY_POINT(SetClientColorDesc); + OCULUS_DECLARE_ENTRY_POINT(GetHmdColorDesc); + OCULUS_DECLARE_ENTRY_POINT(PollEvent); + + OCULUS_DECLARE_ENTRY_POINT(GetNativeXrApiType); + OCULUS_DECLARE_ENTRY_POINT(GetLocalDimmingSupported); + OCULUS_DECLARE_ENTRY_POINT(SetLocalDimming); + OCULUS_DECLARE_ENTRY_POINT(GetCurrentInteractionProfile); + OCULUS_DECLARE_ENTRY_POINT(GetLayerRecommendedResolution); + OCULUS_DECLARE_ENTRY_POINT(IsLayerShapeSupported); + OCULUS_DECLARE_ENTRY_POINT(SetEyeBufferSharpenType); + + OCULUS_DECLARE_ENTRY_POINT(InitializeEnvironmentDepth); + OCULUS_DECLARE_ENTRY_POINT(DestroyEnvironmentDepth); + OCULUS_DECLARE_ENTRY_POINT(GetEnvironmentDepthTextureDesc); + OCULUS_DECLARE_ENTRY_POINT(GetEnvironmentDepthTextureStageCount); + OCULUS_DECLARE_ENTRY_POINT(GetEnvironmentDepthTexture); + OCULUS_DECLARE_ENTRY_POINT(SetEnvironmentDepthHandRemoval); + OCULUS_DECLARE_ENTRY_POINT(StartEnvironmentDepth); + OCULUS_DECLARE_ENTRY_POINT(StopEnvironmentDepth); + OCULUS_DECLARE_ENTRY_POINT(GetEnvironmentDepthFrameDesc); + +#ifndef OVRPLUGIN_JNI_LIB_EXCLUDED + OCULUS_DECLARE_ENTRY_POINT(GetSystemVolume2); + OCULUS_DECLARE_ENTRY_POINT(GetSystemHeadphonesPresent2); +#endif + + // Anchors + OCULUS_DECLARE_ENTRY_POINT(LocateSpace); + OCULUS_DECLARE_ENTRY_POINT(LocateSpace2); + OCULUS_DECLARE_ENTRY_POINT(CreateSpatialAnchor); + OCULUS_DECLARE_ENTRY_POINT(DestroySpace); + OCULUS_DECLARE_ENTRY_POINT(SetSpaceComponentStatus); + OCULUS_DECLARE_ENTRY_POINT(GetSpaceComponentStatus); + OCULUS_DECLARE_ENTRY_POINT(EnumerateSpaceSupportedComponents); + OCULUS_DECLARE_ENTRY_POINT(QuerySpaces); + OCULUS_DECLARE_ENTRY_POINT(RetrieveSpaceQueryResults); + OCULUS_DECLARE_ENTRY_POINT(SaveSpace); + OCULUS_DECLARE_ENTRY_POINT(EraseSpace); + OCULUS_DECLARE_ENTRY_POINT(GetSpaceUuid); + OCULUS_DECLARE_ENTRY_POINT(SaveSpaceList); + OCULUS_DECLARE_ENTRY_POINT(ShareSpaces); + OCULUS_DECLARE_ENTRY_POINT(CreateSpaceUser); + OCULUS_DECLARE_ENTRY_POINT(DestroySpaceUser); + + + // Scene + OCULUS_DECLARE_ENTRY_POINT(GetSpaceContainer); + OCULUS_DECLARE_ENTRY_POINT(GetSpaceBoundingBox2D); + OCULUS_DECLARE_ENTRY_POINT(GetSpaceBoundingBox3D); + OCULUS_DECLARE_ENTRY_POINT(GetSpaceSemanticLabels); + OCULUS_DECLARE_ENTRY_POINT(GetSpaceRoomLayout); + OCULUS_DECLARE_ENTRY_POINT(GetSpaceBoundary2D); + OCULUS_DECLARE_ENTRY_POINT(RequestSceneCapture); + OCULUS_DECLARE_ENTRY_POINT(GetSpaceTriangleMesh); + + + + + // Local Groups + + // MovementSDK + OCULUS_DECLARE_ENTRY_POINT(GetBodyTrackingEnabled); + OCULUS_DECLARE_ENTRY_POINT(GetBodyTrackingSupported); + OCULUS_DECLARE_ENTRY_POINT(StopBodyTracking); + OCULUS_DECLARE_ENTRY_POINT(GetBodyState4); + OCULUS_DECLARE_ENTRY_POINT(GetFullBodyTrackingEnabled); + OCULUS_DECLARE_ENTRY_POINT(StartBodyTracking2); + OCULUS_DECLARE_ENTRY_POINT(RequestBodyTrackingFidelity); + OCULUS_DECLARE_ENTRY_POINT(ResetBodyTrackingCalibration); + OCULUS_DECLARE_ENTRY_POINT(SuggestBodyTrackingCalibrationOverride); + + OCULUS_DECLARE_ENTRY_POINT(GetFaceTracking2Enabled); + OCULUS_DECLARE_ENTRY_POINT(GetFaceTracking2Supported); + OCULUS_DECLARE_ENTRY_POINT(GetFaceState2); + OCULUS_DECLARE_ENTRY_POINT(StartFaceTracking2); + OCULUS_DECLARE_ENTRY_POINT(StopFaceTracking2); + OCULUS_DECLARE_ENTRY_POINT(GetEyeTrackingEnabled); + OCULUS_DECLARE_ENTRY_POINT(GetEyeTrackingSupported); + OCULUS_DECLARE_ENTRY_POINT(GetEyeGazesState); + OCULUS_DECLARE_ENTRY_POINT(StartEyeTracking); + OCULUS_DECLARE_ENTRY_POINT(StopEyeTracking); + + // QPL + OCULUS_DECLARE_ENTRY_POINT(QplMarkerStart); + OCULUS_DECLARE_ENTRY_POINT(QplMarkerEnd); + OCULUS_DECLARE_ENTRY_POINT(QplMarkerPoint); + OCULUS_DECLARE_ENTRY_POINT(QplMarkerPointCached); + OCULUS_DECLARE_ENTRY_POINT(QplMarkerAnnotation); + OCULUS_DECLARE_ENTRY_POINT(QplCreateMarkerHandle); + OCULUS_DECLARE_ENTRY_POINT(QplDestroyMarkerHandle); + OCULUS_DECLARE_ENTRY_POINT(OnEditorShutdown); + OCULUS_DECLARE_ENTRY_POINT(QplSetConsent); + + //OVR_Plugin_Insight.h + OCULUS_DECLARE_ENTRY_POINT(InitializeInsightPassthrough); + OCULUS_DECLARE_ENTRY_POINT(ShutdownInsightPassthrough); + OCULUS_DECLARE_ENTRY_POINT(GetInsightPassthroughInitialized); + OCULUS_DECLARE_ENTRY_POINT(GetInsightPassthroughInitializationState); + OCULUS_DECLARE_ENTRY_POINT(CreateInsightTriangleMesh); + OCULUS_DECLARE_ENTRY_POINT(DestroyInsightTriangleMesh); + OCULUS_DECLARE_ENTRY_POINT(AddInsightPassthroughSurfaceGeometry); + OCULUS_DECLARE_ENTRY_POINT(DestroyInsightPassthroughGeometryInstance); + OCULUS_DECLARE_ENTRY_POINT(UpdateInsightPassthroughGeometryTransform); + OCULUS_DECLARE_ENTRY_POINT(SetInsightPassthroughStyle); + OCULUS_DECLARE_ENTRY_POINT(SetInsightPassthroughStyle2); + OCULUS_DECLARE_ENTRY_POINT(GetPassthroughCapabilityFlags); + OCULUS_DECLARE_ENTRY_POINT(CreatePassthroughColorLut); + OCULUS_DECLARE_ENTRY_POINT(DestroyPassthroughColorLut); + OCULUS_DECLARE_ENTRY_POINT(UpdatePassthroughColorLut); + OCULUS_DECLARE_ENTRY_POINT(GetPassthroughCapabilities); + OCULUS_DECLARE_ENTRY_POINT(GetPassthroughPreferences); + + //OVR_Plugin_MixedReality.h + + OCULUS_DECLARE_ENTRY_POINT(InitializeMixedReality); + OCULUS_DECLARE_ENTRY_POINT(ShutdownMixedReality); + OCULUS_DECLARE_ENTRY_POINT(GetMixedRealityInitialized); + OCULUS_DECLARE_ENTRY_POINT(UpdateExternalCamera); + OCULUS_DECLARE_ENTRY_POINT(GetExternalCameraCount); + OCULUS_DECLARE_ENTRY_POINT(GetExternalCameraName); + OCULUS_DECLARE_ENTRY_POINT(GetExternalCameraIntrinsics); + OCULUS_DECLARE_ENTRY_POINT(GetExternalCameraExtrinsics); + + // OVR_Plugin_Media.h + + OCULUS_DECLARE_ENTRY_POINT(Media_Initialize); + OCULUS_DECLARE_ENTRY_POINT(Media_Shutdown); + OCULUS_DECLARE_ENTRY_POINT(Media_GetInitialized); + OCULUS_DECLARE_ENTRY_POINT(Media_Update); + OCULUS_DECLARE_ENTRY_POINT(Media_GetMrcActivationMode); + OCULUS_DECLARE_ENTRY_POINT(Media_SetMrcActivationMode); + OCULUS_DECLARE_ENTRY_POINT(Media_IsMrcEnabled); + OCULUS_DECLARE_ENTRY_POINT(Media_IsMrcActivated); + OCULUS_DECLARE_ENTRY_POINT(Media_UseMrcDebugCamera); + OCULUS_DECLARE_ENTRY_POINT(Media_SetMrcInputVideoBufferType); + OCULUS_DECLARE_ENTRY_POINT(Media_GetMrcInputVideoBufferType); + OCULUS_DECLARE_ENTRY_POINT(Media_SetMrcFrameSize); + OCULUS_DECLARE_ENTRY_POINT(Media_GetMrcFrameSize); + OCULUS_DECLARE_ENTRY_POINT(Media_SetMrcAudioSampleRate); + OCULUS_DECLARE_ENTRY_POINT(Media_GetMrcAudioSampleRate); + OCULUS_DECLARE_ENTRY_POINT(Media_SetMrcFrameImageFlipped); + OCULUS_DECLARE_ENTRY_POINT(Media_GetMrcFrameImageFlipped); + OCULUS_DECLARE_ENTRY_POINT(Media_SetMrcFrameInverseAlpha); + OCULUS_DECLARE_ENTRY_POINT(Media_GetMrcFrameInverseAlpha); + OCULUS_DECLARE_ENTRY_POINT(Media_SetAvailableQueueIndexVulkan); + OCULUS_DECLARE_ENTRY_POINT(Media_EncodeMrcFrame); + OCULUS_DECLARE_ENTRY_POINT(Media_EncodeMrcFrameWithDualTextures); + OCULUS_DECLARE_ENTRY_POINT(Media_SyncMrcFrame); + OCULUS_DECLARE_ENTRY_POINT(Media_EncodeMrcFrameWithPoseTime); + OCULUS_DECLARE_ENTRY_POINT(Media_EncodeMrcFrameDualTexturesWithPoseTime); + OCULUS_DECLARE_ENTRY_POINT(Media_SetHeadsetControllerPose); + OCULUS_DECLARE_ENTRY_POINT(Media_EnumerateCameraAnchorHandles); + OCULUS_DECLARE_ENTRY_POINT(Media_GetCurrentCameraAnchorHandle); + OCULUS_DECLARE_ENTRY_POINT(Media_GetCameraAnchorName); + OCULUS_DECLARE_ENTRY_POINT(Media_GetCameraAnchorHandle); + OCULUS_DECLARE_ENTRY_POINT(Media_GetCameraAnchorType); + OCULUS_DECLARE_ENTRY_POINT(Media_CreateCustomCameraAnchor); + OCULUS_DECLARE_ENTRY_POINT(Media_DestroyCustomCameraAnchor); + OCULUS_DECLARE_ENTRY_POINT(Media_GetCustomCameraAnchorPose); + OCULUS_DECLARE_ENTRY_POINT(Media_SetCustomCameraAnchorPose); + OCULUS_DECLARE_ENTRY_POINT(Media_GetCameraMinMaxDistance); + OCULUS_DECLARE_ENTRY_POINT(Media_SetCameraMinMaxDistance); + + OCULUS_DECLARE_ENTRY_POINT(SetControllerDrivenHandPoses); + OCULUS_DECLARE_ENTRY_POINT(SetControllerDrivenHandPosesAreNatural); + + static bool InitializeOculusPluginWrapper(OculusPluginWrapper* wrapper); + static void DestroyOculusPluginWrapper(OculusPluginWrapper* wrapper); + +private: + ovrpVersion ovrpHeaderVersion; + bool Initialized; +}; + +#undef OCULUS_DECLARE_ENTRY_POINT diff --git a/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRQPL.cpp b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRQPL.cpp new file mode 100644 index 0000000..71baf26 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRQPL.cpp @@ -0,0 +1,106 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#include "OculusXRQPL.h" +#include "OculusXRHMDModule.h" +#include "OculusXRPluginWrapper.h" + +namespace OculusXRTelemetry +{ + namespace QPL + { + bool MarkerStart(const int MarkerId, const FTelemetryInstanceKey InstanceKey, const FTelemetryTimestamp Timestamp) + { + const ovrpResult Result = FOculusXRHMDModule::GetPluginWrapper().QplMarkerStart( + MarkerId, + InstanceKey.GetValue(), + Timestamp.GetTimestamp()); + + return OVRP_SUCCESS(Result); + } + bool MarkerEnd(const int MarkerId, const EAction Action, const FTelemetryInstanceKey InstanceKey, const FTelemetryTimestamp Timestamp) + { + const ovrpResult Result = FOculusXRHMDModule::GetPluginWrapper().QplMarkerEnd( + MarkerId, + static_cast(Action), + InstanceKey.GetValue(), + Timestamp.GetTimestamp()); + + return OVRP_SUCCESS(Result); + } + + bool MarkerPoint(const int MarkerId, const char* Name, const FTelemetryInstanceKey InstanceKey, const FTelemetryTimestamp Timestamp) + { + const ovrpResult Result = FOculusXRHMDModule::GetPluginWrapper().QplMarkerPoint( + MarkerId, + Name, + InstanceKey.GetValue(), + Timestamp.GetTimestamp()); + + return OVRP_SUCCESS(Result); + } + + bool MarkerPointCached(const int MarkerId, const int NameHandle, const FTelemetryInstanceKey InstanceKey, const FTelemetryTimestamp Timestamp) + { + const ovrpResult Result = FOculusXRHMDModule::GetPluginWrapper().QplMarkerPointCached( + MarkerId, + NameHandle, + InstanceKey.GetValue(), + Timestamp.GetTimestamp()); + + return OVRP_SUCCESS(Result); + } + + bool MarkerAnnotation(const int MarkerId, const char* AnnotationKey, const char* AnnotationValue, const FTelemetryInstanceKey InstanceKey) + { + if (nullptr == AnnotationValue) + { + return false; + } + const ovrpResult Result = FOculusXRHMDModule::GetPluginWrapper().QplMarkerAnnotation( + MarkerId, + AnnotationKey, + AnnotationValue, + InstanceKey.GetValue()); + + return OVRP_SUCCESS(Result); + } + + bool CreateMarkerHandle(const char* Name, int* NameHandle) + { + if (nullptr == NameHandle) + { + return false; + } + + const ovrpResult Result = FOculusXRHMDModule::GetPluginWrapper().QplCreateMarkerHandle( + Name, + NameHandle); + + return OVRP_SUCCESS(Result); + } + + bool DestroyMarkerHandle(const int NameHandle) + { + const ovrpResult Result = FOculusXRHMDModule::GetPluginWrapper().QplDestroyMarkerHandle( + NameHandle); + + return OVRP_SUCCESS(Result); + } + + bool OnEditorShutdown() + { + const ovrpResult Result = FOculusXRHMDModule::GetPluginWrapper().OnEditorShutdown(); + + return OVRP_SUCCESS(Result); + } + + } // namespace QPL + bool FQPLBackend::MarkerStart(const int MarkerId, const FTelemetryInstanceKey InstanceKey, const FTelemetryTimestamp Timestamp) { return QPL::MarkerStart(MarkerId, InstanceKey, Timestamp); } + bool FQPLBackend::MarkerEnd(const int MarkerId, const EAction Action, const FTelemetryInstanceKey InstanceKey, const FTelemetryTimestamp Timestamp) { return QPL::MarkerEnd(MarkerId, Action, InstanceKey, Timestamp); }; + bool FQPLBackend::MarkerPoint(const int MarkerId, const char* Name, const FTelemetryInstanceKey InstanceKey, const FTelemetryTimestamp Timestamp) { return QPL::MarkerPoint(MarkerId, Name, InstanceKey, Timestamp); }; + bool FQPLBackend::MarkerPointCached(const int MarkerId, const int NameHandle, const FTelemetryInstanceKey InstanceKey, const FTelemetryTimestamp Timestamp) { return QPL::MarkerPointCached(MarkerId, NameHandle, InstanceKey, Timestamp); }; + bool FQPLBackend::MarkerAnnotation(const int MarkerId, const char* AnnotationKey, const char* AnnotationValue, const FTelemetryInstanceKey InstanceKey) { return QPL::MarkerAnnotation(MarkerId, AnnotationKey, AnnotationValue, InstanceKey); }; + bool FQPLBackend::CreateMarkerHandle(const char* Name, int* NameHandle) { return QPL::CreateMarkerHandle(Name, NameHandle); }; + bool FQPLBackend::DestroyMarkerHandle(const int NameHandle) { return QPL::DestroyMarkerHandle(NameHandle); }; + bool FQPLBackend::OnEditorShutdown() { return QPL::OnEditorShutdown(); }; +} // namespace OculusXRTelemetry diff --git a/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRResourceHolder.cpp b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRResourceHolder.cpp new file mode 100644 index 0000000..c8c6cb3 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRResourceHolder.cpp @@ -0,0 +1,27 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +#include "OculusXRResourceHolder.h" +#include "HeadMountedDisplayTypes.h" // for LogHMD +#include "UObject/ConstructorHelpers.h" +#include "Materials/Material.h" + +////////////////////////////////////////////////////////////////////////// +// UOculusResourceManager + +UOculusXRResourceHolder::UOculusXRResourceHolder(const FObjectInitializer& ObjectInitializer) + : Super(ObjectInitializer) +{ + static ConstructorHelpers::FObjectFinder StaticPokeAHoleMaterial(TEXT("/OculusXR/Materials/PokeAHoleMaterial")); + + PokeAHoleMaterial = StaticPokeAHoleMaterial.Object; + + if (!PokeAHoleMaterial) + { + UE_LOG(LogHMD, Error, TEXT("Unable to load PokeAHoleMaterial")); + } + else + { + UE_LOG(LogHMD, Log, TEXT("PokeAHoleMaterial loaded successfully")); + } +} diff --git a/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRResourceHolder.h b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRResourceHolder.h new file mode 100644 index 0000000..f13ef77 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRResourceHolder.h @@ -0,0 +1,22 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CoreMinimal.h" +#include "UObject/Object.h" +#include "Materials/MaterialInterface.h" +#include "OculusXRResourceHolder.generated.h" + +/** + * + */ +UCLASS() +class UOculusXRResourceHolder : public UObject +{ + GENERATED_UCLASS_BODY() + +public: + UPROPERTY() + UMaterial* PokeAHoleMaterial; +}; diff --git a/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRSceneCaptureCubemap.cpp b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRSceneCaptureCubemap.cpp new file mode 100644 index 0000000..92c3d8b --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRSceneCaptureCubemap.cpp @@ -0,0 +1,193 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +#include "OculusXRSceneCaptureCubemap.h" +#include "OculusXRHMDPrivate.h" +#include "IImageWrapper.h" +#include "IImageWrapperModule.h" +#include "Kismet/GameplayStatics.h" +#include "GameFramework/PlayerController.h" +#include "Components/SceneCaptureComponent2D.h" +#include "Engine/World.h" +#include "Engine/StaticMeshActor.h" +#include "Engine/TextureRenderTarget2D.h" +#include "TextureResource.h" +#include "HAL/FileManager.h" +#include "Misc/FileHelper.h" +#include "XRThreadUtils.h" +#include "RenderingThread.h" + +//------------------------------------------------------------------------------------------------- +// UOculusXRSceneCaptureCubemap +//------------------------------------------------------------------------------------------------- + +UOculusXRSceneCaptureCubemap::UOculusXRSceneCaptureCubemap() + : Stage(None) + , CaptureBoxSideRes(2048) + , CaptureFormat(EPixelFormat::PF_A16B16G16R16) + , OverriddenLocation(FVector::ZeroVector) + , OverriddenOrientation(FQuat::Identity) + , CaptureOffset(FVector::ZeroVector) +{ +} + +void UOculusXRSceneCaptureCubemap::StartCapture(UWorld* World, uint32 InCaptureBoxSideRes, EPixelFormat InFormat) +{ + CaptureBoxSideRes = InCaptureBoxSideRes; + CaptureFormat = InFormat; + + FVector Location = OverriddenLocation; + FQuat Orientation = OverriddenOrientation; + + APlayerController* CapturePlayerController = UGameplayStatics::GetPlayerController(GWorld, 0); + if (CapturePlayerController) + { + FRotator Rotation; + CapturePlayerController->GetPlayerViewPoint(Location, Rotation); + Rotation.Pitch = Rotation.Roll = 0; + Orientation = FQuat(Rotation); + + Location += CaptureOffset; + } + + if (!OverriddenOrientation.IsIdentity()) + { + Orientation = OverriddenOrientation; + } + if (!OverriddenLocation.IsZero()) + { + Location = OverriddenLocation; + } + + const FVector ZAxis(0, 0, 1); + const FVector YAxis(0, 1, 0); + const FQuat FaceOrientations[] = { { ZAxis, PI / 2 }, { ZAxis, -PI / 2 }, // right, left + { YAxis, -PI / 2 }, { YAxis, PI / 2 }, // top, bottom + { ZAxis, 0 }, { ZAxis, -PI } }; // front, back + + for (int i = 0; i < 6; ++i) + { + USceneCaptureComponent2D* CaptureComponent = NewObject(); + CaptureComponent->SetVisibility(true); + CaptureComponent->SetHiddenInGame(false); + + CaptureComponent->FOVAngle = 90.f; + CaptureComponent->bCaptureEveryFrame = true; + CaptureComponent->CaptureSource = ESceneCaptureSource::SCS_FinalColorLDR; + + const FName TargetName = MakeUniqueObjectName(this, UTextureRenderTarget2D::StaticClass(), TEXT("SceneCaptureTextureTarget")); + CaptureComponent->TextureTarget = NewObject(this, TargetName); + CaptureComponent->TextureTarget->InitCustomFormat(CaptureBoxSideRes, CaptureBoxSideRes, CaptureFormat, false); + + CaptureComponents.Add(CaptureComponent); + + CaptureComponent->RegisterComponentWithWorld(GWorld); + + CaptureComponent->SetWorldLocationAndRotation(Location, Orientation * FaceOrientations[i]); + CaptureComponent->UpdateContent(); + } + Stage = SettingPos; + + FActorSpawnParameters SpawnInfo; + SpawnInfo.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn; + SpawnInfo.bNoFail = true; + SpawnInfo.ObjectFlags = RF_Transient; + + AStaticMeshActor* InGameActor; + InGameActor = World->SpawnActor(SpawnInfo); + + OutputDir = FPaths::ProjectSavedDir() + TEXT("/Cubemaps"); + IFileManager::Get().MakeDirectory(*OutputDir); +} + +void UOculusXRSceneCaptureCubemap::Tick(float DeltaTime) +{ + ExecuteOnRenderThread([]() { + TickRenderingTickables(); + }); + + if (Stage == SettingPos) + { + Stage = Capturing; + return; + } + + //Read Whole Capture Buffer + IImageWrapperModule& ImageWrapperModule = FModuleManager::LoadModuleChecked(FName("ImageWrapper")); + TSharedPtr ImageWrapper = ImageWrapperModule.CreateImageWrapper(EImageFormat::PNG); + + TArray OneFaceSurface, WholeCubemapData; + OneFaceSurface.AddUninitialized(CaptureBoxSideRes * CaptureBoxSideRes); + WholeCubemapData.AddUninitialized(CaptureBoxSideRes * 6 * CaptureBoxSideRes); + // Read pixels + for (int cubeFaceIdx = 0; cubeFaceIdx < 6; ++cubeFaceIdx) + { + auto RenderTarget = CaptureComponents[cubeFaceIdx]->TextureTarget->GameThread_GetRenderTargetResource(); + RenderTarget->ReadPixelsPtr(OneFaceSurface.GetData(), FReadSurfaceDataFlags()); + + // enforce alpha to be 1 + for (FColor& Color : OneFaceSurface) + { + Color.A = 255; + } + + // copy subimage into whole cubemap array + const uint32 Stride = CaptureBoxSideRes * 6; + const uint32 XOff = cubeFaceIdx * CaptureBoxSideRes; + const uint32 StripSizeInBytes = CaptureBoxSideRes * sizeof(FColor); + for (uint32 y = 0; y < CaptureBoxSideRes; ++y) + { + FMemory::Memcpy(WholeCubemapData.GetData() + XOff + y * Stride, OneFaceSurface.GetData() + y * CaptureBoxSideRes, StripSizeInBytes); + } + } + + ImageWrapper->SetRaw(WholeCubemapData.GetData(), WholeCubemapData.GetAllocatedSize(), CaptureBoxSideRes * 6, CaptureBoxSideRes, ERGBFormat::BGRA, 8); + const TArray64& PNGData = ImageWrapper->GetCompressed(100); + + const FString Filename = OutputDir + FString::Printf(TEXT("/Cubemap-%d-%s.png"), CaptureBoxSideRes, *FDateTime::Now().ToString(TEXT("%m.%d-%H.%M.%S"))); + + FFileHelper::SaveArrayToFile(PNGData, *Filename); + + check(Stage == Capturing); + Stage = Finished; + for (int i = 0; i < CaptureComponents.Num(); ++i) + { + CaptureComponents[i]->UnregisterComponent(); + } + CaptureComponents.SetNum(0); + RemoveFromRoot(); // We're done here, so remove ourselves from the root set. @TODO: Fix this later +} + +#if !UE_BUILD_SHIPPING +void UOculusXRSceneCaptureCubemap::CaptureCubemapCommandHandler(const TArray& Args, UWorld* World, FOutputDevice& Ar) +{ + bool bCreateOculusMobileCubemap = false; + FVector CaptureOffset(FVector::ZeroVector); + float Yaw = 0.f; + for (const FString& Arg : Args) + { + FParse::Value(*Arg, TEXT("XOFF="), CaptureOffset.X); + FParse::Value(*Arg, TEXT("YOFF="), CaptureOffset.Y); + FParse::Value(*Arg, TEXT("ZOFF="), CaptureOffset.Z); + FParse::Value(*Arg, TEXT("YAW="), Yaw); + + if (Arg.Equals(TEXT("MOBILE"), ESearchCase::IgnoreCase)) + { + bCreateOculusMobileCubemap = true; + } + } + + UOculusXRSceneCaptureCubemap* CubemapCapturer = NewObject(); + CubemapCapturer->AddToRoot(); // TODO: Don't add the object to the GC root + CubemapCapturer->SetOffset((FVector)CaptureOffset); + if (Yaw != 0.f) + { + FRotator Rotation(FRotator::ZeroRotator); + Rotation.Yaw = Yaw; + const FQuat Orient(Rotation); + CubemapCapturer->SetInitialOrientation(Orient); + } + const uint32 CaptureHeight = 2048; + CubemapCapturer->StartCapture(World, bCreateOculusMobileCubemap ? CaptureHeight / 2 : CaptureHeight); +} +#endif diff --git a/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRSceneCaptureCubemap.h b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRSceneCaptureCubemap.h new file mode 100644 index 0000000..561b13e --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRSceneCaptureCubemap.h @@ -0,0 +1,79 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +#pragma once +#include "OculusXRHMDPrivate.h" +#include "UObject/ObjectMacros.h" +#include "Tickable.h" +#include "OculusXRSceneCaptureCubemap.generated.h" + +//------------------------------------------------------------------------------------------------- +// UOculusXRSceneCaptureCubemap +//------------------------------------------------------------------------------------------------- + +class USceneCaptureComponent2D; + +UCLASS() +class UOculusXRSceneCaptureCubemap : public UObject, public FTickableGameObject +{ + GENERATED_BODY() +public: + UOculusXRSceneCaptureCubemap(); + + virtual void Tick(float DeltaTime) override; + + virtual bool IsTickable() const override + { + return CaptureComponents.Num() != 0 && Stage != None; + } + + virtual bool IsTickableWhenPaused() const override + { + return IsTickable(); + } + + virtual TStatId GetStatId() const + { + RETURN_QUICK_DECLARE_CYCLE_STAT(USceneCapturer, STATGROUP_Tickables); + } + + // init capture params and start + void StartCapture(UWorld* World, uint32 InCaptureBoxSideRes, EPixelFormat InFormat = EPixelFormat::PF_A16B16G16R16); + + // sets offset for the capture, in UU, relatively to current player 0 location + void SetOffset(FVector InOffset) { CaptureOffset = InOffset; } + + // overrides player's 0 orientation for the capture. + void SetInitialOrientation(const FQuat& InOrientation) { OverriddenOrientation = InOrientation; } + + // overrides player's 0 location for the capture. + void SetInitialLocation(FVector InLocation) { OverriddenLocation = InLocation; } + + bool IsFinished() const { return Stage == Finished; } + bool IsCapturing() const { return Stage == Capturing || Stage == SettingPos; } + +#if !UE_BUILD_SHIPPING + static void CaptureCubemapCommandHandler(const TArray& Args, UWorld* World, FOutputDevice& Ar); +#endif // UE_BUILD_SHIPPING + +private: + enum EStage + { + None, + SettingPos, + Capturing, + Finished + } Stage; + + UPROPERTY() + TArray CaptureComponents; + + uint32 CaptureBoxSideRes; + EPixelFormat CaptureFormat; + + FString OutputDir; + + FVector OverriddenLocation; // overridden location of the capture, world coordinates, UU + FQuat OverriddenOrientation; // overridden orientation of the capture. Full orientation is used (not only yaw, like with player's rotation). + FVector CaptureOffset; // offset relative to current player's 0 location +}; diff --git a/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRSimulator.cpp b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRSimulator.cpp new file mode 100644 index 0000000..ac1656a --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRSimulator.cpp @@ -0,0 +1,66 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +#include "OculusXRSimulator.h" +#if PLATFORM_WINDOWS +#include "OculusXRHMDRuntimeSettings.h" +#include "OculusXRTelemetryEvents.h" +#include "Misc/MessageDialog.h" + +#include "Windows/WindowsPlatformMisc.h" + +const FString OpenXrRuntimeEnvKey = "XR_RUNTIME_JSON"; +const FString PreviousOpenXrRuntimeEnvKey = "XR_RUNTIME_JSON_PREV"; + +bool FMetaXRSimulator::IsSimulatorActivated() +{ + FString MetaXRSimPath = GetSimulatorJsonPath(); + FString CurRuntimePath = FWindowsPlatformMisc::GetEnvironmentVariable(*OpenXrRuntimeEnvKey); + return (!MetaXRSimPath.IsEmpty() && MetaXRSimPath == CurRuntimePath); +} + +void FMetaXRSimulator::ToggleOpenXRRuntime() +{ + OculusXRTelemetry::TScopedMarker Event; + FString MetaXRSimPath = GetSimulatorJsonPath(); + if (!IFileManager::Get().FileExists(*MetaXRSimPath)) + { + FString Message("Meta XR Simulator Not Found.\nPlease set its path in Project Settings/Meta XR Plugin/PC."); + FMessageDialog::Open(EAppMsgType::Ok, FText::FromString(Message)); + UE_LOG(LogMetaXRSim, Error, TEXT("%s"), *Message); + const auto& NotEnd = Event.SetResult(OculusXRTelemetry::EAction::Fail).AddAnnotation("reason", "not found"); + + return; + } + + if (IsSimulatorActivated()) + { + //Deactivate MetaXR Simulator + FString PrevOpenXrRuntimeEnvKey = FWindowsPlatformMisc::GetEnvironmentVariable(*PreviousOpenXrRuntimeEnvKey); + + FWindowsPlatformMisc::SetEnvironmentVar(*PreviousOpenXrRuntimeEnvKey, + TEXT("")); + FWindowsPlatformMisc::SetEnvironmentVar(*OpenXrRuntimeEnvKey, *PrevOpenXrRuntimeEnvKey); + + UE_LOG(LogMetaXRSim, Log, TEXT("Meta XR Simulator is deactivated. (%s : %s)"), *OpenXrRuntimeEnvKey, *PrevOpenXrRuntimeEnvKey); + const auto& NotEnd = Event.AddAnnotation("action", "deactivated"); + } + else + { + //Activate MetaXR Simulator + FString CurOpenXrRuntimeEnvKey = FWindowsPlatformMisc::GetEnvironmentVariable(*OpenXrRuntimeEnvKey); + + FWindowsPlatformMisc::SetEnvironmentVar(*PreviousOpenXrRuntimeEnvKey, + *CurOpenXrRuntimeEnvKey); + FWindowsPlatformMisc::SetEnvironmentVar(*OpenXrRuntimeEnvKey, *MetaXRSimPath); + + UE_LOG(LogMetaXRSim, Log, TEXT("Meta XR Simulator is activated. (%s : %s)"), *OpenXrRuntimeEnvKey, *MetaXRSimPath); + const auto& NotEnd = Event.AddAnnotation("action", "activated"); + } +} + +FString FMetaXRSimulator::GetSimulatorJsonPath() +{ + return GetMutableDefault()->MetaXRJsonPath.FilePath; +} +#endif diff --git a/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRSimulator.h b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRSimulator.h new file mode 100644 index 0000000..49e860f --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRSimulator.h @@ -0,0 +1,21 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CoreMinimal.h" + +#if PLATFORM_WINDOWS +DEFINE_LOG_CATEGORY_STATIC(LogMetaXRSim, Log, All); + +/** */ +class FMetaXRSimulator +{ +public: + static bool IsSimulatorActivated(); + static void ToggleOpenXRRuntime(); + +private: + static FString GetSimulatorJsonPath(); +}; +#endif diff --git a/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRSyntheticEnvironmentServer.cpp b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRSyntheticEnvironmentServer.cpp new file mode 100644 index 0000000..6d96fa1 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRSyntheticEnvironmentServer.cpp @@ -0,0 +1,108 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +#include "OculusXRSyntheticEnvironmentServer.h" +#if PLATFORM_WINDOWS +#include "OculusXRHMDRuntimeSettings.h" +#include "OculusXRTelemetryEvents.h" +#include "Misc/MessageDialog.h" + +#include "Windows/WindowsPlatformMisc.h" + +const FString SynthEnvServer = "Synthetic Environment Server"; +const FString LocalSharingServer = "Local Sharing Server"; + +FProcHandle FMetaXRSES::EnvProcHandle; +FProcHandle FMetaXRSES::LSSProcHandle; + +void FMetaXRSES::StopServer() +{ + StopProcess(EnvProcHandle, SynthEnvServer); + StopProcess(LSSProcHandle, LocalSharingServer); +} + +void FMetaXRSES::LaunchEnvironment(FString EnvironmentName) +{ + if (GetMetaXRSimPackagePath().IsEmpty()) + { + return; + } + StopServer(); + + OculusXRTelemetry::TScopedMarker Event; + FString SESPath = GetSynthEnvServerPath(); + const bool bLaunched = LaunchProcess(SESPath, EnvironmentName, LocalSharingServer, EnvProcHandle); + const auto& _ = Event.SetResult(bLaunched ? OculusXRTelemetry::EAction::Success : OculusXRTelemetry::EAction::Fail).AddAnnotation("launch", StringCast(*EnvironmentName).Get()); + + LaunchLocalSharingServer(); +} + +void FMetaXRSES::LaunchLocalSharingServer() +{ + OculusXRTelemetry::TScopedMarker Event; + FString LSSPath = GetLocalSharingServerPath(); + const bool bLaunched = LaunchProcess(LSSPath, "", LocalSharingServer, LSSProcHandle); + const auto& _ = Event.SetResult(bLaunched ? OculusXRTelemetry::EAction::Success : OculusXRTelemetry::EAction::Fail).AddAnnotation("launch", "localsharingserver"); +} + +bool FMetaXRSES::LaunchProcess(FString BinaryPath, FString Arguments, FString LogContext, FProcHandle& OutProcHandle) +{ + if (!IFileManager::Get().FileExists(*BinaryPath)) + { + UE_LOG(LogMetaXRSES, Error, TEXT("Failed to find %s."), *BinaryPath); + return false; + } + UE_LOG(LogMetaXRSES, Log, TEXT("Launching %s."), *BinaryPath); + + uint32 OutProcessId = 0; + OutProcHandle = FPlatformProcess::CreateProc(*BinaryPath, *Arguments, false, false, false, &OutProcessId, 0, NULL, NULL); + if (!OutProcHandle.IsValid()) + { + UE_LOG(LogMetaXRSES, Error, TEXT("Failed to launch %s."), *BinaryPath); + FPlatformProcess::CloseProc(OutProcHandle); + return false; + } + + UE_LOG(LogMetaXRSES, Log, TEXT("Launched %s."), *BinaryPath); + return true; +} + +void FMetaXRSES::StopProcess(FProcHandle& ProcHandle, FString LogContext) +{ + if (ProcHandle.IsValid()) + { + if (FPlatformProcess::IsProcRunning(ProcHandle)) + { + UE_LOG(LogMetaXRSES, Log, TEXT("Stopping %s."), *LogContext); + FPlatformProcess::TerminateProc(ProcHandle); + } + FPlatformProcess::CloseProc(ProcHandle); + } + else + { + UE_LOG(LogMetaXRSES, Warning, TEXT("Failed to stop process %s because it is not active anymore."), *LogContext); + } +} + +FString FMetaXRSES::GetMetaXRSimPackagePath() +{ + FString JsonPath = GetMutableDefault()->MetaXRJsonPath.FilePath; + if (JsonPath.IsEmpty() || !IFileManager::Get().FileExists(*JsonPath)) + { + FString Message("Meta XR Simulator Not Found.\nPlease set its path in Project Settings/Meta XR Plugin/PC."); + FMessageDialog::Open(EAppMsgType::Ok, FText::FromString(Message)); + UE_LOG(LogMetaXRSES, Error, TEXT("%s"), *Message); + } + return FPaths::GetPath(JsonPath); +} + +FString FMetaXRSES::GetSynthEnvServerPath() +{ + return GetMetaXRSimPackagePath() + "/.synth_env_server/synth_env_server.exe"; +} + +FString FMetaXRSES::GetLocalSharingServerPath() +{ + return GetMetaXRSimPackagePath() + "/.local_sharing_server/local_sharing_server.exe"; +} +#endif diff --git a/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRSyntheticEnvironmentServer.h b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRSyntheticEnvironmentServer.h new file mode 100644 index 0000000..573c16b --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRSyntheticEnvironmentServer.h @@ -0,0 +1,31 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CoreMinimal.h" +#if PLATFORM_WINDOWS +DEFINE_LOG_CATEGORY_STATIC(LogMetaXRSES, Log, All); + +struct FProcHandle; + +/** */ +class FMetaXRSES +{ +public: + static void LaunchEnvironment(FString EnvironmentName); + static void StopServer(); + +private: + static void LaunchLocalSharingServer(); + static bool LaunchProcess(FString BinaryPath, FString Arguments, FString LogContext, FProcHandle& OutProcHandle); + static void StopProcess(FProcHandle& ProcHandle, FString LogContext); + + static FString GetMetaXRSimPackagePath(); + static FString GetSynthEnvServerPath(); + static FString GetLocalSharingServerPath(); + + static FProcHandle EnvProcHandle; + static FProcHandle LSSProcHandle; +}; +#endif diff --git a/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRTelemetry.cpp b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRTelemetry.cpp new file mode 100644 index 0000000..c2242ab --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRTelemetry.cpp @@ -0,0 +1,49 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#include "OculusXRTelemetry.h" +#include "OculusXRHMDModule.h" +#include "OculusXRTelemetryPrivacySettings.h" +#include "Async/Async.h" + +namespace OculusXRTelemetry +{ + bool IsActive() + { +#if OCULUS_HMD_SUPPORTED_PLATFORMS + if constexpr (FTelemetryBackend::IsNullBackend()) + { + return false; + } + if (FOculusXRHMDModule::Get().IsOVRPluginAvailable() && FOculusXRHMDModule::GetPluginWrapper().IsInitialized()) + { + return true; + } +#endif // OCULUS_HMD_SUPPORTED_PLATFORMS + return false; + } + + void IfActiveThen(TUniqueFunction Function) + { + AsyncTask(ENamedThreads::GameThread, [F = MoveTemp(Function)]() { + if (IsActive()) + { + F(); + } + }); + } + + void PropagateTelemetryConsent() + { + bool HasConsent = true; +#ifdef WITH_EDITOR + if (const auto EditorPrivacySettings = GetDefault()) + { + HasConsent = EditorPrivacySettings->bIsEnabled; + } +#endif + if (FOculusXRHMDModule::Get().IsOVRPluginAvailable() && FOculusXRHMDModule::GetPluginWrapper().IsInitialized()) + { + FOculusXRHMDModule::GetPluginWrapper().QplSetConsent(HasConsent); + } + } +} // namespace OculusXRTelemetry diff --git a/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRTelemetryEvents.h b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRTelemetryEvents.h new file mode 100644 index 0000000..ae7d1e5 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRTelemetryEvents.h @@ -0,0 +1,12 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#pragma once + +#include "OculusXRTelemetry.h" + +namespace OculusXRTelemetry::Events +{ + using FEditorConsent = TMarker<191965622>; + using FSimulator = TMarker<191963436>; + constexpr const char* ConsentOriginKey = "Origin"; +} // namespace OculusXRTelemetry::Events diff --git a/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRTelemetryPrivacySettings.cpp b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRTelemetryPrivacySettings.cpp new file mode 100644 index 0000000..2ceb593 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRTelemetryPrivacySettings.cpp @@ -0,0 +1,82 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#include "OculusXRTelemetryPrivacySettings.h" + +#include "OculusXRHMDModule.h" +#include "OculusXRTelemetry.h" +#include "OculusXRTelemetryEvents.h" + +#define LOCTEXT_NAMESPACE "OculusXRTelemetryPrivacySettings" + +UOculusXRTelemetryPrivacySettings::UOculusXRTelemetryPrivacySettings(const FObjectInitializer& ObjectInitializer) + : Super(ObjectInitializer) +{ +} + +void UOculusXRTelemetryPrivacySettings::GetToggleCategoryAndPropertyNames(FName& OutCategory, FName& OutProperty) const +{ + OutCategory = FName("Options"); + OutProperty = FName("bIsEnabled"); +}; + +FText UOculusXRTelemetryPrivacySettings::GetFalseStateLabel() const +{ + return LOCTEXT("FalseStateLabel", "Don't Send"); +}; + +FText UOculusXRTelemetryPrivacySettings::GetFalseStateTooltip() const +{ + return LOCTEXT("FalseStateTooltip", "Don't send MetaXR plugin usage data to Meta."); +}; + +FText UOculusXRTelemetryPrivacySettings::GetFalseStateDescription() const +{ + return LOCTEXT("FalseStateDescription", "By opting out you don't allow Meta to collect usage data on its SDKs, such as package name, class names and plugin configuration in your projects using Meta SDKs on this machine. This data helps improve the Meta SDKs and is collected in accordance with Meta's Privacy Policy."); +}; + +FText UOculusXRTelemetryPrivacySettings::GetTrueStateLabel() const +{ + return LOCTEXT("TrueStateLabel", "Send Usage Data"); +}; + +FText UOculusXRTelemetryPrivacySettings::GetTrueStateTooltip() const +{ + return LOCTEXT("TrueStateTooltip", "Send MetaXR plugin usage data to Meta."); +}; + +FText UOculusXRTelemetryPrivacySettings::GetTrueStateDescription() const +{ + return LOCTEXT("TrueStateDescription", "By opting in you allow Meta to collect usage data on its SDKs, such as package name, class names and plugin configuration in your projects using Meta SDKs on this machine. This data helps improve the Meta SDKs and is collected in accordance with Meta's Privacy Policy."); +}; + +FString UOculusXRTelemetryPrivacySettings::GetAdditionalInfoUrl() const +{ + return FString(TEXT("https://www.meta.com/legal/quest/privacy-policy/")); +}; + +FText UOculusXRTelemetryPrivacySettings::GetAdditionalInfoUrlLabel() const +{ + return LOCTEXT("HyperlinkLabel", "Meta Platforms Technologies Privacy Policy"); +}; + +#if WITH_EDITOR +void UOculusXRTelemetryPrivacySettings::PostEditChangeProperty(struct FPropertyChangedEvent& PropertyChangedEvent) +{ + Super::PostEditChangeProperty(PropertyChangedEvent); + + const FName PropertyName = (PropertyChangedEvent.Property != nullptr) ? PropertyChangedEvent.Property->GetFName() : NAME_None; + if (PropertyName == GET_MEMBER_NAME_CHECKED(UOculusXRTelemetryPrivacySettings, bIsEnabled)) + { + using namespace OculusXRTelemetry; + if (FOculusXRHMDModule::Get().IsOVRPluginAvailable() && FOculusXRHMDModule::GetPluginWrapper().IsInitialized()) + { + PropagateTelemetryConsent(); + Events::FEditorConsent().Start() // + .AddAnnotation(Events::ConsentOriginKey, "Settings") // + .End(bIsEnabled ? EAction::Success : EAction::Fail); + } + } +} +#endif + +#undef LOCTEXT_NAMESPACE diff --git a/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRTelemetryPrivacySettings.h b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRTelemetryPrivacySettings.h new file mode 100644 index 0000000..2b3487d --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRTelemetryPrivacySettings.h @@ -0,0 +1,39 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#pragma once + +#include "CoreMinimal.h" +#include "UObject/Object.h" +#include "Engine/ImportantToggleSettingInterface.h" +#include "OculusXRTelemetryPrivacySettings.generated.h" + +UCLASS(MinimalAPI, hidecategories = Object, config = EditorSettings) +class UOculusXRTelemetryPrivacySettings : public UObject, public IImportantToggleSettingInterface +{ + GENERATED_UCLASS_BODY() + + UPROPERTY(EditAnywhere, config, Category = Options) + bool bIsEnabled = false; + + UPROPERTY(config) + bool bHasNotified = false; + +public: + // BEGIN IImportantToggleSettingInterface + virtual void GetToggleCategoryAndPropertyNames(FName& OutCategory, FName& OutProperty) const override; + virtual FText GetFalseStateLabel() const override; + virtual FText GetFalseStateTooltip() const override; + virtual FText GetFalseStateDescription() const override; + virtual FText GetTrueStateLabel() const override; + virtual FText GetTrueStateTooltip() const override; + virtual FText GetTrueStateDescription() const override; + virtual FString GetAdditionalInfoUrl() const override; + virtual FText GetAdditionalInfoUrlLabel() const override; + // END IImportantToggleSettingInterface + +#if WITH_EDITOR + //~ Begin UObject Interface + virtual void PostEditChangeProperty(struct FPropertyChangedEvent& PropertyChangedEvent) override; + //~ End UObject Interface +#endif // WITH_EDITOR +}; diff --git a/Plugins/MetaXR/Source/OculusXRHMD/Public/IOculusXRHMDModule.h b/Plugins/MetaXR/Source/OculusXRHMD/Public/IOculusXRHMDModule.h new file mode 100644 index 0000000..31fce6b --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRHMD/Public/IOculusXRHMDModule.h @@ -0,0 +1,132 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +#pragma once +#include "Modules/ModuleManager.h" +#include "IHeadMountedDisplayModule.h" +#include "HeadMountedDisplayTypes.h" + +// Oculus support is not available on Windows XP +#define OCULUS_HMD_SUPPORTED_PLATFORMS (PLATFORM_WINDOWS && WINVER > 0x0502) || (PLATFORM_ANDROID_ARM || PLATFORM_ANDROID_ARM64) + +//------------------------------------------------------------------------------------------------- +// IOculusXRHMDModule +//------------------------------------------------------------------------------------------------- + +/** + * The public interface to this module. In most cases, this interface is only public to sibling modules + * within this plugin. + */ +class IOculusXRHMDModule : public IHeadMountedDisplayModule +{ +public: + /** + * Singleton-like access to this module's interface. This is just for convenience! + * Beware of calling this during the shutdown phase, though. Your module might have been unloaded already. + * + * @return Returns singleton instance, loading the module on demand if needed + */ + static inline IOculusXRHMDModule& Get() + { + return FModuleManager::LoadModuleChecked("OculusXRHMD"); + } + + /** + * Checks to see if this module is loaded and ready. It is only valid to call Get() if IsAvailable() returns true. + * + * @return True if the module is loaded and ready to use + */ + static inline bool IsAvailable() + { + return FModuleManager::Get().IsModuleLoaded("OculusXRHMD"); + } + + /** + * Grabs the current orientation and position for the HMD. If positional tracking is not available, DevicePosition will be a zero vector + * + * @param DeviceRotation (out) The device's current rotation + * @param DevicePosition (out) The device's current position, in its own tracking space + * @param NeckPosition (out) The estimated neck position, calculated using NeckToEye vector from User Profile. Same coordinate space as DevicePosition. + * @param bUseOrienationForPlayerCamera (in) Should be set to 'true' if the orientation is going to be used to update orientation of the camera manually. + * @param bUsePositionForPlayerCamera (in) Should be set to 'true' if the position is going to be used to update position of the camera manually. + * @param PositionScale (in) The 3D scale that will be applied to position. + */ + virtual void GetPose(FRotator& DeviceRotation, FVector& DevicePosition, FVector& NeckPosition, bool bUseOrienationForPlayerCamera = false, bool bUsePositionForPlayerCamera = false, const FVector PositionScale = FVector::ZeroVector) = 0; + + /** + * Reports raw sensor data. If HMD doesn't support any of the parameters then it will be set to zero. + * + * @param AngularAcceleration (out) Angular acceleration in radians per second per second. + * @param LinearAcceleration (out) Acceleration in meters per second per second. + * @param AngularVelocity (out) Angular velocity in radians per second. + * @param LinearVelocity (out) Velocity in meters per second. + * @param TimeInSeconds (out) Time when the reported IMU reading took place, in seconds. + */ + virtual void GetRawSensorData(FVector& AngularAcceleration, FVector& LinearAcceleration, FVector& AngularVelocity, FVector& LinearVelocity, float& TimeInSeconds) = 0; + + /** + * Returns current user profile. + * + * @param Profile (out) Structure to hold current user profile. + * @return (boolean) True, if user profile was acquired. + */ + virtual bool GetUserProfile(struct FOculusXRHmdUserProfile& Profile) = 0; + + /** + * Sets 'base rotation' - the rotation that will be subtracted from + * the actual HMD orientation. + * Sets base position offset (in meters). The base position offset is the distance from the physical (0, 0, 0) position + * to current HMD position (bringing the (0, 0, 0) point to the current HMD position) + * Note, this vector is set by ResetPosition call; use this method with care. + * The axis of the vector are the same as in Unreal: X - forward, Y - right, Z - up. + * + * @param Rotation (in) Rotator object with base rotation + * @param BaseOffsetInMeters (in) the vector to be set as base offset, in meters. + * @param Options (in) specifies either position, orientation or both should be set. + */ + virtual void SetBaseRotationAndBaseOffsetInMeters(FRotator Rotation, FVector BaseOffsetInMeters, EOrientPositionSelector::Type Options) = 0; + + /** + * Returns current base rotation and base offset. + * The base offset is currently used base position offset, previously set by the + * ResetPosition or SetBasePositionOffset calls. It represents a vector that translates the HMD's position + * into (0,0,0) point, in meters. + * The axis of the vector are the same as in Unreal: X - forward, Y - right, Z - up. + * + * @param OutRotation (out) Rotator object with base rotation + * @param OutBaseOffsetInMeters (out) base position offset, vector, in meters. + */ + virtual void GetBaseRotationAndBaseOffsetInMeters(FRotator& OutRotation, FVector& OutBaseOffsetInMeters) = 0; + + /** + * Sets 'base rotation' - the rotation that will be subtracted from + * the actual HMD orientation. + * The position offset might be added to current HMD position, + * effectively moving the virtual camera by the specified offset. The addition + * occurs after the HMD orientation and position are applied. + * + * @param BaseRot (in) Rotator object with base rotation + * @param PosOffset (in) the vector to be added to HMD position. + * @param Options (in) specifies either position, orientation or both should be set. + */ + virtual void SetBaseRotationAndPositionOffset(FRotator BaseRot, FVector PosOffset, EOrientPositionSelector::Type Options) = 0; + + /** + * Returns current base rotation and position offset. + * + * @param OutRot (out) Rotator object with base rotation + * @param OutPosOffset (out) the vector with previously set position offset. + */ + virtual void GetBaseRotationAndPositionOffset(FRotator& OutRot, FVector& OutPosOffset) = 0; + + /** + * Returns IStereoLayers interface to work with overlays. + */ + virtual class IStereoLayers* GetStereoLayers() = 0; + + virtual FString GetDeviceSystemName() = 0; + +#if OCULUS_HMD_SUPPORTED_PLATFORMS + virtual bool PoseToOrientationAndPosition(const FQuat& InOrientation, const FVector& InPosition, FQuat& OutOrientation, FVector& OutPosition) const = 0; +#endif //OCULUS_HMD_SUPPORTED_PLATFORMS +}; diff --git a/Plugins/MetaXR/Source/OculusXRHMD/Public/OculusXRAssetDirectory.h b/Plugins/MetaXR/Source/OculusXRHMD/Public/OculusXRAssetDirectory.h new file mode 100644 index 0000000..86f1019 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRHMD/Public/OculusXRAssetDirectory.h @@ -0,0 +1,18 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CoreMinimal.h" +#include "UObject/SoftObjectPath.h" + +class FOculusAssetDirectory +{ +public: +#if WITH_EDITORONLY_DATA + OCULUSXRHMD_API static void LoadForCook(); + OCULUSXRHMD_API static void ReleaseAll(); +#endif + + static FSoftObjectPath AssetListing[]; +}; diff --git a/Plugins/MetaXR/Source/OculusXRHMD/Public/OculusXREventComponent.h b/Plugins/MetaXR/Source/OculusXRHMD/Public/OculusXREventComponent.h new file mode 100644 index 0000000..0f44905 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRHMD/Public/OculusXREventComponent.h @@ -0,0 +1,34 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. +// OculusEventComponent.h: Component to handle receiving events from Oculus HMDs + +#pragma once + +#include "CoreMinimal.h" +#include "UObject/ObjectMacros.h" +#include "Components/ActorComponent.h" +#include "OculusXREventComponent.generated.h" + +UCLASS(Blueprintable, meta = (BlueprintSpawnableComponent), ClassGroup = OculusXRHMD) +class OCULUSXRHMD_API UOculusXREventComponent : public UActorComponent +{ + GENERATED_BODY() + +public: + DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOculusDisplayRefreshRateChangedEventDelegate, float, fromRefreshRate, float, toRefreshRate); + DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOculusEyeTrackingStateChangedEventDelegate, bool, bEyeTrackingOn); + + UPROPERTY(BlueprintAssignable) + FOculusDisplayRefreshRateChangedEventDelegate OculusDisplayRefreshRateChanged; + + UPROPERTY(BlueprintAssignable) + FOculusEyeTrackingStateChangedEventDelegate OculusEyeTrackingStateChanged; + + void OnRegister() override; + void OnUnregister() override; + +private: + /** Native handlers that get registered with the actual FCoreDelegates, and then proceed to broadcast to the delegates above */ + void OculusDisplayRefreshRateChanged_Handler(float fromRefresh, float toRefresh) { OculusDisplayRefreshRateChanged.Broadcast(fromRefresh, toRefresh); } + void OculusEyeTrackingStateChanged_Handler(bool bEyeTrackingOn) { OculusEyeTrackingStateChanged.Broadcast(bEyeTrackingOn); } +}; diff --git a/Plugins/MetaXR/Source/OculusXRHMD/Public/OculusXRFunctionLibrary.h b/Plugins/MetaXR/Source/OculusXRHMD/Public/OculusXRFunctionLibrary.h new file mode 100644 index 0000000..81fa975 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRHMD/Public/OculusXRFunctionLibrary.h @@ -0,0 +1,436 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +#pragma once +#include "CoreMinimal.h" +#include "OculusXRHMDTypes.h" +#include "UObject/ObjectMacros.h" +#include "Kismet/BlueprintFunctionLibrary.h" +#include "IOculusXRHMDModule.h" +#include "OculusXRFunctionLibrary.generated.h" + +namespace OculusXRHMD +{ + class FOculusXRHMD; +} + +UCLASS() +class OCULUSXRHMD_API UOculusXRFunctionLibrary : public UBlueprintFunctionLibrary +{ + GENERATED_UCLASS_BODY() + + /** + * Grabs the current orientation and position for the HMD. If positional tracking is not available, DevicePosition will be a zero vector + * + * @param DeviceRotation (out) The device's current rotation + * @param DevicePosition (out) The device's current position, in its own tracking space + * @param NeckPosition (out) The estimated neck position, calculated using NeckToEye vector from User Profile. Same coordinate space as DevicePosition. + * @param bUseOrienationForPlayerCamera (in) Should be set to 'true' if the orientation is going to be used to update orientation of the camera manually. + * @param bUsePositionForPlayerCamera (in) Should be set to 'true' if the position is going to be used to update position of the camera manually. + * @param PositionScale (in) The 3D scale that will be applied to position. + */ + UFUNCTION(BlueprintPure, Category = "OculusLibrary") + static void GetPose(FRotator& DeviceRotation, FVector& DevicePosition, FVector& NeckPosition, bool bUseOrienationForPlayerCamera = false, bool bUsePositionForPlayerCamera = false, const FVector PositionScale = FVector::ZeroVector); + + /** + * Reports raw sensor data. If HMD doesn't support any of the parameters then it will be set to zero. + * + * @param AngularAcceleration (out) Angular acceleration in radians per second per second. + * @param LinearAcceleration (out) Acceleration in meters per second per second. + * @param AngularVelocity (out) Angular velocity in radians per second. + * @param LinearVelocity (out) Velocity in meters per second. + * @param TimeInSeconds (out) Time when the reported IMU reading took place, in seconds. + */ + UFUNCTION(BlueprintPure, Category = "OculusLibrary") + static void GetRawSensorData(FVector& AngularAcceleration, FVector& LinearAcceleration, FVector& AngularVelocity, FVector& LinearVelocity, float& TimeInSeconds, EOculusXRTrackedDeviceType DeviceType = EOculusXRTrackedDeviceType::HMD); + + /** + * Returns if the device is currently tracked by the runtime or not. + */ + UFUNCTION(BlueprintPure, Category = "OculusLibrary") + static bool IsDeviceTracked(EOculusXRTrackedDeviceType DeviceType); + + /** + * Set the CPU and GPU levels as hints to the Oculus device (Deprecated). + */ + UFUNCTION(BlueprintCallable, Category = "OculusLibrary", meta = (DeprecatedFunction, DeprecatedMessage = "Deprecated. Please use Get/SetSuggestedCpuAndGpuPerformanceLevels instead")) + static void SetCPUAndGPULevels(int CPULevel, int GPULevel); + + /** + * Get the suggested CPU and GPU levels to the Oculus device. + */ + UFUNCTION(BlueprintCallable, Category = "OculusLibrary") + static void GetSuggestedCpuAndGpuPerformanceLevels(EOculusXRProcessorPerformanceLevel& CpuPerfLevel, EOculusXRProcessorPerformanceLevel& GpuPerfLevel); + + /** + * Set the suggested CPU and GPU levels to the Oculus device. + */ + UFUNCTION(BlueprintCallable, Category = "OculusLibrary") + static void SetSuggestedCpuAndGpuPerformanceLevels(EOculusXRProcessorPerformanceLevel CpuPerfLevel, EOculusXRProcessorPerformanceLevel GpuPerfLevel); + + /** + * Returns current user profile. + * + * @param Profile (out) Structure to hold current user profile. + * @return (boolean) True, if user profile was acquired. + */ + UFUNCTION(BlueprintPure, Category = "OculusLibrary") + static bool GetUserProfile(FOculusXRHmdUserProfile& Profile); + + /** + * Sets 'base rotation' - the rotation that will be subtracted from + * the actual HMD orientation. + * Sets base position offset (in meters). The base position offset is the distance from the physical (0, 0, 0) position + * to current HMD position (bringing the (0, 0, 0) point to the current HMD position) + * Note, this vector is set by ResetPosition call; use this method with care. + * The axis of the vector are the same as in Unreal: X - forward, Y - right, Z - up. + * + * @param Rotation (in) Rotator object with base rotation + * @param BaseOffsetInMeters (in) the vector to be set as base offset, in meters. + * @param Options (in) specifies either position, orientation or both should be set. + */ + UFUNCTION(BlueprintCallable, Category = "OculusLibrary") + static void SetBaseRotationAndBaseOffsetInMeters(FRotator Rotation, FVector BaseOffsetInMeters, EOrientPositionSelector::Type Options); + + /** + * Returns current base rotation and base offset. + * The base offset is currently used base position offset, previously set by the + * ResetPosition or SetBasePositionOffset calls. It represents a vector that translates the HMD's position + * into (0,0,0) point, in meters. + * The axis of the vector are the same as in Unreal: X - forward, Y - right, Z - up. + * + * @param OutRotation (out) Rotator object with base rotation + * @param OutBaseOffsetInMeters (out) base position offset, vector, in meters. + */ + UFUNCTION(BlueprintPure, Category = "OculusLibrary") + static void GetBaseRotationAndBaseOffsetInMeters(FRotator& OutRotation, FVector& OutBaseOffsetInMeters); + + /** + * Scales the HMD position that gets added to the virtual camera position. + * + * @param PosScale3D (in) the scale to apply to the HMD position. + */ + UFUNCTION(BlueprintCallable, Category = "OculusLibrary", meta = (DeprecatedFunction, DeprecationMessage = "This feature is no longer supported.")) + static void SetPositionScale3D(FVector PosScale3D) {} + + /** + * Sets 'base rotation' - the rotation that will be subtracted from + * the actual HMD orientation. + * The position offset might be added to current HMD position, + * effectively moving the virtual camera by the specified offset. The addition + * occurs after the HMD orientation and position are applied. + * + * @param BaseRot (in) Rotator object with base rotation + * @param PosOffset (in) the vector to be added to HMD position. + * @param Options (in) specifies either position, orientation or both should be set. + */ + UFUNCTION(BlueprintCallable, Category = "OculusLibrary", meta = (DeprecatedFunction, DeprecationMessage = "A hack, proper camera positioning should be used")) + static void SetBaseRotationAndPositionOffset(FRotator BaseRot, FVector PosOffset, EOrientPositionSelector::Type Options); + + /** + * Returns current base rotation and position offset. + * + * @param OutRot (out) Rotator object with base rotation + * @param OutPosOffset (out) the vector with previously set position offset. + */ + UFUNCTION(BlueprintCallable, Category = "OculusLibrary", meta = (DeprecatedFunction, DeprecationMessage = "A hack, proper camera positioning should be used")) + static void GetBaseRotationAndPositionOffset(FRotator& OutRot, FVector& OutPosOffset); + + /** + * Adds loading splash screen with parameters + * + * @param Texture (in) A texture asset to be used for the splash. + * @param TranslationInMeters (in) Initial translation of the center of the splash screen (in meters). + * @param Rotation (in) Initial rotation of the splash screen, with the origin at the center of the splash screen. + * @param SizeInMeters (in) Size, in meters, of the quad with the splash screen. + * @param DeltaRotation (in) Incremental rotation, that is added each 2nd frame to the quad transform. The quad is rotated around the center of the quad. + * @param bClearBeforeAdd (in) If true, clears splashes before adding a new one. + */ + UFUNCTION(BlueprintCallable, Category = "OculusLibrary", meta = (DeprecatedFunction, DeprecationMessage = "Use Add Loading Screen Splash from the Head Mounted Display Loading Screen functions instead.")) + static void AddLoadingSplashScreen(class UTexture2D* Texture, FVector TranslationInMeters, FRotator Rotation, FVector2D SizeInMeters = FVector2D(1.0f, 1.0f), FRotator DeltaRotation = FRotator::ZeroRotator, bool bClearBeforeAdd = false); + + /** + * Removes all the splash screens. + */ + UFUNCTION(BlueprintCallable, Category = "OculusLibrary", meta = (DeprecatedFunction, DeprecationMessage = "Use Clear Loading Screen Splashes from the Head Mounted Display Loading Screen functions instead.")) + static void ClearLoadingSplashScreens(); + + /** + * Returns true, if the app has input focus. + */ + UFUNCTION(BlueprintPure, Category = "OculusLibrary") + static bool HasInputFocus(); + + /** + * Returns true, if the system overlay is present. + */ + UFUNCTION(BlueprintPure, Category = "OculusLibrary") + static bool HasSystemOverlayPresent(); + + /** + * Returns the GPU utilization availability and value + */ + UFUNCTION(BlueprintPure, Category = "OculusLibrary") + static void GetGPUUtilization(bool& IsGPUAvailable, float& GPUUtilization); + + /** + * Returns the GPU frame time on supported mobile platforms (Go for now) + */ + UFUNCTION(BlueprintPure, Category = "OculusLibrary") + static float GetGPUFrameTime(); + + /** + * Returns the foveated rendering method currently being used + */ + UFUNCTION(BlueprintCallable, Category = "OculusLibrary") + static EOculusXRFoveatedRenderingMethod GetFoveatedRenderingMethod(); + + /** + * Set the requested foveated rendering method + */ + UFUNCTION(BlueprintCallable, Category = "OculusLibrary") + static void SetFoveatedRenderingMethod(EOculusXRFoveatedRenderingMethod Method); + + /** + * Returns the current multiresolution level + */ + UFUNCTION(BlueprintPure, Category = "OculusLibrary") + static EOculusXRFoveatedRenderingLevel GetFoveatedRenderingLevel(); + + /** + * Set the requested foveated rendering level for the next frame, and whether FFR's level is now dynamic or not. + */ + UFUNCTION(BlueprintCallable, Category = "OculusLibrary") + static void SetFoveatedRenderingLevel(EOculusXRFoveatedRenderingLevel level, bool isDynamic); + + /** + * Returns whether eye-tracked foveated rendering is supported or not + */ + UFUNCTION(BlueprintCallable, Category = "OculusLibrary") + static bool GetEyeTrackedFoveatedRenderingSupported(); + + /** + * Returns the current device's name + */ + UE_DEPRECATED(4.22, "UOculusXRFunctionLibrary::GetDeviceName has been deprecated and no longer functions as before. Please use the enum-based GetDeviceType instead.") + UFUNCTION(BlueprintPure, Category = "OculusLibrary", meta = (DeprecatedFunction, DeprecationMessage = "UOculusXRFunctionLibrary::GetDeviceName has been deprecated and no longer functions as before. Please use the enum-based GetDeviceType instead.")) + static FString GetDeviceName(); + + UFUNCTION(BlueprintPure, Category = "OculusLibrary") + static EOculusXRDeviceType GetDeviceType(); + + /** + * Returns the current controller's type + * @param deviceHand (in) The hand to get the position from + */ + UFUNCTION(BlueprintPure, Category = "OculusLibrary") + static EOculusXRControllerType GetControllerType(EControllerHand deviceHand); + + /** + * Returns the current available frequencies + */ + UFUNCTION(BlueprintPure, Category = "OculusLibrary") + static TArray GetAvailableDisplayFrequencies(); + + /** + * Returns the current display frequency + */ + UFUNCTION(BlueprintPure, Category = "OculusLibrary") + static float GetCurrentDisplayFrequency(); + + /** + * Sets the requested display frequency + */ + UFUNCTION(BlueprintCallable, Category = "OculusLibrary") + static void SetDisplayFrequency(float RequestedFrequency); + + /** + * Enables/disables positional tracking on devices that support it. + */ + UFUNCTION(BlueprintCallable, Category = "OculusLibrary") + static void EnablePositionTracking(bool bPositionTracking); + + /** + * Enables/disables orientation tracking on devices that support it. + */ + UFUNCTION(BlueprintCallable, Category = "OculusLibrary") + static void EnableOrientationTracking(bool bOrientationTracking); + + /** + * Set the Color Scale/Offset + */ + UFUNCTION(BlueprintCallable, Category = "OculusLibrary") + static void SetColorScaleAndOffset(FLinearColor ColorScale, FLinearColor ColorOffset, bool bApplyToAllLayers = false); + + /** + * Returns true if system headset is in 3dof mode + */ + UFUNCTION(BlueprintPure, Category = "OculusLibrary") + static bool GetSystemHmd3DofModeEnabled(); + + /** + * Returns the color space of the target HMD + */ + UFUNCTION(BlueprintPure, Category = "OculusLibrary") + static EOculusXRColorSpace GetHmdColorDesc(); + + /** + * Sets the target HMD to do color space correction to a specific color space + */ + UFUNCTION(BlueprintCallable, Category = "OculusLibrary") + static void SetClientColorDesc(EOculusXRColorSpace ColorSpace); + + /** + * Turns on or off local dimming + */ + UFUNCTION(BlueprintCallable, Category = "OculusLibrary") + static void SetLocalDimmingOn(bool LocalDimmingOn); + + /** + * Checks if passthrough is supported + */ + UFUNCTION(BlueprintCallable, Category = "OculusLibrary") + static bool IsPassthroughSupported(); + + /** + * Checks if color passthrough is supported + */ + UFUNCTION(BlueprintCallable, Category = "OculusLibrary") + static bool IsColorPassthroughSupported(); + + /** + * Create the environment depth texture swap chain and start receiving + * depth texture every frame until stopped. + */ + UFUNCTION(BlueprintCallable, Category = "OculusLibrary") + static void StartEnvironmentDepth(); + + /** + * Destroy the environment depth texture swap chain and stop receiving + * new depth textures every frame. Call this when environment depth is + * no longer needed to free up resources. + */ + UFUNCTION(BlueprintCallable, Category = "OculusLibrary") + static void StopEnvironmentDepth(); + + /** + * Returns true if StartEnvironmentDepth() has been called and is currently running. + * If called right after calling StartEnvironmentDepth() it'll return false as it needs some time for EnvironmentDepth to start + */ + UFUNCTION(BlueprintPure, Category = "OculusLibrary") + static bool IsEnvironmentDepthStarted(); + + /** + * When hands removal is enabled and hand tracking is active, the region + * of the depth texture which contains the hands will be replaced with + * the best estimate for depth behind the hands. + */ + UFUNCTION(BlueprintCallable, Category = "OculusLibrary") + static void SetEnvironmentDepthHandRemoval(bool RemoveHands); + + /** + * Sets the occlusions mode using environment depth. When occlusions are enabled + * virtual objects that are behind physical objects will be occluded so that + * the sense of immersion is preserved. + */ + UFUNCTION(BlueprintCallable, Category = "OculusLibrary", meta = (WorldContext = "WorldContextObject")) + static void SetXROcclusionsMode(UObject* WorldContextObject, EOculusXROcclusionsMode Mode); + + /** + * Sets the eyebuffer sharpen type. This amplifies contrast and fine details. + */ + UFUNCTION(BlueprintCallable, Category = "OculusLibrary") + static void SetEyeBufferSharpenType(EOculusXREyeBufferSharpenType EyeBufferSharpenType); + + /** + * Get a system recommendation on whether Passthrough should be active. + * When set, it is recommended for apps which optionally support an MR experience + * with Passthrough to default to that mode. + * Currently, this is determined based on whether the user has Passthrough active in the home environment. + */ + UFUNCTION(BlueprintCallable, Category = "OculusLibrary") + static bool IsPassthroughRecommended(); + + /** + * Returns IStereoLayers interface to work with overlays. + */ + static class IStereoLayers* GetStereoLayers(); + + /* GUARDIAN API */ + /** + * Returns true if the Guardian Outer Boundary is being displayed + */ + UFUNCTION(BlueprintPure, Category = "OculusLibrary|Guardian") + static bool IsGuardianDisplayed(); + + /* GUARDIAN API */ + /** + * Returns true if the Guardian has been set up by the user, false if the user is in "seated" mode and has not set up a play space. + */ + UFUNCTION(BlueprintPure, Category = "OculusLibrary|Guardian") + static bool IsGuardianConfigured(); + + /** + * Returns the list of points in UE world space of the requested Boundary Type + * @param BoundaryType (in) An enum representing the boundary type requested, either Outer Boundary (exact guardian bounds) or PlayArea (rectangle inside the Outer Boundary) + * @param UsePawnSpace (in) Boolean indicating to return the points in world space or pawn space + */ + UFUNCTION(BlueprintPure, Category = "OculusLibrary|Guardian") + static TArray GetGuardianPoints(EOculusXRBoundaryType BoundaryType, bool UsePawnSpace = false); + + /** + * Returns the dimensions in UE world space of the requested Boundary Type + * @param BoundaryType (in) An enum representing the boundary type requested, either Outer Boundary (exact guardian bounds) or PlayArea (rectangle inside the Outer Boundary) + */ + UFUNCTION(BlueprintPure, Category = "OculusLibrary|Guardian") + static FVector GetGuardianDimensions(EOculusXRBoundaryType BoundaryType); + + /** + * Returns the transform of the play area rectangle, defining its position, rotation and scale to apply to a unit cube to match it with the play area. + */ + UFUNCTION(BlueprintPure, Category = "OculusLibrary|Guardian") + static FTransform GetPlayAreaTransform(); + + /** + * Get the intersection result between a UE4 coordinate and a guardian boundary + * @param Point (in) Point in UE space to test against guardian boundaries + * @param BoundaryType (in) An enum representing the boundary type requested, either Outer Boundary (exact guardian bounds) or PlayArea (rectangle inside the Outer Boundary) + */ + UFUNCTION(BlueprintCallable, Category = "OculusLibrary|Guardian") + static FOculusXRGuardianTestResult GetPointGuardianIntersection(const FVector Point, EOculusXRBoundaryType BoundaryType); + + /** + * Get the intersection result between a tracked device (HMD or controllers) and a guardian boundary + * @param DeviceType (in) Tracked Device type to test against guardian boundaries + * @param BoundaryType (in) An enum representing the boundary type requested, either Outer Boundary (exact guardian bounds) or PlayArea (rectangle inside the Outer Boundary) + */ + UFUNCTION(BlueprintCallable, Category = "OculusLibrary|Guardian") + static FOculusXRGuardianTestResult GetNodeGuardianIntersection(EOculusXRTrackedDeviceType DeviceType, EOculusXRBoundaryType BoundaryType); + + /** + * Forces the runtime to render guardian at all times or not + * @param GuardianVisible (in) True will display guardian, False will hide it + */ + UFUNCTION(BlueprintCallable, Category = "OculusLibrary|Guardian") + static void SetGuardianVisibility(bool GuardianVisible); + + /** When player triggers the Guardian boundary */ + DECLARE_MULTICAST_DELEGATE_OneParam(FOculusGuardianTriggeredEvent, FOculusXRGuardianTestResult); + + /** When player returns within outer bounds */ + DECLARE_MULTICAST_DELEGATE(FOculusGuardianReturnedEvent); + + /** + * For outer boundary only. Devs can bind delegates via something like: BoundaryComponent->OnOuterBoundaryTriggered.AddDynamic(this, &UCameraActor::PauseGameForBoundarySystem) where + * PauseGameForBoundarySystem() takes a TArray parameter. + */ + //UPROPERTY(BlueprintAssignable, Category = "Input|OculusLibrary|Guardian") + //static FOculusGuardianTriggeredEvent OnGuardianTriggered; + + /** For outer boundary only. Devs can bind delegates via something like: BoundaryComponent->OnOuterBoundaryReturned.AddDynamic(this, &UCameraActor::ResumeGameForBoundarySystem) */ + //UPROPERTY(BlueprintAssignable, Category = "OculusLibrary|Guardian") + //FOculusGuardianReturnedEvent OnGuardianReturned; + +protected: + static class OculusXRHMD::FOculusXRHMD* GetOculusXRHMD(); +}; diff --git a/Plugins/MetaXR/Source/OculusXRHMD/Public/OculusXRHMDRuntimeSettings.h b/Plugins/MetaXR/Source/OculusXRHMD/Public/OculusXRHMDRuntimeSettings.h new file mode 100644 index 0000000..e905489 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRHMD/Public/OculusXRHMDRuntimeSettings.h @@ -0,0 +1,212 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CoreMinimal.h" +#include "UObject/Object.h" +#include "OculusXRHMDTypes.h" +#include "OculusXRFunctionLibrary.h" +#include "OculusXRHMDRuntimeSettings.generated.h" + +UENUM() +enum class EOculusXRSupportedDevices : uint8 +{ + /** 0 was the deprecated Meta Quest */ + Quest2 = 1 UMETA(DisplayName = "Meta Quest 2"), + QuestPro = 2 UMETA(DisplayName = "Meta Quest Pro"), + Quest3 = 3 UMETA(DisplayName = "Meta Quest 3"), +}; + +/** +* Implements the settings for the OculusVR plugin. +*/ +UCLASS(config = Engine, defaultconfig) +class OCULUSXRHMD_API UOculusXRHMDRuntimeSettings : public UObject +{ + GENERATED_UCLASS_BODY() + +public: + /** Configure System Splash Screen background type. To configure Splash Image go to Project Settings > Platforms > Android > Launch Image. */ + UPROPERTY(config, EditAnywhere, Category = "System SplashScreen", meta = (DisplayName = "System Splash Screen Background")) + ESystemSplashBackgroundType SystemSplashBackground; + + /** Whether the Splash screen is enabled. */ + UPROPERTY(config, EditAnywhere, Category = "Engine SplashScreen") + bool bAutoEnabled; + + /** An array of splash screen descriptors listing textures to show and their positions. */ + UPROPERTY(config, EditAnywhere, Category = "Engine SplashScreen") + TArray SplashDescs; + + /** + This selects the XR API that the engine will use. If unsure, OVRPlugin OpenXR is the recommended API. + The OpenXR plugin must also be enabled to use Native OpenXR. + */ + UPROPERTY(config, EditAnywhere, Category = General, meta = (DisplayName = "XR API", ConfigRestartRequired = true)) + EOculusXRXrApi XrApi; + + /** The target color space */ + UPROPERTY(config, EditAnywhere, Category = General) + EOculusXRColorSpace ColorSpace; + + /** Whether the controller hand poses align to the Meta XR pose definitions or the OpenXR pose definitions */ + UPROPERTY(config, EditAnywhere, Category = General, meta = (EditCondition = "XrApi != EOculusXRXrApi::NativeOpenXR")) + EOculusXRControllerPoseAlignment ControllerPoseAlignment; + + /** Whether Dash is supported by the app, which will keep the app in foreground when the User presses the oculus button (needs the app to handle input focus loss!) */ + UPROPERTY(config, EditAnywhere, Category = PC) + bool bSupportsDash; + + /** Whether the app's depth buffer is shared with the Rift Compositor, for layer (including Dash) compositing, PTW, and potentially more. */ + UPROPERTY(config, EditAnywhere, Category = PC) + bool bCompositesDepth; + + /** Computes mipmaps for the eye buffers every frame, for a higher quality distortion */ + UPROPERTY(config, EditAnywhere, Category = PC) + bool bHQDistortion; + + /** + Path to Meta XR Simulator JSON file (meta_openxr_simulator.json). + */ + UPROPERTY(config, EditAnywhere, Category = PC, meta = (DisplayName = "Meta XR Simulator JSON File.")) + FFilePath MetaXRJsonPath; + + /** Maximum allowed pixel density. */ + UPROPERTY(config, EditAnywhere, Category = "Mobile|Dynamic Resolution", DisplayName = "Enable Dynamic Resolution") + bool bDynamicResolution; + + /** Minimum allowed pixel density. */ + UPROPERTY(config, EditAnywhere, Category = "Mobile|Dynamic Resolution") + float PixelDensityMin; + + /** Maximum allowed pixel density. */ + UPROPERTY(config, EditAnywhere, Category = "Mobile|Dynamic Resolution") + float PixelDensityMax; + + /** Default CPU level controlling CPU frequency on the mobile device */ + UPROPERTY(config, meta = (DeprecatedProperty, DeprecationMessage = "Use Blueprint Function Get/SetSuggestedCpuAndGpuPerformanceLevels instead.")) + int CPULevel_DEPRECATED; + + /** Default GPU level controlling GPU frequency on the mobile device */ + UPROPERTY(config, meta = (DeprecatedProperty, DeprecationMessage = "Use Blueprint Function Get/SetSuggestedCpuAndGpuPerformanceLevels instead.")) + int GPULevel_DEPRECATED; + + /** Select supported Meta Quest Devices */ + UPROPERTY(config, EditAnywhere, Category = Mobile, meta = (DisplayName = "Supported Meta Quest devices")) + TArray SupportedDevices; + + /** Suggested CPU perf level when application starts on Oculus Quest */ + UPROPERTY(config, EditAnywhere, Category = Mobile) + EOculusXRProcessorPerformanceLevel SuggestedCpuPerfLevel; + + /** Suggested GPU perf level when application starts on Oculus Quest */ + UPROPERTY(config, EditAnywhere, Category = Mobile) + EOculusXRProcessorPerformanceLevel SuggestedGpuPerfLevel; + + /** Foveated rendering method */ + UPROPERTY(config, EditAnywhere, Category = "Mobile|Foveated Rendering", meta = (EditCondition = "XrApi == EOculusXRXrApi::OVRPluginOpenXR")) + EOculusXRFoveatedRenderingMethod FoveatedRenderingMethod; + + /** Foveated rendering level */ + UPROPERTY(config, EditAnywhere, Category = "Mobile|Foveated Rendering", meta = (EditCondition = "XrApi != EOculusXRXrApi::NativeOpenXR")) + EOculusXRFoveatedRenderingLevel FoveatedRenderingLevel; + + /** Whether foveated rendering levels will change dynamically based on performance headroom or not (up to the set Foveation Level) */ + UPROPERTY(config, EditAnywhere, Category = "Mobile|Foveated Rendering", meta = (EditCondition = "XrApi != EOculusXRXrApi::NativeOpenXR")) + bool bDynamicFoveatedRendering; + + /** Whether eye tracked foveated rendering can be used with the app. */ + UPROPERTY(config, EditAnywhere, Category = "Mobile|Foveated Rendering", meta = (EditCondition = "XrApi == EOculusXRXrApi::OVRPluginOpenXR")) + bool bSupportEyeTrackedFoveatedRendering; + + /** Whether the app's depth buffer is shared with the compositor to enable depth testing against other layers. + Mobile depth composition has performance overhead both on the engine (for resolving depth) and on the compositor (for depth testing against other layers) */ + UPROPERTY(config, EditAnywhere, Category = Mobile, meta = (DisplayName = "Composite Depth")) + bool bCompositeDepthMobile; + + /** If enabled the app will be focus aware. This will keep the app in foreground when the User presses the oculus button (needs the app to handle input focus loss!) */ + UPROPERTY(config, EditAnywhere, Category = Mobile, meta = (EditCondition = "false")) + bool bFocusAware; + + /** [Experimental]Enable Late latching for reducing HMD and controller latency, improve tracking prediction quality, multiview and vulkan must be enabled for this feature. */ + UPROPERTY(config, EditAnywhere, Category = Mobile) + bool bLateLatching; + + /** If enabled the app will use the Oculus system keyboard for input fields. This requires that the app be focus aware. */ + UPROPERTY(config, EditAnywhere, Category = Mobile) + bool bRequiresSystemKeyboard; + + /** Whether controllers and/or hands can be used with the app */ + UPROPERTY(config, EditAnywhere, Category = Mobile) + EOculusXRHandTrackingSupport HandTrackingSupport; + + /** Note that a higher tracking frequency will reserve some performance headroom from the application's budget. */ + UPROPERTY(config, EditAnywhere, Category = Mobile) + EOculusXRHandTrackingFrequency HandTrackingFrequency; + + /** The version of hand tracking algorithm */ + UPROPERTY(config, EditAnywhere, Category = Mobile) + EOculusXRHandTrackingVersion HandTrackingVersion; + + /** Whether passthrough functionality can be used with the app */ + UPROPERTY(config, EditAnywhere, Category = Mobile, meta = (DisplayName = "Passthrough Enabled")) + bool bInsightPassthroughEnabled; + + /** Whether Spatial Anchors can be used with the app */ + UPROPERTY(config, EditAnywhere, Category = Mobile, meta = (DisplayName = "Anchor Support")) + bool bAnchorSupportEnabled; + + /** Whether Spatial Anchor Sharing can be used with the app */ + UPROPERTY(config, EditAnywhere, Category = Mobile, meta = (DisplayName = "Anchor Sharing")) + bool bAnchorSharingEnabled; + + /** Whether Scene can be used with the app */ + UPROPERTY(config, EditAnywhere, Category = Mobile, meta = (DisplayName = "Scene Support")) + bool bSceneSupportEnabled; + + + + /** Whether body tracking functionality can be used with the app */ + UPROPERTY(config, EditAnywhere, Category = Mobile, meta = (DisplayName = "Body Tracking Enabled", EditCondition = "XrApi == EOculusXRXrApi::OVRPluginOpenXR")) + bool bBodyTrackingEnabled; + + + /** Whether eye tracking functionality can be used with the app */ + UPROPERTY(config, EditAnywhere, Category = Mobile, meta = (DisplayName = "Eye Tracking Enabled", EditCondition = "XrApi == EOculusXRXrApi::OVRPluginOpenXR")) + bool bEyeTrackingEnabled; + + /** Whether face tracking functionality can be used with the app */ + UPROPERTY(config, EditAnywhere, Category = Mobile, meta = (DisplayName = "Face Tracking Enabled", EditCondition = "XrApi == EOculusXRXrApi::OVRPluginOpenXR")) + bool bFaceTrackingEnabled; + + /** Select preffered Face Tracking data sources */ + UPROPERTY(config, EditAnywhere, Category = Mobile, meta = (DisplayName = "Face Tracking Source", EditCondition = "XrApi == EOculusXRXrApi::OVRPluginOpenXR")) + TSet FaceTrackingDataSource; + + /** On supported Oculus mobile platforms, copy compiled .so directly to device. Allows updating compiled code without rebuilding and installing an APK. */ + UPROPERTY(config, EditAnywhere, Category = Mobile, meta = (DisplayName = "Deploy compiled .so directly to device")) + bool bDeploySoToDevice; + + /** Whether experimental features listed below can be used with the app. */ + UPROPERTY(config, EditAnywhere, Category = Experimental) + bool bSupportExperimentalFeatures; + + /** If selected, will increase the frequency of one processor at the expense of decreasing the frequency of the other on supported devices. */ + UPROPERTY(config, EditAnywhere, Category = Mobile, meta = (DisplayName = "Processor Favor")) + EProcessorFavor ProcessorFavor; + + /** Whether Tile Turn Off is enabled in app */ + UPROPERTY(config, EditAnywhere, Category = Mobile, meta = (DisplayName = "Tile Turn Off", EditCondition = "false")) + bool bTileTurnOffEnabled; + +private: +#if WITH_EDITOR + virtual bool CanEditChange(const FProperty* InProperty) const override; + virtual void PostEditChangeProperty(struct FPropertyChangedEvent& PropertyChangedEvent) override; +#endif // WITH_EDITOR + virtual void PostInitProperties() override; + + void LoadFromIni(); + void RenameProperties(); +}; diff --git a/Plugins/MetaXR/Source/OculusXRHMD/Public/OculusXRHMDTypes.h b/Plugins/MetaXR/Source/OculusXRHMD/Public/OculusXRHMDTypes.h new file mode 100644 index 0000000..e94fbc0 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRHMD/Public/OculusXRHMDTypes.h @@ -0,0 +1,361 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CoreMinimal.h" +#include "UObject/ObjectMacros.h" +#include "RHI.h" +#include "RHIResources.h" +#include "Engine/Texture2D.h" +#include "UObject/SoftObjectPath.h" +#include "OculusXRHMDTypes.generated.h" + +/* Tracked device types corresponding to ovrTrackedDeviceType enum*/ +UENUM(BlueprintType) +enum class EOculusXRTrackedDeviceType : uint8 +{ + None UMETA(DisplayName = "No Devices"), + HMD UMETA(DisplayName = "HMD"), + LTouch UMETA(DisplayName = "Left Hand"), + RTouch UMETA(DisplayName = "Right Hand"), + Touch UMETA(DisplayName = "All Hands"), + DeviceObjectZero UMETA(DisplayName = "DeviceObject Zero"), + All UMETA(DisplayName = "All Devices") +}; + +USTRUCT(BlueprintType, meta = (DisplayName = "HMD User Profile Data Field")) +struct FOculusXRHmdUserProfileField +{ + GENERATED_USTRUCT_BODY() + + UPROPERTY(BlueprintReadWrite, Category = "Input|HeadMountedDisplay") + FString FieldName; + + UPROPERTY(BlueprintReadWrite, Category = "Input|HeadMountedDisplay") + FString FieldValue; + + FOculusXRHmdUserProfileField() {} + FOculusXRHmdUserProfileField(const FString& Name, const FString& Value) + : FieldName(Name), FieldValue(Value) {} +}; + +USTRUCT(BlueprintType, meta = (DisplayName = "HMD User Profile Data")) +struct FOculusXRHmdUserProfile +{ + GENERATED_USTRUCT_BODY() + + /** Name of the user's profile. */ + UPROPERTY(BlueprintReadWrite, Category = "Input|HeadMountedDisplay") + FString Name; + + /** Gender of the user ("male", "female", etc). */ + UPROPERTY(BlueprintReadWrite, Category = "Input|HeadMountedDisplay") + FString Gender; + + /** Height of the player, in meters */ + UPROPERTY(BlueprintReadWrite, Category = "Input|HeadMountedDisplay") + float PlayerHeight; + + /** Height of the player, in meters */ + UPROPERTY(BlueprintReadWrite, Category = "Input|HeadMountedDisplay") + float EyeHeight; + + /** Interpupillary distance of the player, in meters */ + UPROPERTY(BlueprintReadWrite, Category = "Input|HeadMountedDisplay") + float IPD; + + /** Neck-to-eye distance, in meters. X - horizontal, Y - vertical. */ + UPROPERTY(BlueprintReadWrite, Category = "Input|HeadMountedDisplay") + FVector2D NeckToEyeDistance; + + UPROPERTY(BlueprintReadWrite, Category = "Input|HeadMountedDisplay") + TArray ExtraFields; + + FOculusXRHmdUserProfile() + : PlayerHeight(0.f), EyeHeight(0.f), IPD(0.f), NeckToEyeDistance(FVector2D::ZeroVector) {} +}; + +UENUM(BlueprintType) +enum class EOculusXRFoveatedRenderingMethod : uint8 +{ + FixedFoveatedRendering = 0, + EyeTrackedFoveatedRendering = 1, +}; + +UENUM(BlueprintType) +enum class EOculusXRFoveatedRenderingLevel : uint8 +{ + Off = 0, + Low = 1, + Medium = 2, + High = 3, + // High foveation setting with more detail toward the bottom of the view and more foveation near the top + HighTop = 4 +}; + +/* Guardian boundary types*/ +UENUM(BlueprintType) +enum class EOculusXRBoundaryType : uint8 +{ + Boundary_Outer UMETA(DisplayName = "Outer Boundary"), + Boundary_PlayArea UMETA(DisplayName = "Play Area"), +}; + +UENUM(BlueprintType) +enum class EOculusXRColorSpace : uint8 +{ + /// The default value from GetHmdColorSpace until SetClientColorDesc is called. Only valid on PC, and will be remapped to Quest on Mobile + Unknown = 0, + /// No color correction, not recommended for production use. See documentation for more info + Unmanaged = 1, + /// Color space for standardized color across all Oculus HMDs with D65 white point + Rec_2020 = 2, + /// Rec. 709 is used on Oculus Go and shares the same primary color coordinates as sRGB + Rec_709 = 3, + /// Oculus Rift CV1 uses a unique color space, see documentation for more info + Rift_CV1 = 4 UMETA(DisplayName = "Rift CV1"), + /// Oculus Rift S uses a unique color space, see documentation for more info + Rift_S = 5, + /// Oculus Quest's native color space is slightly different than Rift CV1 + Quest = 6 UMETA(DisplayName = "Quest 1"), + /// DCI-P3 color space. See documentation for more details + P3 = 7 UMETA(DisplayName = "P3 (Recommended)"), + /// Similar to sRGB but with deeper greens using D65 white point + Adobe_RGB = 8, +}; + +/* +* Hand tracking settings. Please check https://developer.oculus.com/documentation/unreal/unreal-hand-tracking/ +* for detailed information. +*/ +UENUM(BlueprintType) +enum class EOculusXRHandTrackingSupport : uint8 +{ + ControllersOnly, + ControllersAndHands, + HandsOnly, +}; + +UENUM(BlueprintType) +enum class EOculusXRHandTrackingFrequency : uint8 +{ + LOW, + HIGH, + MAX, +}; + +UENUM(BlueprintType) +enum class EOculusXRHandTrackingVersion : uint8 +{ + Default, + V1, + V2, +}; + +UENUM(BlueprintType) +enum class EOculusXRProcessorPerformanceLevel : uint8 +{ + PowerSavings = 0 UMETA(DisplayName = "PowerSavings", ToolTip = "Usually used in non-XR section (head-locked / static screen), during which power savings are to be prioritized"), + SustainedLow = 1 UMETA(DisplayName = "SustainedLow", ToolTip = "App enters a low and stable complexity section, during which reducing power is more important than occasional late rendering frames"), + SustainedHigh = 2 UMETA(DisplayName = "SustainedHigh", ToolTip = "Let XR Runtime to perform consistent XR compositing and frame rendering within a thermally sustainable range"), + Boost = 3 UMETA(DisplayName = "Boost(*)", ToolTip = "Allow XR Runtime to step up beyond the thermally sustainable range for short period. (Currently equivalent to SustainedHigh and not recommended to be used on Quest)") +}; + +UENUM(BlueprintType) +enum class EOculusXRDeviceType : uint8 +{ + //mobile HMDs + OculusMobile_Deprecated0 = 0, + OculusQuest_Deprecated, + OculusQuest2, + MetaQuestPro, + MetaQuest3, + + //PC HMDs + Rift = 100, + Rift_S, + Quest_Link_Deprecated, + Quest2_Link, + MetaQuestProLink, + MetaQuest3Link, + + //default + OculusUnknown = 200, +}; + +UENUM(BlueprintType) +enum class EOculusXRControllerType : uint8 +{ + None = 0, + MetaQuestTouch = 1, + MetaQuestTouchPro = 2, + MetaQuestTouchPlus = 3, + Unknown = 0x7f, +}; + +UENUM(BlueprintType) +enum class EOculusXRXrApi : uint8 +{ + OVRPluginOpenXR = 0 UMETA(DisplayName = "Oculus OVRPlugin + OpenXR backend (current recommended)", ToolTip = "Oculus plugin integration using OpenXR backend on both Mobile and PC. All new features will ship on backend for the forseeable future."), + + NativeOpenXR = 1 UMETA(DisplayName = "Epic Native OpenXR with Oculus vendor extensions", ToolTip = "Disable Legacy Oculus in favor of the native OpenXR implementation, with Oculus vendor extensions. Must enable the OpenXR plugin. This will be where Epic focuses XR development going forward. Oculus OpenXR extensions may be moved into a separate plugin (or plugins) in the future to improve modularity. The features supported by OpenXR are listed in the OpenXR specification on khronos.org, and the features supported by a given runtime can be verified with the \"OpenXR Explorer\" application on GitHub."), +}; + +/* +* Information about relationships between a triggered boundary (EOculusXRBoundaryType::Boundary_Outer or +* EOculusXRBoundaryType::Boundary_PlayArea) and a device or point in the world. +* All dimensions, points, and vectors are returned in Unreal world coordinate space. +*/ +USTRUCT(BlueprintType) +struct FOculusXRGuardianTestResult +{ + GENERATED_BODY() + + /** Is there a triggering interaction between the device/point and specified boundary? */ + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Boundary Test Result") + bool IsTriggering = false; + + /** Device type triggering boundary (EOculusXRTrackedDeviceType::None if BoundaryTestResult corresponds to a point rather than a device) */ + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Boundary Test Result") + EOculusXRTrackedDeviceType DeviceType = EOculusXRTrackedDeviceType::None; + + /** Distance of device/point to surface of boundary specified by BoundaryType */ + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Boundary Test Result") + float ClosestDistance = 0.0f; + + /** Closest point on surface corresponding to specified boundary */ + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Boundary Test Result") + FVector ClosestPoint = FVector(0.0f); + + /** Normal of closest point */ + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Boundary Test Result") + FVector ClosestPointNormal = FVector(0.0f, 0.0f, 1.0f); +}; + +UENUM() +enum class EOculusXRControllerPoseAlignment : uint8 +{ + Default = 0 UMETA(ToolTip = "Default pose alignment used in all versions of the Meta XR plugin. Recommended pose for compatibility with previous assets designed for the Meta XR plugin."), + + Grip = 1 UMETA(ToolTip = "Grip pose alignment as defined by OpenXR. Use this for cross-plugin compatibility with assets designed for the native OpenXR grip pose."), + + Aim = 2 UMETA(ToolTip = "Aim pose alignment as defined by OpenXR. Use this for cross-plugin compatibility with assets designed for the native OpenXR aim pose."), +}; + +USTRUCT() +struct FOculusXRSplashDesc +{ + GENERATED_USTRUCT_BODY() + + UPROPERTY(config, EditAnywhere, Category = Settings, meta = (AllowedClasses = "/Script/Engine.Texture", ToolTip = "Texture to display")) + FSoftObjectPath TexturePath; + + UPROPERTY(config, EditAnywhere, Category = Settings, meta = (ToolTip = "transform of center of quad (meters).")) + FTransform TransformInMeters; + + UPROPERTY(config, EditAnywhere, Category = Settings, meta = (ToolTip = "Dimensions in meters.")) + FVector2D QuadSizeInMeters; + + UPROPERTY(config, EditAnywhere, Category = Settings, meta = (ToolTip = "A delta rotation that will be added each rendering frame (half rate of full vsync).")) + FQuat DeltaRotation; + + UPROPERTY(config, EditAnywhere, Category = Settings, meta = (ToolTip = "Texture offset amount from the top left corner.")) + FVector2D TextureOffset; + + UPROPERTY(config, EditAnywhere, Category = Settings, meta = (ToolTip = "Texture scale.")) + FVector2D TextureScale; + + UPROPERTY(config, EditAnywhere, Category = Settings, meta = (ToolTip = "Whether the splash layer uses it's alpha channel.")) + bool bNoAlphaChannel; + + // Runtime data + UTexture* LoadingTexture; + FTextureRHIRef LoadedTexture; + bool bIsDynamic; + + FOculusXRSplashDesc() + : TransformInMeters(FVector(4.0f, 0.f, 0.f)) + , QuadSizeInMeters(3.f, 3.f) + , DeltaRotation(FQuat::Identity) + , TextureOffset(0.0f, 0.0f) + , TextureScale(1.0f, 1.0f) + , bNoAlphaChannel(false) + , LoadingTexture(nullptr) + , LoadedTexture(nullptr) + , bIsDynamic(false) + { + } + + bool operator==(const FOculusXRSplashDesc& d) const + { + return TexturePath == d.TexturePath && TransformInMeters.Equals(d.TransformInMeters) && QuadSizeInMeters == d.QuadSizeInMeters && DeltaRotation.Equals(d.DeltaRotation) && TextureOffset == d.TextureOffset && TextureScale == d.TextureScale && bNoAlphaChannel == d.bNoAlphaChannel && LoadingTexture == d.LoadingTexture && LoadedTexture == d.LoadedTexture && bIsDynamic == d.bIsDynamic; + } +}; + +UENUM(BlueprintType) +enum class EOculusXROcclusionsMode : uint8 +{ + /// Environment depth occlusions disabled. + Disabled = 0, + /// Hard occlusions, good performance, shows hard edges between the real and virtual world. + HardOcclusions = 1, + /// Soft occlusions, most expensive, shows soft edges between the real and virtual world. + SoftOcclusions = 2, +}; + +UENUM(BlueprintType) +enum class EOculusXREyeBufferSharpenType : uint8 +{ + /// No Sharpening + SLST_None UMETA(DisplayName = "No Sharpening"), + + /// Normal Sharpening + SLST_Normal UMETA(DisplayName = "Normal Sharpening"), + + /// Quality Sharpening + SLST_Quality UMETA(DisplayName = "Quality Sharpening"), + + /// Auto Filtering: Runtime automatically chooses the appropriate sharpening filter + SLST_Auto UMETA(DisplayName = "Auto Filtering"), + + SLST_MAX, +}; + +UENUM() +enum class EProcessorFavor : int8 +{ + FavorEqually = 0 UMETA(DisplayName = "Favor Equally"), + FavorCPU = 1 UMETA(DisplayName = "Favor CPU"), + FavorGPU = 2 UMETA(DisplayName = "Favor GPU"), +}; + +UENUM(BlueprintType) +enum class EOculusXRHMDBodyTrackingFidelity : uint8 +{ + Unset = 0 UMETA(Hidden), + Low = 1, + High = 2, +}; + +UENUM(BlueprintType) +enum class EOculusXRHMDBodyJointSet : uint8 +{ + UpperBody = 0, + FullBody = 1, +}; + +UENUM() +enum class EFaceTrackingDataSourceConfig : int8 +{ + Visual = 0 UMETA(DisplayName = "Visual"), + Audio = 1 UMETA(DisplayName = "Audio"), + MAX = 2 UMETA(Hidden), +}; + +UENUM() +enum class ESystemSplashBackgroundType : int8 +{ + Black = 0 UMETA(DisplayName = "Black"), + Contextual = 1 UMETA(DisplayName = "Passthrough (Contextual)"), +}; diff --git a/Plugins/MetaXR/Source/OculusXRHMD/Public/OculusXRPassthroughLayerShapes.h b/Plugins/MetaXR/Source/OculusXRHMD/Public/OculusXRPassthroughLayerShapes.h new file mode 100644 index 0000000..69d6555 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRHMD/Public/OculusXRPassthroughLayerShapes.h @@ -0,0 +1,164 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#pragma once + +#include "StereoLayerShapes.h" +#include "OculusXRPassthroughMesh.h" +#include "Misc/EngineVersionComparison.h" +#include "OculusXRPassthroughLayerShapes.generated.h" + +UENUM() +enum EOculusXRColorMapType +{ + /** None*/ + ColorMapType_None = 0 UMETA(DisplayName = "None"), + + /** Grayscale to color */ + ColorMapType_GrayscaleToColor = 1 UMETA(DisplayName = "Grayscale To Color"), + + /** Grayscale */ + ColorMapType_Grayscale = 2 UMETA(DisplayName = "Grayscale"), + + /** Color Adjustment */ + ColorMapType_ColorAdjustment = 3 UMETA(DisplayName = "Color Adjustment"), + + /** Color LUT */ + ColorMapType_ColorLut = 4 UMETA(DisplayName = "Color LUT"), + + /** Interpolated Color LUT */ + ColorMapType_ColorLut_Interpolated = 5 UMETA(DisplayName = "Interpolated Color LUT"), + + ColorMapType_MAX = 255, +}; + +UENUM() +enum EOculusXRPassthroughLayerOrder +{ + /** Layer is rendered on top of scene */ + PassthroughLayerOrder_Overlay = 0 UMETA(DisplayName = "Overlay"), + + /** Layer is rendered under scene */ + PassthroughLayerOrder_Underlay = 1 UMETA(DisplayName = "Underlay"), + + PassthroughLayerOrder_MAX = 255, +}; + +struct OCULUSXRHMD_API FColorLutDesc +{ + FColorLutDesc(); + + FColorLutDesc(const TArray& InColorLuts, float InWeight); + + float Weight; + TArray ColorLuts; +}; + +struct OCULUSXRHMD_API FEdgeStyleParameters +{ +public: + FEdgeStyleParameters(); + + FEdgeStyleParameters( + bool bEnableEdgeColor, + bool bEnableColorMap, + float TextureOpacityFactor, + float Brightness, + float Contrast, + float Posterize, + float Saturation, + FLinearColor EdgeColor, + FLinearColor ColorScale, + FLinearColor ColorOffset, + EOculusXRColorMapType InColorMapType, + const TArray& InColorMapGradient, + const FColorLutDesc& InLutDesc); + + bool bEnableEdgeColor; + bool bEnableColorMap; + bool bUseColorLuts; + float TextureOpacityFactor; + float Brightness; + float Contrast; + float Posterize; + float Saturation; + FLinearColor EdgeColor; + FLinearColor ColorScale; + FLinearColor ColorOffset; + EOculusXRColorMapType ColorMapType; + TArray ColorMapData; + FColorLutDesc ColorLutDesc; + +private: + /** Generates the corresponding color map based on given color map type */ + TArray GenerateColorMapData(EOculusXRColorMapType InColorMapType, const TArray& InColorMapGradient); + + /** Generates a grayscale to color color map based on given gradient --> It also applies the color scale and offset */ + TArray GenerateMonoToRGBA(const TArray& InGradient, const TArray& InColorMapData); + + /** Generates a grayscale color map with given Brightness/Contrast/Posterize settings */ + TArray GenerateMonoBrightnessContrastPosterizeMap(); + + /** Generates a luminance based colormap from the the Brightness/Contrast */ + TArray GenerateBrightnessContrastSaturationColorMap(); +}; + +#if UE_VERSION_OLDER_THAN(5, 3, 0) +#define OCULUSXRHMD_API_CLASS OCULUSXRHMD_API +#define OCULUSXRHMD_API_MEMBER +#else +#define OCULUSXRHMD_API_CLASS +#define OCULUSXRHMD_API_MEMBER OCULUSXRHMD_API +#endif + +class OCULUSXRHMD_API_CLASS FReconstructedLayer : public IStereoLayerShape +{ +public: + OCULUSXRHMD_API_MEMBER static const FName ShapeName; + virtual FName GetShapeName() override { return ShapeName; } + virtual IStereoLayerShape* Clone() const override { return new FReconstructedLayer(*this); } + +public: + FReconstructedLayer(){}; + FReconstructedLayer(const FEdgeStyleParameters& EdgeStyleParameters, EOculusXRPassthroughLayerOrder PassthroughLayerOrder) + : EdgeStyleParameters(EdgeStyleParameters), PassthroughLayerOrder(PassthroughLayerOrder){}; + FEdgeStyleParameters EdgeStyleParameters; + EOculusXRPassthroughLayerOrder PassthroughLayerOrder; +}; + +struct FUserDefinedGeometryDesc +{ + FUserDefinedGeometryDesc(const FString& MeshName, OculusXRHMD::FOculusPassthroughMeshRef PassthroughMesh, const FTransform& Transform, bool bUpdateTransform) + : MeshName(MeshName) + , PassthroughMesh(PassthroughMesh) + , Transform(Transform) + , bUpdateTransform(bUpdateTransform){}; + + FString MeshName; + OculusXRHMD::FOculusPassthroughMeshRef PassthroughMesh; + FTransform Transform; + bool bUpdateTransform; +}; + +class OCULUSXRHMD_API_CLASS FUserDefinedLayer : public IStereoLayerShape +{ +public: + OCULUSXRHMD_API_MEMBER static const FName ShapeName; + virtual FName GetShapeName() override { return ShapeName; } + virtual IStereoLayerShape* Clone() const override { return new FUserDefinedLayer(*this); } + +public: + FUserDefinedLayer(){}; + FUserDefinedLayer(TArray InUserGeometryList, const FEdgeStyleParameters& EdgeStyleParameters, EOculusXRPassthroughLayerOrder PassthroughLayerOrder) + : UserGeometryList{} + , EdgeStyleParameters(EdgeStyleParameters) + , PassthroughLayerOrder(PassthroughLayerOrder) + { + UserGeometryList = InUserGeometryList; + } + + TArray UserGeometryList; + FEdgeStyleParameters EdgeStyleParameters; + EOculusXRPassthroughLayerOrder PassthroughLayerOrder; + +private: +}; diff --git a/Plugins/MetaXR/Source/OculusXRHMD/Public/OculusXRPassthroughMesh.h b/Plugins/MetaXR/Source/OculusXRHMD/Public/OculusXRPassthroughMesh.h new file mode 100644 index 0000000..0ac2d5c --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRHMD/Public/OculusXRPassthroughMesh.h @@ -0,0 +1,30 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#pragma once + +#include "CoreMinimal.h" +#include "Templates/RefCounting.h" + +namespace OculusXRHMD +{ + + class FOculusPassthroughMesh : public FRefCountedObject + { + public: + FOculusPassthroughMesh(const TArray& InVertices, const TArray& InTriangles) + : Vertices(InVertices) + , Triangles(InTriangles) + { + } + + const TArray& GetVertices() const { return Vertices; }; + const TArray& GetTriangles() const { return Triangles; }; + + private: + TArray Vertices; + TArray Triangles; + }; + + typedef TRefCountPtr FOculusPassthroughMeshRef; + +} // namespace OculusXRHMD diff --git a/Plugins/MetaXR/Source/OculusXRHMD/Public/OculusXRQPL.h b/Plugins/MetaXR/Source/OculusXRHMD/Public/OculusXRQPL.h new file mode 100644 index 0000000..fb60663 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRHMD/Public/OculusXRQPL.h @@ -0,0 +1,75 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#pragma once + +#include "Misc/DateTime.h" + +namespace OculusXRTelemetry +{ + enum class OCULUSXRHMD_API EAction : short + { + Start = 1, + Success = 2, + Fail = 3, + Cancel = 4, + DrawComplete = 5, + OnResume = 6 + }; + + class OCULUSXRHMD_API FTelemetryInstanceKey + { + public: + constexpr FTelemetryInstanceKey(const int InstanceKey) + : Value(InstanceKey){}; + + constexpr int GetValue() const { return Value; } + + private: + int Value; + }; + + constexpr FTelemetryInstanceKey DefaultTelemetryInstance = FTelemetryInstanceKey(0); + + class OCULUSXRHMD_API FTelemetryTimestamp + { + static constexpr int OneHundredNsToMs = 1000; + + public: + FTelemetryTimestamp(FDateTime Timestamp) + : TotalMs(Timestamp.GetTicks() / OneHundredNsToMs){}; + constexpr FTelemetryTimestamp(int64 TimestampMs) + : TotalMs(TimestampMs){}; + + constexpr int64 GetTimestamp() const { return TotalMs; } + + private: + int64 TotalMs; + }; + + constexpr FTelemetryTimestamp AutoSetTimestamp = FTelemetryTimestamp(-1); + + struct OCULUSXRHMD_API FEmptyBackend + { + static bool MarkerStart(int, FTelemetryInstanceKey, FTelemetryTimestamp) { return false; }; + static bool MarkerEnd(int, EAction, FTelemetryInstanceKey, FTelemetryTimestamp) { return false; }; + static bool MarkerPoint(int, const char*, FTelemetryInstanceKey, FTelemetryTimestamp) { return false; }; + static bool MarkerPointCached(int, int, FTelemetryInstanceKey, FTelemetryTimestamp) { return false; }; + static bool MarkerAnnotation(int, const char*, const char*, FTelemetryInstanceKey) { return false; }; + static bool CreateMarkerHandle(const char*, int*) { return false; }; + static bool DestroyMarkerHandle(int) { return false; }; + static bool OnEditorShutdown() { return false; }; + static constexpr bool IsNullBackend() { return true; }; + }; + struct OCULUSXRHMD_API FQPLBackend + { + static bool MarkerStart(int MarkerId, FTelemetryInstanceKey InstanceKey, FTelemetryTimestamp Timestamp); + static bool MarkerEnd(int MarkerId, EAction Action, FTelemetryInstanceKey InstanceKey, FTelemetryTimestamp Timestamp); + static bool MarkerPoint(int MarkerId, const char* Name, FTelemetryInstanceKey InstanceKey, FTelemetryTimestamp Timestamp); + static bool MarkerPointCached(int MarkerId, int NameHandle, FTelemetryInstanceKey InstanceKey, FTelemetryTimestamp Timestamp); + static bool MarkerAnnotation(int MarkerId, const char* AnnotationKey, const char* AnnotationValue, FTelemetryInstanceKey InstanceKey); + static bool CreateMarkerHandle(const char* Name, int* NameHandle); + static bool DestroyMarkerHandle(int NameHandle); + static bool OnEditorShutdown(); + static constexpr bool IsNullBackend() { return false; }; + }; +} // namespace OculusXRTelemetry diff --git a/Plugins/MetaXR/Source/OculusXRHMD/Public/OculusXRTelemetry.h b/Plugins/MetaXR/Source/OculusXRHMD/Public/OculusXRTelemetry.h new file mode 100644 index 0000000..d248dea --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRHMD/Public/OculusXRTelemetry.h @@ -0,0 +1,170 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#pragma once + +#include "OculusXRQPL.h" + +namespace OculusXRTelemetry +{ +#ifndef TURN_OFF_META_TELEMETRY + using FTelemetryBackend = FQPLBackend; +#else + using FTelemetryBackend = FEmptyBackend; +#endif + + OCULUSXRHMD_API bool IsActive(); + OCULUSXRHMD_API void IfActiveThen(TUniqueFunction Function); + OCULUSXRHMD_API void PropagateTelemetryConsent(); + + template + class OCULUSXRHMD_API TMarkerPoint : FNoncopyable + { + public: + explicit TMarkerPoint(const char* Name) + : bCreated(Backend::CreateMarkerHandle(Name, Handle)) {} + ~TMarkerPoint() + { + if (bCreated) + { + Backend::DestroyMarkerHandle(Handle); + } + } + int GetHandle() const { return Handle; } + + private: + const bool bCreated{ false }; + const int Handle{ -1 }; + }; + + template + class TMarker + { + public: + explicit TMarker(const FTelemetryInstanceKey InstanceKey = DefaultTelemetryInstance) + : InstanceKey(InstanceKey) + { + } + TMarker(const TMarker&& Other) noexcept + : InstanceKey(Other.GetMarkerId()) {} + + const TMarker& Start(const FTelemetryTimestamp Timestamp = AutoSetTimestamp) const + { + Backend::MarkerStart(MarkerId, InstanceKey, Timestamp); + return *this; + } + const TMarker& AddAnnotation(const char* Key, const char* Value) const + { + Backend::MarkerAnnotation(MarkerId, Key, Value, InstanceKey); + return *this; + } + const TMarker& AddPoint(const char* Name, const FTelemetryTimestamp Timestamp = AutoSetTimestamp) const + { + Backend::MarkerPoint(MarkerId, Name, InstanceKey, Timestamp); + return *this; + } + const TMarker& AddPoint(const TMarkerPoint& MarkerPoint, const FTelemetryTimestamp Timestamp = AutoSetTimestamp) const + { + Backend::MarkerPoint(MarkerId, MarkerPoint.GetHandle(), InstanceKey, Timestamp); + return *this; + } + void End(EAction Result, const FTelemetryTimestamp Timestamp = AutoSetTimestamp) const + { + Backend::MarkerEnd(MarkerId, Result, InstanceKey, Timestamp); + } + constexpr static int GetMarkerId() + { + return MarkerId; + } + + private: + const FTelemetryInstanceKey InstanceKey; + }; + + struct FIgnoreNotEndedMarker + { + template + constexpr const FIgnoreNotEndedMarker& operator=(const TMarker&) const noexcept + { + // do nothing + return *this; + } + }; + + constexpr FIgnoreNotEndedMarker NotEnd{}; + + enum class EScopeMode + { + StartAndEnd, + Start, + End + }; + + template + class TScopedMarker : public FNoncopyable + { + TOptional Marker; + EAction Result{ EAction::Success }; + static constexpr EScopeMode Scope{ TScope }; + + public: + TScopedMarker(const FTelemetryInstanceKey InstanceKey = DefaultTelemetryInstance) + { + if (IsActive()) + { + Marker.Emplace(InstanceKey); + if constexpr (Scope != EScopeMode::End) + { + const auto& Self = Start(); + } + } + } + ~TScopedMarker() + { + if constexpr (Scope != EScopeMode::Start) + { + End(); + } + } + + const TScopedMarker& Start() const + { + if (Marker) + { + Marker->Start(); + } + return *this; + } + + const TScopedMarker& AddPoint(const char* Name) const + { + if (Marker) + { + Marker->AddPoint(Name); + } + return *this; + } + + const TScopedMarker& AddAnnotation(const char* Key, const char* Value) const + { + if (Marker) + { + Marker->AddAnnotation(Key, Value); + } + return *this; + } + + const TScopedMarker& SetResult(EAction InResult) + { + Result = InResult; + return *this; + } + + void End() const + { + if (Marker) + { + Marker->End(Result); + } + } + }; +} // namespace OculusXRTelemetry diff --git a/Plugins/MetaXR/Source/OculusXRInput/OculusXRInput.Build.cs b/Plugins/MetaXR/Source/OculusXRInput/OculusXRInput.Build.cs new file mode 100644 index 0000000..972dcf2 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRInput/OculusXRInput.Build.cs @@ -0,0 +1,61 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +namespace UnrealBuildTool.Rules +{ + public class OculusXRInput : ModuleRules + { + public OculusXRInput(ReadOnlyTargetRules Target) : base(Target) + { + bUseUnity = true; + + PrivateIncludePathModuleNames.AddRange( + new string[] + { + "InputDevice", // For IInputDevice.h + "HeadMountedDisplay", // For IMotionController.h + "ImageWrapper" + }); + + PrivateDependencyModuleNames.AddRange( + new string[] + { + "Core", + "CoreUObject", + "ApplicationCore", + "Engine", + "InputCore", + "HeadMountedDisplay", + "OculusXRHMD", + "OculusXRMR", + "OVRPluginXR", + }); + + if (Target.Version.MajorVersion > 5 || (Target.Version.MajorVersion == 5 && Target.Version.MinorVersion >= 3)) + { + PrivateDependencyModuleNames.AddRange( + new string[] + { + "XRBase", + }); + } + + PrivateIncludePaths.AddRange( + new string[] { + // Relative to Engine\Plugins\Runtime\Oculus\OculusVR\Source + "OculusXRHMD/Private", + }); + + PublicIncludePaths.AddRange( + new string[] { + "Runtime/Renderer/Private", + "Runtime/Engine/Classes/Components", + }); + + if (Target.Platform == UnrealTargetPlatform.Win64) + { + RuntimeDependencies.Add("$(PluginDir)/Source/ThirdParty/OVRPlugin/OVRPlugin/Lib/" + Target.Platform.ToString() + "/OpenXR/OVRPlugin.dll"); + } + } + } +} diff --git a/Plugins/MetaXR/Source/OculusXRInput/Private/OculusXRControllerComponent.cpp b/Plugins/MetaXR/Source/OculusXRInput/Private/OculusXRControllerComponent.cpp new file mode 100644 index 0000000..32c9ee6 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRInput/Private/OculusXRControllerComponent.cpp @@ -0,0 +1,161 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +// A class to render the currently connected controller. +// Similar to how hands are tracked. + +#include "OculusXRControllerComponent.h" +#include "OculusXRInput.h" +#include "Components/StaticMeshComponent.h" +#include "OculusXRHandTracking.h" +#include + +UOculusXRControllerComponent::UOculusXRControllerComponent() + : Super(), + // These position and rotation offsets are needed to correctly position the controller + // when using natural or controller based hand positioning. + // Why do these need to be hardcoded and not come from the skeleton etc? + // It seems like the offset comes from somewhere in unreal in the first place, + // not from a bone position, so there's not a place to load the correct orientation from. + PositionOffsets{ + { + FVector(0, 0, 0), // Side: None, Controller Mapping: None + FVector(0, 0, 0), // Side: None, Controller Mapping: Natural + FVector(0, 0, 0), // Side: None, Controller Mapping: Controller + }, + { + FVector(0, 0, 0), // Side: Left, Controller Mapping: None + FVector(4.278, 9.969, 4.638), // Side: Left, Controller Mapping: Natural + FVector(4.278, 9.969, 4.638), // Side: Left, Controller Mapping: Controller + }, + { + FVector(0, 0, 0), // Side: Right, Controller Mapping: None + FVector(-4.104, -9.993, -4.244), // Side: Right, Controller Mapping: Natural + FVector(-4.104, -9.993, -4.244), // Side: Right, Controller Mapping: Controller + }, + } + , RotationOffsets{ + { + FVector(0, 0, 0), // Side: None, Controller Mapping: None + FVector(0, 0, 0), // Side: None, Controller Mapping: Natural + FVector(0, 0, 0), // Side: None, Controller Mapping: Controller + }, + { + FVector(0, 0, 0), // Side: Left, Controller Mapping: None + FVector(90, 166.229, 263.738), // Side: Left, Controller Mapping: Natural + FVector(90, 168.515, 259.149), // Side: Left, Controller Mapping: Controller + }, + { + FVector(0, 0, 0), // Side: Right, Controller Mapping: None + FVector(90, 194.995, 83.863), // Side: Right, Controller Mapping: Natural + FVector(90, 191.485, 79.149), // Side: Right, Controller Mapping: Controller + }, + } +{ + _meshLoadingState = MeshLoadingState::None; + PrimaryComponentTick.bCanEverTick = true; +} + +void UOculusXRControllerComponent::BeginPlay() +{ + Super::BeginPlay(); +} + +void UOculusXRControllerComponent::TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) +{ + Super::TickComponent(DeltaTime, TickType, ThisTickFunction); + + // If we're in a capsense mode, we need to offset the controller position so that it's correct / consistent with the hand position. + if (_cachedControllerHandType != OculusXRInput::FOculusHandTracking::ControllerDrivenHandType) + { + _cachedControllerHandType = OculusXRInput::FOculusHandTracking::ControllerDrivenHandType; + + const FVector positionOffset = PositionOffsets[static_cast(SkeletonType)][static_cast(_cachedControllerHandType)]; + const FVector rotationOffset = RotationOffsets[static_cast(SkeletonType)][static_cast(_cachedControllerHandType)]; + + SetRelativeLocation(positionOffset); + SetRelativeRotation(FQuat::MakeFromEuler(rotationOffset)); + } + + bool isHandTrackingEnabled = UOculusXRInputFunctionLibrary::IsHandTrackingEnabled(); + bool shouldHide = isHandTrackingEnabled && !(RenderWhenUsingControllerDrivenHands && OculusXRInput::FOculusHandTracking::ControllerDrivenHandType == EOculusXRControllerDrivenHandPoseTypes::Controller); + if (shouldHide && !bHiddenInGame) + { + SetHiddenInGame(true, false); + } + if (!shouldHide && bHiddenInGame) + { + SetHiddenInGame(false, false); + } + + if (_meshLoadingState == MeshLoadingState::None || _controllerType != GetControllerType()) + { + InitializeMesh(); + } +} + +EOculusXRControllerType UOculusXRControllerComponent::GetControllerType() +{ + EControllerHand controllerHand = EControllerHand::AnyHand; + if (SkeletonType == EOculusXRSide::Left) + { + controllerHand = EControllerHand::Left; + } + else if (SkeletonType == EOculusXRSide::Right) + { + controllerHand = EControllerHand::Right; + } + return UOculusXRFunctionLibrary::GetControllerType(controllerHand); +} + +void UOculusXRControllerComponent::InitializeMesh() +{ + if (_runtimeMesh != nullptr) + { + SetStaticMesh(nullptr); + _streamableManager.Unload(_runtimeMeshPath); + _runtimeMesh = nullptr; + } + + auto left_controller_path = TEXT("none"); + auto right_controller_path = TEXT("none"); + + _controllerType = GetControllerType(); + switch (_controllerType) + { + case EOculusXRControllerType::MetaQuestTouch: + left_controller_path = TEXT("/Script/Engine.StaticMesh'/OculusXR/Meshes/LeftTouchForQuest2.LeftTouchForQuest2'"); + right_controller_path = TEXT("/Script/Engine.StaticMesh'/OculusXR/Meshes/RightTouchForQuest2.RightTouchForQuest2'"); + break; + case EOculusXRControllerType::MetaQuestTouchPlus: + // We don't currently have a model for the touch plus controller, default to the touch pro. + case EOculusXRControllerType::MetaQuestTouchPro: + left_controller_path = TEXT("/Script/Engine.StaticMesh'/OculusXR/Meshes/LeftMetaQuestTouchPro.LeftMetaQuestTouchPro'"); + right_controller_path = TEXT("/Script/Engine.StaticMesh'/OculusXR/Meshes/RightMetaQuestTouchPro.RightMetaQuestTouchPro'"); + break; + case EOculusXRControllerType::None: + case EOculusXRControllerType::Unknown: + default: + return; + } + + auto controllerPath = left_controller_path; + if (SkeletonType == EOculusXRSide::Right) + { + controllerPath = right_controller_path; + } + _runtimeMeshPath = FSoftObjectPath(controllerPath); + + _loadAssetHandle = _streamableManager.RequestAsyncLoad( + _runtimeMeshPath, + FStreamableDelegate::CreateUObject(this, &UOculusXRControllerComponent::MeshLoaded)); +} + +void UOculusXRControllerComponent::MeshLoaded() +{ + if (_loadAssetHandle.IsValid() && _loadAssetHandle.Get()->HasLoadCompleted()) + { + _runtimeMesh = reinterpret_cast(_loadAssetHandle.Get()->GetLoadedAsset()); + _meshLoadingState = MeshLoadingState::Loaded; + SetStaticMesh(_runtimeMesh); + } +} diff --git a/Plugins/MetaXR/Source/OculusXRInput/Private/OculusXRControllerTracking.cpp b/Plugins/MetaXR/Source/OculusXRInput/Private/OculusXRControllerTracking.cpp new file mode 100644 index 0000000..c7d82bf --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRInput/Private/OculusXRControllerTracking.cpp @@ -0,0 +1,67 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +#include "OculusXRControllerTracking.h" +#include "OculusXRHMD.h" +#include "OculusXRInput.h" +#include "Misc/CoreDelegates.h" +#include "IOculusXRInputModule.h" +#include "Haptics/HapticFeedbackEffect_Base.h" + +namespace OculusXRInput +{ + void FOculusXRControllerTracking::PlayHapticEffect( + class UHapticFeedbackEffect_Base* HapticEffect, + EControllerHand Hand, + EOculusXRHandHapticsLocation Location, + bool bAppend, + float Scale, + bool bLoop) + { +#if OCULUS_INPUT_SUPPORTED_PLATFORMS + TSharedPtr OculusXRInputModule = StaticCastSharedPtr(IOculusXRInputModule::Get().GetInputDevice()); + OculusXRInputModule.Get()->PlayHapticEffect(HapticEffect, Hand, Location, bAppend, Scale, bLoop); +#endif + } + + int FOculusXRControllerTracking::PlayHapticEffect(EControllerHand Hand, TArray& Amplitudes, int SampleRate, bool bPCM, bool bAppend) + { +#if OCULUS_INPUT_SUPPORTED_PLATFORMS + TSharedPtr OculusXRInputModule = StaticCastSharedPtr(IOculusXRInputModule::Get().GetInputDevice()); + return OculusXRInputModule.Get()->PlayHapticEffect(Hand, Amplitudes.Num(), Amplitudes.GetData(), SampleRate, bPCM, bAppend); +#endif + } + + void FOculusXRControllerTracking::StopHapticEffect(EControllerHand Hand, EOculusXRHandHapticsLocation Location) + { +#if OCULUS_INPUT_SUPPORTED_PLATFORMS + SetHapticsByValue(0.f, 0.f, Hand, Location); +#endif + } + + void FOculusXRControllerTracking::SetHapticsByValue(float Frequency, float Amplitude, EControllerHand Hand, EOculusXRHandHapticsLocation Location) + { +#if OCULUS_INPUT_SUPPORTED_PLATFORMS + TSharedPtr OculusXRInputModule = StaticCastSharedPtr(IOculusXRInputModule::Get().GetInputDevice()); + OculusXRInputModule.Get()->SetHapticsByValue(Frequency, Amplitude, Hand, Location); +#endif + } + + float FOculusXRControllerTracking::GetControllerSampleRateHz(EControllerHand Hand) + { +#if OCULUS_INPUT_SUPPORTED_PLATFORMS + TSharedPtr OculusXRInputModule = StaticCastSharedPtr(IOculusXRInputModule::Get().GetInputDevice()); + return OculusXRInputModule.Get()->GetControllerSampleRateHz(Hand); +#endif + return 0; + } + + int FOculusXRControllerTracking::GetMaxHapticDuration(EControllerHand Hand) + { +#if OCULUS_INPUT_SUPPORTED_PLATFORMS + TSharedPtr OculusXRInputModule = StaticCastSharedPtr(IOculusXRInputModule::Get().GetInputDevice()); + return OculusXRInputModule.Get()->GetMaxHapticDuration(Hand); +#endif + return 0; + } +} // namespace OculusXRInput diff --git a/Plugins/MetaXR/Source/OculusXRInput/Private/OculusXRControllerTracking.h b/Plugins/MetaXR/Source/OculusXRInput/Private/OculusXRControllerTracking.h new file mode 100644 index 0000000..c4336b3 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRInput/Private/OculusXRControllerTracking.h @@ -0,0 +1,43 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +#pragma once +#include "OculusXRInputFunctionLibrary.h" + +#define LOCTEXT_NAMESPACE "OculusXRControllerTracking" + +DEFINE_LOG_CATEGORY_STATIC(LogOcXRControllerTracking, Log, All); + +//------------------------------------------------------------------------------------------------- +// FOculusXRControllerTracking +//------------------------------------------------------------------------------------------------- + +class UHapticFeedbackEffect_Base; + +namespace OculusXRInput +{ + class FOculusXRControllerTracking + { + public: + static void PlayHapticEffect( + UHapticFeedbackEffect_Base* HapticEffect, + EControllerHand Hand, + EOculusXRHandHapticsLocation Location = EOculusXRHandHapticsLocation::Hand, + bool bAppend = false, + float Scale = 1.f, + bool bLoop = false); + + static int PlayHapticEffect(EControllerHand Hand, TArray& Amplitudes, int SampleRate, bool bPCM = false, bool bAppend = false); + + static void StopHapticEffect(EControllerHand Hand, EOculusXRHandHapticsLocation Location = EOculusXRHandHapticsLocation::Hand); + + static void SetHapticsByValue(float Frequency, float Amplitude, EControllerHand Hand, EOculusXRHandHapticsLocation Location = EOculusXRHandHapticsLocation::Hand); + + static float GetControllerSampleRateHz(EControllerHand Hand); + + static int GetMaxHapticDuration(EControllerHand Hand); + }; + +} // namespace OculusXRInput + +#undef LOCTEXT_NAMESPACE diff --git a/Plugins/MetaXR/Source/OculusXRInput/Private/OculusXRHandComponent.cpp b/Plugins/MetaXR/Source/OculusXRInput/Private/OculusXRHandComponent.cpp new file mode 100644 index 0000000..f148115 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRInput/Private/OculusXRHandComponent.cpp @@ -0,0 +1,221 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. +#include "OculusXRHandComponent.h" +#include "OculusXRInput.h" + +#include "Engine/SkeletalMesh.h" +#include "Components/InputComponent.h" +#include "Materials/MaterialInterface.h" + +#include "GameFramework/Pawn.h" +#include "GameFramework/PlayerController.h" + +UOculusXRHandComponent::UOculusXRHandComponent(const FObjectInitializer& ObjectInitializer) + : Super(ObjectInitializer) +{ + PrimaryComponentTick.bCanEverTick = true; + PrimaryComponentTick.bStartWithTickEnabled = true; + PrimaryComponentTick.TickGroup = TG_PrePhysics; + + bHasAuthority = false; + bAutoActivate = true; + + bWantsInitializeComponent = true; + + for (uint8 BoneIndex = 0; BoneIndex < (uint8)EOculusXRBone::Bone_Max; BoneIndex++) + { + BoneNameMappings.Add((EOculusXRBone)BoneIndex, TEXT("")); + } +} + +void UOculusXRHandComponent::BeginPlay() +{ + Super::BeginPlay(); + + // Use custom mesh if a skeletal mesh is already set, else try to load the runtime mesh + if (GetSkinnedAsset()) + { + bCustomHandMesh = true; + bSkeletalMeshInitialized = true; + } + else + { + RuntimeSkeletalMesh = NewObject(this, TEXT("OculusHandMesh")); + InitializeSkeletalMesh(); + } +} + +void UOculusXRHandComponent::InitializeSkeletalMesh() +{ + if (RuntimeSkeletalMesh) + { + if (UOculusXRInputFunctionLibrary::GetHandSkeletalMesh(RuntimeSkeletalMesh, SkeletonType, MeshType)) + { + SetSkinnedAssetAndUpdate(RuntimeSkeletalMesh, true); + if (MaterialOverride) + { + SetMaterial(0, MaterialOverride); + } + CachedBaseMaterial = GetMaterial(0); + bSkeletalMeshInitialized = true; + + // Initialize physics capsules on the runtime mesh + if (bInitializePhysics) + { + CollisionCapsules = UOculusXRInputFunctionLibrary::InitializeHandPhysics(SkeletonType, this); + } + } + } +} + +void UOculusXRHandComponent::TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) +{ + Super::TickComponent(DeltaTime, TickType, ThisTickFunction); + +#if WITH_EDITOR + if (!bSkeletalMeshInitialized && !bCustomHandMesh) + { + InitializeSkeletalMesh(); + } +#endif + + if (IsInGameThread()) + { + // Cache state from the game thread for use on the render thread + const AActor* MyOwner = GetOwner(); + bHasAuthority = MyOwner->HasLocalNetOwner(); + int i = 0; + } + + if (bHasAuthority) + { + bool bHidden = false; + if (UOculusXRInputFunctionLibrary::IsHandTrackingEnabled()) + { + // Update Visibility based on Confidence + if (ConfidenceBehavior == EOculusXRConfidenceBehavior::HideActor) + { + EOculusXRTrackingConfidence TrackingConfidence = UOculusXRInputFunctionLibrary::GetTrackingConfidence(SkeletonType); + bHidden |= TrackingConfidence != EOculusXRTrackingConfidence::High; + } + + // Update Hand Scale + if (bUpdateHandScale) + { + float NewScale = UOculusXRInputFunctionLibrary::GetHandScale(SkeletonType); + SetRelativeScale3D(FVector(NewScale)); + } + + // Update Bone Pose Rotations + if (GetSkinnedAsset()) + { + UpdateBonePose(); + } + +#if OCULUS_INPUT_SUPPORTED_PLATFORMS + // Check for system gesture pressed through player controller + if (APawn* Pawn = Cast(GetOwner())) + { + if (APlayerController* PC = Pawn->GetController()) + { + if (PC->WasInputKeyJustPressed(SkeletonType == EOculusXRHandType::HandLeft ? OculusXRInput::FOculusKey::OculusHand_Left_SystemGesture : OculusXRInput::FOculusKey::OculusHand_Right_SystemGesture)) + { + SystemGesturePressed(); + } + if (PC->WasInputKeyJustReleased(SkeletonType == EOculusXRHandType::HandLeft ? OculusXRInput::FOculusKey::OculusHand_Left_SystemGesture : OculusXRInput::FOculusKey::OculusHand_Right_SystemGesture)) + { + SystemGestureReleased(); + } + } + } +#endif + } + else + { + bHidden = true; + } + + if (bHidden != bHiddenInGame) + { + SetHiddenInGame(bHidden); + for (int32 i = 0; i < CollisionCapsules.Num(); i++) + { + CollisionCapsules[i].Capsule->SetCollisionEnabled(bHidden ? ECollisionEnabled::NoCollision : ECollisionEnabled::QueryAndPhysics); + } + } + } +} + +void UOculusXRHandComponent::UpdateBonePose() +{ + if (bCustomHandMesh) + { + for (auto& BoneElem : BoneNameMappings) + { + // Set Root Bone Rotaiton + if (BoneElem.Key == EOculusXRBone::Wrist_Root) + { + FQuat RootBoneRotation = UOculusXRInputFunctionLibrary::GetBoneRotation(SkeletonType, EOculusXRBone::Wrist_Root); + RootBoneRotation *= HandRootFixupRotation; + RootBoneRotation.Normalize(); + BoneSpaceTransforms[0].SetRotation(RootBoneRotation); + } + else + { + // Set Remaing Bone Rotations + int32 BoneIndex = GetSkinnedAsset()->GetRefSkeleton().FindBoneIndex(BoneElem.Value); + if (BoneIndex >= 0) + { + FQuat BoneRotation = UOculusXRInputFunctionLibrary::GetBoneRotation(SkeletonType, (EOculusXRBone)BoneElem.Key); + BoneSpaceTransforms[BoneIndex].SetRotation(BoneRotation); + } + } + } + } + else + { + // Set Root Bone Rotation + FQuat RootBoneRotation = UOculusXRInputFunctionLibrary::GetBoneRotation(SkeletonType, EOculusXRBone::Wrist_Root); + RootBoneRotation *= HandRootFixupRotation; + RootBoneRotation.Normalize(); + BoneSpaceTransforms[0].SetRotation(RootBoneRotation); + + // Set Remaining Bone Rotations + for (uint32 BoneIndex = 1; BoneIndex < (uint32)GetSkinnedAsset()->GetRefSkeleton().GetNum(); BoneIndex++) + { + FQuat BoneRotation = UOculusXRInputFunctionLibrary::GetBoneRotation(SkeletonType, (EOculusXRBone)BoneIndex); + BoneSpaceTransforms[BoneIndex].SetRotation(BoneRotation); + } + } + MarkRefreshTransformDirty(); +} + +void UOculusXRHandComponent::SystemGesturePressed() +{ + if (SystemGestureBehavior == EOculusXRSystemGestureBehavior::SwapMaterial) + { + if (SystemGestureMaterial) + { + SetMaterial(0, SystemGestureMaterial); + } + else + { + UE_LOG(LogTemp, Log, TEXT("System Gesture Behavior was set to Swap Material but no System Gesture Material was provided!")); + } + } +} + +void UOculusXRHandComponent::SystemGestureReleased() +{ + if (SystemGestureBehavior == EOculusXRSystemGestureBehavior::SwapMaterial) + { + if (CachedBaseMaterial) + { + SetMaterial(0, CachedBaseMaterial); + } + else + { + UE_LOG(LogTemp, Log, TEXT("System Gesture Behavior was set to Swap Material but no System Gesture Material was provided!")); + } + } +} diff --git a/Plugins/MetaXR/Source/OculusXRInput/Private/OculusXRHandTracking.cpp b/Plugins/MetaXR/Source/OculusXRInput/Private/OculusXRHandTracking.cpp new file mode 100644 index 0000000..e83241e --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRInput/Private/OculusXRHandTracking.cpp @@ -0,0 +1,687 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +#include "OculusXRHandTracking.h" +#include "OculusXRHMD.h" +#include "Misc/CoreDelegates.h" +#include "IOculusXRInputModule.h" + +#include "Animation/Skeleton.h" +#include "BoneWeights.h" +#include "Components/SkeletalMeshComponent.h" +#include "Rendering/SkeletalMeshLODRenderData.h" +#include "Rendering/SkeletalMeshRenderData.h" +#include "Rendering/SkeletalMeshLODModel.h" +#include "Rendering/SkeletalMeshModel.h" +#include "Materials/Material.h" +#include "Materials/MaterialInstanceDynamic.h" +#include "Engine/SkinnedAssetCommon.h" +#include "Model.h" +#include "MaterialDomain.h" + +#define OCULUS_TO_UE4_SCALE 100.0f + +namespace OculusXRInput +{ + + static FInputDeviceId GetDeviceID(int32 ControllerId) + { + IPlatformInputDeviceMapper& DeviceMapper = IPlatformInputDeviceMapper::Get(); + FPlatformUserId InPlatformUser = FGenericPlatformMisc::GetPlatformUserForUserIndex(ControllerId); + FInputDeviceId InDeviceId = INPUTDEVICEID_NONE; + DeviceMapper.RemapControllerIdToPlatformUserAndDevice(ControllerId, InPlatformUser, InDeviceId); + return InDeviceId; + } + + FQuat FOculusHandTracking::GetBoneRotation(const int32 ControllerIndex, const EOculusXRHandType DeviceHand, const EOculusXRBone BoneId) + { + FQuat Rotation = FQuat::Identity; + if (BoneId <= EOculusXRBone::Invalid && BoneId >= EOculusXRBone::Bone_Max) + { + return Rotation; + } + +#if OCULUS_INPUT_SUPPORTED_PLATFORMS + TSharedPtr OculusXRInputModule = StaticCastSharedPtr(IOculusXRInputModule::Get().GetInputDevice()); + if (OculusXRInputModule.IsValid()) + { + const FInputDeviceId InDeviceId = GetDeviceID(ControllerIndex); + TArray ControllerPairs = OculusXRInputModule.Get()->ControllerPairs; + for (const FOculusControllerPair& HandPair : ControllerPairs) + { + if (HandPair.DeviceId == InDeviceId) + { + if (DeviceHand != EOculusXRHandType::None) + { + ovrpHand Hand = DeviceHand == EOculusXRHandType::HandLeft ? ovrpHand_Left : ovrpHand_Right; + const FOculusHandControllerState& HandState = HandPair.HandControllerStates[Hand]; + int32 OvrBoneId = ToOvrBone(BoneId); + Rotation = HandState.BoneRotations[OvrBoneId]; + break; + } + } + } + } +#endif + + return Rotation; + } + + float FOculusHandTracking::GetHandScale(const int32 ControllerIndex, const EOculusXRHandType DeviceHand) + { +#if OCULUS_INPUT_SUPPORTED_PLATFORMS + TSharedPtr OculusXRInputModule = StaticCastSharedPtr(IOculusXRInputModule::Get().GetInputDevice()); + if (OculusXRInputModule.IsValid()) + { + const FInputDeviceId InDeviceId = GetDeviceID(ControllerIndex); + TArray ControllerPairs = OculusXRInputModule.Get()->ControllerPairs; + for (const FOculusControllerPair& HandPair : ControllerPairs) + { + if (HandPair.DeviceId == InDeviceId) + { + if (DeviceHand != EOculusXRHandType::None) + { + ovrpHand Hand = DeviceHand == EOculusXRHandType::HandLeft ? ovrpHand_Left : ovrpHand_Right; + return HandPair.HandControllerStates[Hand].HandScale; + } + } + } + } +#endif + return 1.0f; + } + + EOculusXRTrackingConfidence FOculusHandTracking::GetTrackingConfidence(const int32 ControllerIndex, const EOculusXRHandType DeviceHand) + { +#if OCULUS_INPUT_SUPPORTED_PLATFORMS + TSharedPtr OculusXRInputModule = StaticCastSharedPtr(IOculusXRInputModule::Get().GetInputDevice()); + if (OculusXRInputModule.IsValid()) + { + const FInputDeviceId InDeviceId = GetDeviceID(ControllerIndex); + TArray ControllerPairs = OculusXRInputModule.Get()->ControllerPairs; + for (const FOculusControllerPair& HandPair : ControllerPairs) + { + if (HandPair.DeviceId == InDeviceId) + { + if (DeviceHand != EOculusXRHandType::None) + { + ovrpHand Hand = DeviceHand == EOculusXRHandType::HandLeft ? ovrpHand_Left : ovrpHand_Right; + return HandPair.HandControllerStates[Hand].TrackingConfidence; + } + } + } + } +#endif + return EOculusXRTrackingConfidence::Low; + } + + EOculusXRTrackingConfidence FOculusHandTracking::GetFingerTrackingConfidence(const int32 ControllerIndex, const EOculusXRHandType DeviceHand, const EOculusHandAxes Finger) + { + TSharedPtr OculusXRInputModule = StaticCastSharedPtr(IOculusXRInputModule::Get().GetInputDevice()); + if (OculusXRInputModule.IsValid()) + { + const FInputDeviceId InDeviceId = GetDeviceID(ControllerIndex); + TArray ControllerPairs = OculusXRInputModule.Get()->ControllerPairs; + for (const FOculusControllerPair& HandPair : ControllerPairs) + { + if (HandPair.DeviceId == InDeviceId) + { + if (DeviceHand != EOculusXRHandType::None) + { + ovrpHand Hand = DeviceHand == EOculusXRHandType::HandLeft ? ovrpHand_Left : ovrpHand_Right; + return HandPair.HandControllerStates[Hand].FingerConfidences[(int)Finger]; + } + } + } + } + return EOculusXRTrackingConfidence::Low; + } + + FTransform FOculusHandTracking::GetPointerPose(const int32 ControllerIndex, const EOculusXRHandType DeviceHand, const float WorldToMeters) + { +#if OCULUS_INPUT_SUPPORTED_PLATFORMS + TSharedPtr OculusXRInputModule = StaticCastSharedPtr(IOculusXRInputModule::Get().GetInputDevice()); + if (OculusXRInputModule.IsValid()) + { + const FInputDeviceId InDeviceId = GetDeviceID(ControllerIndex); + TArray ControllerPairs = OculusXRInputModule.Get()->ControllerPairs; + for (const FOculusControllerPair& HandPair : ControllerPairs) + { + if (HandPair.DeviceId == InDeviceId) + { + if (DeviceHand != EOculusXRHandType::None) + { + ovrpHand Hand = DeviceHand == EOculusXRHandType::HandLeft ? ovrpHand_Left : ovrpHand_Right; + FTransform PoseTransform = HandPair.HandControllerStates[Hand].PointerPose; + PoseTransform.SetLocation(PoseTransform.GetLocation() * WorldToMeters); + return PoseTransform; + } + } + } + } +#endif + return FTransform(); + } + + bool FOculusHandTracking::IsPointerPoseValid(const int32 ControllerIndex, const EOculusXRHandType DeviceHand) + { +#if OCULUS_INPUT_SUPPORTED_PLATFORMS + TSharedPtr OculusXRInputModule = StaticCastSharedPtr(IOculusXRInputModule::Get().GetInputDevice()); + if (OculusXRInputModule.IsValid()) + { + const FInputDeviceId InDeviceId = GetDeviceID(ControllerIndex); + TArray ControllerPairs = OculusXRInputModule.Get()->ControllerPairs; + for (const FOculusControllerPair& HandPair : ControllerPairs) + { + if (HandPair.DeviceId == InDeviceId) + { + if (DeviceHand != EOculusXRHandType::None) + { + ovrpHand Hand = DeviceHand == EOculusXRHandType::HandLeft ? ovrpHand_Left : ovrpHand_Right; + return HandPair.HandControllerStates[Hand].bIsPointerPoseValid; + } + } + } + } +#endif + return false; + } + + bool FOculusHandTracking::IsHandTrackingEnabled() + { +#if OCULUS_INPUT_SUPPORTED_PLATFORMS + ovrpBool result; + FOculusXRHMDModule::GetPluginWrapper().GetHandTrackingEnabled(&result); + return result == ovrpBool_True; +#else + return false; +#endif + } + + bool FOculusHandTracking::IsHandDominant(const int32 ControllerIndex, const EOculusXRHandType DeviceHand) + { +#if OCULUS_INPUT_SUPPORTED_PLATFORMS + TSharedPtr OculusXRInputModule = StaticCastSharedPtr(IOculusXRInputModule::Get().GetInputDevice()); + if (OculusXRInputModule.IsValid()) + { + const FInputDeviceId InDeviceId = GetDeviceID(ControllerIndex); + TArray ControllerPairs = OculusXRInputModule.Get()->ControllerPairs; + for (const FOculusControllerPair& HandPair : ControllerPairs) + { + if (HandPair.DeviceId == InDeviceId) + { + if (DeviceHand != EOculusXRHandType::None) + { + ovrpHand Hand = DeviceHand == EOculusXRHandType::HandLeft ? ovrpHand_Left : ovrpHand_Right; + return HandPair.HandControllerStates[Hand].bIsDominantHand; + } + } + } + } +#endif + return false; + } + + bool FOculusHandTracking::IsHandPositionValid(int32 ControllerIndex, EOculusXRHandType DeviceHand) + { + TSharedPtr OculusXRInputModule = StaticCastSharedPtr(IOculusXRInputModule::Get().GetInputDevice()); + if (OculusXRInputModule.IsValid()) + { + const FInputDeviceId InDeviceId = GetDeviceID(ControllerIndex); + TArray ControllerPairs = OculusXRInputModule.Get()->ControllerPairs; + for (const FOculusControllerPair& HandPair : ControllerPairs) + { + if (HandPair.DeviceId == InDeviceId) + { + if (DeviceHand != EOculusXRHandType::None) + { + ovrpHand Hand = DeviceHand == EOculusXRHandType::HandLeft ? ovrpHand_Left : ovrpHand_Right; + return HandPair.HandControllerStates[Hand].bIsPositionValid; + } + } + } + } + return false; + } + + bool FOculusHandTracking::GetHandSkeletalMesh(USkeletalMesh* HandSkeletalMesh, const EOculusXRHandType SkeletonType, const EOculusXRHandType MeshType, const float WorldToMeters) + { +#if OCULUS_INPUT_SUPPORTED_PLATFORMS + if (HandSkeletalMesh) + { + ovrpMesh* OvrMesh = new ovrpMesh(); + ovrpSkeleton2* OvrSkeleton = new ovrpSkeleton2(); + + ovrpSkeletonType OvrSkeletonType = (ovrpSkeletonType)((int32)SkeletonType - 1); + ovrpMeshType OvrMeshType = (ovrpMeshType)((int32)MeshType - 1); + ovrpResult SkelResult = FOculusXRHMDModule::GetPluginWrapper().GetSkeleton2(OvrSkeletonType, OvrSkeleton); + ovrpResult MeshResult = FOculusXRHMDModule::GetPluginWrapper().GetMesh(OvrMeshType, OvrMesh); + if (SkelResult != ovrpSuccess || MeshResult != ovrpSuccess) + { +#if !WITH_EDITOR + UE_LOG(LogOcHandTracking, Error, TEXT("Failed to get mesh or skeleton data from Oculus runtime.")); +#endif + delete OvrMesh; + delete OvrSkeleton; + + return false; + } + + // Create Skeletal Mesh LOD Render Data +#if WITH_EDITOR + FSkeletalMeshLODModel* LodRenderData = new FSkeletalMeshLODModel(); + HandSkeletalMesh->GetImportedModel()->LODModels.Add(LodRenderData); +#else + FSkeletalMeshLODRenderData* LodRenderData = new FSkeletalMeshLODRenderData(); + HandSkeletalMesh->AllocateResourceForRendering(); + HandSkeletalMesh->GetResourceForRendering()->LODRenderData.Add(LodRenderData); +#endif + + // Set default LOD Info + FSkeletalMeshLODInfo& LodInfo = HandSkeletalMesh->AddLODInfo(); + LodInfo.ScreenSize = 0.3f; + LodInfo.LODHysteresis = 0.2f; + LodInfo.BuildSettings.bUseFullPrecisionUVs = true; + + InitializeHandSkeleton(HandSkeletalMesh, OvrSkeleton, WorldToMeters); + + // Add default material as backup + LodInfo.LODMaterialMap.Add(0); + UMaterialInterface* DefaultMaterial = UMaterial::GetDefaultMaterial(MD_Surface); + HandSkeletalMesh->GetMaterials().Add(DefaultMaterial); + HandSkeletalMesh->GetMaterials()[0].UVChannelData.bInitialized = true; + + // Set skeletal mesh properties + HandSkeletalMesh->SetHasVertexColors(true); + HandSkeletalMesh->SetHasBeenSimplified(false); + HandSkeletalMesh->SetEnablePerPolyCollision(false); + + InitializeHandMesh(HandSkeletalMesh, OvrMesh, WorldToMeters); + +#if WITH_EDITOR + HandSkeletalMesh->InvalidateDeriveDataCacheGUID(); + HandSkeletalMesh->PostEditChange(); +#endif + + // Create Skeleton object and merge all bones + HandSkeletalMesh->SetSkeleton(NewObject()); + HandSkeletalMesh->GetSkeleton()->MergeAllBonesToBoneTree(HandSkeletalMesh); + HandSkeletalMesh->PostLoad(); + + delete OvrMesh; + delete OvrSkeleton; + + return true; + } +#endif + return false; + } + + void FOculusHandTracking::InitializeHandMesh(USkeletalMesh* SkeletalMesh, const ovrpMesh* OvrMesh, const float WorldToMeters) + { +#if WITH_EDITOR + FSkeletalMeshLODModel* LodRenderData = &SkeletalMesh->GetImportedModel()->LODModels[0]; + + // Initialize mesh section + LodRenderData->Sections.SetNumUninitialized(1); + new (&LodRenderData->Sections[0]) FSkelMeshSection(); + auto& MeshSection = LodRenderData->Sections[0]; + + // Set default mesh section properties + MeshSection.MaterialIndex = 0; + MeshSection.BaseIndex = 0; + MeshSection.NumTriangles = OvrMesh->NumIndices / 3; + MeshSection.BaseVertexIndex = 0; + MeshSection.MaxBoneInfluences = 4; + MeshSection.NumVertices = OvrMesh->NumVertices; + + float MaxDistSq = MIN_flt; + for (uint32_t VertexIndex = 0; VertexIndex < OvrMesh->NumVertices; VertexIndex++) + { + FSoftSkinVertex SoftVertex; + FMemory::Memzero(SoftVertex.InfluenceWeights); + FMemory::Memzero(SoftVertex.InfluenceBones); + + // Update vertex data + SoftVertex.Color = FColor::White; + ovrpVector3f VertexPosition = OvrMesh->VertexPositions[VertexIndex]; + ovrpVector3f Normal = OvrMesh->VertexNormals[VertexIndex]; + SoftVertex.Position = FVector3f(VertexPosition.x, VertexPosition.z, VertexPosition.y) * WorldToMeters; + SoftVertex.TangentZ = FVector3f(Normal.x, Normal.z, Normal.y); + SoftVertex.TangentX = FVector3f(1.0f, 0.0f, 0.0f); + SoftVertex.TangentY = FVector3f(0.0f, 1.0f, 0.0f); // SoftVertex.TangentZ^ SoftVertex.TangentX* SoftVertex.TangentZ.W; + SoftVertex.UVs[0] = FVector2f(OvrMesh->VertexUV0[VertexIndex].x, OvrMesh->VertexUV0[VertexIndex].y); + + // Update the Bounds + float VertexDistSq = SoftVertex.Position.SizeSquared(); + if (VertexDistSq > MaxDistSq) + MaxDistSq = VertexDistSq; + + // Update blend weights and indices + ovrpVector4f BlendWeights = OvrMesh->BlendWeights[VertexIndex]; + ovrpVector4s BlendIndices = OvrMesh->BlendIndices[VertexIndex]; + + SoftVertex.InfluenceWeights[0] = UE::AnimationCore::MaxRawBoneWeightFloat * BlendWeights.x; + SoftVertex.InfluenceBones[0] = BlendIndices.x; + SoftVertex.InfluenceWeights[1] = UE::AnimationCore::MaxRawBoneWeightFloat * BlendWeights.y; + SoftVertex.InfluenceBones[1] = BlendIndices.y; + SoftVertex.InfluenceWeights[2] = UE::AnimationCore::MaxRawBoneWeightFloat * BlendWeights.z; + SoftVertex.InfluenceBones[2] = BlendIndices.z; + SoftVertex.InfluenceWeights[3] = UE::AnimationCore::MaxRawBoneWeightFloat * BlendWeights.w; + SoftVertex.InfluenceBones[3] = BlendIndices.w; + + MeshSection.SoftVertices.Add(SoftVertex); + } + + // Update bone map + for (uint32 BoneIndex = 0; BoneIndex < (uint32)SkeletalMesh->GetRefSkeleton().GetNum(); BoneIndex++) + { + MeshSection.BoneMap.Add(BoneIndex); + } + + // Update LOD render data + LodRenderData->NumVertices = OvrMesh->NumVertices; + LodRenderData->NumTexCoords = 1; + + // Create index buffer + for (uint32_t Index = 0; Index < OvrMesh->NumIndices; Index++) + { + LodRenderData->IndexBuffer.Add(OvrMesh->Indices[Index]); + } + + // Finalize Bounds + float MaxDist = FMath::Sqrt(MaxDistSq); + FBoxSphereBounds Bounds; + Bounds.Origin = FVector::ZeroVector; + Bounds.BoxExtent = FVector(MaxDist); + Bounds.SphereRadius = MaxDist; + SkeletalMesh->SetImportedBounds(Bounds); + +#else + FSkeletalMeshLODRenderData* LodRenderData = &SkeletalMesh->GetResourceForRendering()->LODRenderData[0]; + + // Initialize Mesh Section + LodRenderData->RenderSections.SetNumUninitialized(1); + new (&LodRenderData->RenderSections[0]) FSkelMeshRenderSection(); + auto& MeshSection = LodRenderData->RenderSections[0]; + + // Initialize render section properties + MeshSection.MaterialIndex = 0; + MeshSection.BaseIndex = 0; + MeshSection.NumTriangles = OvrMesh->NumIndices / 3; + MeshSection.BaseVertexIndex = 0; + MeshSection.MaxBoneInfluences = 4; + MeshSection.NumVertices = OvrMesh->NumVertices; + MeshSection.bCastShadow = true; + MeshSection.bDisabled = false; + MeshSection.bRecomputeTangent = false; + + // Initialize Vertex Buffers + LodRenderData->StaticVertexBuffers.PositionVertexBuffer.Init(OvrMesh->NumVertices); + LodRenderData->StaticVertexBuffers.StaticMeshVertexBuffer.Init(OvrMesh->NumVertices, 1); + LodRenderData->StaticVertexBuffers.ColorVertexBuffer.Init(OvrMesh->NumVertices); + + // Initialize Skin Weights + TArray InWeights; + InWeights.AddUninitialized(OvrMesh->NumVertices); + + float MaxDistSq = MIN_flt; + TMap> OverlappingVertices; + for (uint32_t VertexIndex = 0; VertexIndex < OvrMesh->NumVertices; VertexIndex++) + { + FMemory::Memzero(InWeights[VertexIndex].InfluenceWeights); + FMemory::Memzero(InWeights[VertexIndex].InfluenceBones); + // Initialize vertex data + FModelVertex ModelVertex; + + // Update Model Vertex + ovrpVector3f VertexPosition = OvrMesh->VertexPositions[VertexIndex]; + ovrpVector3f Normal = OvrMesh->VertexNormals[VertexIndex]; + ModelVertex.Position = FVector3f(VertexPosition.x, VertexPosition.z, VertexPosition.y) * WorldToMeters; + ModelVertex.TangentZ = FVector3f(Normal.x, Normal.z, Normal.y); + ModelVertex.TangentX = FVector3f(1.0f, 0.0f, 0.0f); + ModelVertex.TexCoord = FVector2f(OvrMesh->VertexUV0[VertexIndex].x, OvrMesh->VertexUV0[VertexIndex].y); + + // Add Model Vertex data to vertex buffer + LodRenderData->StaticVertexBuffers.PositionVertexBuffer.VertexPosition(VertexIndex) = ModelVertex.Position; + LodRenderData->StaticVertexBuffers.StaticMeshVertexBuffer.SetVertexTangents(VertexIndex, ModelVertex.TangentX, ModelVertex.GetTangentY(), ModelVertex.TangentZ); + LodRenderData->StaticVertexBuffers.StaticMeshVertexBuffer.SetVertexUV(VertexIndex, 0, ModelVertex.TexCoord); + + // Update the Bounds + float VertexDistSq = ModelVertex.Position.SizeSquared(); + if (VertexDistSq > MaxDistSq) + MaxDistSq = VertexDistSq; + + // Set vertex blend weights and indices + TArray Vertices; + ovrpVector4f BlendWeights = OvrMesh->BlendWeights[VertexIndex]; + ovrpVector4s BlendIndices = OvrMesh->BlendIndices[VertexIndex]; + + InWeights[VertexIndex].InfluenceWeights[0] = UE::AnimationCore::MaxRawBoneWeightFloat * BlendWeights.x; + InWeights[VertexIndex].InfluenceBones[0] = BlendIndices.x; + Vertices.Add(BlendIndices.x); + InWeights[VertexIndex].InfluenceWeights[1] = UE::AnimationCore::MaxRawBoneWeightFloat * BlendWeights.y; + InWeights[VertexIndex].InfluenceBones[1] = BlendIndices.y; + Vertices.Add(BlendIndices.y); + InWeights[VertexIndex].InfluenceWeights[2] = UE::AnimationCore::MaxRawBoneWeightFloat * BlendWeights.z; + InWeights[VertexIndex].InfluenceBones[2] = BlendIndices.z; + Vertices.Add(BlendIndices.z); + InWeights[VertexIndex].InfluenceWeights[3] = UE::AnimationCore::MaxRawBoneWeightFloat * BlendWeights.w; + InWeights[VertexIndex].InfluenceBones[3] = BlendIndices.w; + Vertices.Add(BlendIndices.w); + + OverlappingVertices.Add(VertexIndex, Vertices); + } + + // Update bone map for mesh section + for (uint32 BoneIndex = 0; BoneIndex < (uint32)SkeletalMesh->GetRefSkeleton().GetNum(); BoneIndex++) + { + MeshSection.BoneMap.Add(BoneIndex); + } + + // Finalize Bounds + float MaxDist = FMath::Sqrt(MaxDistSq); + FBoxSphereBounds Bounds; + Bounds.Origin = FVector::ZeroVector; + Bounds.BoxExtent = FVector(MaxDist); + Bounds.SphereRadius = MaxDist; + SkeletalMesh->SetImportedBounds(Bounds); + + // Assign skin weights to vertex buffer + LodRenderData->SkinWeightVertexBuffer = InWeights; + MeshSection.DuplicatedVerticesBuffer.Init(OvrMesh->NumVertices, OverlappingVertices); + + // Set index buffer + LodRenderData->MultiSizeIndexContainer.CreateIndexBuffer(sizeof(uint16_t)); + for (uint32_t Index = 0; Index < OvrMesh->NumIndices; Index++) + { + LodRenderData->MultiSizeIndexContainer.GetIndexBuffer()->AddItem(OvrMesh->Indices[Index]); + } +#endif + } + + void FOculusHandTracking::InitializeHandSkeleton(USkeletalMesh* SkeletalMesh, const ovrpSkeleton2* OvrSkeleton, const float WorldToMeters) + { + SkeletalMesh->GetRefSkeleton().Empty(OvrSkeleton->NumBones); + +#if WITH_EDITOR + FSkeletalMeshLODModel* LodRenderData = &SkeletalMesh->GetImportedModel()->LODModels[0]; +#else + FSkeletalMeshLODRenderData* LodRenderData = &SkeletalMesh->GetResourceForRendering()->LODRenderData[0]; +#endif + SkeletalMesh->SetHasBeenSimplified(false); + SkeletalMesh->SetHasVertexColors(true); + + checkf(OvrSkeleton->NumBones <= static_cast(TNumericLimits::Max()), TEXT("Bone indices are stored as uint8 type.")); + for (uint8 BoneIndex = 0; BoneIndex < static_cast(OvrSkeleton->NumBones); BoneIndex++) + { + LodRenderData->ActiveBoneIndices.Add(BoneIndex); + LodRenderData->RequiredBones.Add(BoneIndex); + + FText BoneDisplayName; + if (!FindBoneDisplayName(BoneDisplayName, BoneIndex)) + { + UE_LOG(LogOcHandTracking, Error, TEXT("Cannot find bone display name for bone index: %d."), BoneIndex) + continue; + } + FString BoneString = BoneDisplayName.ToString(); + FName BoneName = FName(*BoneString); + + FTransform Transform = FTransform::Identity; + FVector BonePosition = OvrBoneVectorToFVector(OvrSkeleton->Bones[BoneIndex].Pose.Position, WorldToMeters); + FQuat BoneRotation = BoneIndex == 0 ? FQuat(-1.0f, 0.0f, 0.0f, 1.0f) : OvrBoneQuatToFQuat(OvrSkeleton->Bones[BoneIndex].Pose.Orientation); + Transform.SetLocation(BonePosition); + Transform.SetRotation(BoneRotation); + + FReferenceSkeletonModifier Modifier = FReferenceSkeletonModifier(SkeletalMesh->GetRefSkeleton(), nullptr); + int32 ParentIndex = -1; + if (BoneIndex > 0) + { + if (OvrSkeleton->Bones[BoneIndex].ParentBoneIndex == ovrpBoneId::ovrpBoneId_Invalid) + { + ParentIndex = 0; + } + else + { + ParentIndex = OvrSkeleton->Bones[BoneIndex].ParentBoneIndex; + } + } + Modifier.Add(FMeshBoneInfo(BoneName, BoneString, ParentIndex), Transform); + } + SkeletalMesh->CalculateInvRefMatrices(); + } + + TArray FOculusHandTracking::InitializeHandPhysics(const EOculusXRHandType SkeletonType, USkinnedMeshComponent* HandComponent, const float WorldToMeters) + { + TArray CollisionCapsules; + ovrpSkeleton2* OvrSkeleton = new ovrpSkeleton2(); + +#if OCULUS_INPUT_SUPPORTED_PLATFORMS + ovrpSkeletonType OvrSkeletonType = (ovrpSkeletonType)((int32)SkeletonType - 1); + if (FOculusXRHMDModule::GetPluginWrapper().GetSkeleton2(OvrSkeletonType, OvrSkeleton) != ovrpSuccess) + { +#if !WITH_EDITOR + UE_LOG(LogOcHandTracking, Error, TEXT("Failed to get skeleton data from Oculus runtime.")); +#endif + delete OvrSkeleton; + return CollisionCapsules; + } +#endif + + TArray IgnoreCapsules; + CollisionCapsules.AddDefaulted(OvrSkeleton->NumBoneCapsules); + for (uint32 CapsuleIndex = 0; CapsuleIndex < OvrSkeleton->NumBoneCapsules; CapsuleIndex++) + { + ovrpBoneCapsule OvrBoneCapsule = OvrSkeleton->BoneCapsules[CapsuleIndex]; + + UCapsuleComponent* Capsule = NewObject(HandComponent); + + FVector CapsulePointZero = OvrBoneVectorToFVector(OvrBoneCapsule.Points[0], WorldToMeters); + FVector CapsulePointOne = OvrBoneVectorToFVector(OvrBoneCapsule.Points[1], WorldToMeters); + FVector Delta = (CapsulePointOne - CapsulePointZero); + + FName BoneName = HandComponent->GetSkinnedAsset()->GetRefSkeleton().GetBoneName(OvrBoneCapsule.BoneIndex); + + float CapsuleHeight = Delta.Size(); + float CapsuleRadius = OvrBoneCapsule.Radius * WorldToMeters; + + Capsule->SetCapsuleRadius(CapsuleRadius); + Capsule->SetCapsuleHalfHeight(Delta.Size() / 2 + CapsuleRadius); + Capsule->SetupAttachment(HandComponent, BoneName); + Capsule->SetCollisionProfileName(HandComponent->GetCollisionProfileName()); + Capsule->RegisterComponentWithWorld(HandComponent->GetWorld()); + Capsule->SetCollisionEnabled(ECollisionEnabled::QueryAndPhysics); + FRotator CapsuleRotation = FQuat::FindBetweenVectors(FVector::RightVector, Delta).Rotator() + FRotator(0, 0, 90); + ; + + Capsule->SetRelativeRotation(CapsuleRotation); + Capsule->SetRelativeLocation(CapsulePointZero + (Delta / 2)); + + CollisionCapsules[CapsuleIndex].Capsule = Capsule; + CollisionCapsules[CapsuleIndex].BoneId = (EOculusXRBone)OvrBoneCapsule.BoneIndex; + + IgnoreCapsules.Add(Capsule); + } + + for (int32 CapsuleIndex = 0; CapsuleIndex < CollisionCapsules.Num(); CapsuleIndex++) + { + CollisionCapsules[CapsuleIndex].Capsule->MoveIgnoreComponents = IgnoreCapsules; + } + + return CollisionCapsules; + } + + ovrpBoneId FOculusHandTracking::ToOvrBone(EOculusXRBone Bone) + { + if (Bone > EOculusXRBone::Bone_Max) + return ovrpBoneId_Invalid; + + return static_cast(Bone); + } + + FString FOculusHandTracking::GetBoneName(const uint8 Bone) + { + FText DisplayName; + if (FindBoneDisplayName(DisplayName, Bone)) + { + return DisplayName.ToString(); + } + if (FindBoneDisplayName(DisplayName, static_cast(EOculusXRBone::Invalid))) + { + return DisplayName.ToString(); + } + return { "Invalid" }; + } + + bool FOculusHandTracking::FindBoneDisplayName(FText& DisplayName, uint8 Bone) + { + return StaticEnum()->FindDisplayNameTextByValue(DisplayName, Bone); + } + + EOculusXRTrackingConfidence FOculusHandTracking::ToEOculusXRTrackingConfidence(ovrpTrackingConfidence Confidence) + { + EOculusXRTrackingConfidence TrackingConfidence = EOculusXRTrackingConfidence::Low; + switch (Confidence) + { + case ovrpTrackingConfidence_Low: + TrackingConfidence = EOculusXRTrackingConfidence::Low; + break; + case ovrpTrackingConfidence_High: + TrackingConfidence = EOculusXRTrackingConfidence::High; + break; + } + return TrackingConfidence; + } + + FVector FOculusHandTracking::OvrBoneVectorToFVector(ovrpVector3f ovrpVector, float WorldToMeters) + { + return FVector(ovrpVector.x, -ovrpVector.y, ovrpVector.z) * WorldToMeters; + } + + FQuat FOculusHandTracking::OvrBoneQuatToFQuat(ovrpQuatf ovrpQuat) + { + return FQuat(ovrpQuat.x, -ovrpQuat.y, ovrpQuat.z, -ovrpQuat.w); + } + + EOculusXRControllerDrivenHandPoseTypes FOculusHandTracking::ControllerDrivenHandType = EOculusXRControllerDrivenHandPoseTypes::None; + + void FOculusHandTracking::SetControllerDrivenHandPoses(const EOculusXRControllerDrivenHandPoseTypes Type) + { + FOculusHandTracking::ControllerDrivenHandType = Type; + switch (Type) + { + case EOculusXRControllerDrivenHandPoseTypes::None: + FOculusXRHMDModule::GetPluginWrapper().SetControllerDrivenHandPoses(false); + FOculusXRHMDModule::GetPluginWrapper().SetControllerDrivenHandPosesAreNatural(false); + break; + case EOculusXRControllerDrivenHandPoseTypes::Natural: + FOculusXRHMDModule::GetPluginWrapper().SetControllerDrivenHandPoses(true); + FOculusXRHMDModule::GetPluginWrapper().SetControllerDrivenHandPosesAreNatural(true); + break; + case EOculusXRControllerDrivenHandPoseTypes::Controller: + FOculusXRHMDModule::GetPluginWrapper().SetControllerDrivenHandPoses(true); + FOculusXRHMDModule::GetPluginWrapper().SetControllerDrivenHandPosesAreNatural(false); + break; + } + } +} // namespace OculusXRInput diff --git a/Plugins/MetaXR/Source/OculusXRInput/Private/OculusXRHandTracking.h b/Plugins/MetaXR/Source/OculusXRInput/Private/OculusXRHandTracking.h new file mode 100644 index 0000000..b3264ec --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRInput/Private/OculusXRHandTracking.h @@ -0,0 +1,58 @@ +// @lint-ignore-every LICENSELINT +// Copyright 1998-2019 Epic Games, Inc. All Rights Reserved. + +#pragma once +#include "OculusXRHMDModule.h" +#include "OculusXRInput.h" +#include "Engine/SkeletalMesh.h" +#include "Components/CapsuleComponent.h" + +#include "OculusXRInputFunctionLibrary.h" + +#define LOCTEXT_NAMESPACE "OculusHandTracking" + +DEFINE_LOG_CATEGORY_STATIC(LogOcHandTracking, Log, All); + +//------------------------------------------------------------------------------------------------- +// FOculusHandTracking +//------------------------------------------------------------------------------------------------- +namespace OculusXRInput +{ + class FOculusHandTracking + { + public: + // Oculus Hand Tracking + static FQuat GetBoneRotation(const int32 ControllerIndex, const EOculusXRHandType DeviceHand, const EOculusXRBone BoneId); + static float GetHandScale(const int32 ControllerIndex, const EOculusXRHandType DeviceHand); + static EOculusXRTrackingConfidence GetTrackingConfidence(const int32 ControllerIndex, const EOculusXRHandType DeviceHand); + static EOculusXRTrackingConfidence GetFingerTrackingConfidence(const int32 ControllerIndex, const EOculusXRHandType DeviceHand, const EOculusHandAxes Finger); // OCULUS STRIKE + static FTransform GetPointerPose(const int32 ControllerIndex, const EOculusXRHandType DeviceHand, const float WorldToMeters = 100.f); + static bool IsPointerPoseValid(const int32 ControllerIndex, const EOculusXRHandType DeviceHand); + static bool GetHandSkeletalMesh(USkeletalMesh* HandSkeletalMesh, const EOculusXRHandType SkeletonType, const EOculusXRHandType MeshType, const float WorldToMeters = 100.f); + static TArray InitializeHandPhysics(const EOculusXRHandType SkeletonType, USkinnedMeshComponent* HandComponent, const float WorldToMeters = 100.f); + static EOculusXRTrackingConfidence ToEOculusXRTrackingConfidence(ovrpTrackingConfidence Confidence); + static bool IsHandTrackingEnabled(); + static bool IsHandDominant(const int32 ControllerIndex, const EOculusXRHandType DeviceHand); + static bool IsHandPositionValid(int32 ControllerIndex, EOculusXRHandType DeviceHand); + static void SetControllerDrivenHandPoses(const EOculusXRControllerDrivenHandPoseTypes Type); + + // Helper functions + static ovrpBoneId ToOvrBone(EOculusXRBone Bone); + static FString GetBoneName(uint8 Bone); + static bool FindBoneDisplayName(FText& DisplayName, uint8 Bone); + + // Converters for converting from ovr bone space (should match up with ovr avatar) + static FVector OvrBoneVectorToFVector(ovrpVector3f ovrpVector, float WorldToMeters); + static FQuat OvrBoneQuatToFQuat(ovrpQuatf ovrpQuat); + + static EOculusXRControllerDrivenHandPoseTypes ControllerDrivenHandType; + + private: + // Initializers for runtime hand assets + static void InitializeHandMesh(USkeletalMesh* SkeletalMesh, const ovrpMesh* OvrMesh, const float WorldToMeters); + static void InitializeHandSkeleton(USkeletalMesh* SkeletalMesh, const ovrpSkeleton2* OvrSkeleton, const float WorldToMeters); + }; + +} // namespace OculusXRInput + +#undef LOCTEXT_NAMESPACE diff --git a/Plugins/MetaXR/Source/OculusXRInput/Private/OculusXRInput.cpp b/Plugins/MetaXR/Source/OculusXRInput/Private/OculusXRInput.cpp new file mode 100644 index 0000000..7537a24 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRInput/Private/OculusXRInput.cpp @@ -0,0 +1,1875 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +#include "OculusXRInput.h" + +#if OCULUS_INPUT_SUPPORTED_PLATFORMS +#include "OculusXRHMD.h" +#include "OculusXRHandTracking.h" +#include "OculusXRMRFunctionLibrary.h" +#include "Misc/CoreDelegates.h" +#include "Features/IModularFeatures.h" +#include "Misc/ConfigCacheIni.h" +#include "Haptics/HapticFeedbackEffect_Base.h" +#include "GenericPlatform/GenericPlatformInputDeviceMapper.h" + +#define OVR_DEBUG_LOGGING 0 +#define OVR_HAP_LOGGING 0 + +#define LOCTEXT_NAMESPACE "OculusXRInput" + +static TAutoConsoleVariable CVarOculusPCMBatchDuration( + TEXT("r.Mobile.Oculus.PCMBatchDuration"), + 36, + TEXT("The duration that each PCM haptic batch lasts in ms. Default is 36ms.\n"), + ECVF_Scalability | ECVF_RenderThreadSafe); + +static TAutoConsoleVariable CVarOculusControllerPose( + TEXT("r.Oculus.ControllerPose"), + 0, + TEXT("0 Default controller pose.\n") + TEXT("1 Legacy controller pose.\n") + TEXT("2 Grip controller pose.\n") + TEXT("3 Aim controller pose.\n"), + ECVF_Scalability | ECVF_RenderThreadSafe); + +static TAutoConsoleVariable CVarOculusResetUntrackedInputStates( + TEXT("r.Mobile.Oculus.ResetUntrackedInputStates"), + 0, + TEXT("If true, reset input states of input devices if they are untracked (for example, controllers or hands after Oculus button is held to pause the app).\n"), + ECVF_Scalability | ECVF_RenderThreadSafe); + +namespace OculusXRInput +{ + + const FKey FOculusKey::OculusTouch_Left_Thumbstick("OculusTouch_Left_Thumbstick"); + const FKey FOculusKey::OculusTouch_Left_Trigger("OculusTouch_Left_Trigger"); + const FKey FOculusKey::OculusTouch_Left_FaceButton1("OculusTouch_Left_FaceButton1"); + const FKey FOculusKey::OculusTouch_Left_FaceButton2("OculusTouch_Left_FaceButton2"); + const FKey FOculusKey::OculusTouch_Left_IndexPointing("OculusTouch_Left_IndexPointing"); + const FKey FOculusKey::OculusTouch_Left_ThumbUp("OculusTouch_Left_ThumbUp"); + const FKey FOculusKey::OculusTouch_Left_ThumbRest("OculusTouch_Left_ThumbRest"); + const FKey FOculusKey::OculusTouch_Left_ThumbRest_Force("OculusTouch_Left_ThumbRest_Force"); + const FKey FOculusKey::OculusTouch_Left_Stylus_Force("OculusTouch_Left_Stylus_Force"); + const FKey FOculusKey::OculusTouch_Left_IndexTrigger_Curl("OculusTouch_Left_IndexTrigger_Curl"); + const FKey FOculusKey::OculusTouch_Left_IndexTrigger_Slide("OculusTouch_Left_IndexTrigger_Slide"); + const FKey FOculusKey::OculusTouch_Left_IndexTrigger_Force("OculusTouch_Left_IndexTrigger_Force"); + + const FKey FOculusKey::OculusTouch_Right_Thumbstick("OculusTouch_Right_Thumbstick"); + const FKey FOculusKey::OculusTouch_Right_Trigger("OculusTouch_Right_Trigger"); + const FKey FOculusKey::OculusTouch_Right_FaceButton1("OculusTouch_Right_FaceButton1"); + const FKey FOculusKey::OculusTouch_Right_FaceButton2("OculusTouch_Right_FaceButton2"); + const FKey FOculusKey::OculusTouch_Right_IndexPointing("OculusTouch_Right_IndexPointing"); + const FKey FOculusKey::OculusTouch_Right_ThumbUp("OculusTouch_Right_ThumbUp"); + const FKey FOculusKey::OculusTouch_Right_ThumbRest("OculusTouch_Right_ThumbRest"); + + const FKey FOculusKey::OculusTouch_Right_ThumbRest_Force("OculusTouch_Right_ThumbRest_Force"); + const FKey FOculusKey::OculusTouch_Right_Stylus_Force("OculusTouch_Right_Stylus_Force"); + const FKey FOculusKey::OculusTouch_Right_IndexTrigger_Curl("OculusTouch_Right_IndexTrigger_Curl"); + const FKey FOculusKey::OculusTouch_Right_IndexTrigger_Slide("OculusTouch_Right_IndexTrigger_Slide"); + const FKey FOculusKey::OculusTouch_Right_IndexTrigger_Force("OculusTouch_Right_IndexTrigger_Force"); + + const FKey FOculusKey::OculusRemote_DPad_Down("OculusRemote_DPad_Down"); + const FKey FOculusKey::OculusRemote_DPad_Up("OculusRemote_DPad_Up"); + const FKey FOculusKey::OculusRemote_DPad_Left("OculusRemote_DPad_Left"); + const FKey FOculusKey::OculusRemote_DPad_Right("OculusRemote_DPad_Right"); + const FKey FOculusKey::OculusRemote_Enter("OculusRemote_Enter"); + const FKey FOculusKey::OculusRemote_Back("OculusRemote_Back"); + const FKey FOculusKey::OculusRemote_VolumeUp("OculusRemote_VolumeUp"); + const FKey FOculusKey::OculusRemote_VolumeDown("OculusRemote_VolumeDown"); + const FKey FOculusKey::OculusRemote_Home("OculusRemote_Home"); + + const FKey FOculusKey::OculusHand_Left_ThumbPinch("OculusHand_Left_ThumbPinch"); + const FKey FOculusKey::OculusHand_Left_IndexPinch("OculusHand_Left_IndexPinch"); + const FKey FOculusKey::OculusHand_Left_MiddlePinch("OculusHand_Left_MiddlePinch"); + const FKey FOculusKey::OculusHand_Left_RingPinch("OculusHand_Left_RingPinch"); + const FKey FOculusKey::OculusHand_Left_PinkyPinch("OculusHand_Left_PinkPinch"); + + const FKey FOculusKey::OculusHand_Right_ThumbPinch("OculusHand_Right_ThumbPinch"); + const FKey FOculusKey::OculusHand_Right_IndexPinch("OculusHand_Right_IndexPinch"); + const FKey FOculusKey::OculusHand_Right_MiddlePinch("OculusHand_Right_MiddlePinch"); + const FKey FOculusKey::OculusHand_Right_RingPinch("OculusHand_Right_RingPinch"); + const FKey FOculusKey::OculusHand_Right_PinkyPinch("OculusHand_Right_PinkPinch"); + + const FKey FOculusKey::OculusHand_Left_SystemGesture("OculusHand_Left_SystemGesture"); + const FKey FOculusKey::OculusHand_Right_SystemGesture("OculusHand_Right_SystemGesture"); + + const FKey FOculusKey::OculusHand_Left_ThumbPinchStrength("OculusHand_Left_ThumbPinchStrength"); + const FKey FOculusKey::OculusHand_Left_IndexPinchStrength("OculusHand_Left_IndexPinchStrength"); + const FKey FOculusKey::OculusHand_Left_MiddlePinchStrength("OculusHand_Left_MiddlePinchStrength"); + const FKey FOculusKey::OculusHand_Left_RingPinchStrength("OculusHand_Left_RingPinchStrength"); + const FKey FOculusKey::OculusHand_Left_PinkyPinchStrength("OculusHand_Left_PinkPinchStrength"); + + const FKey FOculusKey::OculusHand_Right_ThumbPinchStrength("OculusHand_Right_ThumbPinchStrength"); + const FKey FOculusKey::OculusHand_Right_IndexPinchStrength("OculusHand_Right_IndexPinchStrength"); + const FKey FOculusKey::OculusHand_Right_MiddlePinchStrength("OculusHand_Right_MiddlePinchStrength"); + const FKey FOculusKey::OculusHand_Right_RingPinchStrength("OculusHand_Right_RingPinchStrength"); + const FKey FOculusKey::OculusHand_Right_PinkyPinchStrength("OculusHand_Right_PinkPinchStrength"); + + const FOculusKeyNames::Type FOculusKeyNames::OculusTouch_Left_Thumbstick("OculusTouch_Left_Thumbstick"); + const FOculusKeyNames::Type FOculusKeyNames::OculusTouch_Left_Trigger("OculusTouch_Left_Trigger"); + const FOculusKeyNames::Type FOculusKeyNames::OculusTouch_Left_FaceButton1("OculusTouch_Left_FaceButton1"); + const FOculusKeyNames::Type FOculusKeyNames::OculusTouch_Left_FaceButton2("OculusTouch_Left_FaceButton2"); + const FOculusKeyNames::Type FOculusKeyNames::OculusTouch_Left_IndexPointing("OculusTouch_Left_IndexPointing"); + const FOculusKeyNames::Type FOculusKeyNames::OculusTouch_Left_ThumbUp("OculusTouch_Left_ThumbUp"); + const FOculusKeyNames::Type FOculusKeyNames::OculusTouch_Left_ThumbRest("OculusTouch_Left_ThumbRest"); + + const FOculusKeyNames::Type FOculusKeyNames::OculusTouch_Right_Thumbstick("OculusTouch_Right_Thumbstick"); + const FOculusKeyNames::Type FOculusKeyNames::OculusTouch_Right_Trigger("OculusTouch_Right_Trigger"); + const FOculusKeyNames::Type FOculusKeyNames::OculusTouch_Right_FaceButton1("OculusTouch_Right_FaceButton1"); + const FOculusKeyNames::Type FOculusKeyNames::OculusTouch_Right_FaceButton2("OculusTouch_Right_FaceButton2"); + const FOculusKeyNames::Type FOculusKeyNames::OculusTouch_Right_IndexPointing("OculusTouch_Right_IndexPointing"); + const FOculusKeyNames::Type FOculusKeyNames::OculusTouch_Right_ThumbUp("OculusTouch_Right_ThumbUp"); + const FOculusKeyNames::Type FOculusKeyNames::OculusTouch_Right_ThumbRest("OculusTouch_Right_ThumbRest"); + + const FOculusKeyNames::Type FOculusKeyNames::OculusRemote_DPad_Down("OculusRemote_DPad_Down"); + const FOculusKeyNames::Type FOculusKeyNames::OculusRemote_DPad_Up("OculusRemote_DPad_Up"); + const FOculusKeyNames::Type FOculusKeyNames::OculusRemote_DPad_Left("OculusRemote_DPad_Left"); + const FOculusKeyNames::Type FOculusKeyNames::OculusRemote_DPad_Right("OculusRemote_DPad_Right"); + const FOculusKeyNames::Type FOculusKeyNames::OculusRemote_Enter("OculusRemote_Enter"); + const FOculusKeyNames::Type FOculusKeyNames::OculusRemote_Back("OculusRemote_Back"); + const FOculusKeyNames::Type FOculusKeyNames::OculusRemote_VolumeUp("OculusRemote_VolumeUp"); + const FOculusKeyNames::Type FOculusKeyNames::OculusRemote_VolumeDown("OculusRemote_VolumeDown"); + const FOculusKeyNames::Type FOculusKeyNames::OculusRemote_Home("OculusRemote_Home"); + + const FOculusKeyNames::Type FOculusKeyNames::OculusHand_Left_ThumbPinch("OculusHand_Left_ThumbPinch"); + const FOculusKeyNames::Type FOculusKeyNames::OculusHand_Left_IndexPinch("OculusHand_Left_IndexPinch"); + const FOculusKeyNames::Type FOculusKeyNames::OculusHand_Left_MiddlePinch("OculusHand_Left_MiddlePinch"); + const FOculusKeyNames::Type FOculusKeyNames::OculusHand_Left_RingPinch("OculusHand_Left_RingPinch"); + const FOculusKeyNames::Type FOculusKeyNames::OculusHand_Left_PinkyPinch("OculusHand_Left_PinkPinch"); + + const FOculusKeyNames::Type FOculusKeyNames::OculusHand_Right_ThumbPinch("OculusHand_Right_ThumbPinch"); + const FOculusKeyNames::Type FOculusKeyNames::OculusHand_Right_IndexPinch("OculusHand_Right_IndexPinch"); + const FOculusKeyNames::Type FOculusKeyNames::OculusHand_Right_MiddlePinch("OculusHand_Right_MiddlePinch"); + const FOculusKeyNames::Type FOculusKeyNames::OculusHand_Right_RingPinch("OculusHand_Right_RingPinch"); + const FOculusKeyNames::Type FOculusKeyNames::OculusHand_Right_PinkyPinch("OculusHand_Right_PinkPinch"); + + const FOculusKeyNames::Type FOculusKeyNames::OculusHand_Left_SystemGesture("OculusHand_Left_SystemGesture"); + const FOculusKeyNames::Type FOculusKeyNames::OculusHand_Right_SystemGesture("OculusHand_Right_SystemGesture"); + + const FOculusKeyNames::Type FOculusKeyNames::OculusHand_Left_ThumbPinchStrength("OculusHand_Left_ThumbPinchStrength"); + const FOculusKeyNames::Type FOculusKeyNames::OculusHand_Left_IndexPinchStrength("OculusHand_Left_IndexPinchStrength"); + const FOculusKeyNames::Type FOculusKeyNames::OculusHand_Left_MiddlePinchStrength("OculusHand_Left_MiddlePinchStrength"); + const FOculusKeyNames::Type FOculusKeyNames::OculusHand_Left_RingPinchStrength("OculusHand_Left_RingPinchStrength"); + const FOculusKeyNames::Type FOculusKeyNames::OculusHand_Left_PinkyPinchStrength("OculusHand_Left_PinkPinchStrength"); + + const FOculusKeyNames::Type FOculusKeyNames::OculusHand_Right_ThumbPinchStrength("OculusHand_Right_ThumbPinchStrength"); + const FOculusKeyNames::Type FOculusKeyNames::OculusHand_Right_IndexPinchStrength("OculusHand_Right_IndexPinchStrength"); + const FOculusKeyNames::Type FOculusKeyNames::OculusHand_Right_MiddlePinchStrength("OculusHand_Right_MiddlePinchStrength"); + const FOculusKeyNames::Type FOculusKeyNames::OculusHand_Right_RingPinchStrength("OculusHand_Right_RingPinchStrength"); + const FOculusKeyNames::Type FOculusKeyNames::OculusHand_Right_PinkyPinchStrength("OculusHand_Right_PinkPinchStrength"); + + /** Threshold for treating trigger pulls as button presses, from 0.0 to 1.0 */ + float FOculusXRInput::TriggerThreshold = 0.8f; + + /** Are Remote keys mapped to gamepad or not. */ + bool FOculusXRInput::bRemoteKeysMappedToGamepad = true; + + float FOculusXRInput::InitialButtonRepeatDelay = 0.2f; + float FOculusXRInput::ButtonRepeatDelay = 0.1f; + bool FOculusXRInput::bPulledHapticsDesc = false; + + FOculusXRInput::FOculusXRInput(const TSharedRef& InMessageHandler) + : MessageHandler(InMessageHandler) + , ControllerPairs() + { + // take care of backward compatibility of Remote with Gamepad + if (bRemoteKeysMappedToGamepad) + { + Remote.MapKeysToGamepad(); + } + + FOculusControllerPair& ControllerPair = *new (ControllerPairs) FOculusControllerPair(); + + // TODO: Map the oculus controllers uniquely instead of using the default + ControllerPair.DeviceId = IPlatformInputDeviceMapper::Get().GetDefaultInputDevice(); + + IModularFeatures::Get().RegisterModularFeature(GetModularFeatureName(), this); + + LocalTrackingSpaceRecenterCount = 0; + + UE_LOG(LogOcInput, Log, TEXT("OculusXRInput is initialized")); + } + + FOculusXRInput::~FOculusXRInput() + { + IModularFeatures::Get().UnregisterModularFeature(GetModularFeatureName(), this); + } + + void FOculusXRInput::PreInit() + { + // Load the config, even if we failed to initialize a controller + LoadConfig(); + + // Register the FKeys + EKeys::AddKey(FKeyDetails(FOculusKey::OculusTouch_Left_Thumbstick, LOCTEXT("OculusTouch_Left_Thumbstick", "Oculus Touch (L) Thumbstick CapTouch"), FKeyDetails::GamepadKey | FKeyDetails::Axis1D)); + EKeys::AddKey(FKeyDetails(FOculusKey::OculusTouch_Left_FaceButton1, LOCTEXT("OculusTouch_Left_FaceButton1", "Oculus Touch (L) X Button CapTouch"), FKeyDetails::GamepadKey | FKeyDetails::Axis1D)); + EKeys::AddKey(FKeyDetails(FOculusKey::OculusTouch_Left_Trigger, LOCTEXT("OculusTouch_Left_Trigger", "Oculus Touch (L) Trigger CapTouch"), FKeyDetails::GamepadKey | FKeyDetails::Axis1D)); + EKeys::AddKey(FKeyDetails(FOculusKey::OculusTouch_Left_FaceButton2, LOCTEXT("OculusTouch_Left_FaceButton2", "Oculus Touch (L) Y Button CapTouch"), FKeyDetails::GamepadKey | FKeyDetails::Axis1D)); + EKeys::AddKey(FKeyDetails(FOculusKey::OculusTouch_Left_IndexPointing, LOCTEXT("OculusTouch_Left_IndexPointing", "Oculus Touch (L) Pointing CapTouch"), FKeyDetails::GamepadKey | FKeyDetails::Axis1D | FKeyDetails::NotBlueprintBindableKey, "OculusTouch")); + EKeys::AddKey(FKeyDetails(FOculusKey::OculusTouch_Left_ThumbUp, LOCTEXT("OculusTouch_Left_ThumbUp", "Oculus Touch (L) Thumb Up CapTouch"), FKeyDetails::GamepadKey | FKeyDetails::Axis1D | FKeyDetails::NotBlueprintBindableKey, "OculusTouch")); + EKeys::AddKey(FKeyDetails(FOculusKey::OculusTouch_Left_ThumbRest, LOCTEXT("OculusTouch_Left_ThumbRest", "Oculus Touch (L) Thumb Rest CapTouch"), FKeyDetails::GamepadKey | FKeyDetails::Axis1D | FKeyDetails::NotBlueprintBindableKey, "OculusTouch")); + EKeys::AddKey(FKeyDetails(FOculusKey::OculusTouch_Left_ThumbRest_Force, LOCTEXT("OculusTouch_Left_ThumbRest_Force", "Oculus Touch (L) Thumb Rest Force"), FKeyDetails::GamepadKey | FKeyDetails::Axis1D | FKeyDetails::NotBlueprintBindableKey, "OculusTouch")); + EKeys::AddKey(FKeyDetails(FOculusKey::OculusTouch_Left_Stylus_Force, LOCTEXT("OculusTouch_Left_Stylus_Force", "Oculus Touch (L) Stylus Force"), FKeyDetails::GamepadKey | FKeyDetails::Axis1D | FKeyDetails::NotBlueprintBindableKey, "OculusTouch")); + EKeys::AddKey(FKeyDetails(FOculusKey::OculusTouch_Left_IndexTrigger_Curl, LOCTEXT("OculusTouch_Left_IndexTrigger_Curl", "Oculus Touch (L) Trigger Curl CapTouch"), FKeyDetails::GamepadKey | FKeyDetails::Axis1D | FKeyDetails::NotBlueprintBindableKey, "OculusTouch")); + EKeys::AddKey(FKeyDetails(FOculusKey::OculusTouch_Left_IndexTrigger_Slide, LOCTEXT("OculusTouch_Left_IndexTrigger_Slide", "Oculus Touch (L) Trigger Slide CapTouch"), FKeyDetails::GamepadKey | FKeyDetails::Axis1D | FKeyDetails::NotBlueprintBindableKey, "OculusTouch")); + EKeys::AddKey(FKeyDetails(FOculusKey::OculusTouch_Left_IndexTrigger_Force, LOCTEXT("OculusTouch_Left_IndexTrigger_Force", "Oculus Touch (L) Trigger Force"), FKeyDetails::GamepadKey | FKeyDetails::Axis1D | FKeyDetails::NotBlueprintBindableKey, "OculusTouch")); + + EKeys::AddKey(FKeyDetails(FOculusKey::OculusTouch_Right_Thumbstick, LOCTEXT("OculusTouch_Right_Thumbstick", "Oculus Touch (R) Thumbstick CapTouch"), FKeyDetails::GamepadKey | FKeyDetails::Axis1D | FKeyDetails::NotBlueprintBindableKey)); + EKeys::AddKey(FKeyDetails(FOculusKey::OculusTouch_Right_FaceButton1, LOCTEXT("OculusTouch_Right_FaceButton1", "Oculus Touch (R) A Button CapTouch"), FKeyDetails::GamepadKey | FKeyDetails::Axis1D | FKeyDetails::NotBlueprintBindableKey)); + EKeys::AddKey(FKeyDetails(FOculusKey::OculusTouch_Right_Trigger, LOCTEXT("OculusTouch_Right_Trigger", "Oculus Touch (R) Trigger CapTouch"), FKeyDetails::GamepadKey | FKeyDetails::Axis1D | FKeyDetails::NotBlueprintBindableKey)); + EKeys::AddKey(FKeyDetails(FOculusKey::OculusTouch_Right_FaceButton2, LOCTEXT("OculusTouch_Right_FaceButton2", "Oculus Touch (R) B Button CapTouch"), FKeyDetails::GamepadKey | FKeyDetails::Axis1D | FKeyDetails::NotBlueprintBindableKey)); + EKeys::AddKey(FKeyDetails(FOculusKey::OculusTouch_Right_IndexPointing, LOCTEXT("OculusTouch_Right_IndexPointing", "Oculus Touch (R) Pointing CapTouch"), FKeyDetails::GamepadKey | FKeyDetails::Axis1D | FKeyDetails::NotBlueprintBindableKey, "OculusTouch")); + EKeys::AddKey(FKeyDetails(FOculusKey::OculusTouch_Right_ThumbUp, LOCTEXT("OculusTouch_Right_ThumbUp", "Oculus Touch (R) Thumb Up CapTouch"), FKeyDetails::GamepadKey | FKeyDetails::Axis1D | FKeyDetails::NotBlueprintBindableKey, "OculusTouch")); + EKeys::AddKey(FKeyDetails(FOculusKey::OculusTouch_Right_ThumbRest, LOCTEXT("OculusTouch_Right_ThumbRest", "Oculus Touch (R) Thumb Rest CapTouch"), FKeyDetails::GamepadKey | FKeyDetails::Axis1D | FKeyDetails::NotBlueprintBindableKey, "OculusTouch")); + EKeys::AddKey(FKeyDetails(FOculusKey::OculusTouch_Right_ThumbRest_Force, LOCTEXT("OculusTouch_Right_ThumbRest_Force", "Oculus Touch (R) Thumb Rest Force"), FKeyDetails::GamepadKey | FKeyDetails::Axis1D | FKeyDetails::NotBlueprintBindableKey, "OculusTouch")); + EKeys::AddKey(FKeyDetails(FOculusKey::OculusTouch_Right_Stylus_Force, LOCTEXT("OculusTouch_Right_Stylus_Force", "Oculus Touch (R) Stylus Force"), FKeyDetails::GamepadKey | FKeyDetails::Axis1D | FKeyDetails::NotBlueprintBindableKey, "OculusTouch")); + EKeys::AddKey(FKeyDetails(FOculusKey::OculusTouch_Right_IndexTrigger_Curl, LOCTEXT("OculusTouch_Right_IndexTrigger_Curl", "Oculus Touch (R) Trigger Curl CapTouch"), FKeyDetails::GamepadKey | FKeyDetails::Axis1D | FKeyDetails::NotBlueprintBindableKey, "OculusTouch")); + EKeys::AddKey(FKeyDetails(FOculusKey::OculusTouch_Right_IndexTrigger_Slide, LOCTEXT("OculusTouch_Right_IndexTrigger_Slide", "Oculus Touch (R) Trigger Slide CapTouch"), FKeyDetails::GamepadKey | FKeyDetails::Axis1D | FKeyDetails::NotBlueprintBindableKey, "OculusTouch")); + EKeys::AddKey(FKeyDetails(FOculusKey::OculusTouch_Right_IndexTrigger_Force, LOCTEXT("OculusTouch_Right_IndexTrigger_Force", "Oculus Touch (R) Trigger Force"), FKeyDetails::GamepadKey | FKeyDetails::Axis1D | FKeyDetails::NotBlueprintBindableKey, "OculusTouch")); + + EKeys::AddMenuCategoryDisplayInfo("OculusRemote", LOCTEXT("OculusRemoteSubCategory", "Oculus Remote"), TEXT("GraphEditor.PadEvent_16x")); + + EKeys::AddKey(FKeyDetails(FOculusKey::OculusRemote_DPad_Up, LOCTEXT("OculusRemote_DPad_Up", "Oculus Remote D-pad Up"), FKeyDetails::GamepadKey, "OculusRemote")); + EKeys::AddKey(FKeyDetails(FOculusKey::OculusRemote_DPad_Down, LOCTEXT("OculusRemote_DPad_Down", "Oculus Remote D-pad Down"), FKeyDetails::GamepadKey, "OculusRemote")); + EKeys::AddKey(FKeyDetails(FOculusKey::OculusRemote_DPad_Left, LOCTEXT("OculusRemote_DPad_Left", "Oculus Remote D-pad Left"), FKeyDetails::GamepadKey, "OculusRemote")); + EKeys::AddKey(FKeyDetails(FOculusKey::OculusRemote_DPad_Right, LOCTEXT("OculusRemote_DPad_Right", "Oculus Remote D-pad Right"), FKeyDetails::GamepadKey, "OculusRemote")); + + EKeys::AddKey(FKeyDetails(FOculusKey::OculusRemote_Enter, LOCTEXT("OculusRemote_Enter", "Oculus Remote Enter"), FKeyDetails::GamepadKey, "OculusRemote")); + EKeys::AddKey(FKeyDetails(FOculusKey::OculusRemote_Back, LOCTEXT("OculusRemote_Back", "Oculus Remote Back"), FKeyDetails::GamepadKey, "OculusRemote")); + + EKeys::AddKey(FKeyDetails(FOculusKey::OculusRemote_VolumeUp, LOCTEXT("OculusRemote_VolumeUp", "Oculus Remote Volume Up"), FKeyDetails::GamepadKey, "OculusRemote")); + EKeys::AddKey(FKeyDetails(FOculusKey::OculusRemote_VolumeDown, LOCTEXT("OculusRemote_VolumeDown", "Oculus Remote Volume Down"), FKeyDetails::GamepadKey, "OculusRemote")); + EKeys::AddKey(FKeyDetails(FOculusKey::OculusRemote_Home, LOCTEXT("OculusRemote_Home", "Oculus Remote Home"), FKeyDetails::GamepadKey, "OculusRemote")); + + EKeys::AddMenuCategoryDisplayInfo("OculusHand", LOCTEXT("OculusHandSubCategory", "Oculus Hand"), TEXT("GraphEditor.PadEvent_16x")); + + EKeys::AddKey(FKeyDetails(FOculusKey::OculusHand_Left_ThumbPinch, LOCTEXT("OculusHand_Left_ThumbPinch", "Oculus Hand (L) Thumb Pinch"), FKeyDetails::GamepadKey | FKeyDetails::NotBlueprintBindableKey, "OculusHand")); + EKeys::AddKey(FKeyDetails(FOculusKey::OculusHand_Left_IndexPinch, LOCTEXT("OculusHand_Left_IndexPinch", "Oculus Hand (L) Index Pinch"), FKeyDetails::GamepadKey | FKeyDetails::NotBlueprintBindableKey, "OculusHand")); + EKeys::AddKey(FKeyDetails(FOculusKey::OculusHand_Left_MiddlePinch, LOCTEXT("OculusHand_Left_MiddlePinch", "Oculus Hand (L) Middle Pinch"), FKeyDetails::GamepadKey | FKeyDetails::NotBlueprintBindableKey, "OculusHand")); + EKeys::AddKey(FKeyDetails(FOculusKey::OculusHand_Left_RingPinch, LOCTEXT("OculusHand_Left_RingPinch", "Oculus Hand (L) Ring Pinch"), FKeyDetails::GamepadKey | FKeyDetails::NotBlueprintBindableKey, "OculusHand")); + EKeys::AddKey(FKeyDetails(FOculusKey::OculusHand_Left_PinkyPinch, LOCTEXT("OculusHand_Left_PinkyPinch", "Oculus Hand (L) Pinky Pinch"), FKeyDetails::GamepadKey | FKeyDetails::NotBlueprintBindableKey, "OculusHand")); + + EKeys::AddKey(FKeyDetails(FOculusKey::OculusHand_Right_ThumbPinch, LOCTEXT("OculusHand_Right_ThumbPinch", "Oculus Hand (R) Thumb Pinch"), FKeyDetails::GamepadKey | FKeyDetails::NotBlueprintBindableKey, "OculusHand")); + EKeys::AddKey(FKeyDetails(FOculusKey::OculusHand_Right_IndexPinch, LOCTEXT("OculusHand_Right_IndexPinch", "Oculus Hand (R) Index Pinch"), FKeyDetails::GamepadKey | FKeyDetails::NotBlueprintBindableKey, "OculusHand")); + EKeys::AddKey(FKeyDetails(FOculusKey::OculusHand_Right_MiddlePinch, LOCTEXT("OculusHand_Right_MiddlePinch", "Oculus Hand (R) Middle Pinch"), FKeyDetails::GamepadKey | FKeyDetails::NotBlueprintBindableKey, "OculusHand")); + EKeys::AddKey(FKeyDetails(FOculusKey::OculusHand_Right_RingPinch, LOCTEXT("OculusHand_Right_RingPinch", "Oculus Hand (R) Ring Pinch"), FKeyDetails::GamepadKey | FKeyDetails::NotBlueprintBindableKey, "OculusHand")); + EKeys::AddKey(FKeyDetails(FOculusKey::OculusHand_Right_PinkyPinch, LOCTEXT("OculusHand_Right_PinkyPinch", "Oculus Hand (R) Pinky Pinch"), FKeyDetails::GamepadKey | FKeyDetails::NotBlueprintBindableKey, "OculusHand")); + + EKeys::AddKey(FKeyDetails(FOculusKey::OculusHand_Left_SystemGesture, LOCTEXT("OculusHand_Left_SystemGesture", "Oculus Hand (L) System Gesture"), FKeyDetails::GamepadKey | FKeyDetails::NotBlueprintBindableKey, "OculusHand")); + EKeys::AddKey(FKeyDetails(FOculusKey::OculusHand_Right_SystemGesture, LOCTEXT("OculusHand_Right_SystemGesture", "Oculus Hand (R) System Gesture"), FKeyDetails::GamepadKey | FKeyDetails::NotBlueprintBindableKey, "OculusHand")); + + EKeys::AddKey(FKeyDetails(FOculusKey::OculusHand_Left_ThumbPinchStrength, LOCTEXT("OculusHand_Left_ThumbPinchStrength", "Oculus Hand (L) Thumb Pinch Strength"), FKeyDetails::GamepadKey | FKeyDetails::Axis1D, "OculusHand")); + EKeys::AddKey(FKeyDetails(FOculusKey::OculusHand_Left_IndexPinchStrength, LOCTEXT("OculusHand_Left_IndexPinchStrength", "Oculus Hand (L) Index Pinch Strength"), FKeyDetails::GamepadKey | FKeyDetails::Axis1D, "OculusHand")); + EKeys::AddKey(FKeyDetails(FOculusKey::OculusHand_Left_MiddlePinchStrength, LOCTEXT("OculusHand_Left_MiddlePinchStrength", "Oculus Hand (L) Middle Pinch Strength"), FKeyDetails::GamepadKey | FKeyDetails::Axis1D, "OculusHand")); + EKeys::AddKey(FKeyDetails(FOculusKey::OculusHand_Left_RingPinchStrength, LOCTEXT("OculusHand_Left_RingPinchStrength", "Oculus Hand (L) Ring Pinch Strength"), FKeyDetails::GamepadKey | FKeyDetails::Axis1D, "OculusHand")); + EKeys::AddKey(FKeyDetails(FOculusKey::OculusHand_Left_PinkyPinchStrength, LOCTEXT("OculusHand_Left_PinkyPinchStrength", "Oculus Hand (L) Pinky Pinch Strength"), FKeyDetails::GamepadKey | FKeyDetails::Axis1D, "OculusHand")); + + EKeys::AddKey(FKeyDetails(FOculusKey::OculusHand_Right_ThumbPinchStrength, LOCTEXT("OculusHand_Right_ThumbPinchStrength", "Oculus Hand (R) Thumb Pinch Strength"), FKeyDetails::GamepadKey | FKeyDetails::Axis1D, "OculusHand")); + EKeys::AddKey(FKeyDetails(FOculusKey::OculusHand_Right_IndexPinchStrength, LOCTEXT("OculusHand_Right_IndexPinchStrength", "Oculus Hand (R) Index Pinch Strength"), FKeyDetails::GamepadKey | FKeyDetails::Axis1D, "OculusHand")); + EKeys::AddKey(FKeyDetails(FOculusKey::OculusHand_Right_MiddlePinchStrength, LOCTEXT("OculusHand_Right_MiddlePinchStrength", "Oculus Hand (R) Middle Pinch Strength"), FKeyDetails::GamepadKey | FKeyDetails::Axis1D, "OculusHand")); + EKeys::AddKey(FKeyDetails(FOculusKey::OculusHand_Right_RingPinchStrength, LOCTEXT("OculusHand_Right_RingPinchStrength", "Oculus Hand (R) Ring Pinch Strength"), FKeyDetails::GamepadKey | FKeyDetails::Axis1D, "OculusHand")); + EKeys::AddKey(FKeyDetails(FOculusKey::OculusHand_Right_PinkyPinchStrength, LOCTEXT("OculusHand_Right_PinkyPinchStrength", "Oculus Hand (R) Pinky Pinch Strength"), FKeyDetails::GamepadKey | FKeyDetails::Axis1D, "OculusHand")); + + UE_LOG(LogOcInput, Log, TEXT("OculusXRInput pre-init called")); + } + + void FOculusXRInput::LoadConfig() + { + const TCHAR* OculusTouchSettings = TEXT("OculusTouch.Settings"); + float ConfigThreshold = TriggerThreshold; + if (GConfig->GetFloat(OculusTouchSettings, TEXT("TriggerThreshold"), ConfigThreshold, GEngineIni)) + { + TriggerThreshold = ConfigThreshold; + } + + const TCHAR* OculusRemoteSettings = TEXT("OculusRemote.Settings"); + bool bConfigRemoteKeysMappedToGamepad; + if (GConfig->GetBool(OculusRemoteSettings, TEXT("bRemoteKeysMappedToGamepad"), bConfigRemoteKeysMappedToGamepad, GEngineIni)) + { + bRemoteKeysMappedToGamepad = bConfigRemoteKeysMappedToGamepad; + } + + GConfig->GetFloat(TEXT("/Script/Engine.InputSettings"), TEXT("InitialButtonRepeatDelay"), InitialButtonRepeatDelay, GInputIni); + GConfig->GetFloat(TEXT("/Script/Engine.InputSettings"), TEXT("ButtonRepeatDelay"), ButtonRepeatDelay, GInputIni); + } + + void FOculusXRInput::Tick(float DeltaTime) + { + // Nothing to do when ticking, for now. SendControllerEvents() handles everything. + } + + void FOculusXRInput::SendControllerEvents() + { + const double CurrentTime = FPlatformTime::Seconds(); + const float AnalogButtonPressThreshold = TriggerThreshold; + float DeltaTime = 0.0; + if (StartTime < CurrentTime) + { + DeltaTime = (float)(CurrentTime - StartTime); + StartTime = CurrentTime; + } + + if (IOculusXRHMDModule::IsAvailable() && FOculusXRHMDModule::GetPluginWrapper().GetInitialized() && FApp::HasVRFocus()) + { + if (MessageHandler.IsValid() && GEngine->XRSystem->GetHMDDevice()) + { + FPlatformUserId PlatUser = IPlatformInputDeviceMapper::Get().GetPrimaryPlatformUser(); + FInputDeviceId DeviceId = IPlatformInputDeviceMapper::Get().GetDefaultInputDevice(); + + OculusXRHMD::FOculusXRHMD* OculusXRHMD = static_cast(GEngine->XRSystem->GetHMDDevice()); + OculusXRHMD->StartGameFrame_GameThread(); + + ovrpControllerState6 OvrpControllerState; + if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetControllerState6(ovrpController_Remote, &OvrpControllerState)) && (OvrpControllerState.ConnectedControllerTypes & ovrpController_Remote)) + { + for (int32 ButtonIndex = 0; ButtonIndex < (int32)EOculusRemoteControllerButton::TotalButtonCount; ++ButtonIndex) + { + FOculusButtonState& ButtonState = Remote.Buttons[ButtonIndex]; + check(!ButtonState.Key.IsNone()); // is button's name initialized? + + // Determine if the button is pressed down + bool bButtonPressed = false; + switch ((EOculusRemoteControllerButton)ButtonIndex) + { + case EOculusRemoteControllerButton::DPad_Up: + bButtonPressed = (OvrpControllerState.Buttons & ovrpButton_Up) != 0; + break; + + case EOculusRemoteControllerButton::DPad_Down: + bButtonPressed = (OvrpControllerState.Buttons & ovrpButton_Down) != 0; + break; + + case EOculusRemoteControllerButton::DPad_Left: + bButtonPressed = (OvrpControllerState.Buttons & ovrpButton_Left) != 0; + break; + + case EOculusRemoteControllerButton::DPad_Right: + bButtonPressed = (OvrpControllerState.Buttons & ovrpButton_Right) != 0; + break; + + case EOculusRemoteControllerButton::Enter: + bButtonPressed = (OvrpControllerState.Buttons & ovrpButton_Start) != 0; + break; + + case EOculusRemoteControllerButton::Back: + bButtonPressed = (OvrpControllerState.Buttons & ovrpButton_Back) != 0; + break; + + case EOculusRemoteControllerButton::VolumeUp: +#ifdef SUPPORT_INTERNAL_BUTTONS + bButtonPressed = (OvrpControllerState.Buttons & ovrpButton_VolUp) != 0; +#endif + break; + + case EOculusRemoteControllerButton::VolumeDown: +#ifdef SUPPORT_INTERNAL_BUTTONS + bButtonPressed = (OvrpControllerState.Buttons & ovrpButton_VolDown) != 0; +#endif + break; + + case EOculusRemoteControllerButton::Home: +#ifdef SUPPORT_INTERNAL_BUTTONS + bButtonPressed = (OvrpControllerState.Buttons & ovrpButton_Home) != 0; +#endif + break; + + default: + check(0); // unhandled button, shouldn't happen + break; + } + + // Update button state + if (bButtonPressed != ButtonState.bIsPressed) + { + ButtonState.bIsPressed = bButtonPressed; + if (ButtonState.bIsPressed) + { + OnControllerButtonPressed(ButtonState, PlatUser, DeviceId, false); + + // Set the timer for the first repeat + ButtonState.NextRepeatTime = CurrentTime + InitialButtonRepeatDelay; + } + else + { + OnControllerButtonReleased(ButtonState, PlatUser, DeviceId, false); + } + } + + // Apply key repeat, if its time for that + if (ButtonState.bIsPressed && ButtonState.NextRepeatTime <= CurrentTime) + { + OnControllerButtonPressed(ButtonState, PlatUser, DeviceId, true); + + // Set the timer for the next repeat + ButtonState.NextRepeatTime = CurrentTime + ButtonRepeatDelay; + } + } + } + + if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetControllerState6((ovrpController)(ovrpController_LTrackedRemote | ovrpController_RTrackedRemote | ovrpController_Touch), &OvrpControllerState))) + { + UE_CLOG(OVR_DEBUG_LOGGING, LogOcInput, Log, TEXT("SendControllerEvents: ButtonState = 0x%X"), OvrpControllerState.Buttons); + UE_CLOG(OVR_DEBUG_LOGGING, LogOcInput, Log, TEXT("SendControllerEvents: Touches = 0x%X"), OvrpControllerState.Touches); + + // If using touch controllers (Quest) use the local tracking space recentering as a signal for recenter + if ((OvrpControllerState.ConnectedControllerTypes & ovrpController_LTouch) != 0 || (OvrpControllerState.ConnectedControllerTypes & ovrpController_RTouch) != 0) + { + int32 recenterCount = 0; + if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetLocalTrackingSpaceRecenterCount(&recenterCount))) + { + if (LocalTrackingSpaceRecenterCount != recenterCount) + { + FCoreDelegates::VRControllerRecentered.Broadcast(); + LocalTrackingSpaceRecenterCount = recenterCount; + } + } + } + + for (FOculusControllerPair& ControllerPair : ControllerPairs) + { + FPlatformUserId PlatformUser = IPlatformInputDeviceMapper::Get().GetUserForInputDevice(ControllerPair.DeviceId); + + for (int32 HandIndex = 0; HandIndex < UE_ARRAY_COUNT(ControllerPair.TouchControllerStates); ++HandIndex) + { + FOculusTouchControllerState& State = ControllerPair.TouchControllerStates[HandIndex]; + bool bIsLeft = (HandIndex == (int32)EControllerHand::Left); + + bool bIsMobileController = bIsLeft ? (OvrpControllerState.ConnectedControllerTypes & ovrpController_LTrackedRemote) != 0 : (OvrpControllerState.ConnectedControllerTypes & ovrpController_RTrackedRemote) != 0; + bool bIsTouchController = bIsLeft ? (OvrpControllerState.ConnectedControllerTypes & ovrpController_LTouch) != 0 : (OvrpControllerState.ConnectedControllerTypes & ovrpController_RTouch) != 0; + bool bIsCurrentlyTracked = bIsMobileController || bIsTouchController; + + if (bIsCurrentlyTracked) + { + ovrpNode OvrpNode = (HandIndex == (int32)EControllerHand::Left) ? ovrpNode_HandLeft : ovrpNode_HandRight; + + State.bIsConnected = true; + ovrpBool bResult = true; + State.bIsPositionTracked = OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetNodePositionTracked2(OvrpNode, &bResult)) && bResult; + State.bIsPositionValid = OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetNodePositionValid(OvrpNode, &bResult)) && bResult; + State.bIsOrientationTracked = OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetNodeOrientationTracked2(OvrpNode, &bResult)) && bResult; + State.bIsOrientationValid = OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetNodeOrientationValid(OvrpNode, &bResult)) && bResult; + + const float OvrTriggerAxis = OvrpControllerState.IndexTrigger[HandIndex]; + const float OvrGripAxis = OvrpControllerState.HandTrigger[HandIndex]; + const float OvrThumbRestForce = OvrpControllerState.ThumbRestForce[HandIndex]; + const float OvrStylusForce = OvrpControllerState.StylusForce[HandIndex]; + const float OvrIndexTriggerCurl = OvrpControllerState.IndexTriggerCurl[HandIndex]; + const float OvrIndexTriggerSlide = OvrpControllerState.IndexTriggerSlide[HandIndex]; + const float OvrIndexTriggerForce = OvrpControllerState.IndexTriggerForce[HandIndex]; + + UE_CLOG(OVR_DEBUG_LOGGING, LogOcInput, Log, TEXT("SendControllerEvents: IndexTrigger[%d] = %f"), int(HandIndex), OvrTriggerAxis); + UE_CLOG(OVR_DEBUG_LOGGING, LogOcInput, Log, TEXT("SendControllerEvents: HandTrigger[%d] = %f"), int(HandIndex), OvrGripAxis); + UE_CLOG(OVR_DEBUG_LOGGING, LogOcInput, Log, TEXT("SendControllerEvents: ThumbStick[%d] = { %f, %f }"), int(HandIndex), OvrpControllerState.Thumbstick[HandIndex].x, OvrpControllerState.Thumbstick[HandIndex].y); + UE_CLOG(OVR_DEBUG_LOGGING, LogOcInput, Log, TEXT("SendControllerEvents: ThumbRestForce[%d] = %f"), int(HandIndex), OvrThumbRestForce); + UE_CLOG(OVR_DEBUG_LOGGING, LogOcInput, Log, TEXT("SendControllerEvents: StylusForce[%d] = %f"), int(HandIndex), OvrStylusForce); + UE_CLOG(OVR_DEBUG_LOGGING, LogOcInput, Log, TEXT("SendControllerEvents: IndexTriggerCurl[%d] = %f"), int(HandIndex), OvrIndexTriggerCurl); + UE_CLOG(OVR_DEBUG_LOGGING, LogOcInput, Log, TEXT("SendControllerEvents: IndexTriggerSlide[%d] = %f"), int(HandIndex), OvrIndexTriggerSlide); + UE_CLOG(OVR_DEBUG_LOGGING, LogOcInput, Log, TEXT("SendControllerEvents: IndexTriggerForce[%d] = %f"), int(HandIndex), OvrIndexTriggerForce); + if (bIsMobileController) + { + if (OvrpControllerState.RecenterCount[HandIndex] != State.RecenterCount) + { + State.RecenterCount = OvrpControllerState.RecenterCount[HandIndex]; + FCoreDelegates::VRControllerRecentered.Broadcast(); + } + } + + if (OvrTriggerAxis != State.TriggerAxis) + { + State.TriggerAxis = OvrTriggerAxis; + MessageHandler->OnControllerAnalog(bIsLeft ? EKeys::OculusTouch_Left_Trigger_Axis.GetFName() : EKeys::OculusTouch_Right_Trigger_Axis.GetFName(), PlatformUser, ControllerPair.DeviceId, State.TriggerAxis); + } + + if (OvrGripAxis != State.GripAxis) + { + State.GripAxis = OvrGripAxis; + MessageHandler->OnControllerAnalog(bIsLeft ? EKeys::OculusTouch_Left_Grip_Axis.GetFName() : EKeys::OculusTouch_Right_Grip_Axis.GetFName(), PlatformUser, ControllerPair.DeviceId, State.GripAxis); + } + + ovrpVector2f ThumbstickValue = OvrpControllerState.Thumbstick[HandIndex]; + ovrpVector2f TouchpadValue = OvrpControllerState.Touchpad[HandIndex]; + + if (ThumbstickValue.x != State.ThumbstickAxes.X) + { + State.ThumbstickAxes.X = ThumbstickValue.x; + MessageHandler->OnControllerAnalog(bIsLeft ? EKeys::OculusTouch_Left_Thumbstick_X.GetFName() : EKeys::OculusTouch_Right_Thumbstick_X.GetFName(), PlatformUser, ControllerPair.DeviceId, State.ThumbstickAxes.X); + } + + if (ThumbstickValue.y != State.ThumbstickAxes.Y) + { + State.ThumbstickAxes.Y = ThumbstickValue.y; + MessageHandler->OnControllerAnalog(bIsLeft ? EKeys::OculusTouch_Left_Thumbstick_Y.GetFName() : EKeys::OculusTouch_Right_Thumbstick_Y.GetFName(), PlatformUser, ControllerPair.DeviceId, State.ThumbstickAxes.Y); + } + + if (TouchpadValue.x != State.TouchpadAxes.X) + { + State.TouchpadAxes.X = TouchpadValue.x; + } + + if (TouchpadValue.y != State.TouchpadAxes.Y) + { + State.TouchpadAxes.Y = TouchpadValue.y; + } + + if (OvrThumbRestForce != State.ThumbRestForce) + { + State.ThumbRestForce = OvrThumbRestForce; + MessageHandler->OnControllerAnalog(bIsLeft ? FOculusKey::OculusTouch_Left_ThumbRest_Force.GetFName() : FOculusKey::OculusTouch_Right_ThumbRest_Force.GetFName(), PlatformUser, ControllerPair.DeviceId, State.ThumbRestForce); + } + + if (OvrStylusForce != State.StylusForce) + { + State.StylusForce = OvrStylusForce; + MessageHandler->OnControllerAnalog(bIsLeft ? FOculusKey::OculusTouch_Left_Stylus_Force.GetFName() : FOculusKey::OculusTouch_Right_Stylus_Force.GetFName(), PlatformUser, ControllerPair.DeviceId, State.StylusForce); + } + + if (OvrIndexTriggerCurl != State.IndexTriggerCurl) + { + State.IndexTriggerCurl = OvrIndexTriggerCurl; + MessageHandler->OnControllerAnalog(bIsLeft ? FOculusKey::OculusTouch_Left_IndexTrigger_Curl.GetFName() : FOculusKey::OculusTouch_Right_IndexTrigger_Curl.GetFName(), PlatformUser, ControllerPair.DeviceId, State.IndexTriggerCurl); + } + + if (OvrIndexTriggerSlide != State.IndexTriggerSlide) + { + State.IndexTriggerSlide = OvrIndexTriggerSlide; + MessageHandler->OnControllerAnalog(bIsLeft ? FOculusKey::OculusTouch_Left_IndexTrigger_Slide.GetFName() : FOculusKey::OculusTouch_Right_IndexTrigger_Slide.GetFName(), PlatformUser, ControllerPair.DeviceId, State.IndexTriggerSlide); + } + + if (OvrIndexTriggerForce != State.IndexTriggerForce) + { + State.IndexTriggerForce = OvrIndexTriggerForce; + MessageHandler->OnControllerAnalog(bIsLeft ? FOculusKey::OculusTouch_Left_IndexTrigger_Force.GetFName() : FOculusKey::OculusTouch_Right_IndexTrigger_Force.GetFName(), PlatformUser, ControllerPair.DeviceId, State.IndexTriggerForce); + } + for (int32 ButtonIndex = 0; ButtonIndex < (int32)EOculusTouchControllerButton::TotalButtonCount; ++ButtonIndex) + { + FOculusButtonState& ButtonState = State.Buttons[ButtonIndex]; + check(!ButtonState.Key.IsNone()); // is button's name initialized? + + // Determine if the button is pressed down + bool bButtonPressed = false; + switch ((EOculusTouchControllerButton)ButtonIndex) + { + case EOculusTouchControllerButton::Trigger: + bButtonPressed = State.TriggerAxis >= AnalogButtonPressThreshold; + break; + + case EOculusTouchControllerButton::Grip: + bButtonPressed = State.GripAxis >= AnalogButtonPressThreshold; + break; + + case EOculusTouchControllerButton::XA: + bButtonPressed = bIsLeft ? (OvrpControllerState.Buttons & ovrpButton_X) != 0 : (OvrpControllerState.Buttons & ovrpButton_A) != 0; + break; + + case EOculusTouchControllerButton::YB: + bButtonPressed = bIsLeft ? (OvrpControllerState.Buttons & ovrpButton_Y) != 0 : (OvrpControllerState.Buttons & ovrpButton_B) != 0; + break; + + case EOculusTouchControllerButton::Thumbstick: + bButtonPressed = bIsLeft ? (OvrpControllerState.Buttons & ovrpButton_LThumb) != 0 : (OvrpControllerState.Buttons & ovrpButton_RThumb) != 0; + break; + + case EOculusTouchControllerButton::Thumbstick_Up: + if (bIsTouchController && State.ThumbstickAxes.Size() > 0.7f || bIsMobileController && State.Buttons[(int)EOculusTouchControllerButton::Thumbstick].bIsPressed && State.ThumbstickAxes.Size() > 0.5f) + { + float Angle = FMath::Atan2(State.ThumbstickAxes.Y, State.ThumbstickAxes.X); + bButtonPressed = Angle >= (1.0f / 8.0f) * PI && Angle <= (7.0f / 8.0f) * PI; + } + break; + + case EOculusTouchControllerButton::Thumbstick_Down: + if (bIsTouchController && State.ThumbstickAxes.Size() > 0.7f || bIsMobileController && State.Buttons[(int)EOculusTouchControllerButton::Thumbstick].bIsPressed && State.ThumbstickAxes.Size() > 0.5f) + { + float Angle = FMath::Atan2(State.ThumbstickAxes.Y, State.ThumbstickAxes.X); + bButtonPressed = Angle >= (-7.0f / 8.0f) * PI && Angle <= (-1.0f / 8.0f) * PI; + } + break; + + case EOculusTouchControllerButton::Thumbstick_Left: + if (bIsTouchController && State.ThumbstickAxes.Size() > 0.7f || bIsMobileController && State.Buttons[(int)EOculusTouchControllerButton::Thumbstick].bIsPressed && State.ThumbstickAxes.Size() > 0.5f) + { + float Angle = FMath::Atan2(State.ThumbstickAxes.Y, State.ThumbstickAxes.X); + bButtonPressed = Angle <= (-5.0f / 8.0f) * PI || Angle >= (5.0f / 8.0f) * PI; + } + break; + + case EOculusTouchControllerButton::Thumbstick_Right: + if (bIsTouchController && State.ThumbstickAxes.Size() > 0.7f || bIsMobileController && State.Buttons[(int)EOculusTouchControllerButton::Thumbstick].bIsPressed && State.ThumbstickAxes.Size() > 0.5f) + { + float Angle = FMath::Atan2(State.ThumbstickAxes.Y, State.ThumbstickAxes.X); + bButtonPressed = Angle >= (-3.0f / 8.0f) * PI && Angle <= (3.0f / 8.0f) * PI; + } + break; + + case EOculusTouchControllerButton::Menu: + bButtonPressed = bIsLeft && (OvrpControllerState.Buttons & ovrpButton_Start); + break; + + case EOculusTouchControllerButton::Thumbstick_Touch: + bButtonPressed = bIsLeft ? (OvrpControllerState.Touches & ovrpTouch_LThumb) != 0 : (OvrpControllerState.Touches & ovrpTouch_RThumb) != 0; + break; + + case EOculusTouchControllerButton::Trigger_Touch: + bButtonPressed = bIsLeft ? (OvrpControllerState.Touches & ovrpTouch_LIndexTrigger) != 0 : (OvrpControllerState.Touches & ovrpTouch_RIndexTrigger) != 0; + break; + + case EOculusTouchControllerButton::XA_Touch: + bButtonPressed = bIsLeft ? (OvrpControllerState.Touches & ovrpTouch_X) != 0 : (OvrpControllerState.Touches & ovrpTouch_A) != 0; + break; + + case EOculusTouchControllerButton::YB_Touch: + bButtonPressed = bIsLeft ? (OvrpControllerState.Touches & ovrpTouch_Y) != 0 : (OvrpControllerState.Touches & ovrpTouch_B) != 0; + break; + + default: + check(0); + break; + } + + // Update button state + if (bButtonPressed != ButtonState.bIsPressed) + { + ButtonState.bIsPressed = bButtonPressed; + if (ButtonState.bIsPressed) + { + OnControllerButtonPressed(ButtonState, PlatformUser, ControllerPair.DeviceId, false); + + // Set the timer for the first repeat + ButtonState.NextRepeatTime = CurrentTime + InitialButtonRepeatDelay; + } + else + { + OnControllerButtonReleased(ButtonState, PlatformUser, ControllerPair.DeviceId, false); + } + } + + // Apply key repeat, if its time for that + if (ButtonState.bIsPressed && ButtonState.NextRepeatTime <= CurrentTime) + { + OnControllerButtonPressed(ButtonState, PlatformUser, ControllerPair.DeviceId, true); + + // Set the timer for the next repeat + ButtonState.NextRepeatTime = CurrentTime + ButtonRepeatDelay; + } + } + + // Handle Capacitive States + for (int32 CapTouchIndex = 0; CapTouchIndex < (int32)EOculusTouchCapacitiveAxes::TotalAxisCount; ++CapTouchIndex) + { + FOculusAxisState& CapState = State.CapacitiveAxes[CapTouchIndex]; + + float CurrentAxisVal = 0.f; + switch ((EOculusTouchCapacitiveAxes)CapTouchIndex) + { + case EOculusTouchCapacitiveAxes::XA: + { + const uint32 mask = (bIsLeft) ? ovrpTouch_X : ovrpTouch_A; + CurrentAxisVal = (OvrpControllerState.Touches & mask) != 0 ? 1.f : 0.f; + break; + } + case EOculusTouchCapacitiveAxes::YB: + { + const uint32 mask = (bIsLeft) ? ovrpTouch_Y : ovrpTouch_B; + CurrentAxisVal = (OvrpControllerState.Touches & mask) != 0 ? 1.f : 0.f; + break; + } + case EOculusTouchCapacitiveAxes::Thumbstick: + { + const uint32 mask = bIsMobileController ? ((bIsLeft) ? ovrpTouch_LTouchpad : ovrpTouch_RTouchpad) : ((bIsLeft) ? ovrpTouch_LThumb : ovrpTouch_RThumb); + CurrentAxisVal = (OvrpControllerState.Touches & mask) != 0 ? 1.f : 0.f; + break; + } + case EOculusTouchCapacitiveAxes::Trigger: + { + const uint32 mask = (bIsLeft) ? ovrpTouch_LIndexTrigger : ovrpTouch_RIndexTrigger; + CurrentAxisVal = (OvrpControllerState.Touches & mask) != 0 ? 1.f : 0.f; + break; + } + case EOculusTouchCapacitiveAxes::IndexPointing: + { + const uint32 mask = (bIsLeft) ? ovrpNearTouch_LIndexTrigger : ovrpNearTouch_RIndexTrigger; + CurrentAxisVal = (OvrpControllerState.NearTouches & mask) != 0 ? 0.f : 1.f; + break; + } + case EOculusTouchCapacitiveAxes::ThumbUp: + { + const uint32 mask = (bIsLeft) ? ovrpNearTouch_LThumbButtons : ovrpNearTouch_RThumbButtons; + CurrentAxisVal = (OvrpControllerState.NearTouches & mask) != 0 ? 0.f : 1.f; + break; + } + case EOculusTouchCapacitiveAxes::ThumbRest: + { + const uint32 mask = (bIsLeft) ? ovrpTouch_LThumbRest : ovrpTouch_RThumbRest; + CurrentAxisVal = (OvrpControllerState.Touches & mask) != 0 ? 1.f : 0.f; + break; + } + default: + check(0); + } + + if (CurrentAxisVal != CapState.State) + { + MessageHandler->OnControllerAnalog(CapState.Axis, PlatformUser, ControllerPair.DeviceId, CurrentAxisVal); + + CapState.State = CurrentAxisVal; + } + } + ProcessHaptics(DeltaTime); + } + else + { + // Controller isn't available right now. + if (CVarOculusResetUntrackedInputStates.GetValueOnAnyThread()) + { + //Zero out input state, so that if controller comes back it will send fresh event deltas + State = FOculusTouchControllerState((EControllerHand)HandIndex); + UE_CLOG(OVR_DEBUG_LOGGING, LogOcInput, Log, TEXT("SendControllerEvents: Controller for the hand %d is not tracked and input states are reset"), int(HandIndex)); + } + else + { + //Cache input state, so that if controller comes back it will send event deltas + UE_CLOG(OVR_DEBUG_LOGGING, LogOcInput, Log, TEXT("SendControllerEvents: Controller for the hand %d is not tracked and input states are saved"), int(HandIndex)); + } + } + } + } + } + else + { + // Controller isn't available right now. Zero out input state, so that if it comes back it will send fresh event deltas + for (FOculusControllerPair& ControllerPair : ControllerPairs) + { + for (int32 HandIndex = 0; HandIndex < UE_ARRAY_COUNT(ControllerPair.TouchControllerStates); ++HandIndex) + { + FOculusTouchControllerState& State = ControllerPair.TouchControllerStates[HandIndex]; + State = FOculusTouchControllerState((EControllerHand)HandIndex); + } + } + } + + if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetControllerState6((ovrpController)(ovrpController_LHand | ovrpController_RHand | ovrpController_Hands), &OvrpControllerState))) + { + for (FOculusControllerPair& ControllerPair : ControllerPairs) + { + FPlatformUserId PlatformUser = IPlatformInputDeviceMapper::Get().GetUserForInputDevice(ControllerPair.DeviceId); + + for (int32 HandIndex = 0; HandIndex < UE_ARRAY_COUNT(ControllerPair.HandControllerStates); ++HandIndex) + { + FOculusHandControllerState& State = ControllerPair.HandControllerStates[HandIndex]; + + bool bIsLeft = (HandIndex == (int32)EControllerHand::Left); + bool bIsCurrentlyTracked = bIsLeft ? (OvrpControllerState.ConnectedControllerTypes & ovrpController_LHand) != 0 : (OvrpControllerState.ConnectedControllerTypes & ovrpController_RHand) != 0; + + if (bIsCurrentlyTracked) + { + State.bIsConnected = true; + ovrpBool bResult = true; + + // Hand Tracking requires the frame number for accurate results + OculusXRHMD::FGameFrame* CurrentFrame; + if (IsInGameThread()) + { + CurrentFrame = OculusXRHMD->GetNextFrameToRender(); + } + else + { + CurrentFrame = OculusXRHMD->GetFrame_RenderThread(); + } + + // Poll for Hand Tracking State + ovrpHandState HandState; + if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetHandState2(ovrpStep_Render, CurrentFrame ? CurrentFrame->FrameNumber : OVRP_CURRENT_FRAMEINDEX, (ovrpHand)HandIndex, &HandState))) + { + // Update various data about hands + State.HandScale = HandState.HandScale; + + // Update Bone Rotations + for (uint32 BoneIndex = 0; BoneIndex < UE_ARRAY_COUNT(State.BoneRotations); BoneIndex++) + { + ovrpQuatf RawRotation = HandState.BoneRotations[BoneIndex]; + FQuat BoneRotation = FOculusHandTracking::OvrBoneQuatToFQuat(RawRotation); + BoneRotation.Normalize(); + State.BoneRotations[BoneIndex] = BoneRotation; + } + + // Update Pinch State and Pinch Strength + bool bTracked = (HandState.Status & ovrpHandStatus_HandTracked) != 0; + State.TrackingConfidence = FOculusHandTracking::ToEOculusXRTrackingConfidence(HandState.HandConfidence); + + State.bIsPositionTracked = bTracked && State.TrackingConfidence == EOculusXRTrackingConfidence::High; + State.bIsPositionValid = bTracked; + State.bIsOrientationTracked = bTracked && State.TrackingConfidence == EOculusXRTrackingConfidence::High; + State.bIsOrientationValid = bTracked; + + State.bIsPointerPoseValid = (HandState.Status & ovrpHandStatus_InputValid) != 0; + + ovrpPosef PointerPose = HandState.PointerPose; + State.PointerPose.SetTranslation(OculusXRHMD::ToFVector(PointerPose.Position)); + State.PointerPose.SetRotation(OculusXRHMD::ToFQuat(PointerPose.Orientation)); + + State.bIsDominantHand = (HandState.Status & ovrpHandStatus_DominantHand) != 0; + + // Poll for finger confidence + for (uint32 FingerIndex = 0; FingerIndex < (int32)EOculusHandAxes::TotalAxisCount; FingerIndex++) + { + State.FingerConfidences[FingerIndex] = FOculusHandTracking::ToEOculusXRTrackingConfidence(HandState.FingerConfidences[FingerIndex]); + } + + // Poll for finger pinches + for (uint32 FingerIndex = 0; FingerIndex < (uint32)EOculusHandButton::TotalButtonCount; FingerIndex++) + { + FOculusButtonState& PinchState = State.HandButtons[FingerIndex]; + check(!PinchState.Key.IsNone()); + + bool bPressed = false; + if (FingerIndex < (uint32)EOculusHandButton::System) + { + bPressed = (((uint32)HandState.Pinches & (1 << FingerIndex)) != 0); + bPressed &= (HandState.HandConfidence == ovrpTrackingConfidence_High) && (HandState.FingerConfidences[FingerIndex] == ovrpTrackingConfidence_High); + } + else if (FingerIndex == (uint32)EOculusHandButton::System) + { + bPressed = (HandState.Status & ovrpHandStatus_SystemGestureInProgress) != 0; + } + else + { + bPressed = (OvrpControllerState.Buttons & ovrpButton_Start) != 0 && !State.bIsDominantHand; + } + + if (bPressed != PinchState.bIsPressed) + { + PinchState.bIsPressed = bPressed; + if (PinchState.bIsPressed) + { + OnControllerButtonPressed(PinchState, PlatformUser, ControllerPair.DeviceId, false); + } + else + { + OnControllerButtonReleased(PinchState, PlatformUser, ControllerPair.DeviceId, false); + } + } + } + + // Poll for finger strength + for (uint32 FingerIndex = 0; FingerIndex < (uint32)EOculusHandAxes::TotalAxisCount; FingerIndex++) + { + FOculusAxisState& PinchStrength = State.HandAxes[FingerIndex]; + check(!PinchStrength.Axis.IsNone()); + + float PinchValue = 0.0f; + if (HandState.HandConfidence == ovrpTrackingConfidence_High) + { + PinchValue = HandState.PinchStrength[FingerIndex]; + } + + if (PinchValue != PinchStrength.State) + { + MessageHandler->OnControllerAnalog(PinchStrength.Axis, PlatformUser, ControllerPair.DeviceId, PinchValue); + PinchStrength.State = PinchValue; + } + } + } + } + else + { + // Hand isn't available right now. + if (CVarOculusResetUntrackedInputStates.GetValueOnAnyThread()) + { + //Zero out input state, so that if hand comes back it will send fresh event deltas + State = FOculusHandControllerState((EControllerHand)HandIndex); + UE_CLOG(OVR_DEBUG_LOGGING, LogOcInput, Log, TEXT("SendControllerEvents: Hand for the hand %d is not tracked and input states are reset"), int32(HandIndex)); + } + else + { + //Cache input state, so that if hand comes back it will send event deltas + UE_CLOG(OVR_DEBUG_LOGGING, LogOcInput, Log, TEXT("SendControllerEvents: Hand for the hand %d is not tracked and input states are saved"), int(HandIndex)); + } + } + } + } + } + else + { + // Hands are not availble right now, zero out the hand state + for (FOculusControllerPair& ControllerPair : ControllerPairs) + { + for (int32 HandIndex = 0; HandIndex < UE_ARRAY_COUNT(ControllerPair.HandControllerStates); ++HandIndex) + { + FOculusHandControllerState& State = ControllerPair.HandControllerStates[HandIndex]; + State = FOculusHandControllerState((EControllerHand)HandIndex); + } + } + } + } + } + UE_CLOG(OVR_DEBUG_LOGGING, LogOcInput, Log, TEXT("")); + } + + void FOculusXRInput::SetMessageHandler(const TSharedRef& InMessageHandler) + { + MessageHandler = InMessageHandler; + } + + bool FOculusXRInput::Exec(UWorld* InWorld, const TCHAR* Cmd, FOutputDevice& Ar) + { + // No exec commands supported, for now. + return false; + } + + void FOculusXRInput::SetChannelValue(int32 ControllerId, FForceFeedbackChannelType ChannelType, float Value) + { + const EControllerHand Hand = (ChannelType == FForceFeedbackChannelType::LEFT_LARGE || ChannelType == FForceFeedbackChannelType::LEFT_SMALL) ? EControllerHand::Left : EControllerHand::Right; + + IPlatformInputDeviceMapper& DeviceMapper = IPlatformInputDeviceMapper::Get(); + FPlatformUserId InPlatformUser = FGenericPlatformMisc::GetPlatformUserForUserIndex(ControllerId); + FInputDeviceId InDeviceId = INPUTDEVICEID_NONE; + DeviceMapper.RemapControllerIdToPlatformUserAndDevice(ControllerId, InPlatformUser, InDeviceId); + + for (FOculusControllerPair& ControllerPair : ControllerPairs) + { + if (ControllerPair.DeviceId == InDeviceId) + { + FOculusTouchControllerState& ControllerState = ControllerPair.TouchControllerStates[(int32)Hand]; + + if (ControllerState.bPlayingHapticEffect) + { + continue; + } + + // @todo: The SMALL channel controls frequency, the LARGE channel controls amplitude. This is a bit of a weird fit. + if (ChannelType == FForceFeedbackChannelType::LEFT_SMALL || ChannelType == FForceFeedbackChannelType::RIGHT_SMALL) + { + ControllerState.ForceFeedbackHapticFrequency = Value; + } + else + { + ControllerState.ForceFeedbackHapticAmplitude = Value; + } + + UpdateForceFeedback(ControllerPair, Hand); + + break; + } + } + } + + void FOculusXRInput::SetChannelValues(int32 ControllerId, const FForceFeedbackValues& Values) + { + IPlatformInputDeviceMapper& DeviceMapper = IPlatformInputDeviceMapper::Get(); + FPlatformUserId InPlatformUser = FGenericPlatformMisc::GetPlatformUserForUserIndex(ControllerId); + FInputDeviceId InDeviceId = INPUTDEVICEID_NONE; + DeviceMapper.RemapControllerIdToPlatformUserAndDevice(ControllerId, InPlatformUser, InDeviceId); + + for (FOculusControllerPair& ControllerPair : ControllerPairs) + { + if (ControllerPair.DeviceId == InDeviceId) + { + // @todo: The SMALL channel controls frequency, the LARGE channel controls amplitude. This is a bit of a weird fit. + FOculusTouchControllerState& LeftControllerState = ControllerPair.TouchControllerStates[(int32)EControllerHand::Left]; + if (!LeftControllerState.bPlayingHapticEffect) + { + LeftControllerState.ForceFeedbackHapticFrequency = Values.LeftSmall; + LeftControllerState.ForceFeedbackHapticAmplitude = Values.LeftLarge; + UpdateForceFeedback(ControllerPair, EControllerHand::Left); + } + + FOculusTouchControllerState& RightControllerState = ControllerPair.TouchControllerStates[(int32)EControllerHand::Right]; + if (!RightControllerState.bPlayingHapticEffect) + { + RightControllerState.ForceFeedbackHapticFrequency = Values.RightSmall; + RightControllerState.ForceFeedbackHapticAmplitude = Values.RightLarge; + UpdateForceFeedback(ControllerPair, EControllerHand::Right); + } + } + } + } + + bool FOculusXRInput::SupportsForceFeedback(int32 ControllerId) + { + IPlatformInputDeviceMapper& DeviceMapper = IPlatformInputDeviceMapper::Get(); + FPlatformUserId InPlatformUser = FGenericPlatformMisc::GetPlatformUserForUserIndex(ControllerId); + FInputDeviceId InDeviceId = INPUTDEVICEID_NONE; + DeviceMapper.RemapControllerIdToPlatformUserAndDevice(ControllerId, InPlatformUser, InDeviceId); + + for (FOculusControllerPair& ControllerPair : ControllerPairs) + { + if (ControllerPair.DeviceId == InDeviceId) + { + const FOculusTouchControllerState& ControllerStateLeft = ControllerPair.TouchControllerStates[(int32)EControllerHand::Left]; + const FOculusTouchControllerState& ControllerStateRight = ControllerPair.TouchControllerStates[(int32)EControllerHand::Right]; + + if (!(ControllerStateLeft.bIsConnected || ControllerStateRight.bIsConnected)) + { + // neither hand connected, won't be receiving force feedback + continue; + } + + if (IOculusXRHMDModule::IsAvailable() && FOculusXRHMDModule::GetPluginWrapper().GetInitialized()) + { + // available so could receive feedback + return true; + } + } + } + + // not handling force feedback + return false; + } + + void FOculusXRInput::UpdateForceFeedback(const FOculusControllerPair& ControllerPair, const EControllerHand Hand) + { + const FOculusTouchControllerState& ControllerState = ControllerPair.TouchControllerStates[(int32)Hand]; + + if (ControllerState.bIsConnected && !ControllerState.bPlayingHapticEffect) + { + if (IOculusXRHMDModule::IsAvailable() && FOculusXRHMDModule::GetPluginWrapper().GetInitialized() && FApp::HasVRFocus()) + { + ovrpControllerState6 OvrpControllerState; + if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetControllerState6((ovrpController)(ovrpController_Active | ovrpController_LTrackedRemote | ovrpController_RTrackedRemote), &OvrpControllerState)) && (OvrpControllerState.ConnectedControllerTypes & (ovrpController_Touch | ovrpController_LTrackedRemote | ovrpController_RTrackedRemote))) + { + float FreqMin, FreqMax = 0.f; + GetHapticFrequencyRange(FreqMin, FreqMax); + + // Map the [0.0 - 1.0] range to a useful range of frequencies for the Oculus controllers + const float ActualFrequency = FMath::Lerp(FreqMin, FreqMax, FMath::Clamp(ControllerState.ForceFeedbackHapticFrequency, 0.0f, 1.0f)); + + // Oculus SDK wants amplitude values between 0.0 and 1.0 + const float ActualAmplitude = ControllerState.ForceFeedbackHapticAmplitude * GetHapticAmplitudeScale(); + + ovrpController OvrController = ovrpController_None; + if (OvrpControllerState.ConnectedControllerTypes & (ovrpController_Touch)) + { + OvrController = (Hand == EControllerHand::Left) ? ovrpController_LTouch : ovrpController_RTouch; + } + else if (OvrpControllerState.ConnectedControllerTypes & (ovrpController_LTrackedRemote | ovrpController_RTrackedRemote)) + { + OvrController = (Hand == EControllerHand::Left) ? ovrpController_LTrackedRemote : ovrpController_RTrackedRemote; + } + + static float LastAmplitudeSent = -1; + if (ActualAmplitude != LastAmplitudeSent) + { + ovrpHapticsLocation hapticsLocationMask = ovrpHapticsLocation::ovrpHapticsLocation_Hand; + FOculusXRHMDModule::GetPluginWrapper().SetControllerLocalizedVibration(OvrController, hapticsLocationMask, ActualFrequency, ActualAmplitude); + LastAmplitudeSent = ActualAmplitude; + } + } + } + } + } + + bool FOculusXRInput::OnControllerButtonPressed(const FOculusButtonState& ButtonState, FPlatformUserId UserId, FInputDeviceId DeviceId, bool IsRepeat) + { + bool result = MessageHandler->OnControllerButtonPressed(ButtonState.Key, UserId, DeviceId, IsRepeat); + + if (!ButtonState.EmulatedKey.IsNone()) + { + MessageHandler->OnControllerButtonPressed(ButtonState.EmulatedKey, UserId, DeviceId, IsRepeat); + } + + return result; + } + + bool FOculusXRInput::OnControllerButtonReleased(const FOculusButtonState& ButtonState, FPlatformUserId UserId, FInputDeviceId DeviceId, bool IsRepeat) + { + bool result = MessageHandler->OnControllerButtonReleased(ButtonState.Key, UserId, DeviceId, IsRepeat); + + if (!ButtonState.EmulatedKey.IsNone()) + { + MessageHandler->OnControllerButtonReleased(ButtonState.EmulatedKey, UserId, DeviceId, IsRepeat); + } + + return result; + } + + FName FOculusXRInput::GetMotionControllerDeviceTypeName() const + { + const static FName DefaultName(TEXT("OculusXRInputDevice")); + return DefaultName; + } + + // Supported motion sources + const TMap MotionSourceMap{ + { FName("Left"), ovrpNode_HandLeft }, + { FName("Right"), ovrpNode_HandRight }, + { FName("LeftGrip"), ovrpNode_HandLeft }, + { FName("RightGrip"), ovrpNode_HandRight }, + { FName("LeftAim"), ovrpNode_HandLeft }, + { FName("RightAim"), ovrpNode_HandRight }, + // Sometimes we can get an enum as the motion source name + { FName("EControllerHand::Left"), ovrpNode_HandLeft }, + { FName("EControllerHand::Right"), ovrpNode_HandRight } + }; + +#if UE_VERSION_OLDER_THAN(5, 3, 0) + bool FOculusXRInput::GetControllerOrientationAndPosition(const int32 ControllerIndex, const EControllerHand DeviceHand, FRotator& OutOrientation, FVector& OutPosition, float WorldToMetersScale) const + { + FName MotionSource; + switch (DeviceHand) + { + case EControllerHand::Left: + MotionSource = FName("Left"); + break; + case EControllerHand::Right: + MotionSource = FName("Right"); + break; + default: + MotionSource = FName("Unknown"); + break; + } + return GetControllerOrientationAndPosition(ControllerIndex, MotionSource, OutOrientation, OutPosition, WorldToMetersScale); + } + + ETrackingStatus FOculusXRInput::GetControllerTrackingStatus(const int32 ControllerIndex, const EControllerHand DeviceHand) const + { + ETrackingStatus TrackingStatus = ETrackingStatus::NotTracked; + + if (DeviceHand != EControllerHand::Left && DeviceHand != EControllerHand::Right) + { + return TrackingStatus; + } + + IPlatformInputDeviceMapper& DeviceMapper = IPlatformInputDeviceMapper::Get(); + FPlatformUserId InPlatformUser = FGenericPlatformMisc::GetPlatformUserForUserIndex(ControllerIndex); + FInputDeviceId InDeviceId = INPUTDEVICEID_NONE; + DeviceMapper.RemapControllerIdToPlatformUserAndDevice(ControllerIndex, InPlatformUser, InDeviceId); + + for (const FOculusControllerPair& ControllerPair : ControllerPairs) + { + if (ControllerPair.DeviceId == InDeviceId) + { + const FOculusTouchControllerState& ControllerState = ControllerPair.TouchControllerStates[(int32)DeviceHand]; + if (ControllerState.bIsConnected) + { + if (ControllerState.bIsPositionTracked && ControllerState.bIsOrientationTracked) + { + TrackingStatus = ETrackingStatus::Tracked; + } + else if (ControllerState.bIsPositionValid && ControllerState.bIsOrientationValid) + { + TrackingStatus = ETrackingStatus::InertialOnly; + } + + break; + } + + const FOculusHandControllerState& HandState = ControllerPair.HandControllerStates[(int32)DeviceHand]; + if (HandState.bIsConnected) + { + if (HandState.bIsPositionTracked && HandState.bIsOrientationTracked) + { + TrackingStatus = ETrackingStatus::Tracked; + } + + break; + } + } + } + + return TrackingStatus; + } +#endif + + bool FOculusXRInput::GetControllerOrientationAndPosition(const int32 ControllerIndex, const FName MotionSource, FRotator& OutOrientation, FVector& OutPosition, float WorldToMetersScale) const + { + IPlatformInputDeviceMapper& DeviceMapper = IPlatformInputDeviceMapper::Get(); + FPlatformUserId InPlatformUser = FGenericPlatformMisc::GetPlatformUserForUserIndex(ControllerIndex); + FInputDeviceId InDeviceId = INPUTDEVICEID_NONE; + DeviceMapper.RemapControllerIdToPlatformUserAndDevice(ControllerIndex, InPlatformUser, InDeviceId); + + // Don't do renderthread pose update if MRC is active due to controller jitter issues with SceneCaptures + if (IsInGameThread() || !UOculusXRMRFunctionLibrary::IsMrcActive()) + { + for (const FOculusControllerPair& ControllerPair : ControllerPairs) + { + if (ControllerPair.DeviceId == InDeviceId) + { + if (MotionSourceMap.Contains(MotionSource)) + { + if (IOculusXRHMDModule::IsAvailable() && FOculusXRHMDModule::GetPluginWrapper().GetInitialized()) + { + OculusXRHMD::FOculusXRHMD* OculusXRHMD = static_cast(GEngine->XRSystem->GetHMDDevice()); + ovrpNode Node = MotionSourceMap[MotionSource]; + + ovrpBool bResult = true; + bool bIsPositionValid = OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetNodePositionValid(Node, &bResult)) && bResult; + bool bIsOrientationValid = OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetNodeOrientationValid(Node, &bResult)) && bResult; + + if (bIsPositionValid || bIsOrientationValid) + { + OculusXRHMD::FSettings* Settings; + OculusXRHMD::FGameFrame* CurrentFrame; + + if (IsInGameThread()) + { + Settings = OculusXRHMD->GetSettings(); + CurrentFrame = OculusXRHMD->GetNextFrameToRender(); + } + else + { + Settings = OculusXRHMD->GetSettings_RenderThread(); + CurrentFrame = OculusXRHMD->GetFrame_RenderThread(); + } + + if (Settings) + { + ovrpPoseStatef InPoseState; + OculusXRHMD::FPose OutPose; + + EOculusXRControllerPoseAlignment ControllerPoseAlignment = Settings->ControllerPoseAlignment; + switch (CVarOculusControllerPose.GetValueOnAnyThread()) + { + case 1: + ControllerPoseAlignment = EOculusXRControllerPoseAlignment::Default; + break; + case 2: + ControllerPoseAlignment = EOculusXRControllerPoseAlignment::Grip; + break; + case 3: + ControllerPoseAlignment = EOculusXRControllerPoseAlignment::Aim; + break; + default: + break; + } + + if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetNodePoseState3(ovrpStep_Render, CurrentFrame ? CurrentFrame->FrameNumber : OVRP_CURRENT_FRAMEINDEX, Node, &InPoseState)) && OculusXRHMD->ConvertPose_Internal(InPoseState.Pose, OutPose, Settings, WorldToMetersScale)) + { + FName FinalMotionSource = MotionSource; + FString MotionSourceStr = MotionSource.ToString(); + + // Converting controller hand enum to motion source can leave behind the enum name in the resulting motion source, so just remove that before handling it + MotionSourceStr.RemoveFromStart("EControllerHand::"); + + if (MotionSourceStr.Equals("Left") || MotionSourceStr.Equals("Right")) + { + switch (ControllerPoseAlignment) + { + case EOculusXRControllerPoseAlignment::Grip: + FinalMotionSource = FName(MotionSourceStr.Append(FString("Grip"))); + break; + case EOculusXRControllerPoseAlignment::Aim: + FinalMotionSource = FName(MotionSourceStr.Append(FString("Aim"))); + break; + case EOculusXRControllerPoseAlignment::Default: + default: + break; + } + } + + // TODO: Just pass the pose info to OVRPlugin instead of doing the conversion between poses here + if (FinalMotionSource == FName("LeftGrip") || FinalMotionSource == FName("RightGrip")) + { + OutPose = OutPose * OculusXRHMD::FPose(FQuat(FVector(0, 1, 0), -FMath::DegreesToRadians(double(60))), FVector(-0.04, 0, -0.03) * WorldToMetersScale); + } + else if (FinalMotionSource == FName("LeftAim") || FinalMotionSource == FName("RightAim")) + { + OutPose = OutPose * OculusXRHMD::FPose(FQuat::Identity, FVector(0.055, 0, 0) * WorldToMetersScale); + } + + if (bIsPositionValid) + { + OutPosition = OutPose.Position; + } + + if (bIsOrientationValid) + { + OutOrientation = OutPose.Orientation.Rotator(); + } + + // Avoid any broadcasting in other threads than the game thread because that is undefined behavior + if (IsInGameThread()) + { + auto bSuccess = true; + EControllerHand ControllerHand; + if (GetHandEnumForSourceName(MotionSource, ControllerHand)) + { + // TODO: Just use the motion source name here instead of the legacy enum + UOculusXRInputFunctionLibrary::HandMovementFilter.Broadcast( + ControllerHand, + &OutPosition, + &OutOrientation, + &bSuccess); + } + return bSuccess; + } + + return true; + } + } + } + } + } + + break; + } + } + } + + // Avoid any broadcasting in other threads than the game thread because that is undefined behavior + auto bSuccess = false; + if (IsInGameThread()) + { + EControllerHand ControllerHand; + if (GetHandEnumForSourceName(MotionSource, ControllerHand)) + { + // TODO: Just use the motion source name here instead of the legacy enum + UOculusXRInputFunctionLibrary::HandMovementFilter.Broadcast( + ControllerHand, + &OutPosition, + &OutOrientation, + &bSuccess); + } + } + return bSuccess; + } + + ETrackingStatus FOculusXRInput::GetControllerTrackingStatus(const int32 ControllerIndex, const FName MotionSource) const + { + ETrackingStatus TrackingStatus = ETrackingStatus::NotTracked; + + bool IsLeftHand = MotionSource == FName("Left") || MotionSource == FName("EControllerHand::Left") || MotionSource == FName("LeftGrip") || MotionSource == FName("LeftAim"); + bool IsRightHand = MotionSource == FName("Right") || MotionSource == FName("EControllerHand::Right") || MotionSource == FName("RightGrip") || MotionSource == FName("RightAim"); + + if (!IsLeftHand && !IsRightHand) + { + return TrackingStatus; + } + + IPlatformInputDeviceMapper& DeviceMapper = IPlatformInputDeviceMapper::Get(); + FPlatformUserId InPlatformUser = FGenericPlatformMisc::GetPlatformUserForUserIndex(ControllerIndex); + FInputDeviceId InDeviceId = INPUTDEVICEID_NONE; + DeviceMapper.RemapControllerIdToPlatformUserAndDevice(ControllerIndex, InPlatformUser, InDeviceId); + + for (const FOculusControllerPair& ControllerPair : ControllerPairs) + { + if (ControllerPair.DeviceId == InDeviceId) + { + const FOculusTouchControllerState& ControllerState = ControllerPair.TouchControllerStates[IsLeftHand ? 0 : 1]; + if (ControllerState.bIsConnected) + { + if (ControllerState.bIsPositionTracked && ControllerState.bIsOrientationTracked) + { + TrackingStatus = ETrackingStatus::Tracked; + } + else if (ControllerState.bIsPositionValid && ControllerState.bIsOrientationValid) + { + TrackingStatus = ETrackingStatus::InertialOnly; + } + + break; + } + + const FOculusHandControllerState& HandState = ControllerPair.HandControllerStates[IsLeftHand ? 0 : 1]; + if (HandState.bIsConnected) + { + if (HandState.bIsPositionTracked && HandState.bIsOrientationTracked) + { + TrackingStatus = ETrackingStatus::Tracked; + } + + break; + } + } + } + + return TrackingStatus; + } + + void FOculusXRInput::SetHapticFeedbackValues(int32 ControllerId, int32 Hand, const FHapticFeedbackValues& Values) + { + SetHapticFeedbackValues(ControllerId, Hand, Values, nullptr); + } + + void FOculusXRInput::SetHapticFeedbackValues(int32 ControllerId, int32 Hand, const FHapticFeedbackValues& Values, TSharedPtr HapticsDesc) + { + IPlatformInputDeviceMapper& DeviceMapper = IPlatformInputDeviceMapper::Get(); + FPlatformUserId InPlatformUser = FGenericPlatformMisc::GetPlatformUserForUserIndex(ControllerId); + FInputDeviceId InDeviceId = INPUTDEVICEID_NONE; + DeviceMapper.RemapControllerIdToPlatformUserAndDevice(ControllerId, InPlatformUser, InDeviceId); + + for (FOculusControllerPair& ControllerPair : ControllerPairs) + { + if (ControllerPair.DeviceId == InDeviceId) + { + FOculusTouchControllerState& ControllerState = ControllerPair.TouchControllerStates[Hand]; + if (ControllerState.bIsConnected) + { + if (IOculusXRHMDModule::IsAvailable() && FOculusXRHMDModule::GetPluginWrapper().GetInitialized() && FApp::HasVRFocus()) + { + ovrpController ControllerTypes = (ovrpController)(ovrpController_Active | ovrpController_LTrackedRemote | ovrpController_RTrackedRemote); +#ifdef USE_ANDROID_INPUT + ControllerTypes = (ovrpController)(ControllerTypes | ovrpController_Touch); +#endif + ovrpControllerState6 OvrpControllerState; + if (OVRP_FAILURE(FOculusXRHMDModule::GetPluginWrapper().GetControllerState6(ControllerTypes, &OvrpControllerState))) + { + UE_LOG(LogOcInput, Error, TEXT("GetControllerState6 failed.")); + return; + } + if (OvrpControllerState.ConnectedControllerTypes & (ovrpController_Touch | ovrpController_LTrackedRemote | ovrpController_RTrackedRemote)) + { + // Buffered haptics is currently only supported on Touch + FHapticFeedbackBuffer* HapticBuffer = Values.HapticBuffer; + bool bHapticBuffer = (HapticBuffer && HapticBuffer->BufferLength > 0); + if ((OvrpControllerState.ConnectedControllerTypes & (ovrpController_Touch)) && bHapticBuffer) + { + const ovrpController OvrpController = (EControllerHand(Hand) == EControllerHand::Left) ? ovrpController_LTouch : ovrpController_RTouch; + ovrpHapticsState OvrpHapticsState; + if (OVRP_FAILURE(FOculusXRHMDModule::GetPluginWrapper().GetControllerHapticsState2(OvrpController, &OvrpHapticsState))) + { + UE_LOG(LogOcInput, Error, TEXT("ControllerHapticsState2 failed.")); + return; + } + double StartTimePCM = FPlatformTime::Seconds(); + float TimeToSend = GetMaxHapticDuration(EControllerHand(Hand)); + int WantToSend = (int)(TimeToSend * HapticBuffer->SamplingRate); + if (WantToSend == 0) + return; + WantToSend = FMath::Min(WantToSend, OvrpHapticsDesc.MaximumBufferSamplesCount); + WantToSend = FMath::Max(WantToSend, OvrpHapticsDesc.MinimumBufferSamplesCount); + + ovrpUInt32 SamplesSent = 0; + if (OvrpHapticsState.SamplesQueued < OvrpHapticsDesc.MinimumSafeSamplesQueued + WantToSend) //trying to minimize latency + { + WantToSend = (OvrpHapticsDesc.MinimumSafeSamplesQueued + WantToSend - OvrpHapticsState.SamplesQueued); + void* BufferToFree = nullptr; + ovrpHapticsBuffer OvrpHapticsBuffer; + WantToSend = FMath::Min(WantToSend, HapticBuffer->BufferLength - HapticBuffer->SamplesSent); + WantToSend = FMath::Min(WantToSend, (int)(0.001f * CVarOculusPCMBatchDuration.GetValueOnAnyThread() * HapticBuffer->SamplingRate)); + TimeToSend = 1.f * WantToSend / HapticBuffer->SamplingRate; + OvrpHapticsBuffer.SamplesCount = WantToSend; + if (OvrpHapticsBuffer.SamplesCount == 0 && OvrpHapticsState.SamplesQueued == 0) + { + Values.HapticBuffer->bFinishedPlaying = HapticBuffer->bFinishedPlaying = true; + + ControllerState.bPlayingHapticEffect = false; + } + else + { + if (OvrpHapticsDesc.SampleSizeInBytes == 1) + { + uint8* Samples = (uint8*)FMemory::Malloc(OvrpHapticsBuffer.SamplesCount * sizeof(*Samples)); + for (int i = 0; i < OvrpHapticsBuffer.SamplesCount; i++) + { + Samples[i] = static_cast(HapticBuffer->RawData[HapticBuffer->CurrentPtr + i] * HapticBuffer->ScaleFactor); + } + OvrpHapticsBuffer.Samples = BufferToFree = Samples; + } + else if (OvrpHapticsDesc.SampleSizeInBytes == 2) + { + uint16* Samples = (uint16*)FMemory::Malloc(OvrpHapticsBuffer.SamplesCount * sizeof(*Samples)); + for (int i = 0; i < OvrpHapticsBuffer.SamplesCount; i++) + { + const uint32 DataIndex = HapticBuffer->CurrentPtr + (i * 2); + const uint16* const RawData = reinterpret_cast(&HapticBuffer->RawData[DataIndex]); + Samples[i] = static_cast(*RawData * HapticBuffer->ScaleFactor); + } + OvrpHapticsBuffer.Samples = BufferToFree = Samples; + } + else if (OvrpHapticsDesc.SampleSizeInBytes == 4) + { + uint32* Samples = (uint32*)FMemory::Malloc(OvrpHapticsBuffer.SamplesCount * sizeof(*Samples)); + for (int i = 0; i < OvrpHapticsBuffer.SamplesCount; i++) + { + const uint32 DataIndex = HapticBuffer->CurrentPtr + (i * 4); + const uint32* const RawData = reinterpret_cast(&HapticBuffer->RawData[DataIndex]); + Samples[i] = static_cast(*RawData * HapticBuffer->ScaleFactor); + } + OvrpHapticsBuffer.Samples = BufferToFree = Samples; + } + else + { + UE_LOG(LogOcInput, Error, TEXT("Unsupported OvrpHapticsDesc.SampleSizeInBytes: %d."), OvrpHapticsDesc.SampleSizeInBytes); + return; + } + + ovrpHapticsPcmVibration HapticsVibration; + bool bAppend = HapticsDesc ? HapticsDesc->bAppend : false; + HapticsVibration.Append = (bAppend || HapticBuffer->SamplesSent > 0); + float* PCMBuffer = (float*)FMemory::Malloc(OvrpHapticsBuffer.SamplesCount * sizeof(*PCMBuffer)); + for (int i = 0; i < OvrpHapticsBuffer.SamplesCount; i++) + { + float Amplitude = ((uint8_t*)OvrpHapticsBuffer.Samples)[i] / 255.0f; + Amplitude = FMath::Min(1.0f, Amplitude); + Amplitude = FMath::Max(-1.0f, Amplitude); + PCMBuffer[i] = Amplitude; + } + HapticsVibration.Buffer = PCMBuffer; + HapticsVibration.BufferSize = (ovrpUInt32)OvrpHapticsBuffer.SamplesCount; + HapticsVibration.SampleRateHz = HapticBuffer->SamplingRate; + HapticsVibration.SamplesConsumed = &SamplesSent; + FOculusXRHMDModule::GetPluginWrapper().SetControllerHapticsPcm( + OvrpController, + HapticsVibration); + double EndTimePCM = FPlatformTime::Seconds(); + if (PCMBuffer) + { + FMemory::Free(PCMBuffer); + } + UE_CLOG(OVR_HAP_LOGGING, LogOcInput, Log, TEXT("PCMHaptics is finished: bAppend: %d, BufferSize: %d, SampleRate: %.3f, SamplesConsumed: %d, Total SamplesSent: %d, TimeSpent: %fms"), + (int)(HapticsVibration.Append), + HapticsVibration.BufferSize, + HapticsVibration.SampleRateHz, + SamplesSent, + HapticBuffer->SamplesSent + SamplesSent, + (EndTimePCM - StartTimePCM) * 1000.0); + + if (BufferToFree) + { + FMemory::Free(BufferToFree); + } + + HapticBuffer->CurrentPtr += (SamplesSent * OvrpHapticsDesc.SampleSizeInBytes); + HapticBuffer->SamplesSent += SamplesSent; + + ControllerState.bPlayingHapticEffect = true; + } + } + } + else + { + float FreqMin, FreqMax = 0.f; + GetHapticFrequencyRange(FreqMin, FreqMax); + + const float InitialFreq = (Values.Frequency > 0.0f) ? Values.Frequency : 1.0f; + const float Frequency = FMath::Lerp(FreqMin, FreqMax, FMath::Clamp(InitialFreq, 0.f, 1.f)); + + const float Amplitude = Values.Amplitude * GetHapticAmplitudeScale(); + + if (ControllerState.HapticAmplitude != Amplitude || ControllerState.HapticFrequency != Frequency) + { + ControllerState.HapticAmplitude = Amplitude; + ControllerState.HapticFrequency = Frequency; + + ovrpController OvrController = ovrpController_None; + if (OvrpControllerState.ConnectedControllerTypes & (ovrpController_Touch)) + { + OvrController = (EControllerHand(Hand) == EControllerHand::Left) ? ovrpController_LTouch : ovrpController_RTouch; + } + else if (OvrpControllerState.ConnectedControllerTypes & (ovrpController_LTrackedRemote | ovrpController_RTrackedRemote)) + { + OvrController = (EControllerHand(Hand) == EControllerHand::Left) ? ovrpController_LTrackedRemote : ovrpController_RTrackedRemote; + } + + ovrpHapticsLocation Loc = (HapticsDesc ? GetOVRPHapticsLocation(HapticsDesc->Location) : ovrpHapticsLocation::ovrpHapticsLocation_Hand); + FOculusXRHMDModule::GetPluginWrapper().SetControllerLocalizedVibration(OvrController, + Loc, + Frequency, + Amplitude); + UE_CLOG(OVR_HAP_LOGGING, LogOcInput, Log, TEXT("LocalizedVibration is finished: Location: %d, Frequency: %f, Amplitude: %f"), (int)(Loc), Frequency, Amplitude); + + ControllerState.bPlayingHapticEffect = (Amplitude != 0.f) && (Frequency != 0.f); + } + } + } + } + } + + break; + } + } + } + + void FOculusXRInput::PlayHapticEffect( + UHapticFeedbackEffect_Base* HapticEffect, + EControllerHand Hand, + EOculusXRHandHapticsLocation Location, + bool bAppend, + float Scale, + bool bLoop) + { + if (HapticEffect) + { + switch (Hand) + { + case EControllerHand::Left: + ActiveHapticEffect_Left.Reset(); + HapticsDesc_Left.Reset(); + ActiveHapticEffect_Left = MakeShareable(new FActiveHapticFeedbackEffect(HapticEffect, Scale, bLoop)); + HapticsDesc_Left = MakeShareable(new FOculusXRHapticsDesc(Location, bAppend)); + break; + case EControllerHand::Right: + ActiveHapticEffect_Right.Reset(); + HapticsDesc_Right.Reset(); + ActiveHapticEffect_Right = MakeShareable(new FActiveHapticFeedbackEffect(HapticEffect, Scale, bLoop)); + HapticsDesc_Right = MakeShareable(new FOculusXRHapticsDesc(Location, bAppend)); + break; + default: + UE_LOG(LogOcInput, Warning, TEXT("Invalid hand specified (%d) for haptic feedback effect %s"), (int32)Hand, *HapticEffect->GetName()); + break; + } + } + } + + int FOculusXRInput::PlayHapticEffect(EControllerHand Hand, int SamplesCount, void* Samples, int InSampleRate, bool bPCM, bool bAppend) + { + int TimeToSend = GetMaxHapticDuration(Hand); + if (TimeToSend == 0) + return 0; + + const ovrpController OvrpController = (EControllerHand(Hand) == EControllerHand::Left) ? ovrpController_LTouch : ovrpController_RTouch; + int SampleRate = (InSampleRate > 0 ? InSampleRate : OvrpHapticsDesc.SampleRateHz); + int MaxSamplesCount = TimeToSend * SampleRate; + if (SamplesCount > MaxSamplesCount || SamplesCount < OvrpHapticsDesc.MinimumBufferSamplesCount) + { + UE_LOG(LogOcInput, Error, TEXT("Sample count should be between %d and %d which last %d time."), + OvrpHapticsDesc.MinimumBufferSamplesCount, MaxSamplesCount, TimeToSend); + } + int WantToSend = FMath::Min(SamplesCount, MaxSamplesCount); + WantToSend = FMath::Max(WantToSend, OvrpHapticsDesc.MinimumBufferSamplesCount); + + float* BufferToSend = (float*)FMemory::Malloc(WantToSend * sizeof(*BufferToSend)); + for (int i = 0; i < WantToSend; i++) + { + float Amplitude = ((uint8_t*)Samples)[i] / 255.0f; + Amplitude = FMath::Min(1.0f, Amplitude); + Amplitude = FMath::Max((bPCM ? -1.f : 0.0f), Amplitude); + BufferToSend[i] = Amplitude; + UE_CLOG(OVR_HAP_LOGGING, LogOcInput, Log, TEXT("amplitude, %.3f"), Amplitude); + } + + ovrpUInt32 SamplesSent = 0; + if (bPCM) + { //PCM + ovrpHapticsPcmVibration HapticsVibration; + HapticsVibration.Buffer = BufferToSend; + HapticsVibration.BufferSize = (ovrpUInt32)WantToSend; + HapticsVibration.SampleRateHz = SampleRate; + HapticsVibration.SamplesConsumed = &SamplesSent; + FOculusXRHMDModule::GetPluginWrapper().SetControllerHapticsPcm( + OvrpController, + HapticsVibration); + UE_CLOG(OVR_HAP_LOGGING, LogOcInput, Log, TEXT("PCMHaptics is finished: bAppend: %d, BufferSize: %d, SampleRate: %.3f, SamplesConsumed: %d"), + (int)(HapticsVibration.Append), + HapticsVibration.BufferSize, + HapticsVibration.SampleRateHz, + SamplesSent); + } + else + { //HAE + ovrpHapticsAmplitudeEnvelopeVibration HapticsVibration; + HapticsVibration.Duration = WantToSend / SampleRate; + HapticsVibration.AmplitudeCount = WantToSend; + HapticsVibration.Amplitudes = BufferToSend; + + FOculusXRHMDModule::GetPluginWrapper().SetControllerHapticsAmplitudeEnvelope( + OvrpController, + HapticsVibration); + UE_CLOG(OVR_HAP_LOGGING, LogOcInput, Log, TEXT("HAEHaptics is finished: AmplitudeCount: %d, SampleRate: %d"), + HapticsVibration.AmplitudeCount, + SampleRate); + } + if (BufferToSend) + { + FMemory::Free(BufferToSend); + } + return (int)SamplesSent; + } + + void FOculusXRInput::SetHapticsByValue(float Frequency, float Amplitude, EControllerHand Hand, EOculusXRHandHapticsLocation Location) + { + const ovrpController OvrpController = (EControllerHand(Hand) == EControllerHand::Left) ? ovrpController_LTouch : ovrpController_RTouch; + FOculusXRHMDModule::GetPluginWrapper().SetControllerLocalizedVibration(OvrpController, GetOVRPHapticsLocation(Location), Frequency, Amplitude); + UE_CLOG(OVR_HAP_LOGGING, LogOcInput, Log, TEXT("LocalizedVibration is finished: Location: %d, Frequency: %f, Amplitude: %f"), (int)(Location), Frequency, Amplitude); + } + + void FOculusXRInput::ProcessHaptics(const float DeltaTime) + { + FHapticFeedbackValues LeftHaptics, RightHaptics; + bool bLeftHapticsNeedUpdate = false; + bool bRightHapticsNeedUpdate = false; + + if (ActiveHapticEffect_Left.IsValid()) + { + const bool bPlaying = ActiveHapticEffect_Left->Update(DeltaTime, LeftHaptics); + if (!bPlaying) + { + ActiveHapticEffect_Left->bLoop ? HapticsDesc_Left->Restart() : HapticsDesc_Left.Reset(); + ActiveHapticEffect_Left->bLoop ? ActiveHapticEffect_Left->Restart() : ActiveHapticEffect_Left.Reset(); + } + + bLeftHapticsNeedUpdate = true; + } + + if (ActiveHapticEffect_Right.IsValid()) + { + const bool bPlaying = ActiveHapticEffect_Right->Update(DeltaTime, RightHaptics); + if (!bPlaying) + { + ActiveHapticEffect_Right->bLoop ? HapticsDesc_Right->Restart() : HapticsDesc_Right.Reset(); + ActiveHapticEffect_Right->bLoop ? ActiveHapticEffect_Right->Restart() : ActiveHapticEffect_Right.Reset(); + } + + bRightHapticsNeedUpdate = true; + } + + // Haptic Updates + if (bLeftHapticsNeedUpdate) + { + SetHapticFeedbackValues(0, (int32)(EControllerHand::Left), LeftHaptics, HapticsDesc_Left); + } + if (bRightHapticsNeedUpdate) + { + SetHapticFeedbackValues(0, (int32)(EControllerHand::Right), RightHaptics, HapticsDesc_Right); + } + } + + void FOculusTouchControllerState::ResampleHapticBufferData(const FHapticFeedbackBuffer& HapticBuffer, TMap>>& ResampledRawDataCache) + { + const uint8* OriginalRawData = HapticBuffer.RawData; + TSharedPtr>* ResampledRawDataSharedPtrPtr = ResampledRawDataCache.Find(OriginalRawData); + if (ResampledRawDataSharedPtrPtr == nullptr) + { + // We need to resample and cache the resampled data. + + ResampledHapticBuffer = HapticBuffer; + + int32 SampleRate = HapticBuffer.SamplingRate; + int TargetFrequency = 320; + int TargetBufferSize = (HapticBuffer.BufferLength * TargetFrequency) / (SampleRate * 2) + 1; //2 because we're only using half of the 16bit source PCM buffer + ResampledHapticBuffer.BufferLength = TargetBufferSize; + ResampledHapticBuffer.CurrentPtr = 0; + ResampledHapticBuffer.SamplingRate = TargetFrequency; + + TSharedPtr>& NewResampledRawDataSharedPtr = ResampledRawDataCache.Add(OriginalRawData); + NewResampledRawDataSharedPtr = MakeShared>(); + ResampledRawDataSharedPtrPtr = &NewResampledRawDataSharedPtr; + TArray& ResampledRawData = *NewResampledRawDataSharedPtr; + ResampledRawData.SetNum(TargetBufferSize); + + const uint8* PCMData = HapticBuffer.RawData; + + int previousTargetIndex = -1; + int currentMin = 0; + for (int i = 1; i < HapticBuffer.BufferLength; i += 2) + { + int targetIndex = i * TargetFrequency / (SampleRate * 2); + int val = PCMData[i]; + if (val & 0x80) + { + val = ~val; + } + currentMin = FMath::Min(currentMin, val); + + if (targetIndex != previousTargetIndex) + { + + ResampledRawData[targetIndex] = val * 2; // *Scale; + previousTargetIndex = targetIndex; + currentMin = 0; + } + } + + ResampledHapticBuffer.RawData = ResampledRawData.GetData(); + } + else if (ResampledHapticBuffer.RawData != (*ResampledRawDataSharedPtrPtr)->GetData()) + { + // If this a cached effect, but not the same one we played last so we need to copy the new one's buffer and reference its cached resampled data. + ResampledHapticBuffer = HapticBuffer; + ResampledHapticBuffer.RawData = (*ResampledRawDataSharedPtrPtr)->GetData(); + } + } + + void FOculusXRInput::GetHapticFrequencyRange(float& MinFrequency, float& MaxFrequency) const + { + MinFrequency = 0.f; + MaxFrequency = 1.f; + } + + float FOculusXRInput::GetHapticAmplitudeScale() const + { + return 1.f; + } + + uint32 FOculusXRInput::GetNumberOfTouchControllers() const + { + uint32 RetVal = 0; + + for (FOculusControllerPair Pair : ControllerPairs) + { + RetVal += (Pair.TouchControllerStates[0].bIsConnected ? 1 : 0); + RetVal += (Pair.TouchControllerStates[1].bIsConnected ? 1 : 0); + } + + return RetVal; + } + + uint32 FOculusXRInput::GetNumberOfHandControllers() const + { + uint32 RetVal = 0; + + for (FOculusControllerPair Pair : ControllerPairs) + { + RetVal += (Pair.HandControllerStates[0].bIsConnected ? 1 : 0); + RetVal += (Pair.HandControllerStates[1].bIsConnected ? 1 : 0); + } + + return RetVal; + } + + ovrpHapticsLocation FOculusXRInput::GetOVRPHapticsLocation(EOculusXRHandHapticsLocation Location) + { + switch (Location) + { + case EOculusXRHandHapticsLocation::Hand: + return ovrpHapticsLocation::ovrpHapticsLocation_Hand; + case EOculusXRHandHapticsLocation::Thumb: + return ovrpHapticsLocation::ovrpHapticsLocation_Thumb; + case EOculusXRHandHapticsLocation::Index: + return ovrpHapticsLocation::ovrpHapticsLocation_Index; + default: + UE_LOG(LogOcInput, Error, TEXT("Unsupported Haptics Location: %d"), Location); + return ovrpHapticsLocation::ovrpHapticsLocation_None; + } + } + + bool FOculusXRInput::GetOvrpHapticsDesc(int Hand) + { + if (!bPulledHapticsDesc) + { + const ovrpController OvrpController = (EControllerHand(Hand) == EControllerHand::Left) ? ovrpController_LTouch : ovrpController_RTouch; + // Buffered haptics is currently only supported on Touch + if (OVRP_FAILURE(FOculusXRHMDModule::GetPluginWrapper().GetControllerHapticsDesc2(OvrpController, &OvrpHapticsDesc))) + { + UE_LOG(LogOcInput, Error, TEXT("ControllerHapticsDesc2 failed.")); + return false; + } + bPulledHapticsDesc = true; + if (OvrpHapticsDesc.SampleRateHz == 0) + { + UE_LOG(LogOcInput, Error, TEXT("GetControllerHapticsDesc2 returns OvrpHapticsDesc.SampleRateHz = %d"), OvrpHapticsDesc.SampleRateHz); + OvrpHapticsDesc.SampleRateHz = 2000; + return true; + } + else + { + UE_CLOG(OVR_HAP_LOGGING, LogOcInput, Log, TEXT("GetControllerHapticsDesc2 returns OvrpHapticsDesc.SampleRateHz = %d"), OvrpHapticsDesc.SampleRateHz); + } + } + return true; + } + + float FOculusXRInput::GetControllerSampleRateHz(EControllerHand Hand) + { + float sampleRateHz = 0.f; + const ovrpController OvrpController = (EControllerHand(Hand) == EControllerHand::Left) ? ovrpController_LTouch : ovrpController_RTouch; + if (OVRP_FAILURE(FOculusXRHMDModule::GetPluginWrapper().GetControllerSampleRateHz(OvrpController, &sampleRateHz))) + { + UE_LOG(LogOcInput, Error, TEXT("GetControllerSampleRateHz failed.")); + } + return sampleRateHz; + } + + int FOculusXRInput::GetMaxHapticDuration(EControllerHand Hand) + { + const ovrpController OvrpController = (EControllerHand(Hand) == EControllerHand::Left) ? ovrpController_LTouch : ovrpController_RTouch; + if (!GetOvrpHapticsDesc((int32)Hand)) + return 0; + + return OvrpHapticsDesc.MaximumBufferSamplesCount / OvrpHapticsDesc.SampleRateHz; + } +} // namespace OculusXRInput + +#undef LOCTEXT_NAMESPACE +#endif // OCULUS_INPUT_SUPPORTED_PLATFORMS diff --git a/Plugins/MetaXR/Source/OculusXRInput/Private/OculusXRInput.h b/Plugins/MetaXR/Source/OculusXRInput/Private/OculusXRInput.h new file mode 100644 index 0000000..5999df1 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRInput/Private/OculusXRInput.h @@ -0,0 +1,145 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +#pragma once +#include "IOculusXRInputModule.h" + +#if OCULUS_INPUT_SUPPORTED_PLATFORMS +#include "OculusXRHMDModule.h" +#include "GenericPlatform/IInputInterface.h" +#include "XRMotionControllerBase.h" +#include "IHapticDevice.h" +#include "OculusXRInputState.h" + +#if PLATFORM_SUPPORTS_PRAGMA_PACK +#pragma pack(push, 8) +#endif + +#include "OculusXRPluginWrapper.h" + +#if PLATFORM_SUPPORTS_PRAGMA_PACK +#pragma pack(pop) +#endif + +DEFINE_LOG_CATEGORY_STATIC(LogOcInput, Log, All); + +class UHapticFeedbackEffect_Base; +struct FActiveHapticFeedbackEffect; +struct FOculusXRHapticsDesc; + +namespace OculusXRInput +{ + + //------------------------------------------------------------------------------------------------- + // FOculusXRInput + //------------------------------------------------------------------------------------------------- + + class FOculusXRInput : public IInputDevice, public FXRMotionControllerBase, public IHapticDevice + { + friend class FOculusHandTracking; + + public: + /** Constructor that takes an initial message handler that will receive motion controller events */ + FOculusXRInput(const TSharedRef& InMessageHandler); + + /** Clean everything up */ + virtual ~FOculusXRInput(); + + static void PreInit(); + + /** Loads any settings from the config folder that we need */ + static void LoadConfig(); + + // IInputDevice overrides + virtual void Tick(float DeltaTime) override; + virtual void SendControllerEvents() override; + virtual void SetMessageHandler(const TSharedRef& InMessageHandler) override; + virtual bool Exec(UWorld* InWorld, const TCHAR* Cmd, FOutputDevice& Ar) override; + virtual void SetChannelValue(int32 ControllerId, FForceFeedbackChannelType ChannelType, float Value) override; + virtual void SetChannelValues(int32 ControllerId, const FForceFeedbackValues& Values) override; + virtual bool SupportsForceFeedback(int32 ControllerId) override; + + // IMotionController overrides + virtual FName GetMotionControllerDeviceTypeName() const override; +#if UE_VERSION_OLDER_THAN(5, 3, 0) + virtual bool GetControllerOrientationAndPosition(const int32 ControllerIndex, const EControllerHand DeviceHand, FRotator& OutOrientation, FVector& OutPosition, float WorldToMetersScale) const override; + virtual ETrackingStatus GetControllerTrackingStatus(const int32 ControllerIndex, const EControllerHand DeviceHand) const override; +#endif + virtual bool GetControllerOrientationAndPosition(const int32 ControllerIndex, const FName MotionSource, FRotator& OutOrientation, FVector& OutPosition, float WorldToMetersScale) const override; + virtual ETrackingStatus GetControllerTrackingStatus(const int32 ControllerIndex, const FName MotionSource) const override; + + // IHapticDevice overrides + IHapticDevice* GetHapticDevice() override { return (IHapticDevice*)this; } + virtual void SetHapticFeedbackValues(int32 ControllerId, int32 Hand, const FHapticFeedbackValues& Values) override; + + void PlayHapticEffect( + UHapticFeedbackEffect_Base* HapticEffect, + EControllerHand Hand, + EOculusXRHandHapticsLocation Location = EOculusXRHandHapticsLocation::Hand, + bool bAppend = false, + float Scale = 1.f, + bool bLoop = false); + int PlayHapticEffect(EControllerHand Hand, int SamplesCount, void* Samples, int SampleRate = -1, bool bPCM = false, bool bAppend = false); + void SetHapticsByValue(float Frequency, float Amplitude, EControllerHand Hand, EOculusXRHandHapticsLocation Location = EOculusXRHandHapticsLocation::Hand); + + virtual void GetHapticFrequencyRange(float& MinFrequency, float& MaxFrequency) const override; + virtual float GetHapticAmplitudeScale() const override; + + uint32 GetNumberOfTouchControllers() const; + uint32 GetNumberOfHandControllers() const; + + float GetControllerSampleRateHz(EControllerHand Hand); + int GetMaxHapticDuration(EControllerHand Hand); + + private: + /** Applies force feedback settings to the controller */ + void UpdateForceFeedback(const FOculusControllerPair& ControllerPair, const EControllerHand Hand); + + bool OnControllerButtonPressed(const FOculusButtonState& ButtonState, FPlatformUserId UserId, FInputDeviceId DeviceId, bool IsRepeat); + bool OnControllerButtonReleased(const FOculusButtonState& ButtonState, FPlatformUserId UserId, FInputDeviceId DeviceId, bool IsRepeat); + + void SetHapticFeedbackValues(int32 ControllerId, int32 Hand, const FHapticFeedbackValues& Values, TSharedPtr HapticsDesc); + ovrpHapticsLocation GetOVRPHapticsLocation(EOculusXRHandHapticsLocation InLocation); + + void ProcessHaptics(const float DeltaTime); + bool GetOvrpHapticsDesc(int Hand); + + private: + /** The recipient of motion controller input events */ + TSharedPtr MessageHandler; + + /** List of the connected pairs of controllers, with state for each controller device */ + TArray ControllerPairs; + + FOculusRemoteControllerState Remote; + + ovrpHapticsDesc OvrpHapticsDesc; + + int LocalTrackingSpaceRecenterCount; + + // Maintain a cache of resampled raw data so we don't resample it on every play. This is a map of OriginalRawData pointers, used only as a key, to ResampledRawData buffers. + // The values are pointers because the map could be reallocated and we cache raw pointers to the uint8 array data elsewhere. + TMap>> ResampledRawDataCache; + + TSharedPtr ActiveHapticEffect_Left; + TSharedPtr ActiveHapticEffect_Right; + TSharedPtr HapticsDesc_Left; + TSharedPtr HapticsDesc_Right; + double StartTime = 0.0; + + /** Threshold for treating trigger pulls as button presses, from 0.0 to 1.0 */ + static float TriggerThreshold; + + /** Are Remote keys mapped to gamepad or not. */ + static bool bRemoteKeysMappedToGamepad; + + /** Repeat key delays, loaded from config */ + static float InitialButtonRepeatDelay; + static float ButtonRepeatDelay; + + static bool bPulledHapticsDesc; + }; + +} // namespace OculusXRInput + +#endif //OCULUS_INPUT_SUPPORTED_PLATFORMS diff --git a/Plugins/MetaXR/Source/OculusXRInput/Private/OculusXRInputFunctionLibrary.cpp b/Plugins/MetaXR/Source/OculusXRInput/Private/OculusXRInputFunctionLibrary.cpp new file mode 100644 index 0000000..bf6a229 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRInput/Private/OculusXRInputFunctionLibrary.cpp @@ -0,0 +1,175 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +#include "OculusXRInputFunctionLibrary.h" +#include "OculusXRHandTracking.h" +#include "OculusXRControllerTracking.h" +#include "Logging/MessageLog.h" +#include "Haptics/HapticFeedbackEffect_Buffer.h" +#include "Haptics/HapticFeedbackEffect_Curve.h" +#include "Haptics/HapticFeedbackEffect_SoundWave.h" + +//------------------------------------------------------------------------------------------------- +// UOculusHandTrackingFunctionLibrary +//------------------------------------------------------------------------------------------------- +UOculusXRInputFunctionLibrary::UOculusXRInputFunctionLibrary(const FObjectInitializer& ObjectInitializer) + : Super(ObjectInitializer) +{ +} + +UOculusXRInputFunctionLibrary::FHandMovementFilterDelegate UOculusXRInputFunctionLibrary::HandMovementFilter; + +EOculusXRFinger UOculusXRInputFunctionLibrary::ConvertBoneToFinger(const EOculusXRBone Bone) +{ + switch (Bone) + { + case EOculusXRBone::Index_1: + case EOculusXRBone::Index_2: + case EOculusXRBone::Index_3: + case EOculusXRBone::Index_Tip: + return EOculusXRFinger::Index; + case EOculusXRBone::Middle_1: + case EOculusXRBone::Middle_2: + case EOculusXRBone::Middle_3: + case EOculusXRBone::Middle_Tip: + return EOculusXRFinger::Middle; + case EOculusXRBone::Pinky_0: + case EOculusXRBone::Pinky_1: + case EOculusXRBone::Pinky_2: + case EOculusXRBone::Pinky_3: + case EOculusXRBone::Pinky_Tip: + return EOculusXRFinger::Pinky; + case EOculusXRBone::Ring_1: + case EOculusXRBone::Ring_2: + case EOculusXRBone::Ring_3: + case EOculusXRBone::Ring_Tip: + return EOculusXRFinger::Ring; + case EOculusXRBone::Thumb_0: + case EOculusXRBone::Thumb_1: + case EOculusXRBone::Thumb_2: + case EOculusXRBone::Thumb_3: + case EOculusXRBone::Thumb_Tip: + return EOculusXRFinger::Thumb; + default: + return EOculusXRFinger::Invalid; + } +} + +EOculusXRTrackingConfidence UOculusXRInputFunctionLibrary::GetFingerTrackingConfidence(const EOculusXRHandType DeviceHand, const EOculusXRFinger Finger, const int32 ControllerIndex) +{ + return OculusXRInput::FOculusHandTracking::GetFingerTrackingConfidence(ControllerIndex, DeviceHand, (OculusXRInput::EOculusHandAxes)(uint8)Finger); +} + +bool UOculusXRInputFunctionLibrary::GetHandSkeletalMesh(USkeletalMesh* HandSkeletalMesh, EOculusXRHandType SkeletonType, EOculusXRHandType MeshType, float WorldToMeters) +{ + return OculusXRInput::FOculusHandTracking::GetHandSkeletalMesh(HandSkeletalMesh, SkeletonType, MeshType, WorldToMeters); +} + +TArray UOculusXRInputFunctionLibrary::InitializeHandPhysics(EOculusXRHandType SkeletonType, USkinnedMeshComponent* HandComponent, const float WorldToMeters) +{ + return OculusXRInput::FOculusHandTracking::InitializeHandPhysics(SkeletonType, HandComponent, WorldToMeters); +} + +FQuat UOculusXRInputFunctionLibrary::GetBoneRotation(const EOculusXRHandType DeviceHand, const EOculusXRBone BoneId, const int32 ControllerIndex) +{ + return OculusXRInput::FOculusHandTracking::GetBoneRotation(ControllerIndex, DeviceHand, BoneId); +} + +EOculusXRTrackingConfidence UOculusXRInputFunctionLibrary::GetTrackingConfidence(const EOculusXRHandType DeviceHand, const int32 ControllerIndex) +{ + return OculusXRInput::FOculusHandTracking::GetTrackingConfidence(ControllerIndex, DeviceHand); +} + +FTransform UOculusXRInputFunctionLibrary::GetPointerPose(const EOculusXRHandType DeviceHand, const int32 ControllerIndex) +{ + return OculusXRInput::FOculusHandTracking::GetPointerPose(ControllerIndex, DeviceHand); +} + +bool UOculusXRInputFunctionLibrary::IsPointerPoseValid(const EOculusXRHandType DeviceHand, const int32 ControllerIndex) +{ + return OculusXRInput::FOculusHandTracking::IsPointerPoseValid(ControllerIndex, DeviceHand); +} + +float UOculusXRInputFunctionLibrary::GetHandScale(const EOculusXRHandType DeviceHand, const int32 ControllerIndex) +{ + return OculusXRInput::FOculusHandTracking::GetHandScale(ControllerIndex, DeviceHand); +} + +EOculusXRHandType UOculusXRInputFunctionLibrary::GetDominantHand(const int32 ControllerIndex) +{ + EOculusXRHandType DominantHand = EOculusXRHandType::None; + if (OculusXRInput::FOculusHandTracking::IsHandDominant(ControllerIndex, EOculusXRHandType::HandLeft)) + { + DominantHand = EOculusXRHandType::HandLeft; + } + else if (OculusXRInput::FOculusHandTracking::IsHandDominant(ControllerIndex, EOculusXRHandType::HandRight)) + { + DominantHand = EOculusXRHandType::HandRight; + } + return DominantHand; +} + +bool UOculusXRInputFunctionLibrary::IsHandTrackingEnabled() +{ + return OculusXRInput::FOculusHandTracking::IsHandTrackingEnabled(); +} + +bool UOculusXRInputFunctionLibrary::IsHandPositionValid(const EOculusXRHandType DeviceHand, const int32 ControllerIndex) +{ + return OculusXRInput::FOculusHandTracking::IsHandPositionValid(ControllerIndex, DeviceHand); +} + +FString UOculusXRInputFunctionLibrary::GetBoneName(EOculusXRBone BoneId) +{ + const auto ovrBoneId = OculusXRInput::FOculusHandTracking::ToOvrBone(BoneId); + if (ovrBoneId == ovrpBoneId_Invalid) + { + return OculusXRInput::FOculusHandTracking::GetBoneName(static_cast(EOculusXRBone::Invalid)); + } + return OculusXRInput::FOculusHandTracking::GetBoneName(static_cast(ovrBoneId)); +} + +void UOculusXRInputFunctionLibrary::PlayCurveHapticEffect(class UHapticFeedbackEffect_Curve* HapticEffect, EControllerHand Hand, EOculusXRHandHapticsLocation Location, float Scale, bool bLoop) +{ + OculusXRInput::FOculusXRControllerTracking::PlayHapticEffect(HapticEffect, Hand, Location, false, Scale, bLoop); +} + +void UOculusXRInputFunctionLibrary::PlayBufferHapticEffect(class UHapticFeedbackEffect_Buffer* HapticEffect, EControllerHand Hand, EOculusXRHandHapticsLocation Location, float Scale, bool bLoop) +{ + OculusXRInput::FOculusXRControllerTracking::PlayHapticEffect(HapticEffect, Hand, Location, false, Scale, bLoop); +} + +void UOculusXRInputFunctionLibrary::PlayAmplitudeEnvelopeHapticEffect(class UHapticFeedbackEffect_Buffer* HapticEffect, EControllerHand Hand) +{ + OculusXRInput::FOculusXRControllerTracking::PlayHapticEffect(Hand, HapticEffect->Amplitudes, HapticEffect->SampleRate, false, false); +} + +void UOculusXRInputFunctionLibrary::PlaySoundWaveHapticEffect(class UHapticFeedbackEffect_SoundWave* HapticEffect, EControllerHand Hand, bool bAppend, float Scale, bool bLoop) +{ + OculusXRInput::FOculusXRControllerTracking::PlayHapticEffect(HapticEffect, Hand, EOculusXRHandHapticsLocation::Hand, bAppend, Scale, bLoop); +} + +void UOculusXRInputFunctionLibrary::StopHapticEffect(EControllerHand Hand, EOculusXRHandHapticsLocation Location) +{ + OculusXRInput::FOculusXRControllerTracking::StopHapticEffect(Hand, Location); +} + +void UOculusXRInputFunctionLibrary::SetHapticsByValue(const float Frequency, const float Amplitude, EControllerHand Hand, EOculusXRHandHapticsLocation Location) +{ + OculusXRInput::FOculusXRControllerTracking::SetHapticsByValue(Frequency, Amplitude, Hand, Location); +} + +float UOculusXRInputFunctionLibrary::GetControllerSampleRateHz(EControllerHand Hand) +{ + return OculusXRInput::FOculusXRControllerTracking::GetControllerSampleRateHz(Hand); +} + +int UOculusXRInputFunctionLibrary::GetMaxHapticDuration(EControllerHand Hand) +{ + return OculusXRInput::FOculusXRControllerTracking::GetMaxHapticDuration(Hand); +} + +void UOculusXRInputFunctionLibrary::SetControllerDrivenHandPoses(EOculusXRControllerDrivenHandPoseTypes Type) +{ + return OculusXRInput::FOculusHandTracking::SetControllerDrivenHandPoses(Type); +} diff --git a/Plugins/MetaXR/Source/OculusXRInput/Private/OculusXRInputModule.cpp b/Plugins/MetaXR/Source/OculusXRInput/Private/OculusXRInputModule.cpp new file mode 100644 index 0000000..ab16cfb --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRInput/Private/OculusXRInputModule.cpp @@ -0,0 +1,72 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +#include "OculusXRInputModule.h" + +#if OCULUS_INPUT_SUPPORTED_PLATFORMS +#include "OculusXRInput.h" +#include "OculusXRHMDModule.h" + +#define LOCTEXT_NAMESPACE "OculusXRInput" + +//------------------------------------------------------------------------------------------------- +// FOculusXRInputModule +//------------------------------------------------------------------------------------------------- + +void FOculusXRInputModule::StartupModule() +{ + IInputDeviceModule::StartupModule(); + OculusXRInput::FOculusXRInput::PreInit(); +} + +TSharedPtr FOculusXRInputModule::CreateInputDevice(const TSharedRef& InMessageHandler) +{ + if (IOculusXRHMDModule::IsAvailable()) + { + if (FOculusXRHMDModule::Get().PreInit()) + { + TSharedPtr InputDevice(new OculusXRInput::FOculusXRInput(InMessageHandler)); + OculusXRInputDevice = InputDevice; + return InputDevice; + } + // else, they may just not have a oculus headset plugged in (which we have to account for - no need for a warning) + } + else + { + UE_LOG(LogOcInput, Warning, TEXT("OculusXRInput plugin enabled, but OculusXRHMD plugin is not available.")); + } + return nullptr; +} + +uint32 FOculusXRInputModule::GetNumberOfTouchControllers() const +{ + if (OculusXRInputDevice.IsValid()) + { + return OculusXRInputDevice.Pin()->GetNumberOfTouchControllers(); + } + return 0; +} + +uint32 FOculusXRInputModule::GetNumberOfHandControllers() const +{ + if (OculusXRInputDevice.IsValid()) + { + return OculusXRInputDevice.Pin()->GetNumberOfHandControllers(); + } + return 0; +} + +TSharedPtr FOculusXRInputModule::GetInputDevice() const +{ + if (OculusXRInputDevice.IsValid()) + { + return OculusXRInputDevice.Pin(); + } + return nullptr; +} + +#endif // OCULUS_INPUT_SUPPORTED_PLATFORMS + +IMPLEMENT_MODULE(FOculusXRInputModule, OculusXRInput) + +#undef LOCTEXT_NAMESPACE diff --git a/Plugins/MetaXR/Source/OculusXRInput/Private/OculusXRInputModule.h b/Plugins/MetaXR/Source/OculusXRInput/Private/OculusXRInputModule.h new file mode 100644 index 0000000..62bdef1 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRInput/Private/OculusXRInputModule.h @@ -0,0 +1,53 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +#pragma once +#include "IOculusXRInputModule.h" +#include "IInputDevice.h" +#include "Templates/SharedPointer.h" + +#define LOCTEXT_NAMESPACE "OculusXRInput" + +//------------------------------------------------------------------------------------------------- +// FOculusXRInputModule +//------------------------------------------------------------------------------------------------- + +#if OCULUS_INPUT_SUPPORTED_PLATFORMS + +namespace OculusXRInput +{ + class FOculusXRInput; +} + +class FOculusXRInputModule : public IOculusXRInputModule +{ + TWeakPtr OculusXRInputDevice; + + // IInputDeviceModule overrides + virtual void StartupModule() override; + virtual TSharedPtr CreateInputDevice(const TSharedRef& InMessageHandler) override; + + // IOculusXRInputModule overrides + virtual uint32 GetNumberOfTouchControllers() const override; + virtual uint32 GetNumberOfHandControllers() const override; + virtual TSharedPtr GetInputDevice() const override; +}; + +#else // OCULUS_INPUT_SUPPORTED_PLATFORMS + +class FOculusXRInputModule : public FDefaultModuleImpl +{ + virtual uint32 GetNumberOfTouchControllers() const + { + return 0; + }; + + virtual uint32 GetNumberOfHandControllers() const + { + return 0; + }; +}; + +#endif // OCULUS_INPUT_SUPPORTED_PLATFORMS + +#undef LOCTEXT_NAMESPACE diff --git a/Plugins/MetaXR/Source/OculusXRInput/Private/OculusXRInputState.h b/Plugins/MetaXR/Source/OculusXRInput/Private/OculusXRInputState.h new file mode 100644 index 0000000..1a0d68d --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRInput/Private/OculusXRInputState.h @@ -0,0 +1,544 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +#pragma once +#include "IOculusXRInputModule.h" + +#if OCULUS_INPUT_SUPPORTED_PLATFORMS +#include "IMotionController.h" +#include "InputCoreTypes.h" +#include "OculusXRInputFunctionLibrary.h" +#include "GenericPlatform/GenericApplicationMessageHandler.h" + +namespace OculusXRInput +{ + + //------------------------------------------------------------------------------------------------- + // Button names + //------------------------------------------------------------------------------------------------- + + enum class EOculusTouchControllerButton + { + // NOTE: The Trigger and Grip digital buttons are synthetic. Oculus hardware doesn't support a digital press for these + Trigger, + Grip, + + XA, + YB, + Thumbstick, + + Thumbstick_Up, + Thumbstick_Down, + Thumbstick_Left, + Thumbstick_Right, + + Menu, + + Thumbstick_Touch, + Trigger_Touch, + XA_Touch, + YB_Touch, + + /** Total number of controller buttons */ + TotalButtonCount + }; + + enum class EOculusRemoteControllerButton + { + DPad_Up, + DPad_Down, + DPad_Left, + DPad_Right, + + Enter, + Back, + + VolumeUp, + VolumeDown, + Home, + + /** Total number of controller buttons */ + TotalButtonCount + }; + + enum class EOculusTouchCapacitiveAxes + { + Thumbstick, + Trigger, + XA, + YB, + IndexPointing, + ThumbUp, + ThumbRest, + + /** Total number of capacitive axes */ + TotalAxisCount + }; + + enum class EOculusHandButton + { + Thumb, + Index, + Middle, + Ring, + Pinky, + System, + Menu, + TotalButtonCount + }; + + enum class EOculusHandAxes + { + Thumb, + Index, + Middle, + Ring, + Pinky, + TotalAxisCount + }; + + //------------------------------------------------------------------------------------------------- + // FOculusKey + //------------------------------------------------------------------------------------------------- + + struct FOculusKey + { + static const FKey OculusTouch_Left_Thumbstick; + static const FKey OculusTouch_Left_Trigger; + static const FKey OculusTouch_Left_FaceButton1; // X or A + static const FKey OculusTouch_Left_FaceButton2; // Y or B + static const FKey OculusTouch_Left_IndexPointing; + static const FKey OculusTouch_Left_ThumbUp; + static const FKey OculusTouch_Left_ThumbRest; + static const FKey OculusTouch_Left_ThumbRest_Force; + static const FKey OculusTouch_Left_Stylus_Force; + static const FKey OculusTouch_Left_IndexTrigger_Curl; + static const FKey OculusTouch_Left_IndexTrigger_Slide; + static const FKey OculusTouch_Left_IndexTrigger_Force; + + static const FKey OculusTouch_Right_Thumbstick; + static const FKey OculusTouch_Right_Trigger; + static const FKey OculusTouch_Right_FaceButton1; // X or A + static const FKey OculusTouch_Right_FaceButton2; // Y or B + static const FKey OculusTouch_Right_IndexPointing; + static const FKey OculusTouch_Right_ThumbUp; + static const FKey OculusTouch_Right_ThumbRest; + static const FKey OculusTouch_Right_ThumbRest_Force; + static const FKey OculusTouch_Right_Stylus_Force; + static const FKey OculusTouch_Right_IndexTrigger_Curl; + static const FKey OculusTouch_Right_IndexTrigger_Slide; + static const FKey OculusTouch_Right_IndexTrigger_Force; + + static const FKey OculusRemote_DPad_Up; + static const FKey OculusRemote_DPad_Down; + static const FKey OculusRemote_DPad_Left; + static const FKey OculusRemote_DPad_Right; + + static const FKey OculusRemote_Enter; + static const FKey OculusRemote_Back; + + static const FKey OculusRemote_VolumeUp; + static const FKey OculusRemote_VolumeDown; + static const FKey OculusRemote_Home; + + static const FKey OculusHand_Left_ThumbPinch; + static const FKey OculusHand_Left_IndexPinch; + static const FKey OculusHand_Left_MiddlePinch; + static const FKey OculusHand_Left_RingPinch; + static const FKey OculusHand_Left_PinkyPinch; + + static const FKey OculusHand_Right_ThumbPinch; + static const FKey OculusHand_Right_IndexPinch; + static const FKey OculusHand_Right_MiddlePinch; + static const FKey OculusHand_Right_RingPinch; + static const FKey OculusHand_Right_PinkyPinch; + + static const FKey OculusHand_Left_SystemGesture; + static const FKey OculusHand_Right_SystemGesture; + + static const FKey OculusHand_Left_ThumbPinchStrength; + static const FKey OculusHand_Left_IndexPinchStrength; + static const FKey OculusHand_Left_MiddlePinchStrength; + static const FKey OculusHand_Left_RingPinchStrength; + static const FKey OculusHand_Left_PinkyPinchStrength; + + static const FKey OculusHand_Right_ThumbPinchStrength; + static const FKey OculusHand_Right_IndexPinchStrength; + static const FKey OculusHand_Right_MiddlePinchStrength; + static const FKey OculusHand_Right_RingPinchStrength; + static const FKey OculusHand_Right_PinkyPinchStrength; + }; + + //------------------------------------------------------------------------------------------------- + // FOculusKeyNames + //------------------------------------------------------------------------------------------------- + + struct FOculusKeyNames + { + typedef FName Type; + + static const FName OculusTouch_Left_Thumbstick; + static const FName OculusTouch_Left_Trigger; + static const FName OculusTouch_Left_FaceButton1; // X or A + static const FName OculusTouch_Left_FaceButton2; // Y or B + static const FName OculusTouch_Left_IndexPointing; + static const FName OculusTouch_Left_ThumbUp; + static const FName OculusTouch_Left_ThumbRest; + + static const FName OculusTouch_Right_Thumbstick; + static const FName OculusTouch_Right_Trigger; + static const FName OculusTouch_Right_FaceButton1; // X or A + static const FName OculusTouch_Right_FaceButton2; // Y or B + static const FName OculusTouch_Right_IndexPointing; + static const FName OculusTouch_Right_ThumbUp; + static const FName OculusTouch_Right_ThumbRest; + + static const FName OculusRemote_DPad_Up; + static const FName OculusRemote_DPad_Down; + static const FName OculusRemote_DPad_Left; + static const FName OculusRemote_DPad_Right; + + static const FName OculusRemote_Enter; + static const FName OculusRemote_Back; + + static const FName OculusRemote_VolumeUp; + static const FName OculusRemote_VolumeDown; + static const FName OculusRemote_Home; + + static const FName OculusHand_Left_ThumbPinch; + static const FName OculusHand_Left_IndexPinch; + static const FName OculusHand_Left_MiddlePinch; + static const FName OculusHand_Left_RingPinch; + static const FName OculusHand_Left_PinkyPinch; + + static const FName OculusHand_Right_ThumbPinch; + static const FName OculusHand_Right_IndexPinch; + static const FName OculusHand_Right_MiddlePinch; + static const FName OculusHand_Right_RingPinch; + static const FName OculusHand_Right_PinkyPinch; + + static const FName OculusHand_Left_SystemGesture; + static const FName OculusHand_Right_SystemGesture; + + static const FName OculusHand_Left_ThumbPinchStrength; + static const FName OculusHand_Left_IndexPinchStrength; + static const FName OculusHand_Left_MiddlePinchStrength; + static const FName OculusHand_Left_RingPinchStrength; + static const FName OculusHand_Left_PinkyPinchStrength; + + static const FName OculusHand_Right_ThumbPinchStrength; + static const FName OculusHand_Right_IndexPinchStrength; + static const FName OculusHand_Right_MiddlePinchStrength; + static const FName OculusHand_Right_RingPinchStrength; + static const FName OculusHand_Right_PinkyPinchStrength; + }; + + //------------------------------------------------------------------------------------------------- + // FOculusButtonState - Digital button state + //------------------------------------------------------------------------------------------------- + + struct FOculusButtonState + { + /** The Unreal button this maps to. Different depending on whether this is the Left or Right hand controller */ + FName Key; + + /** The Unreal button this maps to. Different depending on whether this is the Left or Right hand controller */ + FName EmulatedKey; + + /** Whether we're pressed or not. While pressed, we will generate repeat presses on a timer */ + bool bIsPressed; + + /** Next time a repeat event should be generated for each button */ + double NextRepeatTime; + + /** Default constructor that just sets sensible defaults */ + FOculusButtonState() + : Key(NAME_None), EmulatedKey(NAME_None), bIsPressed(false), NextRepeatTime(0.0) + { + } + }; + + //------------------------------------------------------------------------------------------------- + // FOculusTouchCapacitiveState - Capacitive Axis State + //------------------------------------------------------------------------------------------------- + + struct FOculusAxisState + { + /** The axis that this button state maps to */ + FName Axis; + + /** How close the finger is to this button, from 0.f to 1.f */ + float State; + + FOculusAxisState() + : Axis(NAME_None) + , State(0.f) + { + } + }; + + struct FOculusControllerState + { + /** True if the device is connected, otherwise false */ + bool bIsConnected; + + /** True if position is being tracked, otherwise false */ + bool bIsPositionTracked; + + /** True if position is valid (tracked or estimated), otherwise false */ + bool bIsPositionValid; + + /** True if orientation is being tracked, otherwise false */ + bool bIsOrientationTracked; + + /** True if orientation is valid (tracked or estimated), otherwise false */ + bool bIsOrientationValid; + + FOculusControllerState() + : bIsConnected(false), bIsPositionTracked(false), bIsPositionValid(false), bIsOrientationTracked(false), bIsOrientationValid(false) + { + } + }; + + //------------------------------------------------------------------------------------------------- + // FOculusTouchControllerState - Input state for an Oculus motion controller + //------------------------------------------------------------------------------------------------- + + struct FOculusTouchControllerState : FOculusControllerState + { + /** Analog trigger */ + float TriggerAxis; + + /** Grip trigger */ + float GripAxis; + + /** Thumbstick */ + FVector2D ThumbstickAxes; + + /** Thumbstick */ + FVector2D TouchpadAxes; + + /** Button states */ + FOculusButtonState Buttons[(int32)EOculusTouchControllerButton::TotalButtonCount]; + + /** Capacitive Touch axes */ + FOculusAxisState CapacitiveAxes[(int32)EOculusTouchCapacitiveAxes::TotalAxisCount]; + + /** Thumb Rest Force **/ + float ThumbRestForce; + + /** Stylus tip**/ + float StylusForce; + + /** Index trigger Curl**/ + float IndexTriggerCurl; + + /** Index trigger Slide**/ + float IndexTriggerSlide; + + /** Second stage Index trigger force **/ + float IndexTriggerForce; + + /** Whether or not we're playing a haptic effect. If true, force feedback calls will be early-outed in favor of the haptic effect */ + bool bPlayingHapticEffect; + + /** Haptic frequency (zero to disable) */ + float HapticFrequency; + + /** Haptic amplitude (zero to disable) */ + float HapticAmplitude; + + /** Force feedback haptic frequency (zero to disable) */ + float ForceFeedbackHapticFrequency; + + /** Force feedback haptic amplitude (zero to disable) */ + float ForceFeedbackHapticAmplitude; + + /** Number of times that controller was recentered (for mobile controllers) */ + int RecenterCount; + + public: + FHapticFeedbackBuffer ResampledHapticBuffer; + void ResampleHapticBufferData(const FHapticFeedbackBuffer& HapticBuffer, TMap>>& ResampledRawDataCache); + + /** Explicit constructor sets up sensible defaults */ + FOculusTouchControllerState(const EControllerHand Hand) + : TriggerAxis(0.0f), GripAxis(0.0f), ThumbstickAxes(FVector2D::ZeroVector), bPlayingHapticEffect(false), HapticFrequency(0.0f), HapticAmplitude(0.0f), ForceFeedbackHapticFrequency(0.0f), ForceFeedbackHapticAmplitude(0.0f), RecenterCount(0) + { + for (FOculusButtonState& Button : Buttons) + { + Button.bIsPressed = false; + Button.NextRepeatTime = 0.0; + } + + Buttons[(int32)EOculusTouchControllerButton::Trigger].Key = (Hand == EControllerHand::Left) ? EKeys::OculusTouch_Left_Trigger_Click.GetFName() : EKeys::OculusTouch_Right_Trigger_Click.GetFName(); + Buttons[(int32)EOculusTouchControllerButton::Grip].Key = (Hand == EControllerHand::Left) ? EKeys::OculusTouch_Left_Grip_Click.GetFName() : EKeys::OculusTouch_Right_Grip_Click.GetFName(); + Buttons[(int32)EOculusTouchControllerButton::Thumbstick].Key = (Hand == EControllerHand::Left) ? EKeys::OculusTouch_Left_Thumbstick_Click.GetFName() : EKeys::OculusTouch_Right_Thumbstick_Click.GetFName(); + Buttons[(int32)EOculusTouchControllerButton::XA].Key = (Hand == EControllerHand::Left) ? EKeys::OculusTouch_Left_X_Click.GetFName() : EKeys::OculusTouch_Right_A_Click.GetFName(); + Buttons[(int32)EOculusTouchControllerButton::YB].Key = (Hand == EControllerHand::Left) ? EKeys::OculusTouch_Left_Y_Click.GetFName() : EKeys::OculusTouch_Right_B_Click.GetFName(); + Buttons[(int32)EOculusTouchControllerButton::Thumbstick_Up].Key = (Hand == EControllerHand::Left) ? EKeys::OculusTouch_Left_Thumbstick_Up.GetFName() : EKeys::OculusTouch_Right_Thumbstick_Up.GetFName(); + Buttons[(int32)EOculusTouchControllerButton::Thumbstick_Down].Key = (Hand == EControllerHand::Left) ? EKeys::OculusTouch_Left_Thumbstick_Down.GetFName() : EKeys::OculusTouch_Right_Thumbstick_Down.GetFName(); + Buttons[(int32)EOculusTouchControllerButton::Thumbstick_Left].Key = (Hand == EControllerHand::Left) ? EKeys::OculusTouch_Left_Thumbstick_Left.GetFName() : EKeys::OculusTouch_Right_Thumbstick_Left.GetFName(); + Buttons[(int32)EOculusTouchControllerButton::Thumbstick_Right].Key = (Hand == EControllerHand::Left) ? EKeys::OculusTouch_Left_Thumbstick_Right.GetFName() : EKeys::OculusTouch_Right_Thumbstick_Right.GetFName(); + + Buttons[(int32)EOculusTouchControllerButton::Menu].Key = (Hand == EControllerHand::Left) ? EKeys::OculusTouch_Left_Menu_Click.GetFName() : FName("OculusTouch_Right_System_Click"); + + Buttons[(int32)EOculusTouchControllerButton::Thumbstick_Touch].Key = (Hand == EControllerHand::Left) ? EKeys::OculusTouch_Left_Thumbstick_Touch.GetFName() : EKeys::OculusTouch_Right_Thumbstick_Touch.GetFName(); + Buttons[(int32)EOculusTouchControllerButton::Trigger_Touch].Key = (Hand == EControllerHand::Left) ? EKeys::OculusTouch_Left_Trigger_Touch.GetFName() : EKeys::OculusTouch_Right_Trigger_Touch.GetFName(); + Buttons[(int32)EOculusTouchControllerButton::XA_Touch].Key = (Hand == EControllerHand::Left) ? EKeys::OculusTouch_Left_X_Touch.GetFName() : EKeys::OculusTouch_Right_A_Touch.GetFName(); + Buttons[(int32)EOculusTouchControllerButton::YB_Touch].Key = (Hand == EControllerHand::Left) ? EKeys::OculusTouch_Left_Y_Touch.GetFName() : EKeys::OculusTouch_Right_B_Touch.GetFName(); + + CapacitiveAxes[(int32)EOculusTouchCapacitiveAxes::Thumbstick].Axis = (Hand == EControllerHand::Left) ? FOculusKeyNames::OculusTouch_Left_Thumbstick : FOculusKeyNames::OculusTouch_Right_Thumbstick; + CapacitiveAxes[(int32)EOculusTouchCapacitiveAxes::Trigger].Axis = (Hand == EControllerHand::Left) ? FOculusKeyNames::OculusTouch_Left_Trigger : FOculusKeyNames::OculusTouch_Right_Trigger; + CapacitiveAxes[(int32)EOculusTouchCapacitiveAxes::XA].Axis = (Hand == EControllerHand::Left) ? FOculusKeyNames::OculusTouch_Left_FaceButton1 : FOculusKeyNames::OculusTouch_Right_FaceButton1; + CapacitiveAxes[(int32)EOculusTouchCapacitiveAxes::YB].Axis = (Hand == EControllerHand::Left) ? FOculusKeyNames::OculusTouch_Left_FaceButton2 : FOculusKeyNames::OculusTouch_Right_FaceButton2; + CapacitiveAxes[(int32)EOculusTouchCapacitiveAxes::IndexPointing].Axis = (Hand == EControllerHand::Left) ? FOculusKeyNames::OculusTouch_Left_IndexPointing : FOculusKeyNames::OculusTouch_Right_IndexPointing; + CapacitiveAxes[(int32)EOculusTouchCapacitiveAxes::ThumbUp].Axis = (Hand == EControllerHand::Left) ? FOculusKeyNames::OculusTouch_Left_ThumbUp : FOculusKeyNames::OculusTouch_Right_ThumbUp; + CapacitiveAxes[(int32)EOculusTouchCapacitiveAxes::ThumbRest].Axis = (Hand == EControllerHand::Left) ? FOculusKeyNames::OculusTouch_Left_ThumbRest : FOculusKeyNames::OculusTouch_Right_ThumbRest; + } + + /** Default constructor does nothing. Don't use it. This only exists because we cannot initialize an array of objects with no default constructor on non-C++ 11 compliant compilers (VS 2013) */ + FOculusTouchControllerState() + { + } + }; + + //------------------------------------------------------------------------------------------------- + // FOculusHandControllerState - Input state for an Oculus Hands + //------------------------------------------------------------------------------------------------- + + struct FOculusHandControllerState : FOculusControllerState + { + /** True if the pointer pose for hands is valid */ + bool bIsPointerPoseValid; + + /** True if the current hand is the dominant hand */ + bool bIsDominantHand; + + /** Scale of the hand */ + float HandScale; + + /** Pose of the pointer */ + FTransform PointerPose; + + /** Tracking confidence of hand tracking */ + EOculusXRTrackingConfidence TrackingConfidence; + + /** Finger Pinch States **/ + FOculusButtonState HandButtons[(int32)EOculusHandButton::TotalButtonCount]; + + /** Finger Pinch Strength States **/ + FOculusAxisState HandAxes[(int32)EOculusHandAxes::TotalAxisCount]; + + /** Finger Confidences **/ + EOculusXRTrackingConfidence FingerConfidences[(int32)EOculusHandAxes::TotalAxisCount] = {}; + + FQuat BoneRotations[(int32)EOculusXRBone::Bone_Max]; + + FOculusHandControllerState(const EControllerHand Hand) + { + TrackingConfidence = EOculusXRTrackingConfidence::Low; + bIsPointerPoseValid = false; + bIsDominantHand = false; + HandScale = 0.0f; + PointerPose = FTransform::Identity; + + for (FOculusButtonState& Button : HandButtons) + { + Button.bIsPressed = false; + Button.NextRepeatTime = 0.0; + } + + for (int32 i = 0; i < (int32)EOculusXRBone::Bone_Max; i++) + { + BoneRotations[i] = FQuat::Identity; + } + + HandButtons[(int32)EOculusHandButton::Thumb].Key = (Hand == EControllerHand::Left) ? FOculusKeyNames::OculusHand_Left_ThumbPinch : FOculusKeyNames::OculusHand_Right_ThumbPinch; + HandButtons[(int32)EOculusHandButton::Index].Key = (Hand == EControllerHand::Left) ? FOculusKeyNames::OculusHand_Left_IndexPinch : FOculusKeyNames::OculusHand_Right_IndexPinch; + HandButtons[(int32)EOculusHandButton::Middle].Key = (Hand == EControllerHand::Left) ? FOculusKeyNames::OculusHand_Left_MiddlePinch : FOculusKeyNames::OculusHand_Right_MiddlePinch; + HandButtons[(int32)EOculusHandButton::Ring].Key = (Hand == EControllerHand::Left) ? FOculusKeyNames::OculusHand_Left_RingPinch : FOculusKeyNames::OculusHand_Right_RingPinch; + HandButtons[(int32)EOculusHandButton::Pinky].Key = (Hand == EControllerHand::Left) ? FOculusKeyNames::OculusHand_Left_PinkyPinch : FOculusKeyNames::OculusHand_Right_PinkyPinch; + HandButtons[(int32)EOculusHandButton::System].Key = (Hand == EControllerHand::Left) ? FOculusKeyNames::OculusHand_Left_SystemGesture : FOculusKeyNames::OculusHand_Right_SystemGesture; + HandButtons[(int32)EOculusHandButton::Menu].Key = (Hand == EControllerHand::Left) ? FGamepadKeyNames::SpecialLeft : FGamepadKeyNames::SpecialRight; + + HandAxes[(int32)EOculusHandAxes::Thumb].Axis = (Hand == EControllerHand::Left) ? FOculusKeyNames::OculusHand_Left_ThumbPinchStrength : FOculusKeyNames::OculusHand_Right_ThumbPinchStrength; + HandAxes[(int32)EOculusHandAxes::Index].Axis = (Hand == EControllerHand::Left) ? FOculusKeyNames::OculusHand_Left_IndexPinchStrength : FOculusKeyNames::OculusHand_Right_IndexPinchStrength; + HandAxes[(int32)EOculusHandAxes::Middle].Axis = (Hand == EControllerHand::Left) ? FOculusKeyNames::OculusHand_Left_MiddlePinchStrength : FOculusKeyNames::OculusHand_Right_MiddlePinchStrength; + HandAxes[(int32)EOculusHandAxes::Ring].Axis = (Hand == EControllerHand::Left) ? FOculusKeyNames::OculusHand_Left_RingPinchStrength : FOculusKeyNames::OculusHand_Right_RingPinchStrength; + HandAxes[(int32)EOculusHandAxes::Pinky].Axis = (Hand == EControllerHand::Left) ? FOculusKeyNames::OculusHand_Left_PinkyPinchStrength : FOculusKeyNames::OculusHand_Right_PinkyPinchStrength; + } + + FOculusHandControllerState() + { + } + }; + + //------------------------------------------------------------------------------------------------- + // FOculusRemoteControllerState + //------------------------------------------------------------------------------------------------- + + struct FOculusRemoteControllerState + { + /** Button states */ + FOculusButtonState Buttons[(int32)EOculusRemoteControllerButton::TotalButtonCount]; + + FOculusRemoteControllerState() + { + for (FOculusButtonState& Button : Buttons) + { + Button.bIsPressed = false; + Button.NextRepeatTime = 0.0; + } + + Buttons[(int32)EOculusRemoteControllerButton::DPad_Up].Key = FOculusKeyNames::OculusRemote_DPad_Up; + Buttons[(int32)EOculusRemoteControllerButton::DPad_Down].Key = FOculusKeyNames::OculusRemote_DPad_Down; + Buttons[(int32)EOculusRemoteControllerButton::DPad_Left].Key = FOculusKeyNames::OculusRemote_DPad_Left; + Buttons[(int32)EOculusRemoteControllerButton::DPad_Right].Key = FOculusKeyNames::OculusRemote_DPad_Right; + Buttons[(int32)EOculusRemoteControllerButton::Enter].Key = FOculusKeyNames::OculusRemote_Enter; + Buttons[(int32)EOculusRemoteControllerButton::Back].Key = FOculusKeyNames::OculusRemote_Back; + + Buttons[(int32)EOculusRemoteControllerButton::VolumeUp].Key = FOculusKeyNames::OculusRemote_VolumeUp; + Buttons[(int32)EOculusRemoteControllerButton::VolumeDown].Key = FOculusKeyNames::OculusRemote_VolumeDown; + Buttons[(int32)EOculusRemoteControllerButton::Home].Key = FOculusKeyNames::OculusRemote_Home; + } + + void MapKeysToGamepad() + { + Buttons[(int32)EOculusRemoteControllerButton::DPad_Up].EmulatedKey = FGamepadKeyNames::DPadUp; + Buttons[(int32)EOculusRemoteControllerButton::DPad_Down].EmulatedKey = FGamepadKeyNames::DPadDown; + Buttons[(int32)EOculusRemoteControllerButton::DPad_Left].EmulatedKey = FGamepadKeyNames::DPadLeft; + Buttons[(int32)EOculusRemoteControllerButton::DPad_Right].EmulatedKey = FGamepadKeyNames::DPadRight; + Buttons[(int32)EOculusRemoteControllerButton::Enter].EmulatedKey = FGamepadKeyNames::SpecialRight; + Buttons[(int32)EOculusRemoteControllerButton::Back].EmulatedKey = FGamepadKeyNames::SpecialLeft; + } + }; + + //------------------------------------------------------------------------------------------------- + // FOculusControllerPair - A pair of Oculus controllers, hand/touch, one for either hand + //------------------------------------------------------------------------------------------------- + + struct FOculusControllerPair + { + /** The input device ID for this oculus controller */ + FInputDeviceId DeviceId; + + /** Current device state for either hand */ + FOculusTouchControllerState TouchControllerStates[2]; + + FOculusHandControllerState HandControllerStates[2]; + + FOculusControllerPair() + : DeviceId(INPUTDEVICEID_NONE), TouchControllerStates(), HandControllerStates() + { + TouchControllerStates[(int32)EControllerHand::Left] = FOculusTouchControllerState(EControllerHand::Left); + TouchControllerStates[(int32)EControllerHand::Right] = FOculusTouchControllerState(EControllerHand::Right); + + HandControllerStates[(int32)EControllerHand::Left] = FOculusHandControllerState(EControllerHand::Left); + HandControllerStates[(int32)EControllerHand::Right] = FOculusHandControllerState(EControllerHand::Right); + } + }; + +} // namespace OculusXRInput + +#endif // OCULUS_INPUT_SUPPORTED_PLATFORMS diff --git a/Plugins/MetaXR/Source/OculusXRInput/Public/IOculusXRInputModule.h b/Plugins/MetaXR/Source/OculusXRInput/Public/IOculusXRInputModule.h new file mode 100644 index 0000000..d2899db --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRInput/Public/IOculusXRInputModule.h @@ -0,0 +1,54 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +#pragma once +#include "Modules/ModuleManager.h" +#include "IInputDeviceModule.h" + +#define OCULUS_INPUT_SUPPORTED_PLATFORMS (PLATFORM_WINDOWS && WINVER > 0x0502) || (PLATFORM_ANDROID_ARM || PLATFORM_ANDROID_ARM64) + +/** + * The public interface to this module. In most cases, this interface is only public to sibling modules + * within this plugin. + */ +class IOculusXRInputModule : public IInputDeviceModule +{ + +public: + /** + * Singleton-like access to this module's interface. This is just for convenience! + * Beware of calling this during the shutdown phase, though. Your module might have been unloaded already. + * + * @return Returns singleton instance, loading the module on demand if needed + */ + static inline IOculusXRInputModule& Get() + { + return FModuleManager::LoadModuleChecked("OculusXRInput"); + } + + /** + * Checks to see if this module is loaded and ready. It is only valid to call Get() if IsAvailable() returns true. + * + * @return True if the module is loaded and ready to use + */ + static inline bool IsAvailable() + { + return FModuleManager::Get().IsModuleLoaded("OculusXRInput"); + } + + /** + * Gets the number of Touch controllers that are active, so that games that require them can check to make sure they're present + * + * @return The number of Touch controllers that are active (but not necessarily tracked) + */ + virtual uint32 GetNumberOfTouchControllers() const = 0; + + /** + * Gets the number of hands that are active, so that games that require them can check to make sure they're present + * + * @return The number of Hands that are active (but not necessarily tracked) + */ + virtual uint32 GetNumberOfHandControllers() const = 0; + + virtual TSharedPtr GetInputDevice() const = 0; +}; diff --git a/Plugins/MetaXR/Source/OculusXRInput/Public/OculusXRControllerComponent.h b/Plugins/MetaXR/Source/OculusXRInput/Public/OculusXRControllerComponent.h new file mode 100644 index 0000000..964d450 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRInput/Public/OculusXRControllerComponent.h @@ -0,0 +1,61 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +// A class to render the currently connected controller. +// Similar to how hands are tracked. + +#pragma once +#include "OculusXRInputFunctionLibrary.h" +#include "OculusXRFunctionLibrary.h" +#include "Components/StaticMeshComponent.h" +#include + +// Must always be the last include. +#include "OculusXRControllerComponent.generated.h" + +UCLASS(Blueprintable, meta = (BlueprintSpawnableComponent), ClassGroup = OculusHand) +class UOculusXRControllerComponent : public UStaticMeshComponent +{ + GENERATED_BODY() + +public: + UOculusXRControllerComponent(); + + virtual void BeginPlay() override; + + virtual void TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override; + + /** The skeleton that will be loaded */ + UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = "Properties") + EOculusXRSide SkeletonType; + + /** Should this controller be rendered when using controller driven hand poses */ + UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = "Properties") + bool RenderWhenUsingControllerDrivenHands; + +private: + enum MeshLoadingState + { + None, + Loading, + Loaded + }; + + UStaticMesh* _runtimeMesh; + MeshLoadingState _meshLoadingState; + TSharedPtr _loadAssetHandle; + FStreamableManager _streamableManager; + EOculusXRControllerType _controllerType; + FSoftObjectPath _runtimeMeshPath; + EOculusXRControllerDrivenHandPoseTypes _cachedControllerHandType; + + void InitializeMesh(); + void MeshLoaded(); + EOculusXRControllerType GetControllerType(); + + const FVector PositionOffsets + [EOculusXRSideCount] + [EOculusXRControllerDrivenHandPoseTypesCount]; + const FVector RotationOffsets + [EOculusXRSideCount] + [EOculusXRControllerDrivenHandPoseTypesCount]; +}; diff --git a/Plugins/MetaXR/Source/OculusXRInput/Public/OculusXRHandComponent.h b/Plugins/MetaXR/Source/OculusXRInput/Public/OculusXRHandComponent.h new file mode 100644 index 0000000..2c360ef --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRInput/Public/OculusXRHandComponent.h @@ -0,0 +1,100 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +#pragma once +#include "OculusXRInputFunctionLibrary.h" +#include "Components/PoseableMeshComponent.h" +#include "OculusXRHandComponent.generated.h" + +UENUM(BlueprintType) +enum class EOculusXRConfidenceBehavior : uint8 +{ + None, + HideActor +}; + +UENUM(BlueprintType) +enum class EOculusXRSystemGestureBehavior : uint8 +{ + None, + SwapMaterial +}; + +static const FQuat HandRootFixupRotation = FQuat(-0.5f, -0.5f, 0.5f, 0.5f); + +UCLASS(Blueprintable, meta = (BlueprintSpawnableComponent), ClassGroup = OculusHand) +class OCULUSXRINPUT_API UOculusXRHandComponent : public UPoseableMeshComponent +{ + GENERATED_UCLASS_BODY() + +public: + virtual void BeginPlay() override; + + virtual void TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override; + + /** The hand skeleton that will be loaded */ + UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = "HandProperties") + EOculusXRHandType SkeletonType; + + /** The hand mesh that will be applied to the skeleton */ + UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = "HandProperties") + EOculusXRHandType MeshType; + + /** Behavior for when hand tracking loses high confidence tracking */ + UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = "HandProperties") + EOculusXRConfidenceBehavior ConfidenceBehavior = EOculusXRConfidenceBehavior::HideActor; + + /** Behavior for when the system gesture is actived */ + UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = "HandProperties") + EOculusXRSystemGestureBehavior SystemGestureBehavior = EOculusXRSystemGestureBehavior::SwapMaterial; + + /** Material that gets applied to the hands when the system gesture is active */ + UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = "HandProperties") + class UMaterialInterface* SystemGestureMaterial; + + /** Whether or not to initialize physics capsules on the skeletal mesh */ + UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = "HandProperties") + bool bInitializePhysics; + + /** Whether or not the hand scale should update based on values from the runtime to match the users hand scale */ + UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = "HandProperties") + bool bUpdateHandScale; + + /** Material override for the runtime skeletal mesh */ + UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = "HandProperties") + class UMaterialInterface* MaterialOverride; + + /** Bone mapping for custom hand skeletal meshes */ + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "CustomSkeletalMesh") + TMap BoneNameMappings; + + /** List of capsule colliders created for the skeletal mesh */ + UPROPERTY(BlueprintReadOnly, Category = "HandProperties") + TArray CollisionCapsules; + + /** Whether or not the runtime skeletal mesh has been loaded and initialized */ + UPROPERTY(BlueprintReadOnly, Category = "HandProperties") + bool bSkeletalMeshInitialized = false; + +protected: + virtual void SystemGesturePressed(); + virtual void SystemGestureReleased(); + +private: + /** Whether or not this component has authority within the frame */ + bool bHasAuthority; + + /** Whether or not a custom hand mesh is being used */ + bool bCustomHandMesh = false; + + /** Whether or not the physics capsules have been initialized */ + bool bInitializedPhysics = false; + + USkeletalMesh* RuntimeSkeletalMesh; + + UMaterialInterface* CachedBaseMaterial; + + void InitializeSkeletalMesh(); + + void UpdateBonePose(); +}; diff --git a/Plugins/MetaXR/Source/OculusXRInput/Public/OculusXRInputFunctionLibrary.h b/Plugins/MetaXR/Source/OculusXRInput/Public/OculusXRInputFunctionLibrary.h new file mode 100644 index 0000000..970e22d --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRInput/Public/OculusXRInputFunctionLibrary.h @@ -0,0 +1,350 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +#pragma once +#include "CoreMinimal.h" +#include "UObject/ObjectMacros.h" +#include "Components/CapsuleComponent.h" +#include "Kismet/BlueprintFunctionLibrary.h" + +#include "OculusXRInputFunctionLibrary.generated.h" + +UENUM(BlueprintType) +enum class EOculusXRHandType : uint8 +{ + None, + HandLeft, + HandRight, +}; + +UENUM(BlueprintType) +enum class EOculusXRSide : uint8 +{ + None = 0, + Left = 1, + Right = 2, +}; + +const int EOculusXRSideCount = 3; + +UENUM(BlueprintType) +enum class EOculusXRTrackingConfidence : uint8 +{ + Low, + High +}; + +UENUM(BlueprintType) +enum class EOculusXRFinger : uint8 +{ + Thumb, + Index, + Middle, + Ring, + Pinky, + Invalid +}; + +/** +* EOculusXRBone is enum representing the Bone Ids that come from the Oculus Runtime. +*/ +UENUM(BlueprintType) +enum class EOculusXRBone : uint8 +{ + Wrist_Root UMETA(DisplayName = "Wrist Root"), + Hand_Start = Wrist_Root UMETA(DisplayName = "Hand Start"), + Forearm_Stub UMETA(DisplayName = "Forearm Stub"), + Thumb_0 UMETA(DisplayName = "Thumb0"), + Thumb_1 UMETA(DisplayName = "Thumb1"), + Thumb_2 UMETA(DisplayName = "Thumb2"), + Thumb_3 UMETA(DisplayName = "Thumb3"), + Index_1 UMETA(DisplayName = "Index1"), + Index_2 UMETA(DisplayName = "Index2"), + Index_3 UMETA(DisplayName = "Index3"), + Middle_1 UMETA(DisplayName = "Middle1"), + Middle_2 UMETA(DisplayName = "Middle2"), + Middle_3 UMETA(DisplayName = "Middle3"), + Ring_1 UMETA(DisplayName = "Ring1"), + Ring_2 UMETA(DisplayName = "Ring2"), + Ring_3 UMETA(DisplayName = "Ring3"), + Pinky_0 UMETA(DisplayName = "Pinky0"), + Pinky_1 UMETA(DisplayName = "Pinky1"), + Pinky_2 UMETA(DisplayName = "Pinky2"), + Pinky_3 UMETA(DisplayName = "Pinky3"), + Thumb_Tip UMETA(DisplayName = "Thumb Tip"), + Max_Skinnable = Thumb_Tip UMETA(DisplayName = "Max Skinnable"), + Index_Tip UMETA(DisplayName = "Index Tip"), + Middle_Tip UMETA(DisplayName = "Middle Tip"), + Ring_Tip UMETA(DisplayName = "Ring Tip"), + Pinky_Tip UMETA(DisplayName = "Pinky Tip"), + Hand_End UMETA(DisplayName = "Hand End"), + Bone_Max = Hand_End UMETA(DisplayName = "Hand Max"), + Invalid UMETA(DisplayName = "Invalid") +}; + +/** Defines the haptics location of controller hands for tracking. */ +UENUM(BlueprintType) +enum class EOculusXRHandHapticsLocation : uint8 +{ + Hand = 0, // Haptics is applied to the whole controller + Thumb, // Haptics is applied to the thumb finger location + Index, // Haptics is applied to the index finger location + + HandHapticsLocation_Count UMETA(Hidden, DisplayName = ""), +}; + +/** Define how a controllers button touches will be used to generate a hand pose. */ +UENUM(BlueprintType) +enum class EOculusXRControllerDrivenHandPoseTypes : uint8 +{ + None = 0, // Controllers do not generate any hand poses. + Natural, // Controller button inputs will be used to generate a normal hand pose. + Controller, // Controller button inputs will be used to generate a hand pose holding a controller. +}; + +const int EOculusXRControllerDrivenHandPoseTypesCount = 3; + +struct FOculusXRHapticsDesc +{ + FOculusXRHapticsDesc( + EOculusXRHandHapticsLocation ILocation = EOculusXRHandHapticsLocation::Hand, + bool bIAppend = false) + : Location(ILocation), bAppend(bIAppend) + { + } + + void Restart() + { + Location = EOculusXRHandHapticsLocation::Hand; + bAppend = false; + } + EOculusXRHandHapticsLocation Location; + bool bAppend; +}; + +/** +* FOculusXRCapsuleCollider is a struct that contains information on the physics/collider capsules created by the runtime for hands. +* +* @var Capsule The UCapsuleComponent that is the collision capsule on the bone. Use this to register for overlap/collision events +* @var BoneIndex The Bone that this collision capsule is parented to. Corresponds to the EOculusXRBone enum. +* +*/ +USTRUCT(BlueprintType) +struct OCULUSXRINPUT_API FOculusXRCapsuleCollider +{ + GENERATED_BODY() + +public: + UPROPERTY(BlueprintReadOnly, Category = "OculusLibrary|HandTracking") + UCapsuleComponent* Capsule = nullptr; + + UPROPERTY(BlueprintReadOnly, Category = "OculusLibrary|HandTracking") + EOculusXRBone BoneId = EOculusXRBone::Wrist_Root; +}; + +UCLASS() +class OCULUSXRINPUT_API UOculusXRInputFunctionLibrary : public UBlueprintFunctionLibrary +{ + GENERATED_UCLASS_BODY() + +public: + UFUNCTION(BlueprintCallable, Category = "OculusLibrary|HandTracking") + static EOculusXRFinger ConvertBoneToFinger(const EOculusXRBone Bone); + + DECLARE_MULTICAST_DELEGATE_FourParams(FHandMovementFilterDelegate, EControllerHand, FVector*, FRotator*, bool*); + static FHandMovementFilterDelegate HandMovementFilter; /// Called to modify Hand position and orientation whenever it is queried + + /** + * Creates a new runtime hand skeletal mesh. + * + * @param HandSkeletalMesh (out) Skeletal Mesh object that will be used for the runtime hand mesh + * @param SkeletonType (in) The skeleton type that will be used for generating the hand bones + * @param MeshType (in) The mesh type that will be used for generating the hand mesh + * @param WorldTometers (in) Optional change to the world to meters conversion value + */ + UFUNCTION(BlueprintCallable, Category = "OculusLibrary|HandTracking") + static bool GetHandSkeletalMesh(USkeletalMesh* HandSkeletalMesh, EOculusXRHandType SkeletonType, EOculusXRHandType MeshType, const float WorldToMeters = 100.0f); + + /** + * Initializes physics capsules for collision and physics on the runtime mesh + * + * @param SkeletonType (in) The skeleton type that will be used to generated the capsules + * @param HandComponent (in) The skinned mesh component that the capsules will be attached to + * @param WorldTometers (in) Optional change to the world to meters conversion value + */ + UFUNCTION(BlueprintCallable, Category = "OculusLibrary|HandTracking") + static TArray InitializeHandPhysics(EOculusXRHandType SkeletonType, USkinnedMeshComponent* HandComponent, const float WorldToMeters = 100.0f); + + /** + * Get the rotation of a specific bone + * + * @param DeviceHand (in) The hand to get the rotations from + * @param BoneId (in) The specific bone to get the rotation from + * @param ControllerIndex (in) Optional different controller index + */ + UFUNCTION(BlueprintPure, Category = "OculusLibrary|HandTracking") + static FQuat GetBoneRotation(const EOculusXRHandType DeviceHand, const EOculusXRBone BoneId, const int32 ControllerIndex = 0); + + /** + * Get the pointer pose + * + * @param DeviceHand (in) The hand to get the pointer pose from + * @param ControllerIndex (in) Optional different controller index + */ + UFUNCTION(BlueprintPure, Category = "OculusLibrary|HandTracking") + static FTransform GetPointerPose(const EOculusXRHandType DeviceHand, const int32 ControllerIndex = 0); + + /** + * Check if the pointer pose is a valid pose + * + * @param DeviceHand (in) The hand to get the pointer status from + * @param ControllerIndex (in) Optional different controller index + */ + UFUNCTION(BlueprintPure, Category = "OculusLibrary|HandTracking") + static bool IsPointerPoseValid(const EOculusXRHandType DeviceHand, const int32 ControllerIndex = 0); + + /** + * Get the tracking confidence of the hand + * + * @param DeviceHand (in) The hand to get tracking confidence of + * @param ControllerIndex (in) Optional different controller index + */ + UFUNCTION(BlueprintPure, Category = "OculusLibrary|HandTracking") + static EOculusXRTrackingConfidence GetTrackingConfidence(const EOculusXRHandType DeviceHand, const int32 ControllerIndex = 0); + + /** + * Get the tracking confidence of a finger + * + * @param DeviceHand (in) The hand to get tracking confidence of + * @param ControllerIndex (in) Optional different controller index + * @param Finger (in) The finger to get tracking confidence of + */ + UFUNCTION(BlueprintPure, Category = "OculusLibrary|HandTracking") + static EOculusXRTrackingConfidence GetFingerTrackingConfidence(const EOculusXRHandType DeviceHand, const EOculusXRFinger Finger, const int32 ControllerIndex = 0); + + /** + * Get the scale of the hand + * + * @param DeviceHand (in) The hand to get scale of + * @param ControllerIndex (in) Optional different controller index + */ + UFUNCTION(BlueprintPure, Category = "OculusLibrary|HandTracking") + static float GetHandScale(const EOculusXRHandType DeviceHand, const int32 ControllerIndex = 0); + + /** + * Get the user's dominant hand + * + * @param ControllerIndex (in) Optional different controller index + */ + UFUNCTION(BlueprintPure, Category = "OculusLibrary|HandTracking") + static EOculusXRHandType GetDominantHand(const int32 ControllerIndex = 0); + + /** + * Check if hand tracking is enabled currently + */ + UFUNCTION(BlueprintPure, Category = "OculusLibrary|HandTracking") + static bool IsHandTrackingEnabled(); + + /** + * Check if the hand position is valid + * + * @param DeviceHand (in) The hand to get the position from + * @param ControllerIndex (in) Optional different controller index + */ + UFUNCTION(BlueprintPure, Category = "OculusLibrary|HandTracking") + static bool IsHandPositionValid(const EOculusXRHandType DeviceHand, const int32 ControllerIndex = 0); + + /** + * Get the bone name from the bone index + * + * @param BoneIndex (in) Bone index to get the name of + */ + UFUNCTION(BlueprintPure, Category = "OculusLibrary|HandTracking") + static FString GetBoneName(EOculusXRBone BoneId); + + /** + * Play a haptic feedback curve on the player's controller with location support. + * The curve data will be sampled and sent to controller to vibrate a specific location at each frame. + * @param HapticEffect The haptic effect to play + * @param Hand Which hand to play the effect on + * @param Location Which hand location to play the effect on + * @param Scale Scale between 0.0 and 1.0 on the intensity of playback + */ + UFUNCTION(BlueprintCallable, Category = "OculusLibrary|Controller") + static void PlayCurveHapticEffect(class UHapticFeedbackEffect_Curve* HapticEffect, EControllerHand Hand, EOculusXRHandHapticsLocation Location = EOculusXRHandHapticsLocation::Hand, float Scale = 1.f, bool bLoop = false); + + /** + * Play a haptic feedback buffer on the player's controller with location support. + * In each frame, the buffer data will be sampled and the individual sampled data will be sent to controller to vibrate a specific location. + * @param HapticEffect The haptic effect to play + * @param Hand Which hand to play the effect on + * @param Location Which hand location to play the effect on + * @param Scale Scale between 0.0 and 1.0 on the intensity of playback + */ + UFUNCTION(BlueprintCallable, Category = "OculusLibrary|Controller") + static void PlayBufferHapticEffect(class UHapticFeedbackEffect_Buffer* HapticEffect, EControllerHand Hand, EOculusXRHandHapticsLocation Location = EOculusXRHandHapticsLocation::Hand, float Scale = 1.f, bool bLoop = false); + + /** + * Play a haptic feedback buffer on the player's controller. + * All buffer data will be sent to controller together in one frame. + * Data duration should be no greater than controller's maximum haptics duration which can be queried with GetMaxHapticDuration. + * @param HapticEffect The haptic effect to play + * @param Hand Which hand to play the effect on + */ + UFUNCTION(BlueprintCallable, Category = "OculusLibrary|Controller") + static void PlayAmplitudeEnvelopeHapticEffect(class UHapticFeedbackEffect_Buffer* HapticEffect, EControllerHand Hand); + + /** + * Play a haptic feedback soundwave on the player's controller. + * In each frame, the soundwave data will be split into a batch of data and sent to controller. + * The data duration of each frame is equal to controller's maximum haptics duration which can be queried with GetMaxHapticDuration. + * @param HapticEffect The haptic effect to play + * @param Hand Which hand to play the effect on + * @param bAppend False: any existing samples will be cleared and a new haptic effect will begin; True: samples will be appended to the currently playing effect + * @param Scale Scale between 0.0 and 1.0 on the intensity of playback + */ + UFUNCTION(BlueprintCallable, Category = "OculusLibrary|Controller") + static void PlaySoundWaveHapticEffect(class UHapticFeedbackEffect_SoundWave* HapticEffect, EControllerHand Hand, bool bAppend = false, float Scale = 1.f, bool bLoop = false); + + /** + * Stops a playing haptic feedback curve at a specific location. + * @param HapticEffect The haptic effect to stop + * @param Hand Which hand to stop the effect for + * @param Location Which hand location to play the effect on + */ + UFUNCTION(BlueprintCallable, Category = "OculusLibrary|Controller") + static void StopHapticEffect(EControllerHand Hand, EOculusXRHandHapticsLocation Location = EOculusXRHandHapticsLocation::Hand); + + /** + * Set the value of the haptics for the specified hand and location directly, using frequency and amplitude. NOTE: If a curve is already + * playing for this hand, it will be cancelled in favour of the specified values. + * + * @param Frequency The normalized frequency [0.0, 1.0] to play through the haptics system + * @param Amplitude The normalized amplitude [0.0, 1.0] to set the haptic feedback to + * @param Hand Which hand to play the effect on + * @param Location Which hand location to play the effect on + */ + UFUNCTION(BlueprintCallable, Category = "OculusLibrary|Controller") + static void SetHapticsByValue(const float Frequency, const float Amplitude, EControllerHand Hand, EOculusXRHandHapticsLocation Location = EOculusXRHandHapticsLocation::Hand); + + /** + * Get the controller haptics sample rate. + * @param Hand Which hand to play the effect on + */ + UFUNCTION(BlueprintCallable, Category = "OculusLibrary|Controller") + static float GetControllerSampleRateHz(EControllerHand Hand); + + /** + * Get the maximum duration (in seconds) that the controller haptics can handle each time. + * @param Hand Which hand to play the effect on + */ + UFUNCTION(BlueprintCallable, Category = "OculusLibrary|Controller") + static int GetMaxHapticDuration(EControllerHand Hand); + + /** + * Set if / how controller inputs are used to build a syntheic hand pose. + * @param Type How the hand should be posed. + */ + UFUNCTION(BlueprintCallable, Category = "OculusLibrary|Controller") + static void SetControllerDrivenHandPoses(EOculusXRControllerDrivenHandPoseTypes Type); +}; diff --git a/Plugins/MetaXR/Source/OculusXRMR/OculusXRMR.Build.cs b/Plugins/MetaXR/Source/OculusXRMR/OculusXRMR.Build.cs new file mode 100644 index 0000000..738db6d --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRMR/OculusXRMR.Build.cs @@ -0,0 +1,77 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +namespace UnrealBuildTool.Rules +{ + public class OculusXRMR : ModuleRules + { + public OculusXRMR(ReadOnlyTargetRules Target) : base(Target) + { + bUseUnity = true; + + PrivateIncludePathModuleNames.AddRange( + new string[] + { + "InputDevice", // For IInputDevice.h + "HeadMountedDisplay", // For IMotionController.h + "ImageWrapper", + "Engine" + }); + + PrivateDependencyModuleNames.AddRange( + new string[] + { + "Core", + "CoreUObject", + "Engine", + "InputCore", + "Slate", + "SlateCore", + "RHI", + "VulkanRHI", + "RenderCore", + "MediaAssets", + "HeadMountedDisplay", + "OculusXRHMD", + "OVRPluginXR", + }); + + if (Target.Version.MajorVersion > 5 || (Target.Version.MajorVersion == 5 && Target.Version.MinorVersion >= 3)) + { + PrivateDependencyModuleNames.AddRange( + new string[] + { + "XRBase", + }); + } + + PrivateIncludePaths.AddRange( + new string[] { + "OculusXRHMD/Private", + "OculusXRInput/Private", + }); + + PublicIncludePaths.AddRange( + new string[] { + "Runtime/Renderer/Private", + "Runtime/Engine/Classes/Components", + "Runtime/MediaAssets/Private", + }); + + if (Target.Platform == UnrealTargetPlatform.Win64) + { + PublicDelayLoadDLLs.Add("OVRPluginXR.dll"); + } + + if (Target.Platform == UnrealTargetPlatform.Android) + { + AddEngineThirdPartyPrivateStaticDependencies(Target, "Vulkan"); + } + + if (Target.bBuildEditor == true) + { + PrivateDependencyModuleNames.Add("UnrealEd"); + } + } + } +} diff --git a/Plugins/MetaXR/Source/OculusXRMR/Private/OculusXRMRFunctionLibrary.cpp b/Plugins/MetaXR/Source/OculusXRMR/Private/OculusXRMRFunctionLibrary.cpp new file mode 100644 index 0000000..f1a8765 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRMR/Private/OculusXRMRFunctionLibrary.cpp @@ -0,0 +1,180 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +#include "OculusXRMRFunctionLibrary.h" +#include "OculusXRMRPrivate.h" +#include "OculusXRMRModule.h" +#include "OculusXRMR_CastingCameraActor.h" +#include "OculusXRMR_State.h" +#include "OculusXRHMD.h" +#include "OculusXRHMDPrivate.h" +#include "IHeadMountedDisplay.h" + +#include "GameFramework/Pawn.h" +#include "GameFramework/PlayerController.h" + +//------------------------------------------------------------------------------------------------- +// UOculusXRFunctionLibrary +//------------------------------------------------------------------------------------------------- + +UOculusXRMRFunctionLibrary::UOculusXRMRFunctionLibrary(const FObjectInitializer& ObjectInitializer) + : Super(ObjectInitializer) +{ +} + +void UOculusXRMRFunctionLibrary::GetAllTrackedCamera(TArray& TrackedCameras, bool bCalibratedOnly) +{ + TrackedCameras.Empty(); + + if (!FOculusXRMRModule::IsAvailable() || !FOculusXRMRModule::Get().IsInitialized()) + { + UE_LOG(LogMR, Error, TEXT("OculusXRMR not available")); + return; + } + + if (FOculusXRHMDModule::GetPluginWrapper().GetInitialized() == ovrpBool_False) + { + UE_LOG(LogMR, Error, TEXT("OVRPlugin not initialized")); + return; + } + + if (OVRP_FAILURE(FOculusXRHMDModule::GetPluginWrapper().UpdateExternalCamera())) + { + UE_LOG(LogMR, Error, TEXT("FOculusXRHMDModule::GetPluginWrapper().UpdateExternalCamera failure")); + return; + } + + int cameraCount = 0; + if (OVRP_FAILURE(FOculusXRHMDModule::GetPluginWrapper().GetExternalCameraCount(&cameraCount))) + { + UE_LOG(LogMR, Log, TEXT("FOculusXRHMDModule::GetPluginWrapper().GetExternalCameraCount failure")); + return; + } + + for (int i = 0; i < cameraCount; ++i) + { + char cameraName[OVRP_EXTERNAL_CAMERA_NAME_SIZE]; + ovrpCameraIntrinsics cameraIntrinsics; + ovrpCameraExtrinsics cameraExtrinsics; + FOculusXRHMDModule::GetPluginWrapper().GetExternalCameraName(i, cameraName); + FOculusXRHMDModule::GetPluginWrapper().GetExternalCameraIntrinsics(i, &cameraIntrinsics); + FOculusXRHMDModule::GetPluginWrapper().GetExternalCameraExtrinsics(i, &cameraExtrinsics); + if ((bCalibratedOnly == false || cameraExtrinsics.CameraStatus == ovrpCameraStatus_Calibrated) && cameraIntrinsics.IsValid && cameraExtrinsics.IsValid) + { + FOculusXRTrackedCamera camera; + camera.Index = i; + camera.Name = cameraName; + camera.FieldOfView = FMath::RadiansToDegrees(FMath::Atan(cameraIntrinsics.FOVPort.LeftTan) + FMath::Atan(cameraIntrinsics.FOVPort.RightTan)); + camera.SizeX = cameraIntrinsics.ImageSensorPixelResolution.w; + camera.SizeY = cameraIntrinsics.ImageSensorPixelResolution.h; + camera.AttachedTrackedDevice = OculusXRHMD::ToEOculusXRTrackedDeviceType(cameraExtrinsics.AttachedToNode); + OculusXRHMD::FPose Pose; + GetOculusXRHMD()->ConvertPose(cameraExtrinsics.RelativePose, Pose); + camera.CalibratedRotation = Pose.Orientation.Rotator(); + camera.CalibratedOffset = Pose.Position; + camera.UserRotation = FRotator::ZeroRotator; + camera.UserOffset = FVector::ZeroVector; + TrackedCameras.Add(camera); + } + } +} + +OculusXRHMD::FOculusXRHMD* UOculusXRMRFunctionLibrary::GetOculusXRHMD() +{ +#if OCULUS_HMD_SUPPORTED_PLATFORMS + if (GEngine && GEngine->XRSystem.IsValid()) + { + static const FName OculusSystemName(TEXT("OculusXRHMD")); + if (GEngine->XRSystem->GetSystemName() == OculusSystemName) + { + return static_cast(GEngine->XRSystem.Get()); + } + } +#endif + return nullptr; +} + +bool UOculusXRMRFunctionLibrary::GetTrackingReferenceLocationAndRotationInWorldSpace(USceneComponent* TrackingReferenceComponent, FVector& TRLocation, FRotator& TRRotation) +{ + if (!TrackingReferenceComponent) + { + APlayerController* PlayerController = GWorld->GetFirstPlayerController(); + if (!PlayerController) + { + return false; + } + APawn* Pawn = PlayerController->GetPawn(); + if (!Pawn) + { + return false; + } + TRLocation = Pawn->GetActorLocation(); + TRRotation = Pawn->GetActorRotation(); + return true; + } + else + { + TRLocation = TrackingReferenceComponent->GetComponentLocation(); + TRRotation = TrackingReferenceComponent->GetComponentRotation(); + return true; + } +} + +UOculusXRMR_Settings* UOculusXRMRFunctionLibrary::GetOculusXRMRSettings() +{ + UOculusXRMR_Settings* Settings = nullptr; + if (FOculusXRMRModule::IsAvailable()) + { + Settings = FOculusXRMRModule::Get().GetMRSettings(); + } + return Settings; +} + +USceneComponent* UOculusXRMRFunctionLibrary::GetTrackingReferenceComponent() +{ + USceneComponent* TrackingRef = nullptr; + if (FOculusXRMRModule::IsAvailable()) + { + TrackingRef = FOculusXRMRModule::Get().GetMRState()->TrackingReferenceComponent; + } + return TrackingRef; +} + +bool UOculusXRMRFunctionLibrary::SetTrackingReferenceComponent(USceneComponent* Component) +{ + if (FOculusXRMRModule::IsAvailable()) + { + FOculusXRMRModule::Get().GetMRState()->TrackingReferenceComponent = Component; + return true; + } + return false; +} + +float UOculusXRMRFunctionLibrary::GetMrcScalingFactor() +{ + if (FOculusXRMRModule::IsAvailable()) + { + return FOculusXRMRModule::Get().GetMRState()->ScalingFactor; + } + return 0.0; +} + +bool UOculusXRMRFunctionLibrary::SetMrcScalingFactor(float ScalingFactor) +{ + if (FOculusXRMRModule::IsAvailable() && ScalingFactor > 0.0f) + { + FOculusXRMRModule::Get().GetMRState()->ScalingFactor = ScalingFactor; + return true; + } + return false; +} + +bool UOculusXRMRFunctionLibrary::IsMrcEnabled() +{ + return FOculusXRMRModule::IsAvailable() && FOculusXRMRModule::Get().IsInitialized(); +} + +bool UOculusXRMRFunctionLibrary::IsMrcActive() +{ + return FOculusXRMRModule::IsAvailable() && FOculusXRMRModule::Get().IsActive(); +} diff --git a/Plugins/MetaXR/Source/OculusXRMR/Private/OculusXRMRModule.cpp b/Plugins/MetaXR/Source/OculusXRMR/Private/OculusXRMRModule.cpp new file mode 100644 index 0000000..7a9a62c --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRMR/Private/OculusXRMRModule.cpp @@ -0,0 +1,537 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. +#include "OculusXRMRModule.h" + +#include "Engine/Engine.h" +#include "ISpectatorScreenController.h" +#include "IXRTrackingSystem.h" +#include "StereoRendering.h" +#include "StereoRenderTargetManager.h" +#include "SceneCaptureComponent2D.h" +#include "Engine/TextureRenderTarget2D.h" +#include "EngineUtils.h" +#include "PostProcess/SceneRenderTargets.h" +#include "Kismet/GameplayStatics.h" +#include "OculusXRHMDModule.h" +#include "OculusXRHMD.h" +#include "OculusXRMRFunctionLibrary.h" +#include "OculusXRMRPrivate.h" +#include "OculusXRMR_Settings.h" +#include "OculusXRMR_State.h" +#include "OculusXRMR_CastingCameraActor.h" +#include "AudioDevice.h" +#if PLATFORM_ANDROID +#include "IVulkanDynamicRHI.h" +#endif + +#if WITH_EDITOR +#include "Editor.h" // for FEditorDelegates::PostPIEStarted +#endif + +#define LOCTEXT_NAMESPACE "OculusXRMR" + +FOculusXRMRModule::FOculusXRMRModule() + : bInitialized(false) + , MRSettings(nullptr) + , MRState(nullptr) + , MRActor(nullptr) + , CurrentWorld(nullptr) + , WorldAddedEventBinding() + , WorldDestroyedEventBinding() + , WorldLoadEventBinding() +#if PLATFORM_ANDROID + , bActivated(false) + , InitialWorldAddedEventBinding() + , InitialWorldLoadEventBinding() + , PreWorldTickEventBinding() +#endif +#if WITH_EDITOR + , PieBeginEventBinding() + , PieStartedEventBinding() + , PieEndedEventBinding() +#endif +{ +} + +FOculusXRMRModule::~FOculusXRMRModule() +{ +} + +void FOculusXRMRModule::StartupModule() +{ +#if OCULUS_MR_SUPPORTED_PLATFORMS +#if PLATFORM_WINDOWS + const TCHAR* CmdLine = FCommandLine::Get(); + const bool bAutoOpenFromParams = FParse::Param(CmdLine, TEXT("mixedreality")); + + if (bAutoOpenFromParams && FOculusXRHMDModule::Get().PreInit()) + { + if (FOculusXRHMDModule::GetPluginWrapper().GetInitialized()) + { + if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().InitializeMixedReality())) + { + InitMixedRealityCapture(); + } + else + { + UE_LOG(LogMR, Error, TEXT("ovrp_InitializeMixedReality() failed")); + } + } + else + { + UE_LOG(LogMR, Error, TEXT("OVRPlugin has not been initialized")); + } + } +#elif PLATFORM_ANDROID + // On Android, FOculusXRHMDModule::GetPluginWrapper().Media_Initialize() needs OVRPlugin to be initialized first, so we should handle that when the world is created + if (GEngine) + { + InitialWorldAddedEventBinding = GEngine->OnWorldAdded().AddRaw(this, &FOculusXRMRModule::OnInitialWorldCreated); + } + InitialWorldLoadEventBinding = FCoreUObjectDelegates::PostLoadMapWithWorld.AddRaw(this, &FOculusXRMRModule::OnInitialWorldCreated); +#endif // PLATFORM_WINDOWS || PLATFORM_ANDROID +#endif // OCULUS_MR_SUPPORTED_PLATFORMS +} + +void FOculusXRMRModule::ShutdownModule() +{ +#if OCULUS_MR_SUPPORTED_PLATFORMS + if (bInitialized) + { + if (GEngine) + { + GEngine->OnWorldAdded().Remove(WorldAddedEventBinding); + GEngine->OnWorldDestroyed().Remove(WorldDestroyedEventBinding); + FCoreUObjectDelegates::PostLoadMapWithWorld.Remove(WorldLoadEventBinding); +#if WITH_EDITOR + FEditorDelegates::PostPIEStarted.Remove(PieStartedEventBinding); + FEditorDelegates::PrePIEEnded.Remove(PieEndedEventBinding); +#else + // Stop casting and close camera with module if it's the game + MRSettings->SetIsCasting(false); +#endif + } +#if PLATFORM_ANDROID + ovrpBool mediaInit = false; + if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().Media_GetInitialized(&mediaInit)) && mediaInit == ovrpBool_True) + { + FOculusXRHMDModule::GetPluginWrapper().Media_Shutdown(); + } +#endif + FOculusXRHMDModule::GetPluginWrapper().ShutdownMixedReality(); + + if (MRSettings->IsRooted()) + { + MRSettings->RemoveFromRoot(); + } + if (MRState->IsRooted()) + { + MRState->RemoveFromRoot(); + } + } +#if PLATFORM_ANDROID + if (InitialWorldAddedEventBinding.IsValid() && GEngine) + { + GEngine->OnWorldAdded().Remove(InitialWorldAddedEventBinding); + InitialWorldAddedEventBinding.Reset(); + } + if (InitialWorldLoadEventBinding.IsValid()) + { + FCoreUObjectDelegates::PostLoadMapWithWorld.Remove(InitialWorldLoadEventBinding); + InitialWorldLoadEventBinding.Reset(); + } +#endif +#endif // OCULUS_MR_SUPPORTED_PLATFORMS +} + +bool FOculusXRMRModule::IsActive() +{ + bool bReturn = bInitialized && MRSettings && MRSettings->GetIsCasting(); +#if PLATFORM_ANDROID + bReturn = bReturn && bActivated; +#endif + return bReturn; +} + +UOculusXRMR_Settings* FOculusXRMRModule::GetMRSettings() +{ + return MRSettings; +} + +UOculusXRMR_State* FOculusXRMRModule::GetMRState() +{ + return MRState; +} + +void FOculusXRMRModule::OnWorldCreated(UWorld* NewWorld) +{ +#if PLATFORM_WINDOWS +#if WITH_EDITORONLY_DATA + const bool bIsGameInst = !IsRunningCommandlet() && NewWorld->IsGameWorld(); + if (bIsGameInst) +#endif + { + CurrentWorld = NewWorld; + SetupInGameCapture(); + } +#endif +#if PLATFORM_ANDROID + CurrentWorld = NewWorld; + // Check MRC activation state initially when loading world + ChangeCaptureState(); + // Poll MRC activation state for future changes + PreWorldTickEventBinding = FWorldDelegates::OnWorldPreActorTick.AddRaw(this, &FOculusXRMRModule::OnWorldTick); +#endif +} + +void FOculusXRMRModule::OnWorldDestroyed(UWorld* NewWorld) +{ + CurrentWorld = nullptr; +#if PLATFORM_ANDROID + if (PreWorldTickEventBinding.IsValid()) + { + FWorldDelegates::OnWorldPreActorTick.Remove(PreWorldTickEventBinding); + PreWorldTickEventBinding.Reset(); + } +#endif // PLATFORM_ANDROID +} + +void FOculusXRMRModule::InitMixedRealityCapture() +{ + bInitialized = true; + + MRSettings = NewObject((UObject*)GetTransientPackage(), FName("OculusXRMR_Settings"), RF_MarkAsRootSet); + MRState = NewObject((UObject*)GetTransientPackage(), FName("OculusXRMR_State"), RF_MarkAsRootSet); + + // Always bind the event handlers in case devs call them without MRC on + MRSettings->TrackedCameraIndexChangeDelegate.BindRaw(this, &FOculusXRMRModule::OnTrackedCameraIndexChanged); + MRSettings->CompositionMethodChangeDelegate.BindRaw(this, &FOculusXRMRModule::OnCompositionMethodChanged); + MRSettings->IsCastingChangeDelegate.BindRaw(this, &FOculusXRMRModule::OnIsCastingChanged); + + ResetSettingsAndState(); + + WorldAddedEventBinding = GEngine->OnWorldAdded().AddRaw(this, &FOculusXRMRModule::OnWorldCreated); + WorldDestroyedEventBinding = GEngine->OnWorldDestroyed().AddRaw(this, &FOculusXRMRModule::OnWorldDestroyed); + WorldLoadEventBinding = FCoreUObjectDelegates::PostLoadMapWithWorld.AddRaw(this, &FOculusXRMRModule::OnWorldCreated); + +#if WITH_EDITOR + // Bind events on PIE start/end to open/close camera + PieBeginEventBinding = FEditorDelegates::BeginPIE.AddRaw(this, &FOculusXRMRModule::OnPieBegin); + PieStartedEventBinding = FEditorDelegates::PostPIEStarted.AddRaw(this, &FOculusXRMRModule::OnPieStarted); + PieEndedEventBinding = FEditorDelegates::PrePIEEnded.AddRaw(this, &FOculusXRMRModule::OnPieEnded); +#else // WITH_EDITOR + // Start casting and open camera with the module if it's the game + MRSettings->SetIsCasting(true); +#endif // WITH_EDITOR +} + +void FOculusXRMRModule::SetupExternalCamera() +{ + using namespace OculusXRHMD; + + if (!MRSettings->GetIsCasting()) + { + return; + } + + // Always request the MRC actor to handle a camera state change on its end + MRState->ChangeCameraStateRequested = true; +} + +void FOculusXRMRModule::SetupInGameCapture() +{ + // Don't do anything if we don't have a UWorld or if we are not casting + if (CurrentWorld == nullptr || !MRSettings->GetIsCasting()) + { + return; + } + + // Set the bind camera request to true + MRState->BindToTrackedCameraIndexRequested = true; + + // Don't add another actor if there's already a MRC camera actor + for (TActorIterator ActorIt(CurrentWorld); ActorIt; ++ActorIt) + { + if (IsValidChecked(*ActorIt) && !ActorIt->IsUnreachable() && ActorIt->IsValidLowLevel()) + { + MRActor = *ActorIt; + return; + } + } + + // Spawn an MRC camera actor if one wasn't already there + MRActor = CurrentWorld->SpawnActorDeferred(AOculusXRMR_CastingCameraActor::StaticClass(), FTransform::Identity); + MRActor->InitializeStates(MRSettings, MRState); + UGameplayStatics::FinishSpawningActor(MRActor, FTransform::Identity); +} + +void FOculusXRMRModule::CloseInGameCapture() +{ + // Destory actor and close the camera when we turn MRC off + if (MRActor != nullptr && MRActor->GetWorld() != nullptr) + { + MRActor->Destroy(); + MRActor = nullptr; + } +} + +void FOculusXRMRModule::ResetSettingsAndState() +{ + // Reset MR State + MRState->TrackedCamera = FOculusXRTrackedCamera(); + MRState->TrackingReferenceComponent = nullptr; + MRState->ChangeCameraStateRequested = false; + MRState->BindToTrackedCameraIndexRequested = false; + + // Reset MR Settings + const bool bAutoOpenInExternalComposition = FParse::Param(FCommandLine::Get(), TEXT("externalcomposition")); + MRSettings->BindToTrackedCameraIndexIfAvailable(0); + MRSettings->LoadFromIni(); + + // Save right after load to write defaults to the config if they weren't already there + MRSettings->SaveToIni(); + + if (bAutoOpenInExternalComposition) + { + MRSettings->CompositionMethod = EOculusXRMR_CompositionMethod::ExternalComposition; + } +} + +#if PLATFORM_ANDROID +void FOculusXRMRModule::ChangeCaptureState() +{ + ovrpBool activated; + // Set up or close in-game capture when activation state changes + if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().Media_Update()) && OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().Media_IsMrcActivated(&activated)) && activated == ovrpBool_True) + { + if (!bActivated) + { + UE_LOG(LogMR, Log, TEXT("Activating MR Capture")) + bActivated = true; + + // UE resizes the main scene color and depth targets to the maximum dimensions of all rendertargets, + // which causes rendering issues if it doesn't match the compositor-allocated eye textures. This is + // a hacky fix by making sure that the scene capture rendertarget is no larger than the eye. + int frameWidth; + int frameHeight; + FOculusXRHMDModule::GetPluginWrapper().Media_GetMrcFrameSize(&frameWidth, &frameHeight); + uint32 maxWidth = frameWidth / 2; + uint32 maxHeight = frameHeight; + IStereoRenderTargetManager* const StereoRenderTargetManager = GEngine->StereoRenderingDevice->GetRenderTargetManager(); + if (StereoRenderTargetManager) + { + StereoRenderTargetManager->CalculateRenderTargetSize(*(FViewport*)GEngine->GameViewport->GetGameViewport(), maxWidth, maxHeight); + } + maxWidth *= 2; + frameWidth = frameWidth > maxWidth ? maxWidth : frameWidth; + frameHeight = frameHeight > maxHeight ? maxHeight : frameHeight; + FOculusXRHMDModule::GetPluginWrapper().Media_SetMrcFrameSize(frameWidth, frameHeight); + UE_LOG(LogMR, Log, TEXT("MRC Frame width: %d height %d"), frameWidth, frameHeight); + + SetupInGameCapture(); + } + } + else + { + if (bActivated) + { + UE_LOG(LogMR, Log, TEXT("Deactivating MR Capture")) + bActivated = false; + CloseInGameCapture(); + } + } +} + +void FOculusXRMRModule::OnWorldTick(UWorld* World, ELevelTick Tick, float Delta) +{ + // Poll MRC activation state + if (CurrentWorld && World == CurrentWorld) + { + ChangeCaptureState(); + } +} + +void FOculusXRMRModule::OnInitialWorldCreated(UWorld* NewWorld) +{ + // Remove the initial world load handlers + if (InitialWorldAddedEventBinding.IsValid()) + { + GEngine->OnWorldAdded().Remove(InitialWorldAddedEventBinding); + InitialWorldAddedEventBinding.Reset(); + } + if (InitialWorldLoadEventBinding.IsValid()) + { + FCoreUObjectDelegates::PostLoadMapWithWorld.Remove(InitialWorldLoadEventBinding); + InitialWorldLoadEventBinding.Reset(); + } + + // Initialize and check if MRC is enabled + if (FOculusXRHMDModule::Get().PreInit()) + { + if (FOculusXRHMDModule::GetPluginWrapper().GetInitialized()) + { + if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().InitializeMixedReality())) + { + ovrpBool mrcEnabled; + + if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().Media_Initialize())) + { + UE_LOG(LogMR, Log, TEXT("MRC Initialized")); + + if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().Media_IsMrcEnabled(&mrcEnabled)) && mrcEnabled == ovrpBool_True) + { + UE_LOG(LogMR, Log, TEXT("MRC Enabled")); + + // Find a free queue index for vulkan + if (RHIGetInterfaceType() == ERHIInterfaceType::Vulkan) + { + unsigned int queueIndex = 0; + ExecuteOnRenderThread([&queueIndex]() { + ExecuteOnRHIThread([&queueIndex]() { + const uint32 GraphicsQueueIndex = GetIVulkanDynamicRHI()->RHIGetGraphicsQueueIndex(); + if (GraphicsQueueIndex == queueIndex) + { + ++queueIndex; + } + }); + }); + FOculusXRHMDModule::GetPluginWrapper().Media_SetAvailableQueueIndexVulkan(queueIndex); + } + + FOculusXRHMDModule::GetPluginWrapper().Media_SetMrcInputVideoBufferType(ovrpMediaInputVideoBufferType_TextureHandle); + + FAudioDeviceHandle AudioDevice = FAudioDevice::GetMainAudioDevice(); + if (AudioDevice.GetAudioDevice()) + { + float SampleRate = AudioDevice->GetSampleRate(); + FOculusXRHMDModule::GetPluginWrapper().Media_SetMrcAudioSampleRate((int)SampleRate); + } + + InitMixedRealityCapture(); + OnWorldCreated(NewWorld); + } + else + { + // Shut down if MRC not enabled or the media couldn't be enabled + FOculusXRHMDModule::GetPluginWrapper().Media_Shutdown(); + FOculusXRHMDModule::GetPluginWrapper().ShutdownMixedReality(); + } + } + else + { + // Shut down if MRC not enabled or the media couldn't be enabled + FOculusXRHMDModule::GetPluginWrapper().ShutdownMixedReality(); + } + } + else + { + UE_LOG(LogMR, Error, TEXT("ovrp_InitializeMixedReality() failed")); + } + } + else + { + UE_LOG(LogMR, Error, TEXT("OVRPlugin has not been initialized")); + } + } +} +#endif + +void FOculusXRMRModule::OnTrackedCameraIndexChanged(int OldVal, int NewVal) +{ + if (OldVal == NewVal) + { + return; + } + MRState->BindToTrackedCameraIndexRequested = true; +} + +void FOculusXRMRModule::OnCompositionMethodChanged(EOculusXRMR_CompositionMethod OldVal, EOculusXRMR_CompositionMethod NewVal) +{ + if (OldVal == NewVal) + { + return; + } + SetupExternalCamera(); +} + +void FOculusXRMRModule::OnIsCastingChanged(bool OldVal, bool NewVal) +{ + if (OldVal == NewVal) + { + return; + } + if (NewVal == true) + { +#if PLATFORM_ANDROID + FOculusXRHMDModule::GetPluginWrapper().Media_SetMrcActivationMode(ovrpMediaMrcActivationMode_Automatic); +#endif + // Initialize everything again if we turn MRC on + SetupExternalCamera(); + SetupInGameCapture(); + } + else + { +#if PLATFORM_ANDROID + FOculusXRHMDModule::GetPluginWrapper().Media_SetMrcActivationMode(ovrpMediaMrcActivationMode_Disabled); +#endif + CloseInGameCapture(); + } +} + +void FOculusXRMRModule::OnUseDynamicLightingChanged(bool OldVal, bool NewVal) +{ + if (OldVal == NewVal) + { + return; + } + SetupExternalCamera(); +} + +void FOculusXRMRModule::OnDepthQualityChanged(EOculusXRMR_DepthQuality OldVal, EOculusXRMR_DepthQuality NewVal) +{ + if (OldVal == NewVal) + { + return; + } + SetupExternalCamera(); +} + +#if WITH_EDITOR +void FOculusXRMRModule::OnPieBegin(bool bIsSimulating) +{ + // Reset all the parameters and start casting when PIE starts but before the game is initialized + if (!bIsSimulating) + { + + ResetSettingsAndState(); + + // Always start casting with PIE (since this can only be reached if the command line param is on) + MRSettings->SetIsCasting(true); + } +} + +void FOculusXRMRModule::OnPieStarted(bool bIsSimulating) +{ + // Handle the PIE world as a normal game world + UWorld* PieWorld = GEditor->GetPIEWorldContext()->World(); + if (!bIsSimulating && PieWorld) + { + OnWorldCreated(PieWorld); + } +} + +void FOculusXRMRModule::OnPieEnded(bool bIsSimulating) +{ + UWorld* PieWorld = GEditor->GetPIEWorldContext()->World(); + if (!bIsSimulating && PieWorld) + { + // Stop casting when PIE ends + MRSettings->SetIsCasting(false); + OnWorldDestroyed(PieWorld); + } +} +#endif // WITH_EDITOR + +IMPLEMENT_MODULE(FOculusXRMRModule, OculusXRMR) + +#undef LOCTEXT_NAMESPACE diff --git a/Plugins/MetaXR/Source/OculusXRMR/Private/OculusXRMRModule.h b/Plugins/MetaXR/Source/OculusXRMR/Private/OculusXRMRModule.h new file mode 100644 index 0000000..9daa5ea --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRMR/Private/OculusXRMRModule.h @@ -0,0 +1,97 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +#pragma once +#include "IOculusXRMRModule.h" +#include "Engine/EngineBaseTypes.h" + +#define LOCTEXT_NAMESPACE "OculusXRMR" + +enum class EOculusXRMR_CompositionMethod : uint8; +enum class EOculusXRMR_DepthQuality : uint8; + +class UOculusXRMR_Settings; +class AOculusXRMR_CastingCameraActor; +class UOculusXRMR_State; + +//------------------------------------------------------------------------------------------------- +// FOculusXRInputModule +//------------------------------------------------------------------------------------------------- + +class FOculusXRMRModule : public IOculusXRMRModule +{ +public: + FOculusXRMRModule(); + ~FOculusXRMRModule(); + + static inline FOculusXRMRModule& Get() + { + return FModuleManager::GetModuleChecked("OculusXRMR"); + } + + // IOculusXRMRModule + virtual void StartupModule() override; + virtual void ShutdownModule() override; + + bool IsInitialized() { return bInitialized; } + + bool IsActive(); + UOculusXRMR_Settings* GetMRSettings(); + UOculusXRMR_State* GetMRState(); + +private: + bool bInitialized; + UOculusXRMR_Settings* MRSettings; + UOculusXRMR_State* MRState; + AOculusXRMR_CastingCameraActor* MRActor; + UWorld* CurrentWorld; + + FDelegateHandle WorldAddedEventBinding; + FDelegateHandle WorldDestroyedEventBinding; + FDelegateHandle WorldLoadEventBinding; + + void InitMixedRealityCapture(); + + /** Initialize the tracked physical camera */ + void SetupExternalCamera(); + /** Set up the needed settings and actors for MRC in-game */ + void SetupInGameCapture(); + /** Destroy actors for MRC in-game */ + void CloseInGameCapture(); + /** Reset all the MRC settings and state to the config and default */ + void ResetSettingsAndState(); + + /** Handle changes on specific settings */ + void OnCompositionMethodChanged(EOculusXRMR_CompositionMethod OldVal, EOculusXRMR_CompositionMethod NewVal); + void OnIsCastingChanged(bool OldVal, bool NewVal); + void OnUseDynamicLightingChanged(bool OldVal, bool NewVal); + void OnDepthQualityChanged(EOculusXRMR_DepthQuality OldVal, EOculusXRMR_DepthQuality NewVal); + void OnTrackedCameraIndexChanged(int OldVal, int NewVal); + + void OnWorldCreated(UWorld* NewWorld); + void OnWorldDestroyed(UWorld* NewWorld); + +#if PLATFORM_ANDROID + bool bActivated; + + FDelegateHandle InitialWorldAddedEventBinding; + FDelegateHandle InitialWorldLoadEventBinding; + FDelegateHandle PreWorldTickEventBinding; + + void ChangeCaptureState(); + void OnWorldTick(UWorld* World, ELevelTick Tick, float Delta); + void OnInitialWorldCreated(UWorld* NewWorld); +#endif + +#if WITH_EDITOR + FDelegateHandle PieBeginEventBinding; + FDelegateHandle PieStartedEventBinding; + FDelegateHandle PieEndedEventBinding; + + void OnPieBegin(bool bIsSimulating); + void OnPieStarted(bool bIsSimulating); + void OnPieEnded(bool bIsSimulating); +#endif +}; + +#undef LOCTEXT_NAMESPACE diff --git a/Plugins/MetaXR/Source/OculusXRMR/Private/OculusXRMRPrivate.h b/Plugins/MetaXR/Source/OculusXRMR/Private/OculusXRMRPrivate.h new file mode 100644 index 0000000..9aca9bc --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRMR/Private/OculusXRMRPrivate.h @@ -0,0 +1,12 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. +#pragma once + +#include "IOculusXRMRModule.h" +#include "CoreMinimal.h" + +#include "OculusXRPluginWrapper.h" + +#if OCULUS_MR_SUPPORTED_PLATFORMS +DEFINE_LOG_CATEGORY_STATIC(LogMR, Log, All); +#endif // OCULUS_MR_SUPPORTED_PLATFORMS diff --git a/Plugins/MetaXR/Source/OculusXRMR/Private/OculusXRMR_CastingCameraActor.cpp b/Plugins/MetaXR/Source/OculusXRMR/Private/OculusXRMR_CastingCameraActor.cpp new file mode 100644 index 0000000..7fd5796 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRMR/Private/OculusXRMR_CastingCameraActor.cpp @@ -0,0 +1,869 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +#include "OculusXRMR_CastingCameraActor.h" + +#include "OculusXRMRPrivate.h" +#include "OculusXRHMD_Settings.h" +#include "OculusXRHMD.h" +#include "OculusXRHMD_SpectatorScreenController.h" +#include "OculusXRMRModule.h" +#include "OculusXRMR_Settings.h" +#include "OculusXRMR_State.h" +#include "OculusXRMR_PlaneMeshComponent.h" +#include "OculusXRMRFunctionLibrary.h" +#include "Components/StaticMeshComponent.h" +#include "Components/SceneCaptureComponent2D.h" +#include "UObject/ConstructorHelpers.h" +#include "Engine/Engine.h" +#include "Engine/World.h" +#include "GameFramework/PlayerController.h" +#include "GameFramework/WorldSettings.h" +#include "Engine/TextureRenderTarget2D.h" +#include "Rendering/Texture2DResource.h" +#include "RenderingThread.h" +#include "Materials/MaterialInstanceDynamic.h" +#include "VRNotificationsComponent.h" +#include "RenderUtils.h" +#include "AudioDevice.h" +#include "Materials/Material.h" +#include "RHIDefinitions.h" +#include "DataDrivenShaderPlatformInfo.h" + +#define LOCTEXT_NAMESPACE "OculusXRMR_CastingCameraActor" + +// Possibly add 2=Limited in a future update +static TAutoConsoleVariable CEnableExternalCompositionPostProcess(TEXT("oculus.mr.ExternalCompositionPostProcess"), 0, TEXT("Enable MR external composition post process: 0=Off, 1=On")); +static TAutoConsoleVariable COverrideMixedRealityParametersVar(TEXT("oculus.mr.OverrideParameters"), 0, TEXT("Use the Mixed Reality console variables")); + +namespace +{ + bool GetCameraTrackedObjectPoseInTrackingSpace(OculusXRHMD::FOculusXRHMD* OculusXRHMD, const FOculusXRTrackedCamera& TrackedCamera, OculusXRHMD::FPose& CameraTrackedObjectPose) + { + using namespace OculusXRHMD; + + CameraTrackedObjectPose = FPose(FQuat::Identity, FVector::ZeroVector); + + if (TrackedCamera.AttachedTrackedDevice != EOculusXRTrackedDeviceType::None) + { + ovrpResult result = ovrpSuccess; + ovrpPoseStatef cameraPoseState; + ovrpNode deviceNode = ToOvrpNode(TrackedCamera.AttachedTrackedDevice); + ovrpBool nodePresent = ovrpBool_False; + result = FOculusXRHMDModule::GetPluginWrapper().GetNodePresent2(deviceNode, &nodePresent); + if (OVRP_FAILURE(result)) + { + UE_LOG(LogMR, Warning, TEXT("Unable to check if AttachedTrackedDevice is present")); + return false; + } + if (!nodePresent) + { + UE_LOG(LogMR, Warning, TEXT("AttachedTrackedDevice is not present")); + return false; + } + + OculusXRHMD::FGameFrame* CurrentFrame; + if (IsInGameThread()) + { + CurrentFrame = OculusXRHMD->GetNextFrameToRender(); + } + else + { + CurrentFrame = OculusXRHMD->GetFrame_RenderThread(); + } + + result = CurrentFrame ? FOculusXRHMDModule::GetPluginWrapper().GetNodePoseState3(ovrpStep_Render, CurrentFrame->FrameNumber, deviceNode, &cameraPoseState) : ovrpFailure; + if (OVRP_FAILURE(result)) + { + UE_LOG(LogMR, Warning, TEXT("Unable to retrieve AttachedTrackedDevice pose state")); + return false; + } + OculusXRHMD->ConvertPose(cameraPoseState.Pose, CameraTrackedObjectPose); + } + + return true; + } +} // namespace + +////////////////////////////////////////////////////////////////////////// +// ACastingCameraActor + +AOculusXRMR_CastingCameraActor::AOculusXRMR_CastingCameraActor(const FObjectInitializer& ObjectInitializer) + : Super(ObjectInitializer) + , TrackedCameraCalibrationRequired(false) + , HasTrackedCameraCalibrationCalibrated(false) + , RefreshBoundaryMeshCounter(3) + , ForegroundLayerBackgroundColor(FColor::Green) + , ForegroundMaxDistance(300.0f) +{ + PrimaryActorTick.bCanEverTick = true; + PrimaryActorTick.bTickEvenWhenPaused = true; + + VRNotificationComponent = CreateDefaultSubobject(TEXT("VRNotificationComponent")); + +#if PLATFORM_WINDOWS + PlaneMeshComponent = CreateDefaultSubobject(TEXT("PlaneMeshComponent")); + PlaneMeshComponent->AttachToComponent(GetRootComponent(), FAttachmentTransformRules::KeepRelativeTransform); + PlaneMeshComponent->ResetRelativeTransform(); + PlaneMeshComponent->SetVisibility(false); +#endif + + OpaqueColoredMaterial = Cast(StaticLoadObject(UMaterial::StaticClass(), nullptr, TEXT("/OculusXR/Materials/OculusMR_OpaqueColoredMaterial"))); + if (!OpaqueColoredMaterial) + { + UE_LOG(LogMR, Warning, TEXT("Invalid OpaqueColoredMaterial")); + } + + // Structure to hold one-time initialization + struct FConstructorStatics + { + ConstructorHelpers::FObjectFinder WhiteSquareTexture; + + FConstructorStatics() + : WhiteSquareTexture(TEXT("/Engine/EngineResources/WhiteSquareTexture")) + { + } + }; + static FConstructorStatics ConstructorStatics; + + DefaultTexture_White = ConstructorStatics.WhiteSquareTexture.Object; + check(DefaultTexture_White); + + ForegroundCaptureActor = nullptr; + + // Set the render targets for background and foreground to copies of the default texture +#if PLATFORM_WINDOWS + BackgroundRenderTargets.SetNum(1); + ForegroundRenderTargets.SetNum(1); + + BackgroundRenderTargets[0] = NewObject(); + BackgroundRenderTargets[0]->RenderTargetFormat = RTF_RGBA8_SRGB; + + ForegroundRenderTargets[0] = NewObject(); + ForegroundRenderTargets[0]->RenderTargetFormat = RTF_RGBA8_SRGB; +#elif PLATFORM_ANDROID + BackgroundRenderTargets.SetNum(NumRTs); + ForegroundRenderTargets.SetNum(NumRTs); + AudioBuffers.SetNum(NumRTs); + AudioTimes.SetNum(NumRTs); + PoseTimes.SetNum(NumRTs); + + for (unsigned int i = 0; i < NumRTs; ++i) + { + BackgroundRenderTargets[i] = NewObject(); + BackgroundRenderTargets[i]->RenderTargetFormat = RTF_RGBA8_SRGB; + + ForegroundRenderTargets[i] = NewObject(); + ForegroundRenderTargets[i]->RenderTargetFormat = RTF_RGBA8_SRGB; + + AudioTimes[i] = 0.0; + PoseTimes[i] = 0.0; + } + + SyncId = -1; + RenderedRTs = 0; + CaptureIndex = 0; +#endif +} + +void AOculusXRMR_CastingCameraActor::BeginDestroy() +{ + CloseTrackedCamera(); + Super::BeginDestroy(); +} + +bool AOculusXRMR_CastingCameraActor::RefreshExternalCamera() +{ + using namespace OculusXRHMD; + if (MRState->TrackedCamera.Index >= 0) + { + int cameraCount; + if (OVRP_FAILURE(FOculusXRHMDModule::GetPluginWrapper().GetExternalCameraCount(&cameraCount))) + { + cameraCount = 0; + } + if (MRState->TrackedCamera.Index >= cameraCount) + { + UE_LOG(LogMR, Error, TEXT("Invalid TrackedCamera Index")); + return false; + } + FOculusXRHMD* OculusXRHMD = GEngine->XRSystem.IsValid() ? (FOculusXRHMD*)(GEngine->XRSystem->GetHMDDevice()) : nullptr; + if (!OculusXRHMD) + { + UE_LOG(LogMR, Error, TEXT("Unable to retrieve OculusXRHMD")); + return false; + } + ovrpResult result = ovrpSuccess; + ovrpCameraExtrinsics cameraExtrinsics; + result = FOculusXRHMDModule::GetPluginWrapper().GetExternalCameraExtrinsics(MRState->TrackedCamera.Index, &cameraExtrinsics); + if (OVRP_FAILURE(result)) + { + UE_LOG(LogMR, Error, TEXT("FOculusXRHMDModule::GetPluginWrapper().GetExternalCameraExtrinsics failed")); + return false; + } + MRState->TrackedCamera.AttachedTrackedDevice = OculusXRHMD::ToEOculusXRTrackedDeviceType(cameraExtrinsics.AttachedToNode); + OculusXRHMD::FPose Pose; + OculusXRHMD->ConvertPose(cameraExtrinsics.RelativePose, Pose); + MRState->TrackedCamera.CalibratedRotation = Pose.Orientation.Rotator(); + MRState->TrackedCamera.CalibratedOffset = Pose.Position; + MRState->TrackedCamera.UpdateTime = cameraExtrinsics.LastChangedTimeSeconds; + } + + return true; +} + +void AOculusXRMR_CastingCameraActor::BeginPlay() +{ + Super::BeginPlay(); + + SetupTrackedCamera(); + RequestTrackedCameraCalibration(); + SetupMRCScreen(); + + FScriptDelegate Delegate; + Delegate.BindUFunction(this, FName(TEXT("OnHMDRecentered"))); + VRNotificationComponent->HMDRecenteredDelegate.Add(Delegate); + +#if PLATFORM_ANDROID + FAudioDeviceHandle AudioDevice = FAudioDevice::GetMainAudioDevice(); + if (AudioDevice.GetAudioDevice()) + { + AudioDevice->StartRecording(nullptr, 0.1); + } +#endif +} + +void AOculusXRMR_CastingCameraActor::EndPlay(EEndPlayReason::Type Reason) +{ +#if PLATFORM_ANDROID + FAudioDeviceHandle AudioDevice = FAudioDevice::GetMainAudioDevice(); + if (AudioDevice.GetAudioDevice()) + { + float NumChannels = 2; + float SampleRate = AudioDevice->GetSampleRate(); + AudioDevice->StopRecording(nullptr, NumChannels, SampleRate); + } +#endif + + VRNotificationComponent->HMDRecenteredDelegate.Remove(this, FName(TEXT("OnHMDRecentered"))); + + MRState->TrackingReferenceComponent = nullptr; + + CloseMRCScreen(); + + CloseTrackedCamera(); + Super::EndPlay(Reason); +} + +void AOculusXRMR_CastingCameraActor::Tick(float DeltaTime) +{ + Super::Tick(DeltaTime); + + if (MRState->BindToTrackedCameraIndexRequested) + { + Execute_BindToTrackedCameraIndexIfAvailable(); + } + + if (!RefreshExternalCamera()) + { + CloseTrackedCamera(); + return; + } + + // Reset capturing components if the composition method changes + if (MRState->ChangeCameraStateRequested) + { + CloseTrackedCamera(); + CloseMRCScreen(); + SetupTrackedCamera(); + SetupMRCScreen(); + } + +#if PLATFORM_WINDOWS + if (MRSettings->GetCompositionMethod() == EOculusXRMR_CompositionMethod::ExternalComposition) +#endif + { + if (ForegroundLayerBackgroundColor != MRSettings->BackdropColor) + { + ForegroundLayerBackgroundColor = MRSettings->BackdropColor; + SetBackdropMaterialColor(); + } + // Enable external composition post process based on setting + bool bPostProcess = MRSettings->ExternalCompositionPostProcessEffects != EOculusXRMR_PostProcessEffects::PPE_Off; + if (COverrideMixedRealityParametersVar.GetValueOnAnyThread() > 0) + { + bPostProcess = CEnableExternalCompositionPostProcess.GetValueOnAnyThread() > 0; + } + GetCaptureComponent2D()->ShowFlags.PostProcessing = bPostProcess; + if (ForegroundCaptureActor) + { + ForegroundCaptureActor->GetCaptureComponent2D()->ShowFlags.PostProcessing = bPostProcess; + } + } + + if (TrackedCameraCalibrationRequired) + { + CalibrateTrackedCameraPose(); + } + + UpdateTrackedCameraPosition(); + +#if PLATFORM_WINDOWS + RepositionPlaneMesh(); +#endif + + UpdateRenderTargetSize(); + +#if PLATFORM_ANDROID + OculusXRHMD::FOculusXRHMD* OculusXRHMD = GEngine->XRSystem.IsValid() ? (OculusXRHMD::FOculusXRHMD*)(GEngine->XRSystem->GetHMDDevice()) : nullptr; + if (OculusXRHMD) + { + ovrpPosef OvrpPose, OvrpHeadPose, OvrpLeftHandPose, OvrpRightHandPose; + FOculusXRHMDModule::GetPluginWrapper().GetTrackingTransformRelativePose(&OvrpPose, ovrpTrackingOrigin_Stage); + OculusXRHMD::FPose StageToLocalPose; + OculusXRHMD->ConvertPose(OvrpPose, StageToLocalPose); + OculusXRHMD::FPose LocalToStagePose = StageToLocalPose.Inverse(); + + OculusXRHMD::FPose HeadPose; + OculusXRHMD->GetCurrentPose(OculusXRHMD::ToExternalDeviceId(ovrpNode_Head), HeadPose.Orientation, HeadPose.Position); + HeadPose = LocalToStagePose * HeadPose; + OculusXRHMD->ConvertPose(HeadPose, OvrpHeadPose); + + OculusXRHMD::FPose LeftHandPose; + OculusXRHMD->GetCurrentPose(OculusXRHMD::ToExternalDeviceId(ovrpNode_HandLeft), HeadPose.Orientation, HeadPose.Position); + LeftHandPose = LocalToStagePose * LeftHandPose; + OculusXRHMD->ConvertPose(LeftHandPose, OvrpLeftHandPose); + + OculusXRHMD::FPose RightHandPose; + OculusXRHMD->GetCurrentPose(OculusXRHMD::ToExternalDeviceId(ovrpNode_HandRight), HeadPose.Orientation, HeadPose.Position); + RightHandPose = LocalToStagePose * RightHandPose; + OculusXRHMD->ConvertPose(RightHandPose, OvrpRightHandPose); + + FOculusXRHMDModule::GetPluginWrapper().Media_SetHeadsetControllerPose(OvrpHeadPose, OvrpLeftHandPose, OvrpRightHandPose); + } + + // Alternate foreground and background captures by nulling the capture component texture target + if (GetCaptureComponent2D()->IsVisible()) + { + GetCaptureComponent2D()->SetVisibility(false); + + // Encode a texture the frame before we render to it again to ensure completed render at the cost of latency + unsigned int EncodeIndex = (CaptureIndex + 1) % NumRTs; + + // Skip encoding for the first few frames before they have completed rendering + if (RenderedRTs > EncodeIndex) + { + FOculusXRHMDModule::GetPluginWrapper().Media_SyncMrcFrame(SyncId); + + int NumChannels = 2; + double AudioTime = AudioTimes[EncodeIndex]; + void* BackgroundTexture; + void* ForegroundTexture; + + if (IsVulkanPlatform(GMaxRHIShaderPlatform)) + { + ExecuteOnRenderThread([this, EncodeIndex, &BackgroundTexture, &ForegroundTexture]() { + ExecuteOnRHIThread([this, EncodeIndex, &BackgroundTexture, &ForegroundTexture]() { + // The Vulkan RHI's implementation of GetNativeResource is different and returns the VkImage cast + // as a void* instead of a pointer to the VkImage, so we need this workaround + BackgroundTexture = (void*)BackgroundRenderTargets[EncodeIndex]->GetResource()->TextureRHI->GetNativeResource(); + ForegroundTexture = (void*)ForegroundRenderTargets[EncodeIndex]->GetResource()->TextureRHI->GetNativeResource(); + }); + }); + } + else + { + ExecuteOnRenderThread([this, EncodeIndex, &BackgroundTexture, &ForegroundTexture]() { + ExecuteOnRHIThread([this, EncodeIndex, &BackgroundTexture, &ForegroundTexture]() { + BackgroundTexture = *((void**)BackgroundRenderTargets[EncodeIndex]->GetResource()->TextureRHI->GetNativeResource()); + ForegroundTexture = *((void**)ForegroundRenderTargets[EncodeIndex]->GetResource()->TextureRHI->GetNativeResource()); + }); + }); + } + FOculusXRHMDModule::GetPluginWrapper().Media_EncodeMrcFrameDualTexturesWithPoseTime(BackgroundTexture, ForegroundTexture, AudioBuffers[EncodeIndex].GetData(), AudioBuffers[EncodeIndex].Num() * sizeof(float), NumChannels, AudioTime, PoseTimes[CaptureIndex], &SyncId); + } + ForegroundCaptureActor->GetCaptureComponent2D()->SetVisibility(true); + } + else if (ForegroundCaptureActor && ForegroundCaptureActor->GetCaptureComponent2D()->IsVisible()) + { + ForegroundCaptureActor->GetCaptureComponent2D()->SetVisibility(false); + + // Increment scene captures to next texture + CaptureIndex = (CaptureIndex + 1) % NumRTs; + GetCaptureComponent2D()->TextureTarget = BackgroundRenderTargets[CaptureIndex]; + ForegroundCaptureActor->GetCaptureComponent2D()->TextureTarget = ForegroundRenderTargets[CaptureIndex]; + GetCaptureComponent2D()->SetVisibility(true); + + FAudioDeviceHandle AudioDevice = FAudioDevice::GetMainAudioDevice(); + if (AudioDevice.GetAudioDevice()) + { + float NumChannels, SampleRate; + NumChannels = 2; + SampleRate = AudioDevice->GetSampleRate(); + AudioBuffers[CaptureIndex] = AudioDevice->StopRecording(nullptr, NumChannels, SampleRate); + AudioTimes[CaptureIndex] = AudioDevice->GetAudioTime(); + //UE_LOG(LogMR, Error, TEXT("SampleRate: %f, NumChannels: %f, Time: %f, Buffer Length: %d, Buffer: %p"), SampleRate, NumChannels, AudioDevice->GetAudioTime(), AudioBuffers[EncodeIndex].Num(), AudioBuffers[EncodeIndex].GetData()); + AudioDevice->StartRecording(nullptr, 0.1); + } + + //PoseTimes[CaptureIndex] = MRState->TrackedCamera.UpdateTime; + + // Increment this counter for the initial cycle through "swapchain" + if (RenderedRTs < NumRTs) + { + RenderedRTs++; + } + } +#endif +} + +void AOculusXRMR_CastingCameraActor::Execute_BindToTrackedCameraIndexIfAvailable() +{ + if (!MRState->BindToTrackedCameraIndexRequested) + { + return; + } + + FOculusXRTrackedCamera TempTrackedCamera; + if (MRSettings->GetBindToTrackedCameraIndex() >= 0) + { + TArray TrackedCameras; + UOculusXRMRFunctionLibrary::GetAllTrackedCamera(TrackedCameras); + int i; + for (i = 0; i < TrackedCameras.Num(); ++i) + { + if (TrackedCameras[i].Index == MRSettings->GetBindToTrackedCameraIndex()) + { + TempTrackedCamera = TrackedCameras[i]; + break; + } + } + if (i == TrackedCameras.Num()) + { + UE_LOG(LogMR, Warning, TEXT("Unable to find TrackedCamera at index %d, use TempTrackedCamera"), MRSettings->GetBindToTrackedCameraIndex()); + } + } + else + { + UE_LOG(LogMR, Warning, TEXT("BindToTrackedCameraIndex == %d, use TempTrackedCamera"), MRSettings->GetBindToTrackedCameraIndex()); + } + + MRState->TrackedCamera = TempTrackedCamera; + if (MRState->TrackedCamera.Index < 0) + { + SetTrackedCameraUserPoseWithCameraTransform(); + } + + MRState->BindToTrackedCameraIndexRequested = false; +} + +void AOculusXRMR_CastingCameraActor::RequestTrackedCameraCalibration() +{ + TrackedCameraCalibrationRequired = true; +} + +void AOculusXRMR_CastingCameraActor::CalibrateTrackedCameraPose() +{ + SetTrackedCameraInitialPoseWithPlayerTransform(); + HasTrackedCameraCalibrationCalibrated = true; + TrackedCameraCalibrationRequired = false; +} + +void AOculusXRMR_CastingCameraActor::SetTrackedCameraInitialPoseWithPlayerTransform() +{ + using namespace OculusXRHMD; + + FOculusXRHMD* OculusXRHMD = GEngine->XRSystem.IsValid() ? (FOculusXRHMD*)(GEngine->XRSystem->GetHMDDevice()) : nullptr; + if (!OculusXRHMD) + { + UE_LOG(LogMR, Warning, TEXT("Unable to retrieve OculusXRHMD")); + return; + } + + FPose CameraTrackedObjectPose; + if (!GetCameraTrackedObjectPoseInTrackingSpace(OculusXRHMD, MRState->TrackedCamera, CameraTrackedObjectPose)) + { + return; + } + + FPose CameraPose = CameraTrackedObjectPose * FPose(MRState->TrackedCamera.CalibratedRotation.Quaternion(), MRState->TrackedCamera.CalibratedOffset); + CameraPose = CameraPose * FPose(MRState->TrackedCamera.UserRotation.Quaternion(), MRState->TrackedCamera.UserOffset); + + FQuat TROrientation; + FVector TRLocation; + FRotator TRRotation; + if (!UOculusXRMRFunctionLibrary::GetTrackingReferenceLocationAndRotationInWorldSpace(MRState->TrackingReferenceComponent, TRLocation, TRRotation)) + { + UE_LOG(LogMR, Warning, TEXT("Could not get player position")); + return; + } + + TROrientation = TRRotation.Quaternion(); + FPose FinalPose = FPose(TROrientation, TRLocation) * CameraPose; + + InitialCameraAbsoluteOrientation = FinalPose.Orientation; + InitialCameraAbsolutePosition = FinalPose.Position; + InitialCameraRelativeOrientation = CameraPose.Orientation; + InitialCameraRelativePosition = CameraPose.Position; + + GetCaptureComponent2D()->FOVAngle = MRState->TrackedCamera.FieldOfView; + + if (ForegroundCaptureActor) + { + ForegroundCaptureActor->GetCaptureComponent2D()->FOVAngle = MRState->TrackedCamera.FieldOfView; + } +} + +void AOculusXRMR_CastingCameraActor::SetTrackedCameraUserPoseWithCameraTransform() +{ + using namespace OculusXRHMD; + + FOculusXRHMD* OculusXRHMD = GEngine->XRSystem.IsValid() ? (FOculusXRHMD*)(GEngine->XRSystem->GetHMDDevice()) : nullptr; + if (!OculusXRHMD) + { + UE_LOG(LogMR, Warning, TEXT("Unable to retrieve OculusXRHMD")); + return; + } + + FPose CameraTrackedObjectPose; + if (!GetCameraTrackedObjectPoseInTrackingSpace(OculusXRHMD, MRState->TrackedCamera, CameraTrackedObjectPose)) + { + return; + } + + FPose CameraPose = CameraTrackedObjectPose * FPose(MRState->TrackedCamera.CalibratedRotation.Quaternion(), MRState->TrackedCamera.CalibratedOffset); + + FQuat TROrientation; + FVector TRLocation; + FRotator TRRotation; + if (!UOculusXRMRFunctionLibrary::GetTrackingReferenceLocationAndRotationInWorldSpace(MRState->TrackingReferenceComponent, TRLocation, TRRotation)) + { + UE_LOG(LogMR, Warning, TEXT("Could not get player position")); + return; + } + TROrientation = TRRotation.Quaternion(); + FPose PlayerPose(TROrientation, TRLocation); + FPose CurrentCameraPose = PlayerPose * CameraPose; + + FPose ExpectedCameraPose(GetCaptureComponent2D()->GetComponentRotation().Quaternion(), GetCaptureComponent2D()->GetComponentLocation()); + FPose UserPose = CurrentCameraPose.Inverse() * ExpectedCameraPose; + + MRState->TrackedCamera.UserRotation = UserPose.Orientation.Rotator(); + MRState->TrackedCamera.UserOffset = UserPose.Position; +} + +void AOculusXRMR_CastingCameraActor::UpdateTrackedCameraPosition() +{ + check(HasTrackedCameraCalibrationCalibrated); + + using namespace OculusXRHMD; + + FOculusXRHMD* OculusXRHMD = GEngine->XRSystem.IsValid() ? (FOculusXRHMD*)(GEngine->XRSystem->GetHMDDevice()) : nullptr; + if (!OculusXRHMD) + { + UE_LOG(LogMR, Warning, TEXT("Unable to retrieve OculusXRHMD")); + return; + } + + FPose CameraTrackedObjectPose; + if (!GetCameraTrackedObjectPoseInTrackingSpace(OculusXRHMD, MRState->TrackedCamera, CameraTrackedObjectPose)) + { + return; + } + + FPose CameraTrackingSpacePose = FPose(MRState->TrackedCamera.CalibratedRotation.Quaternion(), MRState->TrackedCamera.CalibratedOffset); +#if PLATFORM_ANDROID + ovrpPosef OvrpPose; + FOculusXRHMDModule::GetPluginWrapper().GetTrackingTransformRelativePose(&OvrpPose, ovrpTrackingOrigin_Stage); + FPose StageToLocalPose; + OculusXRHMD->ConvertPose(OvrpPose, StageToLocalPose); + CameraTrackingSpacePose = StageToLocalPose * CameraTrackingSpacePose; +#endif + FPose CameraPose = CameraTrackedObjectPose * CameraTrackingSpacePose; + CameraPose = CameraPose * FPose(MRState->TrackedCamera.UserRotation.Quaternion(), MRState->TrackedCamera.UserOffset); + CameraPose.Position = CameraPose.Position * MRState->ScalingFactor; + + float Distance = 0.0f; + if (MRSettings->ClippingReference == EOculusXRMR_ClippingReference::CR_TrackingReference) + { + Distance = -FVector::DotProduct(CameraPose.Orientation.GetForwardVector().GetSafeNormal2D(), CameraPose.Position); + } + else if (MRSettings->ClippingReference == EOculusXRMR_ClippingReference::CR_Head) + { + FQuat HeadOrientation; + FVector HeadPosition; + OculusXRHMD->GetCurrentPose(IXRTrackingSystem::HMDDeviceId, HeadOrientation, HeadPosition); + FVector HeadToCamera = HeadPosition - CameraPose.Position; + Distance = FVector::DotProduct(CameraPose.Orientation.GetForwardVector().GetSafeNormal2D(), HeadToCamera); + } + else + { + checkNoEntry(); + } + ForegroundMaxDistance = FMath::Max(Distance, GMinClipZ); + if (ForegroundCaptureActor) + { + ForegroundCaptureActor->GetCaptureComponent2D()->MaxViewDistanceOverride = ForegroundMaxDistance; + } + + FPose FinalPose; + FQuat TROrientation; + FVector TRLocation; + FRotator TRRotation; + if (!UOculusXRMRFunctionLibrary::GetTrackingReferenceLocationAndRotationInWorldSpace(MRState->TrackingReferenceComponent, TRLocation, TRRotation)) + { + UE_LOG(LogMR, Warning, TEXT("Could not get player position")); + return; + } + + TROrientation = TRRotation.Quaternion(); + FinalPose = FPose(TROrientation, TRLocation) * CameraPose; + + FTransform FinalTransform(FinalPose.Orientation, FinalPose.Position); + RootComponent->SetWorldTransform(FinalTransform); + GetCaptureComponent2D()->FOVAngle = MRState->TrackedCamera.FieldOfView; + + if (ForegroundCaptureActor) + { + ForegroundCaptureActor->GetCaptureComponent2D()->FOVAngle = MRState->TrackedCamera.FieldOfView; + } +} + +void AOculusXRMR_CastingCameraActor::InitializeStates(UOculusXRMR_Settings* MRSettingsIn, UOculusXRMR_State* MRStateIn) +{ + MRSettings = MRSettingsIn; + MRState = MRStateIn; +} + +void AOculusXRMR_CastingCameraActor::SetupTrackedCamera() +{ + if (!RefreshExternalCamera()) + { + return; + } + + RequestTrackedCameraCalibration(); + + // Unset this flag before we can return + MRState->ChangeCameraStateRequested = false; + +#if PLATFORM_WINDOWS + if (MRSettings->GetCompositionMethod() == EOculusXRMR_CompositionMethod::ExternalComposition) + { + SetupBackdropMaterialInstance(); + } + + RepositionPlaneMesh(); +#endif +} + +void AOculusXRMR_CastingCameraActor::SetBackdropMaterialColor() +{ + if (BackdropMaterialInstance) + { + BackdropMaterialInstance->SetVectorParameterValue(FName(TEXT("Color")), GetForegroundLayerBackgroundColor()); + } +} + +void AOculusXRMR_CastingCameraActor::SetupBackdropMaterialInstance() +{ + if (!BackdropMaterialInstance && OpaqueColoredMaterial) + { + BackdropMaterialInstance = UMaterialInstanceDynamic::Create(OpaqueColoredMaterial, this); + BackdropMaterialInstance->SetScalarParameterValue(FName("Opacity"), 0.0f); + } + PlaneMeshComponent->SetMaterial(0, BackdropMaterialInstance); + SetBackdropMaterialColor(); +} + +void AOculusXRMR_CastingCameraActor::RepositionPlaneMesh() +{ + FVector PlaneCenter = FVector::ForwardVector * ForegroundMaxDistance; + FVector PlaneUp = FVector::UpVector; + FVector PlaneNormal = -FVector::ForwardVector; + int ViewWidth = MRSettings->bUseTrackedCameraResolution ? MRState->TrackedCamera.SizeX : MRSettings->WidthPerView; + int ViewHeight = MRSettings->bUseTrackedCameraResolution ? MRState->TrackedCamera.SizeY : MRSettings->HeightPerView; + float Width = ForegroundMaxDistance * FMath::Tan(FMath::DegreesToRadians(GetCaptureComponent2D()->FOVAngle) * 0.5f) * 2.0f; + float Height = Width * ViewHeight / ViewWidth; + FVector2D PlaneSize = FVector2D(Width, Height); + PlaneMeshComponent->Place(PlaneCenter, PlaneUp, PlaneNormal, PlaneSize); + PlaneMeshComponent->ResetRelativeTransform(); + PlaneMeshComponent->SetVisibility(true); +} + +void AOculusXRMR_CastingCameraActor::OnHMDRecentered() +{ +#if PLATFORM_WINDOWS + RefreshBoundaryMesh(); +#endif + RequestTrackedCameraCalibration(); +} + +void AOculusXRMR_CastingCameraActor::RefreshBoundaryMesh() +{ + RefreshBoundaryMeshCounter = 3; +} + +void BuildProjectionMatrix(float YMultiplier, float FOV, float FarClipPlane, FMatrix& ProjectionMatrix) +{ + if (FarClipPlane < GNearClippingPlane) + { + FarClipPlane = GNearClippingPlane; + } + + if ((int32)ERHIZBuffer::IsInverted) + { + ProjectionMatrix = FReversedZPerspectiveMatrix( + FOV, + FOV, + 1.0f, + YMultiplier, + GNearClippingPlane, + FarClipPlane); + } + else + { + ProjectionMatrix = FPerspectiveMatrix( + FOV, + FOV, + 1.0f, + YMultiplier, + GNearClippingPlane, + FarClipPlane); + } +} + +void AOculusXRMR_CastingCameraActor::UpdateRenderTargetSize() +{ + int ViewWidth = MRSettings->bUseTrackedCameraResolution ? MRState->TrackedCamera.SizeX : MRSettings->WidthPerView; + int ViewHeight = MRSettings->bUseTrackedCameraResolution ? MRState->TrackedCamera.SizeY : MRSettings->HeightPerView; + +#if PLATFORM_WINDOWS + BackgroundRenderTargets[0]->ResizeTarget(ViewWidth, ViewHeight); + if (ForegroundRenderTargets[0]) + { + ForegroundRenderTargets[0]->ResizeTarget(ViewWidth, ViewHeight); + } +#endif +#if PLATFORM_ANDROID + FIntPoint CameraTargetSize = FIntPoint(ViewWidth, ViewHeight); + float FOV = GetCaptureComponent2D()->FOVAngle * (float)PI / 360.0f; + + if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().Media_GetMrcFrameSize(&ViewWidth, &ViewHeight))) + { + // Frame size is doublewide, so divide by 2 + ViewWidth /= 2; + + for (unsigned int i = 0; i < NumRTs; ++i) + { + BackgroundRenderTargets[i]->ResizeTarget(ViewWidth, ViewHeight); + if (ForegroundRenderTargets[i]) + { + ForegroundRenderTargets[i]->ResizeTarget(ViewWidth, ViewHeight); + } + } + + // Use custom projection matrix for far clip plane and to use camera aspect ratio instead of rendertarget aspect ratio + float YMultiplier = (float)CameraTargetSize.X / (float)CameraTargetSize.Y; + GetCaptureComponent2D()->bUseCustomProjectionMatrix = true; + BuildProjectionMatrix(YMultiplier, FOV, GNearClippingPlane, GetCaptureComponent2D()->CustomProjectionMatrix); + if (ForegroundCaptureActor) + { + ForegroundCaptureActor->GetCaptureComponent2D()->bUseCustomProjectionMatrix = true; + BuildProjectionMatrix(YMultiplier, FOV, ForegroundMaxDistance, ForegroundCaptureActor->GetCaptureComponent2D()->CustomProjectionMatrix); + } + } +#endif +} + +void AOculusXRMR_CastingCameraActor::SetupMRCScreen() +{ +#if PLATFORM_WINDOWS + OculusXRHMD::FSpectatorScreenController* SpecScreen = nullptr; + IHeadMountedDisplay* HMD = GEngine->XRSystem.IsValid() ? GEngine->XRSystem->GetHMDDevice() : nullptr; + if (HMD) + { + SpecScreen = (OculusXRHMD::FSpectatorScreenController*)HMD->GetSpectatorScreenController(); + } + if (SpecScreen) + { +#endif + UpdateRenderTargetSize(); + + // LDR for gamma correction and post process + GetCaptureComponent2D()->CaptureSource = ESceneCaptureSource::SCS_FinalColorLDR; + + // Render scene capture 2D output to spectator screen + GetCaptureComponent2D()->TextureTarget = BackgroundRenderTargets[0]; + +#if PLATFORM_WINDOWS + if (MRSettings->GetCompositionMethod() == EOculusXRMR_CompositionMethod::ExternalComposition) +#endif + { + ForegroundCaptureActor = GetWorld()->SpawnActor(); + + // LDR for gamma correction and post process + ForegroundCaptureActor->GetCaptureComponent2D()->CaptureSource = ESceneCaptureSource::SCS_FinalColorLDR; +#if PLATFORM_ANDROID + // Start with foreground capture actor off on android + ForegroundCaptureActor->GetCaptureComponent2D()->SetVisibility(false); +#endif + + // Don't render anything past the foreground for performance + ForegroundCaptureActor->GetCaptureComponent2D()->MaxViewDistanceOverride = ForegroundMaxDistance; + + ForegroundCaptureActor->GetCaptureComponent2D()->TextureTarget = ForegroundRenderTargets[0]; +#if PLATFORM_WINDOWS + // Render use split foreground/background rendering to spectator screen + SpecScreen->SetMRForeground(ForegroundRenderTargets[0]); + SpecScreen->SetMRBackground(BackgroundRenderTargets[0]); + SpecScreen->SetMRSpectatorScreenMode(OculusXRHMD::EMRSpectatorScreenMode::ExternalComposition); + + // Set the plane mesh to only render to foreground target + PlaneMeshComponent->SetPlaneRenderTarget(ForegroundRenderTargets[0]); +#endif + // Set foreground capture to match background capture + ForegroundCaptureActor->AttachToActor(this, FAttachmentTransformRules(EAttachmentRule::SnapToTarget, true)); + } +#if PLATFORM_WINDOWS + } + else + { + UE_LOG(LogMR, Error, TEXT("Cannot find spectator screen")); + } +#endif +} + +void AOculusXRMR_CastingCameraActor::CloseMRCScreen() +{ +#if PLATFORM_WINDOWS + OculusXRHMD::FSpectatorScreenController* SpecScreen = nullptr; + IHeadMountedDisplay* HMD = GEngine->XRSystem.IsValid() ? GEngine->XRSystem->GetHMDDevice() : nullptr; + if (HMD) + { + SpecScreen = (OculusXRHMD::FSpectatorScreenController*)HMD->GetSpectatorScreenController(); + } + // Restore original spectator screen mode + if (SpecScreen) + { + SpecScreen->SetMRSpectatorScreenMode(OculusXRHMD::EMRSpectatorScreenMode::Default); + SpecScreen->SetMRForeground(nullptr); + SpecScreen->SetMRBackground(nullptr); + } +#endif + if (ForegroundCaptureActor) + { + ForegroundCaptureActor->Destroy(); + ForegroundCaptureActor = nullptr; + } +} + +void AOculusXRMR_CastingCameraActor::CloseTrackedCamera() +{ + if (PlaneMeshComponent) + { + PlaneMeshComponent->SetVisibility(false); + } +} + +#undef LOCTEXT_NAMESPACE diff --git a/Plugins/MetaXR/Source/OculusXRMR/Private/OculusXRMR_CastingCameraActor.h b/Plugins/MetaXR/Source/OculusXRMR/Private/OculusXRMR_CastingCameraActor.h new file mode 100644 index 0000000..f5c5853 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRMR/Private/OculusXRMR_CastingCameraActor.h @@ -0,0 +1,131 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. +#pragma once + +#include "UObject/ObjectMacros.h" +#include "Engine/SceneCapture2D.h" +#include "AudioResampler.h" +#include "AudioDefines.h" +#include "OculusXRPluginWrapper.h" +#include "Materials/MaterialInstanceDynamic.h" +#include "AudioMixer.h" +#include "OculusXRMR_CastingCameraActor.generated.h" + +#if PLATFORM_ANDROID +#define MRC_SWAPCHAIN_LENGTH 3 +#endif + +class UOculusXRMR_PlaneMeshComponent; +class UMaterial; +class AOculusXRMR_BoundaryActor; +class UTextureRenderTarget2D; +class UOculusXRMR_Settings; +class UOculusXRMR_State; + +/** +* The camera actor in the level that tracks the binded physical camera in game +*/ +UCLASS(ClassGroup = OculusXRMR, NotPlaceable, NotBlueprintable) +class AOculusXRMR_CastingCameraActor : public ASceneCapture2D +{ + GENERATED_BODY() + +public: + AOculusXRMR_CastingCameraActor(const FObjectInitializer& ObjectInitializer); + + /** Initialize the MRC settings and states */ + void InitializeStates(UOculusXRMR_Settings* MRSettingsIn, UOculusXRMR_State* MRStateIn); + + virtual void BeginPlay() override; + virtual void EndPlay(EEndPlayReason::Type Reason) override; + virtual void Tick(float DeltaTime) override; + + virtual void BeginDestroy() override; + + UPROPERTY() + class UVRNotificationsComponent* VRNotificationComponent; + + UPROPERTY() + UOculusXRMR_PlaneMeshComponent* PlaneMeshComponent; + + UPROPERTY() + UMaterial* OpaqueColoredMaterial; + + UPROPERTY() + UMaterialInstanceDynamic* BackdropMaterialInstance; + + UPROPERTY() + class UTexture2D* DefaultTexture_White; + + bool TrackedCameraCalibrationRequired; + bool HasTrackedCameraCalibrationCalibrated; + FQuat InitialCameraAbsoluteOrientation; + FVector InitialCameraAbsolutePosition; + FQuat InitialCameraRelativeOrientation; + FVector InitialCameraRelativePosition; + + int32 RefreshBoundaryMeshCounter; + +private: + /** Move the casting camera to follow the tracking reference (i.e. player) */ + void RequestTrackedCameraCalibration(); + + bool RefreshExternalCamera(); + + void CalibrateTrackedCameraPose(); + void SetTrackedCameraUserPoseWithCameraTransform(); + void SetTrackedCameraInitialPoseWithPlayerTransform(); + void UpdateTrackedCameraPosition(); + + /** Initialize the tracked physical camera */ + void SetupTrackedCamera(); + + /** Close the tracked physical camera */ + void CloseTrackedCamera(); + + void OnHMDRecentered(); + + const FColor& GetForegroundLayerBackgroundColor() const { return ForegroundLayerBackgroundColor; } + + void SetBackdropMaterialColor(); + void SetupBackdropMaterialInstance(); + void RepositionPlaneMesh(); + void RefreshBoundaryMesh(); + void UpdateRenderTargetSize(); + void SetupMRCScreen(); + void CloseMRCScreen(); + + void Execute_BindToTrackedCameraIndexIfAvailable(); + + FColor ForegroundLayerBackgroundColor; + float ForegroundMaxDistance; + + UPROPERTY() + TArray BackgroundRenderTargets; + + UPROPERTY() + ASceneCapture2D* ForegroundCaptureActor; + + UPROPERTY() + TArray ForegroundRenderTargets; + + UPROPERTY() + TArray PoseTimes; + + UPROPERTY() + UOculusXRMR_Settings* MRSettings; + + UPROPERTY() + UOculusXRMR_State* MRState; + +#if PLATFORM_ANDROID + TArray AudioBuffers; + TArray AudioTimes; + + int SyncId; + + const unsigned int NumRTs = MRC_SWAPCHAIN_LENGTH; + unsigned int RenderedRTs; + unsigned int CaptureIndex; +#endif +}; diff --git a/Plugins/MetaXR/Source/OculusXRMR/Private/OculusXRMR_PlaneMeshComponent.cpp b/Plugins/MetaXR/Source/OculusXRMR/Private/OculusXRMR_PlaneMeshComponent.cpp new file mode 100644 index 0000000..ed5d473 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRMR/Private/OculusXRMR_PlaneMeshComponent.cpp @@ -0,0 +1,270 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +#include "OculusXRMR_PlaneMeshComponent.h" +#include "RenderingThread.h" +#include "RenderResource.h" +#include "PrimitiveViewRelevance.h" +#include "PrimitiveSceneProxy.h" +#include "VertexFactory.h" +#include "Engine/CollisionProfile.h" +#include "Engine/TextureRenderTarget2D.h" +#include "Materials/Material.h" +#include "LocalVertexFactory.h" +#include "SceneManagement.h" +#include "DynamicMeshBuilder.h" +#include "EngineGlobals.h" +#include "Engine/Engine.h" +#include "MaterialShared.h" +#include "SceneInterface.h" +#include "TextureResource.h" +#include "MaterialDomain.h" +#include "Materials/MaterialRenderProxy.h" + +/** Scene proxy */ +class FOculusXRMR_PlaneMeshSceneProxy : public FPrimitiveSceneProxy +{ +public: + FOculusXRMR_PlaneMeshSceneProxy(UOculusXRMR_PlaneMeshComponent* Component, UTextureRenderTarget2D* RenderTarget) + : FPrimitiveSceneProxy(Component) + , MaterialRelevance(Component->GetMaterialRelevance(GetScene().GetFeatureLevel())) + , PlaneRenderTarget(RenderTarget) + { + const FColor VertexColor(255, 255, 255); + + const int32 NumTris = Component->CustomMeshTris.Num(); + Vertices.AddUninitialized(NumTris * 3); + Indices.AddUninitialized(NumTris * 3); + // Add each triangle to the vertex/index buffer + for (int32 TriIdx = 0; TriIdx < NumTris; TriIdx++) + { + FOculusXRMR_PlaneMeshTriangle& Tri = Component->CustomMeshTris[TriIdx]; + + const FVector Edge01 = (Tri.Vertex1 - Tri.Vertex0); + const FVector Edge02 = (Tri.Vertex2 - Tri.Vertex0); + + const FVector TangentX = Edge01.GetSafeNormal(); + const FVector TangentZ = (Edge02 ^ Edge01).GetSafeNormal(); + const FVector TangentY = (TangentX ^ TangentZ).GetSafeNormal(); + + FDynamicMeshVertex Vert; + + Vert.Color = VertexColor; + Vert.SetTangents((FVector3f)TangentX, (FVector3f)TangentY, (FVector3f)TangentZ); + + Vert.Position = (FVector3f)Tri.Vertex0; + Vert.TextureCoordinate[0] = FVector2f(Tri.UV0); // LWC_TODO: Precision loss + Vertices[TriIdx * 3 + 0] = Vert; + Indices[TriIdx * 3 + 0] = TriIdx * 3 + 0; + + Vert.Position = (FVector3f)Tri.Vertex1; + Vert.TextureCoordinate[0] = FVector2f(Tri.UV1); // LWC_TODO: Precision loss + Vertices[TriIdx * 3 + 1] = Vert; + Indices[TriIdx * 3 + 1] = TriIdx * 3 + 1; + + Vert.Position = (FVector3f)Tri.Vertex2; + Vert.TextureCoordinate[0] = FVector2f(Tri.UV2); // LWC_TODO: Precision loss + Vertices[TriIdx * 3 + 2] = Vert; + Indices[TriIdx * 3 + 2] = TriIdx * 3 + 2; + } + + // Grab material + Material = Component->GetMaterial(0); + if (Material == nullptr) + { + Material = UMaterial::GetDefaultMaterial(MD_Surface); + } + } + + virtual ~FOculusXRMR_PlaneMeshSceneProxy() + { + } + + SIZE_T GetTypeHash() const override + { + static size_t UniquePointer; + return reinterpret_cast(&UniquePointer); + } + + virtual void GetDynamicMeshElements(const TArray& Views, const FSceneViewFamily& ViewFamily, uint32 VisibilityMap, FMeshElementCollector& Collector) const override + { + QUICK_SCOPE_CYCLE_COUNTER(STAT_OculusXRMR_PlaneMeshSceneProxy_GetDynamicMeshElements); + + // the mesh is only visible inside the CastingViewport, and the Full CastingLayer (the Composition mode) + if (PlaneRenderTarget && ViewFamily.RenderTarget == PlaneRenderTarget->GetRenderTargetResource()) + { + const bool bWireframe = AllowDebugViewmodes() && ViewFamily.EngineShowFlags.Wireframe; + + FMaterialRenderProxy* MaterialProxy = nullptr; + if (bWireframe) + { + auto WireframeMaterialInstance = new FColoredMaterialRenderProxy( + GEngine->WireframeMaterial->GetRenderProxy(), + FLinearColor(0, 0.5f, 1.f)); + + Collector.RegisterOneFrameMaterialProxy(WireframeMaterialInstance); + MaterialProxy = WireframeMaterialInstance; + } + else + { + MaterialProxy = Material->GetRenderProxy(); + } + + for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++) + { + if (VisibilityMap & (1 << ViewIndex)) + { + const FSceneView* View = Views[ViewIndex]; + + FDynamicMeshBuilder DynamicMeshBuilder(View->GetFeatureLevel()); + DynamicMeshBuilder.AddVertices(Vertices); + DynamicMeshBuilder.AddTriangles(Indices); + + DynamicMeshBuilder.GetMesh(GetLocalToWorld(), MaterialProxy, SDPG_World, true, false, ViewIndex, Collector); + + // -- Original draw code for reference -- + //FMeshBatch& Mesh = Collector.AllocateMesh(); + //FMeshBatchElement& BatchElement = Mesh.Elements[0]; + //BatchElement.IndexBuffer = &IndexBuffer; + //Mesh.bWireframe = bWireframe; + //Mesh.VertexFactory = &VertexFactory; + //Mesh.MaterialRenderProxy = MaterialProxy; + //BatchElement.PrimitiveUniformBuffer = CreatePrimitiveUniformBufferImmediate(GetLocalToWorld(), GetBounds(), GetLocalBounds(), true, DrawsVelocity()); + //BatchElement.FirstIndex = 0; + //BatchElement.NumPrimitives = IndexBuffer.Indices.Num() / 3; + //BatchElement.MinVertexIndex = 0; + //BatchElement.MaxVertexIndex = VertexBuffer.Vertices.Num() - 1; + //Mesh.ReverseCulling = IsLocalToWorldDeterminantNegative(); + //Mesh.Type = PT_TriangleList; + //Mesh.DepthPriorityGroup = SDPG_World; + //Mesh.bCanApplyViewModeOverrides = false; + //Collector.AddMesh(ViewIndex, Mesh); + } + } + } + } + + virtual FPrimitiveViewRelevance GetViewRelevance(const FSceneView* View) const override + { + FPrimitiveViewRelevance Result; + Result.bDrawRelevance = IsShown(View); + Result.bShadowRelevance = IsShadowCast(View); + Result.bDynamicRelevance = true; + Result.bRenderInMainPass = ShouldRenderInMainPass(); + Result.bUsesLightingChannels = GetLightingChannelMask() != GetDefaultLightingChannelMask(); + Result.bRenderCustomDepth = ShouldRenderCustomDepth(); + MaterialRelevance.SetPrimitiveViewRelevance(Result); + return Result; + } + + virtual bool CanBeOccluded() const override + { + return !MaterialRelevance.bDisableDepthTest; + } + + virtual uint32 GetMemoryFootprint(void) const override { return (sizeof(*this) + GetAllocatedSize()); } + + uint32 GetAllocatedSize(void) const { return (FPrimitiveSceneProxy::GetAllocatedSize()); } + +private: + UMaterialInterface* Material; + TArray Vertices; + TArray Indices; + FMaterialRelevance MaterialRelevance; + UTextureRenderTarget2D* PlaneRenderTarget; +}; + +////////////////////////////////////////////////////////////////////////// + +UOculusXRMR_PlaneMeshComponent::UOculusXRMR_PlaneMeshComponent(const FObjectInitializer& ObjectInitializer) + : Super(ObjectInitializer) +{ + PrimaryComponentTick.bCanEverTick = false; + + SetCollisionProfileName(UCollisionProfile::BlockAllDynamic_ProfileName); + + bRenderCustomDepth = true; +} + +bool UOculusXRMR_PlaneMeshComponent::SetCustomMeshTriangles(const TArray& Triangles) +{ + CustomMeshTris = Triangles; + + // Need to recreate scene proxy to send it over + MarkRenderStateDirty(); + + return true; +} + +void UOculusXRMR_PlaneMeshComponent::AddCustomMeshTriangles(const TArray& Triangles) +{ + CustomMeshTris.Append(Triangles); + + // Need to recreate scene proxy to send it over + MarkRenderStateDirty(); +} + +void UOculusXRMR_PlaneMeshComponent::ClearCustomMeshTriangles() +{ + CustomMeshTris.Reset(); + + // Need to recreate scene proxy to send it over + MarkRenderStateDirty(); +} + +void UOculusXRMR_PlaneMeshComponent::Place(const FVector& Center, const FVector& Up, const FVector& Normal, const FVector2D& Size) +{ + FVector Right = FVector::CrossProduct(Up, Normal); + + FVector Up_N = Up.GetUnsafeNormal(); + FVector Right_N = Right.GetUnsafeNormal(); + + FVector V0 = Center - Right_N * Size.X * 0.5f - Up_N * Size.Y * 0.5f; + FVector2D UV0(1, 1); + FVector V1 = Center + Right_N * Size.X * 0.5f - Up_N * Size.Y * 0.5f; + FVector2D UV1(0, 1); + FVector V2 = Center - Right_N * Size.X * 0.5f + Up_N * Size.Y * 0.5f; + FVector2D UV2(1, 0); + FVector V3 = Center + Right_N * Size.X * 0.5f + Up_N * Size.Y * 0.5f; + FVector2D UV3(0, 0); + + FOculusXRMR_PlaneMeshTriangle Tri0, Tri1; + Tri0.Vertex0 = V1; + Tri0.UV0 = UV1; + Tri0.Vertex1 = V0; + Tri0.UV1 = UV0; + Tri0.Vertex2 = V2; + Tri0.UV2 = UV2; + Tri1.Vertex0 = V1; + Tri1.UV0 = UV1; + Tri1.Vertex1 = V2; + Tri1.UV1 = UV2; + Tri1.Vertex2 = V3; + Tri1.UV2 = UV3; + + SetCustomMeshTriangles({ Tri0, Tri1 }); +} + +FPrimitiveSceneProxy* UOculusXRMR_PlaneMeshComponent::CreateSceneProxy() +{ + FPrimitiveSceneProxy* Proxy = nullptr; + if (CustomMeshTris.Num() > 0) + { + Proxy = new FOculusXRMR_PlaneMeshSceneProxy(this, PlaneRenderTarget); + } + return Proxy; +} + +int32 UOculusXRMR_PlaneMeshComponent::GetNumMaterials() const +{ + return 1; +} + +FBoxSphereBounds UOculusXRMR_PlaneMeshComponent::CalcBounds(const FTransform& LocalToWorld) const +{ + FBoxSphereBounds NewBounds; + NewBounds.Origin = FVector::ZeroVector; + NewBounds.BoxExtent = FVector(HALF_WORLD_MAX, HALF_WORLD_MAX, HALF_WORLD_MAX); + NewBounds.SphereRadius = FMath::Sqrt(3.0f * FMath::Square(HALF_WORLD_MAX)); + return NewBounds; +} diff --git a/Plugins/MetaXR/Source/OculusXRMR/Private/OculusXRMR_PlaneMeshComponent.h b/Plugins/MetaXR/Source/OculusXRMR/Private/OculusXRMR_PlaneMeshComponent.h new file mode 100644 index 0000000..3650687 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRMR/Private/OculusXRMR_PlaneMeshComponent.h @@ -0,0 +1,77 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "UObject/ObjectMacros.h" +#include "Components/MeshComponent.h" +#include "OculusXRMR_PlaneMeshComponent.generated.h" + +class FPrimitiveSceneProxy; +class UTextureRenderTarget2D; + +USTRUCT(BlueprintType) +struct FOculusXRMR_PlaneMeshTriangle +{ + GENERATED_USTRUCT_BODY() + + UPROPERTY() + FVector Vertex0 = FVector(0.0f); + + UPROPERTY() + FVector2D UV0 = FVector2D(0.0f); + + UPROPERTY() + FVector Vertex1 = FVector(0.0f); + + UPROPERTY() + FVector2D UV1 = FVector2D(0.0f); + + UPROPERTY() + FVector Vertex2 = FVector(0.0f); + + UPROPERTY() + FVector2D UV2 = FVector2D(0.0f); +}; + +/** Component that allows you to specify custom triangle mesh geometry */ +UCLASS(hidecategories = (Object, LOD, Physics, Collision), editinlinenew, ClassGroup = Rendering, NotPlaceable, NotBlueprintable) +class UOculusXRMR_PlaneMeshComponent : public UMeshComponent +{ + GENERATED_UCLASS_BODY() + + /** Set the geometry to use on this triangle mesh */ + UFUNCTION(BlueprintCallable, Category = "Components|CustomMesh") + bool SetCustomMeshTriangles(const TArray& Triangles); + + /** Add to the geometry to use on this triangle mesh. This may cause an allocation. Use SetCustomMeshTriangles() instead when possible to reduce allocations. */ + UFUNCTION(BlueprintCallable, Category = "Components|CustomMesh") + void AddCustomMeshTriangles(const TArray& Triangles); + + /** Removes all geometry from this triangle mesh. Does not deallocate memory, allowing new geometry to reuse the existing allocation. */ + UFUNCTION(BlueprintCallable, Category = "Components|CustomMesh") + void ClearCustomMeshTriangles(); + + void Place(const FVector& Center, const FVector& Up, const FVector& Normal, const FVector2D& Size); + + void SetPlaneRenderTarget(UTextureRenderTarget2D* RT) { PlaneRenderTarget = RT; } + +private: + //~ Begin UPrimitiveComponent Interface. + virtual FPrimitiveSceneProxy* CreateSceneProxy() override; + //~ End UPrimitiveComponent Interface. + + //~ Begin UMeshComponent Interface. + virtual int32 GetNumMaterials() const override; + //~ End UMeshComponent Interface. + + //~ Begin USceneComponent Interface. + virtual FBoxSphereBounds CalcBounds(const FTransform& LocalToWorld) const override; + //~ Begin USceneComponent Interface. + + TArray CustomMeshTris; + + UTextureRenderTarget2D* PlaneRenderTarget; + + friend class FOculusXRMR_PlaneMeshSceneProxy; +}; diff --git a/Plugins/MetaXR/Source/OculusXRMR/Private/OculusXRMR_Settings.cpp b/Plugins/MetaXR/Source/OculusXRMR/Private/OculusXRMR_Settings.cpp new file mode 100644 index 0000000..d4a6931 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRMR/Private/OculusXRMR_Settings.cpp @@ -0,0 +1,142 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +#include "OculusXRMR_Settings.h" +#include "OculusXRMRPrivate.h" +#include "OculusXRHMD.h" +#include "Engine/Engine.h" + +UOculusXRMR_Settings::UOculusXRMR_Settings(const FObjectInitializer& ObjectInitializer) + : Super(ObjectInitializer) + , ClippingReference(EOculusXRMR_ClippingReference::CR_Head) + , bUseTrackedCameraResolution(true) + , WidthPerView(960) + , HeightPerView(540) + , CastingLatency(0.0f) + , BackdropColor(FColor::Green) + , ExternalCompositionPostProcessEffects(EOculusXRMR_PostProcessEffects::PPE_Off) + , bIsCasting(false) + , CompositionMethod(EOculusXRMR_CompositionMethod::ExternalComposition) + , BindToTrackedCameraIndex(-1) +{ +} + +void UOculusXRMR_Settings::SetCompositionMethod(EOculusXRMR_CompositionMethod val) +{ + if (CompositionMethod == val) + { + return; + } + auto old = CompositionMethod; + CompositionMethod = val; + CompositionMethodChangeDelegate.Execute(old, val); +} + +void UOculusXRMR_Settings::SetCapturingCamera(EOculusXRMR_CameraDeviceEnum val) +{ + // deprecated +} + +void UOculusXRMR_Settings::SetIsCasting(bool val) +{ + if (bIsCasting == val) + { + return; + } + auto old = bIsCasting; + bIsCasting = val; + IsCastingChangeDelegate.Execute(old, val); +} + +void UOculusXRMR_Settings::BindToTrackedCameraIndexIfAvailable(int InTrackedCameraIndex) +{ + if (BindToTrackedCameraIndex == InTrackedCameraIndex) + { + return; + } + auto old = BindToTrackedCameraIndex; + BindToTrackedCameraIndex = InTrackedCameraIndex; + TrackedCameraIndexChangeDelegate.Execute(old, InTrackedCameraIndex); +} + +void UOculusXRMR_Settings::LoadFromIni() +{ + if (!GConfig) + { + UE_LOG(LogMR, Warning, TEXT("GConfig is NULL")); + return; + } + + // Flushing the GEngineIni is necessary to get the settings reloaded at the runtime, but the manual flushing + // could cause an assert when loading audio settings if launching through editor at the 2nd time. Disabled temporarily. + //GConfig->Flush(true, GEngineIni); + + const TCHAR* OculusXRMRSettings = TEXT("Oculus.Settings.MixedReality"); + bool v; + float f; + int32 i; + FVector vec; + FColor color; + if (GConfig->GetInt(OculusXRMRSettings, TEXT("CompositionMethod"), i, GEngineIni)) + { + SetCompositionMethod((EOculusXRMR_CompositionMethod)i); + } + if (GConfig->GetInt(OculusXRMRSettings, TEXT("ClippingReference"), i, GEngineIni)) + { + ClippingReference = (EOculusXRMR_ClippingReference)i; + } + if (GConfig->GetBool(OculusXRMRSettings, TEXT("bUseTrackedCameraResolution"), v, GEngineIni)) + { + bUseTrackedCameraResolution = v; + } + if (GConfig->GetInt(OculusXRMRSettings, TEXT("WidthPerView"), i, GEngineIni)) + { + WidthPerView = i; + } + if (GConfig->GetInt(OculusXRMRSettings, TEXT("HeightPerView"), i, GEngineIni)) + { + HeightPerView = i; + } + if (GConfig->GetFloat(OculusXRMRSettings, TEXT("CastingLatency"), f, GEngineIni)) + { + CastingLatency = f; + } + if (GConfig->GetColor(OculusXRMRSettings, TEXT("BackdropColor"), color, GEngineIni)) + { + BackdropColor = color; + } + if (GConfig->GetInt(OculusXRMRSettings, TEXT("BindToTrackedCameraIndex"), i, GEngineIni)) + { + BindToTrackedCameraIndexIfAvailable(i); + } + if (GConfig->GetInt(OculusXRMRSettings, TEXT("ExternalCompositionPostProcessEffects"), i, GEngineIni)) + { + ExternalCompositionPostProcessEffects = (EOculusXRMR_PostProcessEffects)i; + } + + UE_LOG(LogMR, Log, TEXT("MixedReality settings loaded from Engine.ini")); +} + +void UOculusXRMR_Settings::SaveToIni() const +{ + if (!GConfig) + { + UE_LOG(LogMR, Warning, TEXT("GConfig is NULL")); + return; + } + + const TCHAR* OculusXRMRSettings = TEXT("Oculus.Settings.MixedReality"); + GConfig->SetInt(OculusXRMRSettings, TEXT("CompositionMethod"), (int32)CompositionMethod, GEngineIni); + GConfig->SetInt(OculusXRMRSettings, TEXT("ClippingReference"), (int32)ClippingReference, GEngineIni); + GConfig->SetBool(OculusXRMRSettings, TEXT("bUseTrackedCameraResolution"), bUseTrackedCameraResolution, GEngineIni); + GConfig->SetInt(OculusXRMRSettings, TEXT("WidthPerView"), WidthPerView, GEngineIni); + GConfig->SetInt(OculusXRMRSettings, TEXT("HeightPerView"), HeightPerView, GEngineIni); + GConfig->SetFloat(OculusXRMRSettings, TEXT("CastingLatency"), CastingLatency, GEngineIni); + GConfig->SetColor(OculusXRMRSettings, TEXT("BackdropColor"), BackdropColor, GEngineIni); + GConfig->SetInt(OculusXRMRSettings, TEXT("BindToTrackedCameraIndex"), (int32)BindToTrackedCameraIndex, GEngineIni); + GConfig->SetInt(OculusXRMRSettings, TEXT("ExternalCompositionPostProcessEffects"), (int32)ExternalCompositionPostProcessEffects, GEngineIni); + + GConfig->Flush(false, GEngineIni); + + UE_LOG(LogMR, Log, TEXT("MixedReality settings saved to Engine.ini")); +} diff --git a/Plugins/MetaXR/Source/OculusXRMR/Private/OculusXRMR_State.cpp b/Plugins/MetaXR/Source/OculusXRMR/Private/OculusXRMR_State.cpp new file mode 100644 index 0000000..e3525fa --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRMR/Private/OculusXRMR_State.cpp @@ -0,0 +1,13 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. +#include "OculusXRMR_State.h" +#include "OculusXRMRFunctionLibrary.h" + +UOculusXRMR_State::UOculusXRMR_State(const FObjectInitializer& ObjectInitializer) + : TrackedCamera() + , TrackingReferenceComponent(nullptr) + , ScalingFactor(1.0f) + , ChangeCameraStateRequested(false) + , BindToTrackedCameraIndexRequested(false) +{ +} diff --git a/Plugins/MetaXR/Source/OculusXRMR/Private/OculusXRMR_State.h b/Plugins/MetaXR/Source/OculusXRMR/Private/OculusXRMR_State.h new file mode 100644 index 0000000..e1649c3 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRMR/Private/OculusXRMR_State.h @@ -0,0 +1,117 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. +#pragma once + +#include "UObject/ObjectMacros.h" +#include "OculusXRFunctionLibrary.h" +#include "OculusXRPluginWrapper.h" + +#include "OculusXRMR_State.generated.h" + +USTRUCT() +struct FOculusXRTrackedCamera +{ + GENERATED_USTRUCT_BODY() + + /** >=0: the index of the external camera + * -1: not bind to any external camera (and would be setup to match the manual CastingCameraActor placement) + */ + UPROPERTY() + int32 Index; + + /** The external camera name set through the CameraTool */ + UPROPERTY() + FString Name; + + /** The time that this camera was updated */ + UPROPERTY() + double UpdateTime; + + /** The horizontal FOV, in degrees */ + UPROPERTY(meta = (UIMin = "5.0", UIMax = "170", ClampMin = "0.001", ClampMax = "360.0", Units = deg)) + float FieldOfView; + + /** The resolution of the camera frame */ + UPROPERTY() + int32 SizeX; + + /** The resolution of the camera frame */ + UPROPERTY() + int32 SizeY; + + /** The tracking node the external camera is bound to */ + UPROPERTY() + EOculusXRTrackedDeviceType AttachedTrackedDevice; + + /** The relative pose of the camera to the attached tracking device */ + UPROPERTY() + FRotator CalibratedRotation; + + /** The relative pose of the camera to the attached tracking device */ + UPROPERTY() + FVector CalibratedOffset; + + /** (optional) The user pose is provided to fine tuning the relative camera pose at the run-time */ + UPROPERTY() + FRotator UserRotation; + + /** (optional) The user pose is provided to fine tuning the relative camera pose at the run-time */ + UPROPERTY() + FVector UserOffset; + + /** The raw pose of the camera to the attached tracking device (Deprecated) */ + UPROPERTY(meta = (DeprecatedProperty, DeprecationMessage = "All camera pose info is now in stage space, do not use raw pose data.")) + FRotator RawRotation_DEPRECATED; + + /** The raw pose of the camera to the attached tracking device (Deprecated) */ + UPROPERTY(meta = (DeprecatedProperty, DeprecationMessage = "All camera pose info is now in stage space, do not use raw pose data.")) + FVector RawOffset_DEPRECATED; + + FOculusXRTrackedCamera() + : Index(-1) + , Name(TEXT("Unknown")) + , UpdateTime(0.0f) + , FieldOfView(90.0f) + , SizeX(1280) + , SizeY(720) + , AttachedTrackedDevice(EOculusXRTrackedDeviceType::None) + , CalibratedRotation(EForceInit::ForceInitToZero) + , CalibratedOffset(EForceInit::ForceInitToZero) + , UserRotation(EForceInit::ForceInitToZero) + , UserOffset(EForceInit::ForceInitToZero) + , RawRotation_DEPRECATED(EForceInit::ForceInitToZero) + , RawOffset_DEPRECATED(EForceInit::ForceInitToZero) + { + } +}; + +/** +* Object to hold the state of MR capture and capturing camera +*/ +UCLASS(ClassGroup = OculusXRMR, NotPlaceable, NotBlueprintable) +class UOculusXRMR_State : public UObject +{ + GENERATED_BODY() + +public: + UOculusXRMR_State(const FObjectInitializer& ObjectInitializer); + + UPROPERTY() + FOculusXRTrackedCamera TrackedCamera; + + // Component at the tracking origin that the camera calibration is applied to + UPROPERTY() + class USceneComponent* TrackingReferenceComponent; + + // A multiplier on the camera distance, should be based on the scaling of the player component + UPROPERTY() + double ScalingFactor; + + /** Flag indicating a change in the tracked camera state for the camera actor to consume */ + UPROPERTY() + bool ChangeCameraStateRequested; + + /** Flag indicating a change in the tracked camera index for the camera actor to consume */ + UPROPERTY() + bool BindToTrackedCameraIndexRequested; +}; diff --git a/Plugins/MetaXR/Source/OculusXRMR/Public/IOculusXRMRModule.h b/Plugins/MetaXR/Source/OculusXRMR/Public/IOculusXRMRModule.h new file mode 100644 index 0000000..6376d1c --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRMR/Public/IOculusXRMRModule.h @@ -0,0 +1,38 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +#pragma once +#include "Modules/ModuleManager.h" + +// Oculus support is not available on Windows XP +#define OCULUS_MR_SUPPORTED_PLATFORMS ((PLATFORM_WINDOWS && WINVER > 0x0502) || PLATFORM_ANDROID) + +/** + * The public interface to this module. In most cases, this interface is only public to sibling modules + * within this plugin. + */ +class IOculusXRMRModule : public IModuleInterface +{ + +public: + /** + * Singleton-like access to this module's interface. This is just for convenience! + * Beware of calling this during the shutdown phase, though. Your module might have been unloaded already. + * + * @return Returns singleton instance, loading the module on demand if needed + */ + static inline IOculusXRMRModule& Get() + { + return FModuleManager::GetModuleChecked("OculusXRMR"); + } + + /** + * Checks to see if this module is loaded and ready. It is only valid to call Get() if IsAvailable() returns true. + * + * @return True if the module is loaded and ready to use + */ + static inline bool IsAvailable() + { + return FModuleManager::Get().IsModuleLoaded("OculusXRMR"); + } +}; diff --git a/Plugins/MetaXR/Source/OculusXRMR/Public/OculusXRMRFunctionLibrary.h b/Plugins/MetaXR/Source/OculusXRMR/Public/OculusXRMRFunctionLibrary.h new file mode 100644 index 0000000..7baf8fb --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRMR/Public/OculusXRMRFunctionLibrary.h @@ -0,0 +1,59 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +#pragma once +#include "UObject/ObjectMacros.h" +#include "Kismet/BlueprintFunctionLibrary.h" +#include "OculusXRMRFunctionLibrary.generated.h" + +class USceneComponent; +class UOculusXRMR_Settings; +struct FOculusXRTrackedCamera; + +namespace OculusXRHMD +{ + class FOculusXRHMD; +} + +UCLASS() +class OCULUSXRMR_API UOculusXRMRFunctionLibrary : public UBlueprintFunctionLibrary +{ + GENERATED_UCLASS_BODY() + +public: + // Get the OculusXRMR settings object + UFUNCTION(BlueprintCallable, Category = "OculusLibrary|MR", meta = (DisplayName = "Get Oculus MR Settings")) + static UOculusXRMR_Settings* GetOculusXRMRSettings(); + + // Get the component that the OculusXRMR camera is tracking. When this is null, the camera will track the player pawn. + UFUNCTION(BlueprintCallable, Category = "OculusLibrary|MR") + static USceneComponent* GetTrackingReferenceComponent(); + + // Set the component for the OculusXRMR camera to track. If this is set to null, the camera will track the player pawn. + UFUNCTION(BlueprintCallable, Category = "OculusLibrary|MR") + static bool SetTrackingReferenceComponent(USceneComponent* Component); + + // Get the scaling factor for the MRC configuration. Returns 0 if not available. + UFUNCTION(BlueprintCallable, Category = "OculusLibrary|MR", meta = (DisplayName = "Get MRC Scaling Factor")) + static float GetMrcScalingFactor(); + + // Set the scaling factor for the MRC configuration. This should be a positive value set to the same scaling as the VR player pawn so that the game capture and camera video are aligned. + UFUNCTION(BlueprintCallable, Category = "OculusLibrary|MR", meta = (DisplayName = "Set MRC Scaling Factor")) + static bool SetMrcScalingFactor(float ScalingFactor = 1.0f); + + // Check if MRC is enabled + UFUNCTION(BlueprintCallable, Category = "OculusLibrary|MR") + static bool IsMrcEnabled(); + + // Check if MRC is enabled and actively capturing + UFUNCTION(BlueprintCallable, Category = "OculusLibrary|MR") + static bool IsMrcActive(); + +public: + static class OculusXRHMD::FOculusXRHMD* GetOculusXRHMD(); + + /** Retrieve an array of all (calibrated) tracked cameras which were calibrated through the CameraTool */ + static void GetAllTrackedCamera(TArray& TrackedCameras, bool bCalibratedOnly = true); + + static bool GetTrackingReferenceLocationAndRotationInWorldSpace(USceneComponent* TrackingReferenceComponent, FVector& TRLocation, FRotator& TRRotation); +}; diff --git a/Plugins/MetaXR/Source/OculusXRMR/Public/OculusXRMR_Settings.h b/Plugins/MetaXR/Source/OculusXRMR/Public/OculusXRMR_Settings.h new file mode 100644 index 0000000..9a941ca --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRMR/Public/OculusXRMR_Settings.h @@ -0,0 +1,175 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +#pragma once +#include "UObject/ObjectMacros.h" + +#include "OculusXRMR_Settings.generated.h" + +UENUM(BlueprintType) +enum class EOculusXRMR_CameraDeviceEnum : uint8 // Deprecated +{ + CD_None_DEPRECATED UMETA(DisplayName = "None"), + CD_WebCamera0_DEPRECATED UMETA(DisplayName = "Web Camera 0"), + CD_WebCamera1_DEPRECATED UMETA(DisplayName = "Web Camera 1"), +}; + +UENUM(BlueprintType) +enum class EOculusXRMR_ClippingReference : uint8 +{ + CR_TrackingReference UMETA(DisplayName = "Tracking Reference"), + CR_Head UMETA(DisplayName = "Head"), +}; + +UENUM(BlueprintType) +enum class EOculusXRMR_PostProcessEffects : uint8 +{ + PPE_Off UMETA(DisplayName = "Off"), + PPE_On UMETA(DisplayName = "On"), +}; + +UENUM(BlueprintType) +enum class EOculusXRMR_CompositionMethod : uint8 +{ + /* Generate both foreground and background views for compositing with 3rd-party software like OBS. */ + ExternalComposition UMETA(DisplayName = "External Composition"), + /* (Deprecated) Composite the camera stream directly to the output with the proper depth.*/ + DirectComposition_DEPRECATED UMETA(DisplayName = "Direct Composition (DEPRECATED)") +}; + +UCLASS(ClassGroup = OculusXRMR, Blueprintable) +class UOculusXRMR_Settings : public UObject +{ + GENERATED_BODY() + +public: + UOculusXRMR_Settings(const FObjectInitializer& ObjectInitializer); + + /** Specify the distance to the camera which divide the background and foreground in MxR casting. + * Set it to CR_TrackingReference to use the distance to the Tracking Reference, which works better + * in the stationary experience. Set it to CR_Head would use the distance to the HMD, which works better + * in the room scale experience. + */ + UPROPERTY(Category = MetaXR, EditAnywhere, BlueprintReadWrite) + EOculusXRMR_ClippingReference ClippingReference; + + /** The casting viewports would use the same resolution of the camera which used in the calibration process. */ + UPROPERTY(Category = MetaXR, EditAnywhere, BlueprintReadWrite) + bool bUseTrackedCameraResolution; + + /** When bUseTrackedCameraResolution is false, the width of each casting viewport */ + UPROPERTY(Category = MetaXR, EditAnywhere, BlueprintReadWrite) + int WidthPerView; + + /** When bUseTrackedCameraResolution is false, the height of each casting viewport */ + UPROPERTY(Category = MetaXR, EditAnywhere, BlueprintReadWrite) + int HeightPerView; + + /** When CompositionMethod is External Composition, the latency of the casting output which could be adjusted to + * match the camera latency in the external composition application */ + UPROPERTY(Category = MetaXR, EditAnywhere, BlueprintReadWrite, meta = (UIMin = "0.0", UIMax = "0.1")) + float CastingLatency; + + /** When CompositionMethod is External Composition, the color of the backdrop in the foreground view */ + UPROPERTY(Category = MetaXR, EditAnywhere, BlueprintReadWrite) + FColor BackdropColor; + + /** When CompositionMethod is Direct Composition, you could adjust this latency to delay the virtual + * hand movement by a small amount of time to match the camera latency */ + UPROPERTY(meta = (DeprecatedProperty, DeprecationMessage = "Direct Composition deprecated.")) + float HandPoseStateLatency_DEPRECATED; + + /** [Green-screen removal] Chroma Key Color. Apply when CompositionMethod is DirectComposition */ + UPROPERTY(meta = (DeprecatedProperty, DeprecationMessage = "Direct Composition deprecated.")) + FColor ChromaKeyColor_DEPRECATED; + + /** [Green-screen removal] Chroma Key Similarity. Apply when CompositionMethod is DirectComposition */ + UPROPERTY(meta = (DeprecatedProperty, DeprecationMessage = "Direct Composition deprecated.")) + float ChromaKeySimilarity_DEPRECATED; + + /** [Green-screen removal] Chroma Key Smooth Range. Apply when CompositionMethod is DirectComposition */ + UPROPERTY(meta = (DeprecatedProperty, DeprecationMessage = "Direct Composition deprecated.")) + float ChromaKeySmoothRange_DEPRECATED; + + /** [Green-screen removal] Chroma Key Spill Range. Apply when CompositionMethod is DirectComposition */ + UPROPERTY(meta = (DeprecatedProperty, DeprecationMessage = "Direct Composition deprecated.")) + float ChromaKeySpillRange_DEPRECATED; + + /** Set the amount of post process effects in the MR view for external composition */ + UPROPERTY(Category = MetaXR, EditAnywhere, BlueprintReadWrite) + EOculusXRMR_PostProcessEffects ExternalCompositionPostProcessEffects; + + /** ExternalComposition: The casting window includes the background and foreground view + * DirectComposition: The game scene would be composited with the camera frame directly + */ + UFUNCTION(BlueprintCallable, Category = MetaXR) + EOculusXRMR_CompositionMethod GetCompositionMethod() { return CompositionMethod; } + + /** ExternalComposition: The casting window includes the background and foreground view + * DirectComposition: The game scene would be composited with the camera frame directly + */ + UFUNCTION(BlueprintCallable, Category = MetaXR) + void SetCompositionMethod(EOculusXRMR_CompositionMethod val); + + /** When CompositionMethod is DirectComposition, the physical camera device which provide the frame */ + UFUNCTION(BlueprintCallable, Category = MetaXR, meta = (DeprecatedFunction, DeprecationMessage = "Direct Composition deprecated.")) + EOculusXRMR_CameraDeviceEnum GetCapturingCamera() { return EOculusXRMR_CameraDeviceEnum::CD_None_DEPRECATED; } + + /** When CompositionMethod is DirectComposition, the physical camera device which provide the frame */ + UFUNCTION(BlueprintCallable, Category = MetaXR, meta = (DeprecatedFunction, DeprecationMessage = "Direct Composition deprecated.")) + void SetCapturingCamera(EOculusXRMR_CameraDeviceEnum val); + + /** Is MRC on and off */ + UFUNCTION(BlueprintCallable, Category = MetaXR) + bool GetIsCasting() { return bIsCasting; } + + /** Turns MRC on and off */ + UFUNCTION(BlueprintCallable, Category = MetaXR) + void SetIsCasting(bool val); + + /** Bind the casting camera to the calibrated external camera. + * (Requires a calibrated external camera) + */ + UFUNCTION(BlueprintCallable, Category = MetaXR) + void BindToTrackedCameraIndexIfAvailable(int InTrackedCameraIndex); + + UFUNCTION(BlueprintCallable, Category = MetaXR) + int GetBindToTrackedCameraIndex() { return BindToTrackedCameraIndex; } + + /** Load settings from the config file */ + UFUNCTION(BlueprintCallable, Category = MetaXR) + void LoadFromIni(); + + /** Save settings to the config file */ + UFUNCTION(BlueprintCallable, Category = MetaXR) + void SaveToIni() const; + +private: + /** Turns MRC on and off (does not get saved to or loaded from ini) */ + UPROPERTY() + bool bIsCasting; + + /** ExternalComposition: The casting window includes the background and foreground view + * DirectComposition: The game scene would be composited with the camera frame directly + */ + UPROPERTY() + EOculusXRMR_CompositionMethod CompositionMethod; + + /** When CompositionMethod is DirectComposition, the physical camera device which provide the frame */ + UPROPERTY(meta = (DeprecatedProperty, DeprecationMessage = "Direct Composition deprecated.")) + EOculusXRMR_CameraDeviceEnum CapturingCamera_DEPRECATED; + + /** Tracked camera that we want to bind the in-game MR camera to*/ + int BindToTrackedCameraIndex; + + DECLARE_DELEGATE_TwoParams(OnCompositionMethodChangeDelegate, EOculusXRMR_CompositionMethod, EOculusXRMR_CompositionMethod); + DECLARE_DELEGATE_TwoParams(OnBooleanSettingChangeDelegate, bool, bool); + DECLARE_DELEGATE_TwoParams(OnIntegerSettingChangeDelegate, int, int); + + OnIntegerSettingChangeDelegate TrackedCameraIndexChangeDelegate; + OnCompositionMethodChangeDelegate CompositionMethodChangeDelegate; + OnBooleanSettingChangeDelegate IsCastingChangeDelegate; + + // Give the OculusXRMR module access to the delegates so that + friend class FOculusXRMRModule; +}; diff --git a/Plugins/MetaXR/Source/OculusXRMovement/OculusXRMovement.Build.cs b/Plugins/MetaXR/Source/OculusXRMovement/OculusXRMovement.Build.cs new file mode 100644 index 0000000..90975b6 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRMovement/OculusXRMovement.Build.cs @@ -0,0 +1,38 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +namespace UnrealBuildTool.Rules +{ + public class OculusXRMovement : ModuleRules + { + public OculusXRMovement(ReadOnlyTargetRules Target) : base(Target) + { + bUseUnity = true; + + PublicDependencyModuleNames.AddRange( + new string[] { + "LiveLinkInterface", + "LiveLinkAnimationCore", + }); + + PrivateDependencyModuleNames.AddRange( + new string[] + { + "Core", + "CoreUObject", + "ApplicationCore", + "Engine", + "InputCore", + "LiveLink", + "HeadMountedDisplay", + "OVRPluginXR", + "OculusXRHMD", + }); + + PrivateIncludePaths.AddRange( + new string[] { + "OculusXRHMD/Private", + }); + } + } +} diff --git a/Plugins/MetaXR/Source/OculusXRMovement/Private/LiveLinkOculusXRMovementSourceFactory.cpp b/Plugins/MetaXR/Source/OculusXRMovement/Private/LiveLinkOculusXRMovementSourceFactory.cpp new file mode 100644 index 0000000..401dcd5 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRMovement/Private/LiveLinkOculusXRMovementSourceFactory.cpp @@ -0,0 +1,40 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#include "LiveLinkOculusXRMovementSourceFactory.h" +#include "IOculusXRMovementModule.h" + +#include "Features/IModularFeatures.h" +#include "ILiveLinkClient.h" + +#define LOCTEXT_NAMESPACE "OculusXRMovement" + +FText ULiveLinkOculusXRMovementSourceFactory::GetSourceDisplayName() const +{ + return LOCTEXT("OculusXRMovementLiveLinkSourceName", "Meta MovementSDK Live Link"); +} + +FText ULiveLinkOculusXRMovementSourceFactory::GetSourceTooltip() const +{ + return LOCTEXT("OculusXRMovementLiveLinkSourceTooltip", "Meta MovementSDK Live Link Source"); +} + +ULiveLinkOculusXRMovementSourceFactory::EMenuType ULiveLinkOculusXRMovementSourceFactory::GetMenuType() const +{ + if (IModularFeatures::Get().IsModularFeatureAvailable(ILiveLinkClient::ModularFeatureName)) + { + const ILiveLinkClient& LiveLinkClient = IModularFeatures::Get().GetModularFeature(ILiveLinkClient::ModularFeatureName); + + if (!IOculusXRMovementModule::Get().IsLiveLinkSourceValid() || !LiveLinkClient.HasSourceBeenAdded(IOculusXRMovementModule::Get().GetLiveLinkSource())) + { + return EMenuType::MenuEntry; + } + } + return EMenuType::Disabled; +} + +TSharedPtr ULiveLinkOculusXRMovementSourceFactory::CreateSource(const FString& ConnectionString) const +{ + return IOculusXRMovementModule::Get().GetLiveLinkSource(); +} + +#undef LOCTEXT_NAMESPACE diff --git a/Plugins/MetaXR/Source/OculusXRMovement/Private/LiveLinkOculusXRMovementSourceFactory.h b/Plugins/MetaXR/Source/OculusXRMovement/Private/LiveLinkOculusXRMovementSourceFactory.h new file mode 100644 index 0000000..ecacd56 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRMovement/Private/LiveLinkOculusXRMovementSourceFactory.h @@ -0,0 +1,21 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#pragma once + +#include "LiveLinkSourceFactory.h" +#include "LiveLinkOculusXRMovementSourceFactory.generated.h" + +UCLASS() +class ULiveLinkOculusXRMovementSourceFactory : public ULiveLinkSourceFactory +{ +public: + GENERATED_BODY() + + virtual FText GetSourceDisplayName() const override; + virtual FText GetSourceTooltip() const override; + + virtual EMenuType GetMenuType() const override; + virtual TSharedPtr CreateSource(const FString& ConnectionString) const override; + + TSharedPtr ActiveSourceEditor; +}; diff --git a/Plugins/MetaXR/Source/OculusXRMovement/Private/OculusXRBodyTrackingComponent.cpp b/Plugins/MetaXR/Source/OculusXRMovement/Private/OculusXRBodyTrackingComponent.cpp new file mode 100644 index 0000000..98eef86 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRMovement/Private/OculusXRBodyTrackingComponent.cpp @@ -0,0 +1,263 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#include "OculusXRBodyTrackingComponent.h" + +#include "Engine/SkeletalMesh.h" +#include "DrawDebugHelpers.h" +#include "OculusXRHMD.h" +#include "OculusXRPluginWrapper.h" +#include "OculusXRMovementFunctionLibrary.h" +#include "OculusXRMovementLog.h" +#include "OculusXRTelemetryMovementEvents.h" + +#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST) +static TAutoConsoleVariable CVarOVRBodyDebugDraw( + TEXT("ovr.BodyDebugDraw"), + 0, + TEXT("Enables or disables debug drawing for body tracking.\n") + TEXT("<=0: disabled (no drawing)\n") + TEXT(" 1: enabled (debug drawing)\n")); +#endif + +int UOculusXRBodyTrackingComponent::TrackingInstanceCount = 0; + +UOculusXRBodyTrackingComponent::UOculusXRBodyTrackingComponent() + : BodyTrackingMode(EOculusXRBodyTrackingMode::PositionAndRotation) + , ConfidenceThreshold(0.f) + , WorldToMeters(100.f) +{ + PrimaryComponentTick.bCanEverTick = true; + PrimaryComponentTick.bStartWithTickEnabled = true; + + // Setup defaults + BoneNames.Add(EOculusXRBoneID::BodyRoot, "Root"); + BoneNames.Add(EOculusXRBoneID::BodyHips, "Hips"); + BoneNames.Add(EOculusXRBoneID::BodySpineLower, "SpineLower"); + BoneNames.Add(EOculusXRBoneID::BodySpineMiddle, "SpineMiddle"); + BoneNames.Add(EOculusXRBoneID::BodySpineUpper, "SpineUpper"); + BoneNames.Add(EOculusXRBoneID::BodyChest, "Chest"); + BoneNames.Add(EOculusXRBoneID::BodyNeck, "Neck"); + BoneNames.Add(EOculusXRBoneID::BodyHead, "Head"); + BoneNames.Add(EOculusXRBoneID::BodyLeftShoulder, "LeftShoulder"); + BoneNames.Add(EOculusXRBoneID::BodyLeftScapula, "LeftScapula"); + BoneNames.Add(EOculusXRBoneID::BodyLeftArmUpper, "LeftArmUpper"); + BoneNames.Add(EOculusXRBoneID::BodyLeftArmLower, "LeftArmLower"); + BoneNames.Add(EOculusXRBoneID::BodyLeftHandWristTwist, "LeftHandWristTwist"); + BoneNames.Add(EOculusXRBoneID::BodyRightShoulder, "RightShoulder"); + BoneNames.Add(EOculusXRBoneID::BodyRightScapula, "RightScapula"); + BoneNames.Add(EOculusXRBoneID::BodyRightArmUpper, "RightArmUpper"); + BoneNames.Add(EOculusXRBoneID::BodyRightArmLower, "RightArmLower"); + BoneNames.Add(EOculusXRBoneID::BodyRightHandWristTwist, "RightHandWristTwist"); + BoneNames.Add(EOculusXRBoneID::BodyLeftHandPalm, "LeftHandPalm"); + BoneNames.Add(EOculusXRBoneID::BodyLeftHandWrist, "LeftHandWrist"); + BoneNames.Add(EOculusXRBoneID::BodyLeftHandThumbMetacarpal, "LeftHandThumbMetacarpal"); + BoneNames.Add(EOculusXRBoneID::BodyLeftHandThumbProximal, "LeftHandThumbProximal"); + BoneNames.Add(EOculusXRBoneID::BodyLeftHandThumbDistal, "LeftHandThumbDistal"); + BoneNames.Add(EOculusXRBoneID::BodyLeftHandThumbTip, "LeftHandThumbTip"); + BoneNames.Add(EOculusXRBoneID::BodyLeftHandIndexMetacarpal, "LeftHandIndexMetacarpal"); + BoneNames.Add(EOculusXRBoneID::BodyLeftHandIndexProximal, "LeftHandIndexProximal"); + BoneNames.Add(EOculusXRBoneID::BodyLeftHandIndexIntermediate, "LeftHandIndexIntermediate"); + BoneNames.Add(EOculusXRBoneID::BodyLeftHandIndexDistal, "LeftHandIndexDistal"); + BoneNames.Add(EOculusXRBoneID::BodyLeftHandIndexTip, "LeftHandIndexTip"); + BoneNames.Add(EOculusXRBoneID::BodyLeftHandMiddleMetacarpal, "LeftHandMiddleMetacarpal"); + BoneNames.Add(EOculusXRBoneID::BodyLeftHandMiddleProximal, "LeftHandMiddleProximal"); + BoneNames.Add(EOculusXRBoneID::BodyLeftHandMiddleIntermediate, "LeftHandMiddleIntermediate"); + BoneNames.Add(EOculusXRBoneID::BodyLeftHandMiddleDistal, "LeftHandMiddleDistal"); + BoneNames.Add(EOculusXRBoneID::BodyLeftHandMiddleTip, "LeftHandMiddleTip"); + BoneNames.Add(EOculusXRBoneID::BodyLeftHandRingMetacarpal, "LeftHandRingMetacarpal"); + BoneNames.Add(EOculusXRBoneID::BodyLeftHandRingProximal, "LeftHandRingProximal"); + BoneNames.Add(EOculusXRBoneID::BodyLeftHandRingIntermediate, "LeftHandRingIntermediate"); + BoneNames.Add(EOculusXRBoneID::BodyLeftHandRingDistal, "LeftHandRingDistal"); + BoneNames.Add(EOculusXRBoneID::BodyLeftHandRingTip, "LeftHandRingTip"); + BoneNames.Add(EOculusXRBoneID::BodyLeftHandLittleMetacarpal, "LeftHandLittleMetacarpal"); + BoneNames.Add(EOculusXRBoneID::BodyLeftHandLittleProximal, "LeftHandLittleProximal"); + BoneNames.Add(EOculusXRBoneID::BodyLeftHandLittleIntermediate, "LeftHandLittleIntermediate"); + BoneNames.Add(EOculusXRBoneID::BodyLeftHandLittleDistal, "LeftHandLittleDistal"); + BoneNames.Add(EOculusXRBoneID::BodyLeftHandLittleTip, "LeftHandLittleTip"); + BoneNames.Add(EOculusXRBoneID::BodyRightHandPalm, "RightHandPalm"); + BoneNames.Add(EOculusXRBoneID::BodyRightHandWrist, "RightHandWrist"); + BoneNames.Add(EOculusXRBoneID::BodyRightHandThumbMetacarpal, "RightHandThumbMetacarpal"); + BoneNames.Add(EOculusXRBoneID::BodyRightHandThumbProximal, "RightHandThumbProximal"); + BoneNames.Add(EOculusXRBoneID::BodyRightHandThumbDistal, "RightHandThumbDistal"); + BoneNames.Add(EOculusXRBoneID::BodyRightHandThumbTip, "RightHandThumbTip"); + BoneNames.Add(EOculusXRBoneID::BodyRightHandIndexMetacarpal, "RightHandIndexMetacarpal"); + BoneNames.Add(EOculusXRBoneID::BodyRightHandIndexProximal, "RightHandIndexProximal"); + BoneNames.Add(EOculusXRBoneID::BodyRightHandIndexIntermediate, "RightHandIndexIntermediate"); + BoneNames.Add(EOculusXRBoneID::BodyRightHandIndexDistal, "RightHandIndexDistal"); + BoneNames.Add(EOculusXRBoneID::BodyRightHandIndexTip, "RightHandIndexTip"); + BoneNames.Add(EOculusXRBoneID::BodyRightHandMiddleMetacarpal, "RightHandMiddleMetacarpal"); + BoneNames.Add(EOculusXRBoneID::BodyRightHandMiddleProximal, "RightHandMiddleProximal"); + BoneNames.Add(EOculusXRBoneID::BodyRightHandMiddleIntermediate, "RightHandMiddleIntermediate"); + BoneNames.Add(EOculusXRBoneID::BodyRightHandMiddleDistal, "RightHandMiddleDistal"); + BoneNames.Add(EOculusXRBoneID::BodyRightHandMiddleTip, "RightHandMiddleTip"); + BoneNames.Add(EOculusXRBoneID::BodyRightHandRingMetacarpal, "RightHandRingMetacarpal"); + BoneNames.Add(EOculusXRBoneID::BodyRightHandRingProximal, "RightHandRingProximal"); + BoneNames.Add(EOculusXRBoneID::BodyRightHandRingIntermediate, "RightHandRingIntermediate"); + BoneNames.Add(EOculusXRBoneID::BodyRightHandRingDistal, "RightHandRingDistal"); + BoneNames.Add(EOculusXRBoneID::BodyRightHandRingTip, "RightHandRingTip"); + BoneNames.Add(EOculusXRBoneID::BodyRightHandLittleMetacarpal, "RightHandLittleMetacarpal"); + BoneNames.Add(EOculusXRBoneID::BodyRightHandLittleProximal, "RightHandLittleProximal"); + BoneNames.Add(EOculusXRBoneID::BodyRightHandLittleIntermediate, "RightHandLittleIntermediate"); + BoneNames.Add(EOculusXRBoneID::BodyRightHandLittleDistal, "RightHandLittleDistal"); + BoneNames.Add(EOculusXRBoneID::BodyRightHandLittleTip, "RightHandLittleTip"); + BoneNames.Add(EOculusXRBoneID::BodyLeftUpperLeg, "LeftUpperLeg"); + BoneNames.Add(EOculusXRBoneID::BodyLeftLowerLeg, "LeftLowerLeg"); + BoneNames.Add(EOculusXRBoneID::BodyLeftFootAnkleTwist, "LeftFootAnkleTwist"); + BoneNames.Add(EOculusXRBoneID::BodyLeftFootAnkle, "LeftFootAnkle"); + BoneNames.Add(EOculusXRBoneID::BodyLeftFootSubtalar, "LeftFootSubtalar"); + BoneNames.Add(EOculusXRBoneID::BodyLeftFootTransverse, "LeftFootTransverse"); + BoneNames.Add(EOculusXRBoneID::BodyLeftFootBall, "LeftFootBall"); + BoneNames.Add(EOculusXRBoneID::BodyRightUpperLeg, "RightUpperLeg"); + BoneNames.Add(EOculusXRBoneID::BodyRightLowerLeg, "RightLowerLeg"); + BoneNames.Add(EOculusXRBoneID::BodyRightFootAnkleTwist, "RightFootAnkleTwist"); + BoneNames.Add(EOculusXRBoneID::BodyRightFootAnkle, "RightFootAnkle"); + BoneNames.Add(EOculusXRBoneID::BodyRightFootSubtalar, "RightFootSubtalar"); + BoneNames.Add(EOculusXRBoneID::BodyRightFootTransverse, "RightFootTransverse"); + BoneNames.Add(EOculusXRBoneID::BodyRightFootBall, "RightFootBall"); + + OculusXRTelemetry::TScopedMarker(static_cast(GetTypeHash(this))); +} + +void UOculusXRBodyTrackingComponent::BeginPlay() +{ + Super::BeginPlay(); + + if (!UOculusXRMovementFunctionLibrary::IsBodyTrackingSupported()) + { + // Early exit if body tracking isn't supported + UE_LOG(LogOculusXRMovement, Warning, TEXT("Body tracking is not supported. (%s:%s)"), *GetOwner()->GetName(), *GetName()); + SetComponentTickEnabled(false); + return; + } + + if (!OculusXRHMD::GetUnitScaleFactorFromSettings(GetWorld(), WorldToMeters)) + { + UE_LOG(LogOculusXRMovement, Warning, TEXT("Cannot get world settings. (%s:%s)"), *GetOwner()->GetName(), *GetName()); + } + + if (!InitializeBodyBones()) + { + UE_LOG(LogOculusXRMovement, Warning, TEXT("Failed to initialize body data. (%s: %s)"), *GetOwner()->GetName(), *GetName()); + SetComponentTickEnabled(false); + return; + } + + if (!UOculusXRMovementFunctionLibrary::StartBodyTracking()) + { + UE_LOG(LogOculusXRMovement, Warning, TEXT("Failed to start body tracking. (%s: %s)"), *GetOwner()->GetName(), *GetName()); + SetComponentTickEnabled(false); + return; + } + ++TrackingInstanceCount; +} + +void UOculusXRBodyTrackingComponent::EndPlay(const EEndPlayReason::Type EndPlayReason) +{ + if (IsComponentTickEnabled()) + { + if (--TrackingInstanceCount == 0) + { + if (!UOculusXRMovementFunctionLibrary::StopBodyTracking()) + { + UE_LOG(LogOculusXRMovement, Warning, TEXT("Failed to stop body tracking. (%s: %s)"), *GetOwner()->GetName(), *GetName()); + } + } + } + + Super::EndPlay(EndPlayReason); +} + +void UOculusXRBodyTrackingComponent::TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) +{ + Super::TickComponent(DeltaTime, TickType, ThisTickFunction); + + if (UOculusXRMovementFunctionLibrary::TryGetBodyState(BodyState, WorldToMeters)) + { + if (BodyState.IsActive && BodyState.Confidence > ConfidenceThreshold) + { + for (int i = 0; i < BodyState.Joints.Num(); ++i) + { + const FOculusXRBodyJoint& Joint = BodyState.Joints[i]; + if (!Joint.bIsValid) + { + continue; + } + + const FVector& Position = Joint.Position; + const FRotator& Orientation = Joint.Orientation; + +#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST) + if (CVarOVRBodyDebugDraw.GetValueOnGameThread() > 0) + { + const FTransform& ParentTransform = GetOwner()->GetActorTransform(); + + FVector DebugPosition = ParentTransform.TransformPosition(Position); + FRotator DebugOrientation = ParentTransform.TransformRotation(Orientation.Quaternion()).Rotator(); + + DrawDebugLine(GetWorld(), DebugPosition, DebugPosition + DebugOrientation.Quaternion().GetUpVector(), FColor::Blue); + DrawDebugLine(GetWorld(), DebugPosition, DebugPosition + DebugOrientation.Quaternion().GetForwardVector(), FColor::Red); + DrawDebugLine(GetWorld(), DebugPosition, DebugPosition + DebugOrientation.Quaternion().GetRightVector(), FColor::Green); + } +#endif + + int32* BoneIndex = MappedBoneIndices.Find(static_cast(i)); + if (BoneIndex != nullptr) + { + switch (BodyTrackingMode) + { + case EOculusXRBodyTrackingMode::PositionAndRotation: + SetBoneTransformByName(BoneNames[static_cast(i)], FTransform(Orientation, Position), EBoneSpaces::ComponentSpace); + break; + case EOculusXRBodyTrackingMode::RotationOnly: + SetBoneRotationByName(BoneNames[static_cast(i)], Orientation, EBoneSpaces::ComponentSpace); + break; + case EOculusXRBodyTrackingMode::NoTracking: + break; + } + } + } + } + } + else + { + UE_LOG(LogOculusXRMovement, Verbose, TEXT("Failed to get body state (%s:%s)."), *GetOwner()->GetName(), *GetName()); + } +} + +void UOculusXRBodyTrackingComponent::ResetAllBoneTransforms() +{ + for (int i = 0; i < BodyState.Joints.Num(); ++i) + { + int32* BoneIndex = MappedBoneIndices.Find(static_cast(i)); + if (BoneIndex != nullptr) + { + ResetBoneTransformByName(BoneNames[static_cast(i)]); + } + } +} + +bool UOculusXRBodyTrackingComponent::InitializeBodyBones() +{ + USkeletalMesh* BodyMesh = Cast(GetSkinnedAsset()); + if (BodyMesh == nullptr) + { + UE_LOG(LogOculusXRMovement, Display, TEXT("No SkeletalMesh in this component.")); + return false; + } + + for (const auto& it : BoneNames) + { + int32 BoneIndex = GetBoneIndex(it.Value); + + if (BoneIndex == INDEX_NONE) + { + UE_LOG(LogOculusXRMovement, Display, TEXT("Could not find bone %s in skeletal mesh %s"), *StaticEnum()->GetValueAsString(it.Key), *BodyMesh->GetName()); + } + else + { + MappedBoneIndices.Add(it.Key, BoneIndex); + } + } + + return true; +} diff --git a/Plugins/MetaXR/Source/OculusXRMovement/Private/OculusXREyeTrackingComponent.cpp b/Plugins/MetaXR/Source/OculusXRMovement/Private/OculusXREyeTrackingComponent.cpp new file mode 100644 index 0000000..95d3f9c --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRMovement/Private/OculusXREyeTrackingComponent.cpp @@ -0,0 +1,198 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#include "OculusXREyeTrackingComponent.h" + +#include "GameFramework/WorldSettings.h" +#include "GameFramework/PlayerController.h" +#include "OculusXRHMDPrivate.h" +#include "OculusXRPluginWrapper.h" +#include "OculusXRMovementFunctionLibrary.h" +#include "OculusXRMovementHelpers.h" +#include "OculusXRMovementLog.h" +#include "OculusXRTelemetryMovementEvents.h" + +int UOculusXREyeTrackingComponent::TrackingInstanceCount = 0; + +UOculusXREyeTrackingComponent::UOculusXREyeTrackingComponent() + : TargetMeshComponentName(NAME_None) + , bUpdatePosition(true) + , bUpdateRotation(true) + , ConfidenceThreshold(0.f) + , bAcceptInvalid(false) + , WorldToMeters(100.f) + , TargetPoseableMeshComponent(nullptr) +{ + PrimaryComponentTick.bCanEverTick = true; + PrimaryComponentTick.bStartWithTickEnabled = true; + + EyeToBone.Add(EOculusXREye::Left, "LeftEye"); + EyeToBone.Add(EOculusXREye::Right, "RightEye"); + OculusXRTelemetry::TScopedMarker(static_cast(GetTypeHash(this))); +} + +void UOculusXREyeTrackingComponent::BeginPlay() +{ + Super::BeginPlay(); + + if (!UOculusXRMovementFunctionLibrary::IsEyeTrackingSupported()) + { + // Early exit if eye tracking isn't supported + UE_LOG(LogOculusXRMovement, Warning, TEXT("Eye tracking is not supported. (%s:%s)"), *GetOwner()->GetName(), *GetName()); + SetComponentTickEnabled(false); + return; + } + + // Try & check initializing the eye data + if (!InitializeEyes()) + { + UE_LOG(LogOculusXRMovement, Warning, TEXT("Failed to initialize eye tracking data. (%s:%s)"), *GetOwner()->GetName(), *GetName()); + SetComponentTickEnabled(false); + } + + if (!UOculusXRMovementFunctionLibrary::StartEyeTracking()) + { + UE_LOG(LogOculusXRMovement, Warning, TEXT("Failed to start eye tracking. (%s: %s)"), *GetOwner()->GetName(), *GetName()); + SetComponentTickEnabled(false); + return; + } + ++TrackingInstanceCount; +} + +void UOculusXREyeTrackingComponent::EndPlay(const EEndPlayReason::Type EndPlayReason) +{ + if (IsComponentTickEnabled()) + { + if (--TrackingInstanceCount == 0) + { + if (!UOculusXRMovementFunctionLibrary::StopEyeTracking()) + { + UE_LOG(LogOculusXRMovement, Warning, TEXT("Failed to stop eye tracking. (%s: %s)"), *GetOwner()->GetName(), *GetName()); + } + } + } + + Super::EndPlay(EndPlayReason); +} + +void UOculusXREyeTrackingComponent::TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) +{ + Super::TickComponent(DeltaTime, TickType, ThisTickFunction); + + if (!IsValid(TargetPoseableMeshComponent)) + { + UE_LOG(LogOculusXRMovement, VeryVerbose, TEXT("No target mesh specified. (%s:%s)"), *GetOwner()->GetName(), *GetName()); + SetComponentTickEnabled(false); + return; + } + + FOculusXREyeGazesState EyeGazesState; + + if (UOculusXRMovementFunctionLibrary::TryGetEyeGazesState(EyeGazesState, WorldToMeters)) + { + for (uint8 i = 0u; i < static_cast(EOculusXREye::COUNT); ++i) + { + if (PerEyeData[i].EyeIsMapped) + { + const auto& Bone = PerEyeData[i].MappedBoneName; + const auto& EyeGaze = EyeGazesState.EyeGazes[i]; + if ((bAcceptInvalid || EyeGaze.bIsValid) && (EyeGaze.Confidence >= ConfidenceThreshold)) + { + int32 BoneIndex = TargetPoseableMeshComponent->GetBoneIndex(Bone); + FTransform CurrentTransform = TargetPoseableMeshComponent->GetBoneTransformByName(Bone, EBoneSpaces::ComponentSpace); + + if (bUpdatePosition) + { + CurrentTransform.SetLocation(EyeGaze.Position); + } + + if (bUpdateRotation) + { + CurrentTransform.SetRotation(EyeGaze.Orientation.Quaternion() * PerEyeData[i].InitialRotation); + } + + TargetPoseableMeshComponent->SetBoneTransformByName(Bone, CurrentTransform, EBoneSpaces::ComponentSpace); + } + } + } + } + else + { + UE_LOG(LogOculusXRMovement, VeryVerbose, TEXT("Failed to get Eye state from EyeTrackingComponent. (%s:%s)"), *GetOwner()->GetName(), *GetName()); + } +} + +void UOculusXREyeTrackingComponent::ClearRotationValues() +{ + if (!IsValid(TargetPoseableMeshComponent)) + { + UE_LOG(LogOculusXRMovement, VeryVerbose, TEXT("No target mesh specified. (%s:%s)"), *GetOwner()->GetName(), *GetName()); + return; + } + + for (uint8 i = 0u; i < static_cast(EOculusXREye::COUNT); ++i) + { + if (PerEyeData[i].EyeIsMapped) + { + const auto& Bone = PerEyeData[i].MappedBoneName; + + int32 BoneIndex = TargetPoseableMeshComponent->GetBoneIndex(Bone); + FTransform CurrentTransform = TargetPoseableMeshComponent->GetBoneTransformByName(Bone, EBoneSpaces::ComponentSpace); + + CurrentTransform.SetRotation(PerEyeData[i].InitialRotation); + + TargetPoseableMeshComponent->SetBoneTransformByName(Bone, CurrentTransform, EBoneSpaces::ComponentSpace); + } + } +} + +bool UOculusXREyeTrackingComponent::InitializeEyes() +{ + bool bIsAnythingMapped = false; + + TargetPoseableMeshComponent = OculusXRUtility::FindComponentByName(GetOwner(), TargetMeshComponentName); + + if (!IsValid(TargetPoseableMeshComponent)) + { + UE_LOG(LogOculusXRMovement, Warning, TEXT("Could not find mesh with name (%s) for component. (%s:%s)"), *TargetMeshComponentName.ToString(), *GetOwner()->GetName(), *GetName()); + return false; + } + + for (uint8 i = 0u; i < static_cast(EOculusXREye::COUNT); ++i) + { + const EOculusXREye Eye = static_cast(i); + const FName* BoneNameForThisEye = EyeToBone.Find(Eye); + PerEyeData[i].EyeIsMapped = (nullptr != BoneNameForThisEye); + + if (PerEyeData[i].EyeIsMapped) + { + int32 BoneIndex = TargetPoseableMeshComponent->GetBoneIndex(*BoneNameForThisEye); + if (BoneIndex == INDEX_NONE) + { + PerEyeData[i].EyeIsMapped = false; // Eye is explicitly mapped to a bone. But the bone name doesn't exist. + UE_LOG(LogOculusXRMovement, Warning, TEXT("Could not find bone by name (%s) in mesh %s. (%s:%s)"), *BoneNameForThisEye->ToString(), *TargetPoseableMeshComponent->GetName(), *GetOwner()->GetName(), *GetName()); + } + else + { + PerEyeData[i].MappedBoneName = *BoneNameForThisEye; + PerEyeData[i].InitialRotation = TargetPoseableMeshComponent->GetBoneTransformByName(*BoneNameForThisEye, EBoneSpaces::ComponentSpace).GetRotation(); + bIsAnythingMapped = true; + } + } + else + { + UE_LOG(LogOculusXRMovement, Display, TEXT("Eye (%s) is not mapped to any bone on mesh (%s)"), *StaticEnum()->GetValueAsString(Eye), *TargetPoseableMeshComponent->GetName()); + } + } + + if (!bIsAnythingMapped) + { + UE_LOG(LogOculusXRMovement, Warning, TEXT("Component name -- %s:%s, doesn't have a valid configuration."), *GetOwner()->GetName(), *GetName()); + } + + if (!OculusXRHMD::GetUnitScaleFactorFromSettings(GetWorld(), WorldToMeters)) + { + UE_LOG(LogOculusXRMovement, Warning, TEXT("Cannot get world settings. (%s:%s)"), *GetOwner()->GetName(), *GetName()); + } + + return bIsAnythingMapped; +} diff --git a/Plugins/MetaXR/Source/OculusXRMovement/Private/OculusXRFaceTrackingComponent.cpp b/Plugins/MetaXR/Source/OculusXRMovement/Private/OculusXRFaceTrackingComponent.cpp new file mode 100644 index 0000000..e1130f1 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRMovement/Private/OculusXRFaceTrackingComponent.cpp @@ -0,0 +1,315 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#include "OculusXRFaceTrackingComponent.h" +#include "OculusXRHMD.h" +#include "OculusXRPluginWrapper.h" +#include "OculusXRMovementFunctionLibrary.h" +#include "OculusXRMovementHelpers.h" +#include "OculusXRMovementLog.h" +#include "OculusXRTelemetryMovementEvents.h" + +#include "Engine/SkeletalMesh.h" +#include "Components/SkeletalMeshComponent.h" +#include "Math/UnrealMathUtility.h" + +int UOculusXRFaceTrackingComponent::TrackingInstanceCount = 0; + +UOculusXRFaceTrackingComponent::UOculusXRFaceTrackingComponent() + : TargetMeshComponentName(NAME_None) + , InvalidFaceDataResetTime(2.0f) + , bUpdateFace(true) + , TargetMeshComponent(nullptr) +{ + PrimaryComponentTick.bCanEverTick = true; + PrimaryComponentTick.bStartWithTickEnabled = true; + + // Some defaults + ExpressionNames.Add(EOculusXRFaceExpression::BrowLowererL, "browLowerer_L"); + ExpressionNames.Add(EOculusXRFaceExpression::BrowLowererR, "browLowerer_R"); + ExpressionNames.Add(EOculusXRFaceExpression::CheekPuffL, "cheekPuff_L"); + ExpressionNames.Add(EOculusXRFaceExpression::CheekPuffR, "cheekPuff_R"); + ExpressionNames.Add(EOculusXRFaceExpression::CheekRaiserL, "cheekRaiser_L"); + ExpressionNames.Add(EOculusXRFaceExpression::CheekRaiserR, "cheekRaiser_R"); + ExpressionNames.Add(EOculusXRFaceExpression::CheekSuckL, "cheekSuck_L"); + ExpressionNames.Add(EOculusXRFaceExpression::CheekSuckR, "cheekSuck_R"); + ExpressionNames.Add(EOculusXRFaceExpression::ChinRaiserB, "chinRaiser_B"); + ExpressionNames.Add(EOculusXRFaceExpression::ChinRaiserT, "chinRaiser_T"); + ExpressionNames.Add(EOculusXRFaceExpression::DimplerL, "dimpler_L"); + ExpressionNames.Add(EOculusXRFaceExpression::DimplerR, "dimpler_R"); + ExpressionNames.Add(EOculusXRFaceExpression::EyesClosedL, "eyesClosed_L"); + ExpressionNames.Add(EOculusXRFaceExpression::EyesClosedR, "eyesClosed_R"); + ExpressionNames.Add(EOculusXRFaceExpression::EyesLookDownL, "eyesLookDown_L"); + ExpressionNames.Add(EOculusXRFaceExpression::EyesLookDownR, "eyesLookDown_R"); + ExpressionNames.Add(EOculusXRFaceExpression::EyesLookLeftL, "eyesLookLeft_L"); + ExpressionNames.Add(EOculusXRFaceExpression::EyesLookLeftR, "eyesLookLeft_R"); + ExpressionNames.Add(EOculusXRFaceExpression::EyesLookRightL, "eyesLookRight_L"); + ExpressionNames.Add(EOculusXRFaceExpression::EyesLookRightR, "eyesLookRight_R"); + ExpressionNames.Add(EOculusXRFaceExpression::EyesLookUpL, "eyesLookUp_L"); + ExpressionNames.Add(EOculusXRFaceExpression::EyesLookUpR, "eyesLookUp_R"); + ExpressionNames.Add(EOculusXRFaceExpression::InnerBrowRaiserL, "innerBrowRaiser_L"); + ExpressionNames.Add(EOculusXRFaceExpression::InnerBrowRaiserR, "innerBrowRaiser_R"); + ExpressionNames.Add(EOculusXRFaceExpression::JawDrop, "jawDrop"); + ExpressionNames.Add(EOculusXRFaceExpression::JawSidewaysLeft, "jawSidewaysLeft"); + ExpressionNames.Add(EOculusXRFaceExpression::JawSidewaysRight, "jawSidewaysRight"); + ExpressionNames.Add(EOculusXRFaceExpression::JawThrust, "jawThrust"); + ExpressionNames.Add(EOculusXRFaceExpression::LidTightenerL, "lidTightener_L"); + ExpressionNames.Add(EOculusXRFaceExpression::LidTightenerR, "lidTightener_R"); + ExpressionNames.Add(EOculusXRFaceExpression::LipCornerDepressorL, "lipCornerDepressor_L"); + ExpressionNames.Add(EOculusXRFaceExpression::LipCornerDepressorR, "lipCornerDepressor_R"); + ExpressionNames.Add(EOculusXRFaceExpression::LipCornerPullerL, "lipCornerPuller_L"); + ExpressionNames.Add(EOculusXRFaceExpression::LipCornerPullerR, "lipCornerPuller_R"); + ExpressionNames.Add(EOculusXRFaceExpression::LipFunnelerLB, "lipFunneler_LB"); + ExpressionNames.Add(EOculusXRFaceExpression::LipFunnelerLT, "lipFunneler_LT"); + ExpressionNames.Add(EOculusXRFaceExpression::LipFunnelerRB, "lipFunneler_RB"); + ExpressionNames.Add(EOculusXRFaceExpression::LipFunnelerRT, "lipFunneler_RT"); + ExpressionNames.Add(EOculusXRFaceExpression::LipPressorL, "lipPressor_L"); + ExpressionNames.Add(EOculusXRFaceExpression::LipPressorR, "lipPressor_R"); + ExpressionNames.Add(EOculusXRFaceExpression::LipPuckerL, "lipPucker_L"); + ExpressionNames.Add(EOculusXRFaceExpression::LipPuckerR, "lipPucker_R"); + ExpressionNames.Add(EOculusXRFaceExpression::LipStretcherL, "lipStretcher_L"); + ExpressionNames.Add(EOculusXRFaceExpression::LipStretcherR, "lipStretcher_R"); + ExpressionNames.Add(EOculusXRFaceExpression::LipSuckLB, "lipSuck_LB"); + ExpressionNames.Add(EOculusXRFaceExpression::LipSuckLT, "lipSuck_LT"); + ExpressionNames.Add(EOculusXRFaceExpression::LipSuckRB, "lipSuck_RB"); + ExpressionNames.Add(EOculusXRFaceExpression::LipSuckRT, "lipSuck_RT"); + ExpressionNames.Add(EOculusXRFaceExpression::LipTightenerL, "lipTightener_L"); + ExpressionNames.Add(EOculusXRFaceExpression::LipTightenerR, "lipTightener_R"); + ExpressionNames.Add(EOculusXRFaceExpression::LipsToward, "lipsToward"); + ExpressionNames.Add(EOculusXRFaceExpression::LowerLipDepressorL, "lowerLipDepressor_L"); + ExpressionNames.Add(EOculusXRFaceExpression::LowerLipDepressorR, "lowerLipDepressor_R"); + ExpressionNames.Add(EOculusXRFaceExpression::MouthLeft, "mouthLeft"); + ExpressionNames.Add(EOculusXRFaceExpression::MouthRight, "mouthRight"); + ExpressionNames.Add(EOculusXRFaceExpression::NoseWrinklerL, "noseWrinkler_L"); + ExpressionNames.Add(EOculusXRFaceExpression::NoseWrinklerR, "noseWrinkler_R"); + ExpressionNames.Add(EOculusXRFaceExpression::OuterBrowRaiserL, "outerBrowRaiser_L"); + ExpressionNames.Add(EOculusXRFaceExpression::OuterBrowRaiserR, "outerBrowRaiser_R"); + ExpressionNames.Add(EOculusXRFaceExpression::UpperLidRaiserL, "upperLidRaiser_L"); + ExpressionNames.Add(EOculusXRFaceExpression::UpperLidRaiserR, "upperLidRaiser_R"); + ExpressionNames.Add(EOculusXRFaceExpression::UpperLipRaiserL, "upperLipRaiser_L"); + ExpressionNames.Add(EOculusXRFaceExpression::UpperLipRaiserR, "upperLipRaiser_R"); + ExpressionNames.Add(EOculusXRFaceExpression::TongueTipInterdental, "tongueTipInterdental"); + ExpressionNames.Add(EOculusXRFaceExpression::TongueTipAlveolar, "tongueTipAlveolar"); + ExpressionNames.Add(EOculusXRFaceExpression::TongueFrontDorsalPalate, "tongueFrontDorsalPalate"); + ExpressionNames.Add(EOculusXRFaceExpression::TongueMidDorsalPalate, "tongueMidDorsalPalate"); + ExpressionNames.Add(EOculusXRFaceExpression::TongueBackDorsalVelar, "tongueBackDorsalVelar"); + ExpressionNames.Add(EOculusXRFaceExpression::TongueOut, "tongueOut"); + + const int defaultFaceExpressionModifierLength = 33; + ExpressionModifiers.SetNum(defaultFaceExpressionModifierLength); + ExpressionModifiers[0].FaceExpressions = { EOculusXRFaceExpression::EyesClosedL, EOculusXRFaceExpression::EyesClosedR }; + ExpressionModifiers[1].FaceExpressions = { EOculusXRFaceExpression::EyesLookDownL, EOculusXRFaceExpression::EyesLookDownR }; + ExpressionModifiers[2].FaceExpressions = { EOculusXRFaceExpression::EyesLookLeftL, EOculusXRFaceExpression::EyesLookLeftR }; + ExpressionModifiers[3].FaceExpressions = { EOculusXRFaceExpression::EyesLookRightL, EOculusXRFaceExpression::EyesLookRightR }; + ExpressionModifiers[4].FaceExpressions = { EOculusXRFaceExpression::EyesLookUpL, EOculusXRFaceExpression::EyesLookUpR }; + ExpressionModifiers[5].FaceExpressions = { EOculusXRFaceExpression::LidTightenerL, EOculusXRFaceExpression::LidTightenerR }; + ExpressionModifiers[6].FaceExpressions = { EOculusXRFaceExpression::UpperLidRaiserL, EOculusXRFaceExpression::UpperLidRaiserR }; + ExpressionModifiers[7].FaceExpressions = { EOculusXRFaceExpression::JawDrop }; + ExpressionModifiers[8].FaceExpressions = { EOculusXRFaceExpression::JawSidewaysLeft, EOculusXRFaceExpression::JawSidewaysRight }; + ExpressionModifiers[9].FaceExpressions = { EOculusXRFaceExpression::JawThrust }; + ExpressionModifiers[10].FaceExpressions = { EOculusXRFaceExpression::LipFunnelerLB, EOculusXRFaceExpression::LipFunnelerLT }; + ExpressionModifiers[11].FaceExpressions = { EOculusXRFaceExpression::LipFunnelerRB, EOculusXRFaceExpression::LipFunnelerRT }; + ExpressionModifiers[12].FaceExpressions = { EOculusXRFaceExpression::LipPuckerL, EOculusXRFaceExpression::LipPuckerR }; + ExpressionModifiers[13].FaceExpressions = { EOculusXRFaceExpression::LipSuckLB, EOculusXRFaceExpression::LipSuckLT }; + ExpressionModifiers[14].FaceExpressions = { EOculusXRFaceExpression::LipSuckRB, EOculusXRFaceExpression::LipSuckRT }; + ExpressionModifiers[15].FaceExpressions = { EOculusXRFaceExpression::LipsToward }; + ExpressionModifiers[16].FaceExpressions = { EOculusXRFaceExpression::LowerLipDepressorL, EOculusXRFaceExpression::LowerLipDepressorR }; + ExpressionModifiers[17].FaceExpressions = { EOculusXRFaceExpression::ChinRaiserB, EOculusXRFaceExpression::ChinRaiserT }; + ExpressionModifiers[18].FaceExpressions = { EOculusXRFaceExpression::LipCornerDepressorL, EOculusXRFaceExpression::LipCornerDepressorR }; + ExpressionModifiers[19].FaceExpressions = { EOculusXRFaceExpression::LipCornerPullerL, EOculusXRFaceExpression::LipCornerPullerR }; + ExpressionModifiers[20].FaceExpressions = { EOculusXRFaceExpression::LipStretcherL, EOculusXRFaceExpression::LipStretcherR }; + ExpressionModifiers[21].FaceExpressions = { EOculusXRFaceExpression::MouthLeft, EOculusXRFaceExpression::MouthRight }; + ExpressionModifiers[22].FaceExpressions = { EOculusXRFaceExpression::LipPressorL, EOculusXRFaceExpression::LipPressorR }; + ExpressionModifiers[23].FaceExpressions = { EOculusXRFaceExpression::LipTightenerL, EOculusXRFaceExpression::LipTightenerR }; + ExpressionModifiers[24].FaceExpressions = { EOculusXRFaceExpression::UpperLipRaiserL, EOculusXRFaceExpression::UpperLipRaiserR }; + ExpressionModifiers[25].FaceExpressions = { EOculusXRFaceExpression::CheekPuffL, EOculusXRFaceExpression::CheekPuffR }; + ExpressionModifiers[26].FaceExpressions = { EOculusXRFaceExpression::CheekRaiserL, EOculusXRFaceExpression::CheekRaiserR }; + ExpressionModifiers[27].FaceExpressions = { EOculusXRFaceExpression::CheekSuckL, EOculusXRFaceExpression::CheekSuckR }; + ExpressionModifiers[28].FaceExpressions = { EOculusXRFaceExpression::DimplerL, EOculusXRFaceExpression::DimplerR }; + ExpressionModifiers[29].FaceExpressions = { EOculusXRFaceExpression::NoseWrinklerL, EOculusXRFaceExpression::NoseWrinklerR }; + ExpressionModifiers[30].FaceExpressions = { EOculusXRFaceExpression::BrowLowererL, EOculusXRFaceExpression::BrowLowererR }; + ExpressionModifiers[31].FaceExpressions = { EOculusXRFaceExpression::InnerBrowRaiserL, EOculusXRFaceExpression::InnerBrowRaiserR }; + ExpressionModifiers[32].FaceExpressions = { EOculusXRFaceExpression::OuterBrowRaiserL, EOculusXRFaceExpression::OuterBrowRaiserR }; + + OculusXRTelemetry::TScopedMarker(static_cast(GetTypeHash(this))); +} + +void UOculusXRFaceTrackingComponent::BeginPlay() +{ + Super::BeginPlay(); + + if (!UOculusXRMovementFunctionLibrary::IsFaceTrackingSupported()) + { + // Early exit if face tracking isn't supported + UE_LOG(LogOculusXRMovement, Warning, TEXT("Face tracking is not supported. (%s:%s)"), *GetOwner()->GetName(), *GetName()); + SetComponentTickEnabled(false); + return; + } + + if (TargetMeshComponentName == NAME_None) + { + UE_LOG(LogOculusXRMovement, Warning, TEXT("Invalid mesh component name. (%s:%s)"), *GetOwner()->GetName(), *GetName()); + SetComponentTickEnabled(false); + return; + } + + if (!InitializeFaceTracking()) + { + UE_LOG(LogOculusXRMovement, Warning, TEXT("Failed to initialize face tracking. (%s:%s)"), *GetOwner()->GetName(), *GetName()); + SetComponentTickEnabled(false); + return; + } + + if (!UOculusXRMovementFunctionLibrary::StartFaceTracking()) + { + UE_LOG(LogOculusXRMovement, Warning, TEXT("Failed to start face tracking. (%s: %s)"), *GetOwner()->GetName(), *GetName()); + SetComponentTickEnabled(false); + return; + } + ++TrackingInstanceCount; +} + +void UOculusXRFaceTrackingComponent::EndPlay(const EEndPlayReason::Type EndPlayReason) +{ + if (IsComponentTickEnabled()) + { + if (--TrackingInstanceCount == 0) + { + if (!UOculusXRMovementFunctionLibrary::StopFaceTracking()) + { + UE_LOG(LogOculusXRMovement, Warning, TEXT("Failed to stop face tracking. (%s: %s)"), *GetOwner()->GetName(), *GetName()); + } + } + } + + Super::EndPlay(EndPlayReason); +} + +void UOculusXRFaceTrackingComponent::TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) +{ + Super::TickComponent(DeltaTime, TickType, ThisTickFunction); + + if (!IsValid(TargetMeshComponent)) + { + UE_LOG(LogOculusXRMovement, VeryVerbose, TEXT("No target mesh specified. (%s:%s)"), *GetOwner()->GetName(), *GetName()); + return; + } + + if (UOculusXRMovementFunctionLibrary::TryGetFaceState(FaceState) && bUpdateFace) + { + InvalidFaceStateTimer = 0.0f; + + MorphTargets.ResetMorphTargetCurves(TargetMeshComponent); + + for (int32 FaceExpressionIndex = 0; FaceExpressionIndex < static_cast(EOculusXRFaceExpression::COUNT); ++FaceExpressionIndex) + { + if (ExpressionValid[FaceExpressionIndex]) + { + FName ExpressionName = ExpressionNames[static_cast(FaceExpressionIndex)]; + MorphTargets.SetMorphTarget(ExpressionName, FaceState.ExpressionWeights[FaceExpressionIndex]); + } + } + + if (bUseModifiers) + { + for (int32 FaceExpressionModifierIndex = 0; FaceExpressionModifierIndex < ExpressionModifiers.Num(); ++FaceExpressionModifierIndex) + { + for (int32 FaceExpressionIndex = 0; FaceExpressionIndex < ExpressionModifiers[FaceExpressionModifierIndex].FaceExpressions.Num(); ++FaceExpressionIndex) + { + auto Expression = ExpressionModifiers[FaceExpressionModifierIndex].FaceExpressions[FaceExpressionIndex]; + if (ExpressionValid[static_cast(Expression)]) + { + FName ExpressionName = ExpressionNames[Expression]; + float currentValue = MorphTargets.GetMorphTarget(ExpressionName); + + currentValue = FMath::Clamp( + currentValue * ExpressionModifiers[FaceExpressionModifierIndex].Multiplier, + ExpressionModifiers[FaceExpressionModifierIndex].MinValue, + ExpressionModifiers[FaceExpressionModifierIndex].MaxValue); + + MorphTargets.SetMorphTarget(ExpressionName, currentValue); + } + } + } + } + } + else + { + InvalidFaceStateTimer += DeltaTime; + if (InvalidFaceStateTimer >= InvalidFaceDataResetTime) + { + MorphTargets.ResetMorphTargetCurves(TargetMeshComponent); + } + } + + MorphTargets.ApplyMorphTargets(TargetMeshComponent); +} + +void UOculusXRFaceTrackingComponent::SetExpressionValue(EOculusXRFaceExpression Expression, float Value) +{ + if (Expression >= EOculusXRFaceExpression::COUNT) + { + UE_LOG(LogOculusXRMovement, Warning, TEXT("Cannot set expression value with invalid expression index.")); + return; + } + + if (!ExpressionValid[static_cast(Expression)]) + { + UE_LOG(LogOculusXRMovement, Warning, TEXT("Cannot set expression value for an expression with an invalid associated morph target name. Expression name: %s"), *StaticEnum()->GetValueAsString(Expression)); + return; + } + + FName ExpressionName = ExpressionNames[Expression]; + MorphTargets.SetMorphTarget(ExpressionName, Value); +} + +float UOculusXRFaceTrackingComponent::GetExpressionValue(EOculusXRFaceExpression Expression) const +{ + if (Expression >= EOculusXRFaceExpression::COUNT) + { + UE_LOG(LogOculusXRMovement, Warning, TEXT("Cannot request expression value using an invalid expression index.")); + return 0.0f; + } + + FName ExpressionName = ExpressionNames[Expression]; + if (ExpressionName == NAME_None) + { + UE_LOG(LogOculusXRMovement, Warning, TEXT("Cannot request expression value for an expression with an invalid associated morph target name. Expression name: %s"), *StaticEnum()->GetValueAsString(Expression)); + return 0.0f; + } + + return MorphTargets.GetMorphTarget(ExpressionName); +} + +void UOculusXRFaceTrackingComponent::ClearExpressionValues() +{ + MorphTargets.ClearMorphTargets(); +} + +bool UOculusXRFaceTrackingComponent::InitializeFaceTracking() +{ + TargetMeshComponent = OculusXRUtility::FindComponentByName(GetOwner(), TargetMeshComponentName); + + if (!IsValid(TargetMeshComponent)) + { + UE_LOG(LogOculusXRMovement, Warning, TEXT("Could not find skeletal mesh component with name: (%s). (%s:%s)"), *TargetMeshComponentName.ToString(), *GetOwner()->GetName(), *GetName()); + return false; + } + + if (TargetMeshComponent != nullptr) + { + USkeletalMesh* TargetMesh = Cast(TargetMeshComponent->GetSkinnedAsset()); + if (TargetMesh != nullptr) + { + const TMap& MorphTargetIndexMap = TargetMesh->GetMorphTargetIndexMap(); + + for (const auto& it : ExpressionNames) + { + ExpressionValid[static_cast(it.Key)] = MorphTargetIndexMap.Contains(it.Value); + } + + return true; + } + } + + return false; +} diff --git a/Plugins/MetaXR/Source/OculusXRMovement/Private/OculusXRLiveLinkRetargetBodyAsset.cpp b/Plugins/MetaXR/Source/OculusXRMovement/Private/OculusXRLiveLinkRetargetBodyAsset.cpp new file mode 100644 index 0000000..970edfe --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRMovement/Private/OculusXRLiveLinkRetargetBodyAsset.cpp @@ -0,0 +1,157 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#include "OculusXRLiveLinkRetargetBodyAsset.h" + +#include "LiveLinkTypes.h" +#include "Algo/Accumulate.h" +#include "Algo/ForEach.h" +#include "Roles/LiveLinkAnimationTypes.h" +#include "BonePose.h" + +#include "OculusXRHMDPrivate.h" +#include "OculusXRMovementLog.h" +#include "OculusXRMovement.h" + +namespace +{ + // EOculusXRAxis to orientation of that direction + FTransform DirectionTransform(EOculusXRAxis Direction) + { + FVector Dir = FVector::ZeroVector; + const uint8 IndexOfDir = static_cast(Direction); + const double Sign = IndexOfDir < static_cast(EOculusXRAxis::NegativeX) ? 1 : -1; + Dir[IndexOfDir % 3] = Sign * 1.0; + return FTransform(Dir.ToOrientationQuat()); + } +} // namespace + +UOculusXRLiveLinkRetargetBodyAsset::UOculusXRLiveLinkRetargetBodyAsset(const FObjectInitializer& ObjectInitializer) + : Super(ObjectInitializer), RetargetingMode(EOculusXRRetargetingMode::Full), ForwardMesh(EOculusXRAxis::X), Scale(100.f), TrackingSpaceToMeshSpace(FTransform::Identity), BoneNames(InPlace, NAME_None), LastBoneContainerSerialNumber(0) +{ +} + +void UOculusXRLiveLinkRetargetBodyAsset::Initialize() +{ + TrackingSpaceToMeshSpace = DirectionTransform(ForwardTracking).Inverse() * DirectionTransform(ForwardMesh); + GlobalBoneCorrection = FTransform(GlobalCorrection.RotationOffset, GlobalCorrection.PositionOffset); + + for (uint8 BoneId = 0; BoneId < static_cast(EOculusXRBoneID::COUNT); ++BoneId) + { + const FTransform LocalCorrectionCombined = Algo::Accumulate(LocalCorrections, FTransform::Identity, [BoneId](FTransform Correction, const FOculusXRBoneCorrectionSet& BoneCorrectionSet) { + if (BoneCorrectionSet.Bones.Contains(static_cast(BoneId))) + { + Correction *= FTransform(BoneCorrectionSet.BoneCorrection.RotationOffset, BoneCorrectionSet.BoneCorrection.PositionOffset); + } + return Correction; + }); + LocalBoneCorrections[BoneId] = LocalCorrectionCombined; + + const EOculusXRBoneID OculusBoneID = static_cast(BoneId); + if (const FName* NameMapping = BoneRemapping.Find(OculusBoneID)) + { + BoneNames[BoneId] = *NameMapping; + } + else + { + BoneNames[BoneId] = NAME_None; + UE_LOG(LogOculusXRMovement, Warning, TEXT("Bone: %s isn't mapped."), *StaticEnum()->GetValueAsString(OculusBoneID)); + } + } + + if (!OculusXRHMD::GetUnitScaleFactorFromSettings(UObject::GetWorld(), Scale)) + { + UE_LOG(LogOculusXRMovement, Warning, TEXT("Cannot get world settings for body retargetting asset.")); + } + + LastBoneContainerSerialNumber = 0; + Algo::ForEach(LastSkeletonBoneRemapping, [](FCompactPoseBoneIndex& BoneIndex) { BoneIndex = FCompactPoseBoneIndex(INDEX_NONE); }); +} + +void UOculusXRLiveLinkRetargetBodyAsset::BuildPoseFromAnimationData(float DeltaTime, const FLiveLinkSkeletonStaticData* InSkeletonData, const FLiveLinkAnimationFrameData* InFrameData, FCompactPose& OutPose) +{ + check(InFrameData); + if (static_cast(EOculusXRBoneID::COUNT) != InFrameData->Transforms.Num()) + { + UE_LOG(LogOculusXRMovement, Error, TEXT("Received wrong data of live link frame. This retargeting asset must be used with Meta MovementSDK Live Link source and Body subject. (received %d bone transforms, expected %d)"), InFrameData->Transforms.Num(), static_cast(EOculusXRBoneID::COUNT)); + return; + } + + if ((LastBoneContainerSerialNumber != OutPose.GetBoneContainer().GetSerialNumber()) || (LastBoneContainerSerialNumber == 0)) + { + OnBoneContainerChanged(OutPose.GetBoneContainer()); + } + + FCSPose MeshPoses; + MeshPoses.InitPose(OutPose); + for (uint8 BoneId = 0; BoneId < static_cast(EOculusXRBoneID::COUNT); ++BoneId) + { + if (const FCompactPoseBoneIndex& BoneIndex = LastSkeletonBoneRemapping[BoneId]; BoneIndex != INDEX_NONE) + { + FTransform BoneTransform = InFrameData->Transforms[BoneId]; + BoneTransform.ScaleTranslation(Scale); + BoneTransform *= TrackingSpaceToMeshSpace; + BoneTransform = GlobalBoneCorrection * BoneTransform; + BoneTransform = LocalBoneCorrections[BoneId] * BoneTransform; + check(!BoneTransform.ContainsNaN()); + + switch (RetargetingMode) + { + case EOculusXRRetargetingMode::Rotations: + BoneTransform.SetLocation(MeshPoses.GetComponentSpaceTransform(BoneIndex).GetLocation()); + MeshPoses.SetComponentSpaceTransform(BoneIndex, BoneTransform); + break; + + case EOculusXRRetargetingMode::RotationsPlusRoot: + if (BoneId != static_cast(EOculusXRBoneID::BodyRoot)) + { + BoneTransform.SetLocation(MeshPoses.GetComponentSpaceTransform(BoneIndex).GetLocation()); + } + MeshPoses.SetComponentSpaceTransform(BoneIndex, BoneTransform); + break; + + case EOculusXRRetargetingMode::RotationsPlusHips: + if (BoneId != static_cast(EOculusXRBoneID::BodyHips)) + { + BoneTransform.SetLocation(MeshPoses.GetComponentSpaceTransform(BoneIndex).GetLocation()); + } + MeshPoses.SetComponentSpaceTransform(BoneIndex, BoneTransform); + break; + + case EOculusXRRetargetingMode::Full: + MeshPoses.SetComponentSpaceTransform(BoneIndex, BoneTransform); + break; + + case EOculusXRRetargetingMode::None: + default: + break; + } + } + } + FCSPose::ConvertComponentPosesToLocalPosesSafe(MeshPoses, OutPose); +} + +void UOculusXRLiveLinkRetargetBodyAsset::OnBoneContainerChanged(const FBoneContainer& BoneContainer) +{ + LastBoneContainerSerialNumber = 0; + + for (uint8 BoneId = 0; BoneId < static_cast(EOculusXRBoneID::COUNT); ++BoneId) + { + const auto& BoneName = BoneNames[BoneId]; + if (BoneName.IsNone()) + { + LastSkeletonBoneRemapping[BoneId] = FCompactPoseBoneIndex(INDEX_NONE); + continue; + } + + if (const int32 MeshIndex = BoneContainer.GetPoseBoneIndexForBoneName(BoneName); MeshIndex != INDEX_NONE) + { + LastSkeletonBoneRemapping[BoneId] = BoneContainer.MakeCompactPoseIndex(FMeshPoseBoneIndex(MeshIndex)); + if (LastSkeletonBoneRemapping[BoneId] == INDEX_NONE) + { + UE_LOG(LogOculusXRMovement, Warning, TEXT("Bone %s was intentionally mapped to %s. But this target doesn't exist in skeleton."), *StaticEnum()->GetValueAsString(static_cast(BoneId)), *BoneName.ToString()); + } + } + } + + LastBoneContainerSerialNumber = BoneContainer.GetSerialNumber(); +} diff --git a/Plugins/MetaXR/Source/OculusXRMovement/Private/OculusXRLiveLinkRetargetFaceAsset.cpp b/Plugins/MetaXR/Source/OculusXRMovement/Private/OculusXRLiveLinkRetargetFaceAsset.cpp new file mode 100644 index 0000000..db7caa7 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRMovement/Private/OculusXRLiveLinkRetargetFaceAsset.cpp @@ -0,0 +1,82 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#include "OculusXRLiveLinkRetargetFaceAsset.h" + +#include "LiveLinkTypes.h" +#include "Algo/ForEach.h" +#include "Animation/AnimCurveTypes.h" +#include "BonePose.h" +#include "OculusXRMovement.h" +#include "OculusXRMovementLog.h" + +UOculusXRLiveLinkRetargetFaceAsset::UOculusXRLiveLinkRetargetFaceAsset(const FObjectInitializer& ObjectInitializer) + : Super(ObjectInitializer) +{ +} + +void UOculusXRLiveLinkRetargetFaceAsset::Initialize() +{ + LastSkeletonGuid.Invalidate(); +#if UE_VERSION_OLDER_THAN(5, 3, 0) + Algo::ForEach(RemappingForLastSkeleton, [](TArray& Arr) { Arr.Reset(); }); +#else + Algo::ForEach(RemappingForLastSkeleton, [](TArray& Arr) { Arr.Reset(); }); +#endif +} + +void UOculusXRLiveLinkRetargetFaceAsset::BuildPoseAndCurveFromBaseData(float DeltaTime, const FLiveLinkBaseStaticData* InBaseStaticData, const FLiveLinkBaseFrameData* InBaseFrameData, FCompactPose& OutPose, FBlendedCurve& OutCurve) +{ + check(InBaseFrameData); + if (static_cast(EOculusXRFaceExpression::COUNT) != InBaseFrameData->PropertyValues.Num()) + { + UE_LOG(LogOculusXRMovement, Error, TEXT("Received wrong data of live link frame. This retargeting asset must be used with Meta MovementSDK Live Link source and Face subject. (received %d face expressions, expected %d)"), InBaseFrameData->PropertyValues.Num(), static_cast(EOculusXRFaceExpression::COUNT)); + return; + } + const USkeleton* Skeleton = OutPose.GetBoneContainer().GetSkeletonAsset(); + if (!IsValid(Skeleton)) + { + UE_LOG(LogOculusXRMovement, Error, TEXT("No skeleton asset for this retargeting.")); + return; + } + if (LastSkeletonGuid != Skeleton->GetGuid()) + { + OnSkeletonChanged(Skeleton); + } + + for (uint8 ExpressionId = 0; ExpressionId < static_cast(EOculusXRFaceExpression::COUNT); ++ExpressionId) + { +#if UE_VERSION_OLDER_THAN(5, 3, 0) + for (const SmartName::UID_Type UID : RemappingForLastSkeleton[ExpressionId]) + { + OutCurve.Set(UID, InBaseFrameData->PropertyValues[ExpressionId]); + } +#else + for (const FName Name : RemappingForLastSkeleton[ExpressionId]) + { + OutCurve.Set(Name, InBaseFrameData->PropertyValues[ExpressionId]); + } +#endif + } +} + +void UOculusXRLiveLinkRetargetFaceAsset::OnSkeletonChanged(const USkeleton* Skeleton) +{ + Initialize(); + + for (const auto& [ExpressionId, CurveMapping] : CurveRemapping) + { + for (const auto& CurveName : CurveMapping.CurveNames) + { +#if UE_VERSION_OLDER_THAN(5, 3, 0) + if (const SmartName::UID_Type UID = Skeleton->GetUIDByName(USkeleton::AnimCurveMappingName, CurveName); UID != SmartName::MaxUID) + { + RemappingForLastSkeleton[static_cast(ExpressionId)].Emplace(UID); + } +#else + RemappingForLastSkeleton[static_cast(ExpressionId)].Emplace(CurveName); +#endif + } + } + + LastSkeletonGuid = Skeleton->GetGuid(); +} diff --git a/Plugins/MetaXR/Source/OculusXRMovement/Private/OculusXRMorphTargetsController.cpp b/Plugins/MetaXR/Source/OculusXRMovement/Private/OculusXRMorphTargetsController.cpp new file mode 100644 index 0000000..51b4c21 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRMovement/Private/OculusXRMorphTargetsController.cpp @@ -0,0 +1,90 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#include "OculusXRMorphTargetsController.h" +#include "Components/SkeletalMeshComponent.h" +#include "Engine/SkeletalMesh.h" + +#include "AnimationRuntime.h" + +void FOculusXRMorphTargetsController::ResetMorphTargetCurves(USkinnedMeshComponent* TargetMeshComponent) +{ + if (TargetMeshComponent) + { + TargetMeshComponent->ActiveMorphTargets.Reset(); + + USkeletalMesh* TargetMesh = Cast(TargetMeshComponent->GetSkinnedAsset()); + if (TargetMesh != nullptr) + { + TargetMeshComponent->MorphTargetWeights.SetNum(TargetMesh->GetMorphTargets().Num()); + + // we need this code to ensure the buffer gets cleared whether or not you have morphtarget curve set + // the case, where you had morphtargets weight on, and when you clear the weight, you want to make sure + // the buffer gets cleared and resized + if (TargetMeshComponent->MorphTargetWeights.Num() > 0) + { + FMemory::Memzero(TargetMeshComponent->MorphTargetWeights.GetData(), TargetMeshComponent->MorphTargetWeights.GetAllocatedSize()); + } + } + else + { + TargetMeshComponent->MorphTargetWeights.Reset(); + } + } +} + +void FOculusXRMorphTargetsController::ApplyMorphTargets(USkinnedMeshComponent* TargetMeshComponent) +{ + if (TargetMeshComponent != nullptr) + { + const USkeletalMesh* TargetMesh = Cast(TargetMeshComponent->GetSkinnedAsset()); + if (TargetMesh != nullptr && MorphTargetCurves.Num() > 0) + { + FAnimationRuntime::AppendActiveMorphTargets(TargetMesh, MorphTargetCurves, TargetMeshComponent->ActiveMorphTargets, TargetMeshComponent->MorphTargetWeights); + } + } +} + +void FOculusXRMorphTargetsController::SetMorphTarget(FName MorphTargetName, float Value) +{ + float* CurveValPtr = MorphTargetCurves.Find(MorphTargetName); + bool bShouldAddToList = FPlatformMath::Abs(Value) > ZERO_ANIMWEIGHT_THRESH; + if (bShouldAddToList) + { + if (CurveValPtr) + { + // sum up, in the future we might normalize, but for now this just sums up + // this won't work well if all of them have full weight - i.e. additive + *CurveValPtr = Value; + } + else + { + MorphTargetCurves.Add(MorphTargetName, Value); + } + } + // if less than ZERO_ANIMWEIGHT_THRESH + // no reason to keep them on the list + else + { + // remove if found + MorphTargetCurves.Remove(MorphTargetName); + } +} + +float FOculusXRMorphTargetsController::GetMorphTarget(FName MorphTargetName) const +{ + const float* CurveValPtr = MorphTargetCurves.Find(MorphTargetName); + + if (CurveValPtr) + { + return *CurveValPtr; + } + else + { + return 0.0f; + } +} + +void FOculusXRMorphTargetsController::ClearMorphTargets() +{ + MorphTargetCurves.Empty(); +} diff --git a/Plugins/MetaXR/Source/OculusXRMovement/Private/OculusXRMovement.cpp b/Plugins/MetaXR/Source/OculusXRMovement/Private/OculusXRMovement.cpp new file mode 100644 index 0000000..31acce1 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRMovement/Private/OculusXRMovement.cpp @@ -0,0 +1,334 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#include "OculusXRMovement.h" +#include "OculusXRMovementLog.h" +#include "OculusXRMovementModule.h" +#include "OculusXRHMDPrivate.h" +#include "OculusXRHMD.h" +#include "OculusXRPluginWrapper.h" +#include "Logging/MessageLog.h" + +#define LOCTEXT_NAMESPACE "OculusXRMovement" + +bool OculusXRMovement::IsFullBodyTrackingEnabled() +{ + bool bResult = false; + + ovrpBool IsEnabled = ovrpBool_False; + ovrpResult TrackingEnabledResult = FOculusXRHMDModule::GetPluginWrapper().GetFullBodyTrackingEnabled(&IsEnabled); + + if (OVRP_SUCCESS(TrackingEnabledResult)) + { + bResult = (IsEnabled == ovrpBool_True); + } + + return bResult; +} + +bool OculusXRMovement::GetBodyState(FOculusXRBodyState& outOculusXRBodyState, float WorldToMeters) +{ + static_assert(ovrpBoneId_FullBody_End == static_cast(EOculusXRBoneID::COUNT), "The size of the OVRPlugin Bone ID enum should be the same as the EOculusXRBoneID enum."); + + const auto AvailableJoints = IsFullBodyTrackingEnabled() ? ovrpBoneId_FullBody_End : ovrpBoneId_Body_End; + checkf(outOculusXRBodyState.Joints.Num() >= AvailableJoints, TEXT("Not enough joints in FOculusXRBodyState::Joints array. You must have at least %d joints"), AvailableJoints); + + ovrpBodyState4 OVRBodyState; + ovrpResult OVRBodyStateResult = FOculusXRHMDModule::GetPluginWrapper().GetBodyState4(ovrpStep_Render, OVRP_CURRENT_FRAMEINDEX, &OVRBodyState); + ensureMsgf(OVRBodyStateResult != ovrpFailure_NotYetImplemented, TEXT("Body tracking is not implemented on this platform.")); + + if (OVRP_SUCCESS(OVRBodyStateResult)) + { + outOculusXRBodyState.IsActive = (OVRBodyState.IsActive == ovrpBool_True); + outOculusXRBodyState.Confidence = OVRBodyState.Confidence; + outOculusXRBodyState.SkeletonChangedCount = OVRBodyState.SkeletonChangedCount; + outOculusXRBodyState.Time = static_cast(OVRBodyState.Time); + + for (int i = 0; i < AvailableJoints; ++i) + { + ovrpBodyJointLocation OVRJointLocation = OVRBodyState.JointLocations[i]; + ovrpPosef OVRJointPose = OVRJointLocation.Pose; + + FOculusXRBodyJoint& OculusXRBodyJoint = outOculusXRBodyState.Joints[i]; + OculusXRBodyJoint.LocationFlags = OVRJointLocation.LocationFlags; + OculusXRBodyJoint.bIsValid = OVRJointLocation.LocationFlags & (XRSpaceFlags::XR_SPACE_LOCATION_ORIENTATION_VALID_BIT | XRSpaceFlags::XR_SPACE_LOCATION_POSITION_VALID_BIT); + OculusXRBodyJoint.Orientation = FRotator(OculusXRHMD::ToFQuat(OVRJointPose.Orientation)); + OculusXRBodyJoint.Position = OculusXRHMD::ToFVector(OVRJointPose.Position) * WorldToMeters; + } + if (AvailableJoints < outOculusXRBodyState.Joints.Num()) + { + for (int i = AvailableJoints; i < outOculusXRBodyState.Joints.Num(); ++i) + { + outOculusXRBodyState.Joints[i].bIsValid = false; + } + } + + return true; + } + + return false; +} + + +bool OculusXRMovement::IsBodyTrackingEnabled() +{ + bool bResult = false; + + ovrpBool IsEnabled = ovrpBool_False; + ovrpResult TrackingEnabledResult = FOculusXRHMDModule::GetPluginWrapper().GetBodyTrackingEnabled(&IsEnabled); + + if (OVRP_SUCCESS(TrackingEnabledResult)) + { + bResult = (IsEnabled == ovrpBool_True); + } + + return bResult; +} + +bool OculusXRMovement::IsBodyTrackingSupported() +{ + bool bResult = false; + + ovrpBool IsSupported = ovrpBool_False; + ovrpResult TrackingSupportedResult = FOculusXRHMDModule::GetPluginWrapper().GetBodyTrackingSupported(&IsSupported); + + if (OVRP_SUCCESS(TrackingSupportedResult)) + { + bResult = (IsSupported == ovrpBool_True); + } + + return bResult; +} + +bool OculusXRMovement::RequestBodyTrackingFidelity(EOculusXRBodyTrackingFidelity fidelity) +{ + static_assert(static_cast(EOculusXRBodyTrackingFidelity::Low) == static_cast(ovrpBodyTrackingFidelity2::ovrpBodyTrackingFidelity2_Low), "EOculusXRBodyTrackingFidelity and ovrpBodyTrackingFidelity2 should be sync"); + static_assert(static_cast(EOculusXRBodyTrackingFidelity::High) == static_cast(ovrpBodyTrackingFidelity2::ovrpBodyTrackingFidelity2_High), "EOculusXRBodyTrackingFidelity and ovrpBodyTrackingFidelity2 should be sync"); + + auto* OculusXRHMD = OculusXRHMD::FOculusXRHMD::GetOculusXRHMD(); + if (OculusXRHMD) + { + OculusXRHMD->GetSettings()->BodyTrackingFidelity = static_cast(fidelity); + } + + return OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().RequestBodyTrackingFidelity(static_cast(fidelity))); +} + +bool OculusXRMovement::ResetBodyTrackingCalibration() +{ + return OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().ResetBodyTrackingCalibration()); +} + +bool OculusXRMovement::SuggestBodyTrackingCalibrationOverride(float height) +{ + ovrpBodyTrackingCalibrationInfo calibrationInfo{ height }; + return OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().SuggestBodyTrackingCalibrationOverride(calibrationInfo)); +} + +bool OculusXRMovement::StartBodyTracking() +{ + static_assert(static_cast(EOculusXRBodyJointSet::UpperBody) == static_cast(ovrpBodyJointSet::ovrpBodyJointSet_UpperBody), "EOculusXRBodyJointSet and ovrpBodyJointSet should be sync"); + static_assert(static_cast(EOculusXRBodyJointSet::FullBody) == static_cast(ovrpBodyJointSet::ovrpBodyJointSet_FullBody), "EOculusXRBodyJointSet and ovrpBodyJointSet should be sync"); + + bool result = false; + + const auto* OculusXRHMD = OculusXRHMD::FOculusXRHMD::GetOculusXRHMD(); + if (OculusXRHMD) + { + const auto JointSet = OculusXRHMD->GetSettings()->BodyTrackingJointSet; + if (!OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().StartBodyTracking2(static_cast(JointSet)))) + { + return false; + } + + const auto Fidelity = OculusXRHMD->GetSettings()->BodyTrackingFidelity; + FOculusXRHMDModule::GetPluginWrapper().RequestBodyTrackingFidelity(static_cast(Fidelity)); + return true; + } + else + { + return OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().StartBodyTracking2(ovrpBodyJointSet::ovrpBodyJointSet_UpperBody)); + } +} + +bool OculusXRMovement::StartBodyTrackingByJointSet(EOculusXRBodyJointSet jointSet) +{ + bool result = false; + + auto* OculusXRHMD = OculusXRHMD::FOculusXRHMD::GetOculusXRHMD(); + if (OculusXRHMD) + { + OculusXRHMD->GetSettings()->BodyTrackingJointSet = static_cast(jointSet); + result = StartBodyTracking(); + } + else + { + result = OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().StartBodyTracking2(static_cast(jointSet))); + } + + return result; +} + +bool OculusXRMovement::StopBodyTracking() +{ + FOculusXRHMDModule::GetPluginWrapper().RequestBodyTrackingFidelity(ovrpBodyTrackingFidelity2::ovrpBodyTrackingFidelity2_Low); + return OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().StopBodyTracking()); +} + +bool OculusXRMovement::GetFaceState(FOculusXRFaceState& outOculusXRFaceState) +{ + const auto blendShapeCount = ovrpFaceExpression2_Max; + + static_assert(blendShapeCount == static_cast(EOculusXRFaceExpression::COUNT), "The size of the OVRPlugin Face Expression enum should be the same as the EOculusXRFaceExpression enum."); + + checkf(outOculusXRFaceState.ExpressionWeightConfidences.Num() >= ovrpFaceConfidence_Max, TEXT("Not enough expression weight confidences in FOculusXRFaceState::ExpressionWeightConfidences. Requires %d available elements in the array."), ovrpFaceConfidence_Max); + checkf(outOculusXRFaceState.ExpressionWeights.Num() >= blendShapeCount, TEXT("Not enough expression weights in FOculusXRFaceState::ExpressionWeights. Requires %d available elements in the array."), blendShapeCount); + + ovrpFaceState2 OVRFaceState; + ovrpResult OVRFaceStateResult = FOculusXRHMDModule::GetPluginWrapper().GetFaceState2(ovrpStep_Render, OVRP_CURRENT_FRAMEINDEX, &OVRFaceState); + + ensureMsgf(OVRFaceStateResult != ovrpFailure_NotYetImplemented, TEXT("Face tracking is not implemented on this platform.")); + + if (OVRP_SUCCESS(OVRFaceStateResult)) + { + outOculusXRFaceState.bIsValid = (OVRFaceState.Status.IsValid == ovrpBool_True); + outOculusXRFaceState.bIsEyeFollowingBlendshapesValid = (OVRFaceState.Status.IsEyeFollowingBlendshapesValid == ovrpBool_True); + outOculusXRFaceState.Time = static_cast(OVRFaceState.Time); + + for (int i = 0; i < blendShapeCount; ++i) + { + outOculusXRFaceState.ExpressionWeights[i] = OVRFaceState.ExpressionWeights[i]; + } + + for (int i = 0; i < ovrpFaceConfidence_Max; ++i) + { + outOculusXRFaceState.ExpressionWeightConfidences[i] = OVRFaceState.ExpressionWeightConfidences[i]; + } + + outOculusXRFaceState.DataSource = static_cast(OVRFaceState.DataSource); + + return true; + } + + return false; +} + +bool OculusXRMovement::IsFaceTrackingEnabled() +{ + bool bResult = false; + + ovrpBool IsEnabled = ovrpBool_False; + ovrpResult TrackingEnabledResult = FOculusXRHMDModule::GetPluginWrapper().GetFaceTracking2Enabled(&IsEnabled); + + if (OVRP_SUCCESS(TrackingEnabledResult)) + { + bResult = (IsEnabled == ovrpBool_True); + } + + return bResult; +} + +bool OculusXRMovement::IsFaceTrackingSupported() +{ + bool bResult = false; + + ovrpBool IsSupported = ovrpBool_False; + ovrpResult TrackingSupportedResult = FOculusXRHMDModule::GetPluginWrapper().GetFaceTracking2Supported(&IsSupported); + + if (OVRP_SUCCESS(TrackingSupportedResult)) + { + bResult = (IsSupported == ovrpBool_True); + } + + return bResult; +} + +bool OculusXRMovement::StartFaceTracking() +{ + const auto* OculusXRHMD = OculusXRHMD::FOculusXRHMD::GetOculusXRHMD(); + if (OculusXRHMD) + { + ovrpFaceTrackingDataSource2 dataSources[ovrpFaceConstants_FaceTrackingDataSourcesCount]; + int count = 0; + for (auto Iterator = OculusXRHMD->GetSettings()->FaceTrackingDataSource.CreateConstIterator(); Iterator; ++Iterator) + { + dataSources[count++] = static_cast(*Iterator); + } + return OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().StartFaceTracking2(dataSources, count)); + } + return false; +} + +bool OculusXRMovement::StopFaceTracking() +{ + return OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().StopFaceTracking2()); +} + +bool OculusXRMovement::GetEyeGazesState(FOculusXREyeGazesState& outOculusXREyeGazesState, float WorldToMeters) +{ + static_assert(ovrpEye_Count == (int)EOculusXREye::COUNT, "The size of the OVRPlugin Eye enum should be the same as the EOculusXREye enum."); + + checkf(outOculusXREyeGazesState.EyeGazes.Num() >= ovrpEye_Count, TEXT("Not enough eye gaze states in FOculusXREyeGazesState::EyeGazes. Requires %d available elements in the array."), ovrpEye_Count); + + ovrpEyeGazesState OVREyeGazesState; + ovrpResult OVREyeGazesStateResult = FOculusXRHMDModule::GetPluginWrapper().GetEyeGazesState(ovrpStep_Render, OVRP_CURRENT_FRAMEINDEX, &OVREyeGazesState); + ensureMsgf(OVREyeGazesStateResult != ovrpFailure_NotYetImplemented, TEXT("Eye tracking is not implemented on this platform.")); + + if (OVRP_SUCCESS(OVREyeGazesStateResult)) + { + outOculusXREyeGazesState.Time = static_cast(OVREyeGazesState.Time); + for (int i = 0; i < ovrpEye_Count; ++i) + { + const auto& EyeGazePose = OVREyeGazesState.EyeGazes[i].Pose; + outOculusXREyeGazesState.EyeGazes[i].Orientation = FRotator(OculusXRHMD::ToFQuat(EyeGazePose.Orientation)); + outOculusXREyeGazesState.EyeGazes[i].Position = OculusXRHMD::ToFVector(EyeGazePose.Position) * WorldToMeters; + outOculusXREyeGazesState.EyeGazes[i].bIsValid = (OVREyeGazesState.EyeGazes[i].IsValid == ovrpBool_True); + outOculusXREyeGazesState.EyeGazes[i].Confidence = OVREyeGazesState.EyeGazes[i].Confidence; + } + + return true; + } + + return false; +} + +bool OculusXRMovement::IsEyeTrackingEnabled() +{ + bool bResult = false; + + ovrpBool IsEnabled = ovrpBool_False; + ovrpResult TrackingEnabledResult = FOculusXRHMDModule::GetPluginWrapper().GetEyeTrackingEnabled(&IsEnabled); + + if (OVRP_SUCCESS(TrackingEnabledResult)) + { + bResult = (IsEnabled == ovrpBool_True); + } + + return bResult; +} + +bool OculusXRMovement::IsEyeTrackingSupported() +{ + bool bResult = false; + + ovrpBool IsSupported = ovrpBool_False; + ovrpResult TrackingSupportedResult = FOculusXRHMDModule::GetPluginWrapper().GetEyeTrackingSupported(&IsSupported); + + if (OVRP_SUCCESS(TrackingSupportedResult)) + { + bResult = (IsSupported == ovrpBool_True); + } + + return bResult; +} + +bool OculusXRMovement::StartEyeTracking() +{ + return OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().StartEyeTracking()); +} + +bool OculusXRMovement::StopEyeTracking() +{ + return OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().StopEyeTracking()); +} + +#undef LOCTEXT_NAMESPACE diff --git a/Plugins/MetaXR/Source/OculusXRMovement/Private/OculusXRMovementFunctionLibrary.cpp b/Plugins/MetaXR/Source/OculusXRMovement/Private/OculusXRMovementFunctionLibrary.cpp new file mode 100644 index 0000000..2ab0ab9 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRMovement/Private/OculusXRMovementFunctionLibrary.cpp @@ -0,0 +1,105 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#include "OculusXRMovementFunctionLibrary.h" + +#include "IOculusXRMovementModule.h" +#include "LiveLinkOculusXRMovementSourceFactory.h" +#include "OculusXRHMDPrivate.h" +#include "OculusXRMovement.h" +#include "OculusXRHMD.h" +#include "OculusXRMovementLiveLink.h" + +bool UOculusXRMovementFunctionLibrary::TryGetBodyState(FOculusXRBodyState& outBodyState, float WorldToMeters) +{ + return OculusXRMovement::GetBodyState(outBodyState, WorldToMeters); +} + +bool UOculusXRMovementFunctionLibrary::IsBodyTrackingEnabled() +{ + return OculusXRMovement::IsBodyTrackingEnabled(); +} + +bool UOculusXRMovementFunctionLibrary::IsBodyTrackingSupported() +{ + return OculusXRMovement::IsBodyTrackingSupported(); +} + +bool UOculusXRMovementFunctionLibrary::RequestBodyTrackingFidelity(EOculusXRBodyTrackingFidelity fidelity) +{ + return OculusXRMovement::RequestBodyTrackingFidelity(fidelity); +} + +bool UOculusXRMovementFunctionLibrary::ResetBodyTrackingCalibration() +{ + return OculusXRMovement::ResetBodyTrackingCalibration(); +} + +bool UOculusXRMovementFunctionLibrary::SuggestBodyTrackingCalibrationOverride(float height) +{ + return OculusXRMovement::SuggestBodyTrackingCalibrationOverride(height); +} + +bool UOculusXRMovementFunctionLibrary::StartBodyTrackingByJointSet(EOculusXRBodyJointSet jointSet) +{ + return OculusXRMovement::StartBodyTrackingByJointSet(jointSet); +} + +bool UOculusXRMovementFunctionLibrary::StartBodyTracking() +{ + return OculusXRMovement::StartBodyTracking(); +} + +bool UOculusXRMovementFunctionLibrary::StopBodyTracking() +{ + return OculusXRMovement::StopBodyTracking(); +} + +bool UOculusXRMovementFunctionLibrary::TryGetFaceState(FOculusXRFaceState& outFaceState) +{ + return OculusXRMovement::GetFaceState(outFaceState); +} + +bool UOculusXRMovementFunctionLibrary::IsFaceTrackingEnabled() +{ + return OculusXRMovement::IsFaceTrackingEnabled(); +} + +bool UOculusXRMovementFunctionLibrary::IsFaceTrackingSupported() +{ + return OculusXRMovement::IsFaceTrackingSupported(); +} + +bool UOculusXRMovementFunctionLibrary::StartFaceTracking() +{ + return OculusXRMovement::StartFaceTracking(); +} + +bool UOculusXRMovementFunctionLibrary::StopFaceTracking() +{ + return OculusXRMovement::StopFaceTracking(); +} + +bool UOculusXRMovementFunctionLibrary::TryGetEyeGazesState(FOculusXREyeGazesState& outEyeGazesState, float WorldToMeters) +{ + return OculusXRMovement::GetEyeGazesState(outEyeGazesState, WorldToMeters); +} + +bool UOculusXRMovementFunctionLibrary::IsEyeTrackingEnabled() +{ + return OculusXRMovement::IsEyeTrackingEnabled(); +} + +bool UOculusXRMovementFunctionLibrary::IsEyeTrackingSupported() +{ + return OculusXRMovement::IsEyeTrackingSupported(); +} + +bool UOculusXRMovementFunctionLibrary::StartEyeTracking() +{ + return OculusXRMovement::StartEyeTracking(); +} + +bool UOculusXRMovementFunctionLibrary::StopEyeTracking() +{ + return OculusXRMovement::StopEyeTracking(); +} diff --git a/Plugins/MetaXR/Source/OculusXRMovement/Private/OculusXRMovementLiveLink.cpp b/Plugins/MetaXR/Source/OculusXRMovement/Private/OculusXRMovementLiveLink.cpp new file mode 100644 index 0000000..1a043a2 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRMovement/Private/OculusXRMovementLiveLink.cpp @@ -0,0 +1,355 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#include "OculusXRMovementLiveLink.h" + +#include "IHeadMountedDisplayModule.h" +#include "OculusXRHMDModule.h" +#include "OculusXRMovementLog.h" +#include "OculusXRMovement.h" +#include "OculusXRMovementTypes.h" +#include "OculusXRTelemetryMovementEvents.h" + +#include "Roles/LiveLinkAnimationTypes.h" +#include "ILiveLinkClient.h" + +#define LOCTEXT_NAMESPACE "MetaOculusXRMovement" + +namespace +{ + constexpr int32 NoParent = -1; +} + +namespace MetaXRMovement +{ + template <> + void FEyeSubject::InitializeRoleStaticData(FLiveLinkSkeletonStaticData& StaticData) const + { + constexpr auto FieldsCount = static_cast(EOculusXREye::COUNT); + StaticData.BoneNames.Reserve(FieldsCount); + for (uint8 XRBone = 0; XRBone < FieldsCount; ++XRBone) + { + StaticData.BoneNames.Add(UEnum::GetValueAsName(static_cast(XRBone))); + StaticData.BoneParents.Add(NoParent); + } + } + + template <> + void FBodySubject::InitializeRoleStaticData(FLiveLinkSkeletonStaticData& StaticData) const + { + constexpr auto FieldsCount = static_cast(EOculusXRBoneID::COUNT); + StaticData.BoneNames.Reserve(FieldsCount); + for (uint8 XRBone = 0; XRBone < FieldsCount; ++XRBone) + { + StaticData.BoneNames.Add(UEnum::GetValueAsName(static_cast(XRBone))); + StaticData.BoneParents.Add(NoParent); + } + } + + + template <> + void FFaceSubject::InitializeRoleStaticData(FLiveLinkBaseStaticData& StaticData) const + { + constexpr auto FieldsCount = static_cast(EOculusXRFaceExpression::COUNT); + StaticData.PropertyNames.Reserve(FieldsCount); + for (uint8 XRProperty = 0; XRProperty < FieldsCount; ++XRProperty) + { + StaticData.PropertyNames.Add(UEnum::GetValueAsName(static_cast(XRProperty))); + } + } + + template + FLiveLinkStaticDataStruct TSubject::StaticData() const + { + FLiveLinkStaticDataStruct StaticDataStruct(RoleTypeStaticData::StaticStruct()); + RoleTypeStaticData& RoleStaticData(*StaticDataStruct.Cast()); + InitializeRoleStaticData(RoleStaticData); + return StaticDataStruct; + } + template + FLiveLinkFrameDataStruct TSubject::FrameData() + { + FLiveLinkFrameDataStruct FrameDataStruct(RoleTypeFrameData::StaticStruct()); + RoleTypeFrameData& FrameData(*FrameDataStruct.Cast()); + UpdateFrame(FrameData); + return FrameDataStruct; + } + + template <> + FEyeSubject::TSubject() + : Name(TEXT("Eye")) + , bLastFrameIsValid(false) + , bStarted(false) + { + } + template <> + FFaceSubject::TSubject() + : Name(TEXT("Face")) + , bLastFrameIsValid(false) + , bStarted(false) + { + } + template <> + FBodySubject::TSubject() + : Name(TEXT("Body")) + , bLastFrameIsValid(false) + , bStarted(false) + { + } + template <> + bool FEyeSubject::Start() + { + if (!bStarted) + { + bStarted = OculusXRMovement::StartEyeTracking(); + } + return bStarted; + } + template <> + bool FEyeSubject::Stop() + { + if (bStarted) + { + bStarted = !OculusXRMovement::StopEyeTracking(); + } + return !bStarted; + } + template <> + bool FFaceSubject::Start() + { + if (!bStarted) + { + bStarted = OculusXRMovement::StartFaceTracking(); + } + return bStarted; + } + template <> + bool FFaceSubject::Stop() + { + if (bStarted) + { + bStarted = !OculusXRMovement::StopFaceTracking(); + } + return !bStarted; + } + template <> + bool FBodySubject::Start() + { + if (!bStarted) + { + bStarted = OculusXRMovement::StartBodyTracking(); + } + return bStarted; + } + template <> + bool FBodySubject::Stop() + { + if (bStarted) + { + bStarted = !OculusXRMovement::StopBodyTracking(); + } + return !bStarted; + } + template <> + bool FEyeSubject::IsSupported() + { + return OculusXRMovement::IsEyeTrackingSupported(); + } + template <> + bool FFaceSubject::IsSupported() + { + return OculusXRMovement::IsFaceTrackingSupported(); + } + template <> + bool FBodySubject::IsSupported() + { + return OculusXRMovement::IsBodyTrackingSupported(); + } + template <> + void FEyeSubject::UpdateFrame(FLiveLinkAnimationFrameData& FrameData) + { + bLastFrameIsValid = OculusXRMovement::GetEyeGazesState(LastState, 1.f) + && (LastState.EyeGazes[0].bIsValid || LastState.EyeGazes[1].bIsValid); + if (bLastFrameIsValid) + { + constexpr auto FieldsCount = static_cast(EOculusXREye::COUNT); + FrameData.Transforms.Reserve(FieldsCount); + for (uint8 i = 0u; i < FieldsCount; ++i) + { + const auto& EyeGaze = LastState.EyeGazes[i]; + FrameData.Transforms.Emplace(EyeGaze.Orientation, EyeGaze.Position); + } + FrameData.WorldTime = FPlatformTime::Seconds(); + } + } + template <> + void FFaceSubject::UpdateFrame(FLiveLinkBaseFrameData& FrameData) + { + bLastFrameIsValid = OculusXRMovement::GetFaceState(LastState) && (LastState.bIsValid); + if (bLastFrameIsValid) + { + constexpr auto FieldsCount = static_cast(EOculusXRFaceExpression::COUNT); + FrameData.PropertyValues.Reserve(FieldsCount); + for (uint8 i = 0u; i < FieldsCount; ++i) + { + FrameData.PropertyValues.Emplace(LastState.ExpressionWeights[i]); + } + FrameData.WorldTime = FPlatformTime::Seconds(); + } + } + template <> + void FBodySubject::UpdateFrame(FLiveLinkAnimationFrameData& FrameData) + { + bLastFrameIsValid = OculusXRMovement::GetBodyState(LastState, 1.f) && (LastState.IsActive) && (LastState.SkeletonChangedCount > 0); + if (bLastFrameIsValid) + { + constexpr auto FieldsCount = static_cast(EOculusXRBoneID::COUNT); + FrameData.Transforms.Reserve(FieldsCount); + for (uint8 i = 0u; i < FieldsCount; ++i) + { + const auto& Joint = LastState.Joints[i]; + FrameData.Transforms.Emplace(Joint.Orientation, Joint.Position); + } + FrameData.WorldTime = FPlatformTime::Seconds(); + } + } + + LiveLinkSource::LiveLinkSource() + : bAnySupported(FEyeSubject::IsSupported() || FFaceSubject::IsSupported() || FBodySubject::IsSupported()) + { + OculusXRTelemetry::TScopedMarker(); + } + + void LiveLinkSource::ReceiveClient(ILiveLinkClient* InClient, FGuid InSourceGuid) + { + Client = InClient; + SourceGuid = InSourceGuid; + + InitializeMovementSubjects(); + UpdateMovementSubjects(); + } + + bool LiveLinkSource::IsSourceStillValid() const + { + return Client != nullptr; + } + + bool LiveLinkSource::RequestSourceShutdown() + { + Client = nullptr; + SourceGuid.Invalidate(); + + if (!( + Body.Stop() && Face.Stop() && Eye.Stop())) + { + UE_LOG(LogOculusXRMovement, Error, TEXT("At least one of the trackers cannot stop.")); + } + return true; + } + + FText LiveLinkSource::GetSourceType() const + { + return LOCTEXT("MetaOculusXRMovementLiveLinkSourceType", "MetaXR MovementSDK"); + } + + FText LiveLinkSource::GetSourceMachineName() const + { + if (IHeadMountedDisplayModule::IsAvailable()) + { + const FString DeviceName = IHeadMountedDisplayModule::Get().GetDeviceSystemName(); + return FText::FromString(DeviceName); + } + return LOCTEXT("MetaOculusXRMovementLiveLinkMachineName", "MetaXR Device"); + } + + FText LiveLinkSource::GetSourceStatus() const + { + if (bAnySupported) + { + return LOCTEXT("MetaOculusXRMovementLiveLinkStatusSupported", "Active"); + } + return LOCTEXT("MetaOculusXRMovementLiveLinkStatusNotSupported", "Not Supported"); + } + + void LiveLinkSource::Tick(float DeltaTime) + { + UpdateMovementSubjects(); + } + + template + LiveLinkSource::ESubjectInitializationResult LiveLinkSource::InitializeMovementSubject(TOptional& Key, SubjectT& Subject) + { + ESubjectInitializationResult FinalState; + if (Key) + { + if (Key->Source.IsValid()) + { // If the key was already in use. Remove it. + Client->RemoveSubject_AnyThread(*Key); + } + Key.Reset(); + } + if (Subject.IsSupported()) + { + Key = FLiveLinkSubjectKey(SourceGuid, Subject.Name); + FinalState = ESubjectInitializationResult::Started; + if (!Subject.Start()) + { + UE_LOG(LogOculusXRMovement, Error, TEXT("Tracker for LiveLink subject %s cannot start."), *Subject.Name.ToString()); + FinalState = ESubjectInitializationResult::StartFailed; + } + using Role = typename std::remove_reference_t::Role; + Client->PushSubjectStaticData_AnyThread(*Key, Role::StaticClass(), Subject.StaticData()); + } + else + { + UE_LOG(LogOculusXRMovement, Log, TEXT("LiveLink subject %s is not supported."), *Subject.Name.ToString()); + FinalState = ESubjectInitializationResult::NotSupported; + } + return FinalState; + } + + void LiveLinkSource::InitializeMovementSubjects() + { + check(IsInGameThread()); + const OculusXRTelemetry::TScopedMarker LiveLinkInit; + + const auto EyeInit = InitializeMovementSubject(KeyEye, Eye); + const auto FaceInit = InitializeMovementSubject(KeyFace, Face); + const auto BodyInit = InitializeMovementSubject(KeyBody, Body); + + LiveLinkInit.AddAnnotation(StringCast(*Eye.Name.ToString()).Get(), ResultToText[static_cast(EyeInit)]) + .AddAnnotation(StringCast(*Face.Name.ToString()).Get(), ResultToText[static_cast(FaceInit)]) + .AddAnnotation(StringCast(*Body.Name.ToString()).Get(), ResultToText[static_cast(BodyInit)]) + ; + } + + template + void LiveLinkSource::UpdateMovementSubject(const TOptional& Key, SubjectT& Subject) + { + if (Key) + { + const bool bPreviousFrameValid = Subject.IsLastFrameValid(); + auto FrameData = Subject.FrameData(); + const bool bFrameValid = Subject.IsLastFrameValid(); + if (bPreviousFrameValid != bFrameValid) + { + UE_LOG(LogOculusXRMovement, Log, TEXT("LiveLink subject %s became %s."), *Subject.Name.ToString(), bFrameValid ? TEXT("valid") : TEXT("invalid")); + } + if (bFrameValid) + { + Client->PushSubjectFrameData_AnyThread(*Key, MoveTemp(FrameData)); + } + } + } + + void LiveLinkSource::UpdateMovementSubjects() + { + check(IsInGameThread()); + if (IsSourceStillValid()) + { + UpdateMovementSubject(KeyEye, Eye); + UpdateMovementSubject(KeyFace, Face); + UpdateMovementSubject(KeyBody, Body); + } + } +} // namespace MetaXRMovement +#undef LOCTEXT_NAMESPACE diff --git a/Plugins/MetaXR/Source/OculusXRMovement/Private/OculusXRMovementLiveLink.h b/Plugins/MetaXR/Source/OculusXRMovement/Private/OculusXRMovementLiveLink.h new file mode 100644 index 0000000..3f3f1f6 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRMovement/Private/OculusXRMovementLiveLink.h @@ -0,0 +1,112 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#pragma once + +#include "CoreMinimal.h" +#include "ILiveLinkSource.h" +#include "LiveLinkTypes.h" +#include "Roles/LiveLinkAnimationRole.h" +#include "Roles/LiveLinkAnimationTypes.h" +#include "Roles/LiveLinkBasicRole.h" +#include "Tickable.h" + +#include "OculusXRMovementTypes.h" + +#define LOCTEXT_NAMESPACE "MetaOculusXRMovement" + +namespace MetaXRMovement +{ + + template + class TSubject + { + public: + explicit TSubject(); + using Role = RoleT; + + const FLiveLinkSubjectName Name; + + FLiveLinkStaticDataStruct StaticData() const; + FLiveLinkFrameDataStruct FrameData(); + bool IsLastFrameValid() const { return bLastFrameIsValid; }; + bool Start(); + bool Stop(); + static bool IsSupported(); + + private: + bool bLastFrameIsValid; + bool bStarted; + MetaXRState LastState; + + void InitializeRoleStaticData(RoleTypeStaticData& StaticData) const; + void UpdateFrame(RoleTypeFrameData& FrameData); + }; + + using FEyeSubject = TSubject; + using FFaceSubject = TSubject; + using FBodySubject = TSubject; + + class LiveLinkSource : public ILiveLinkSource, public FTickableGameObject + { + public: + LiveLinkSource(); + virtual ~LiveLinkSource() override = default; + + // ILiveLinkSource implementation + + virtual void ReceiveClient(ILiveLinkClient* InClient, FGuid InSourceGuid) override; + virtual bool IsSourceStillValid() const override; + virtual bool RequestSourceShutdown() override; + virtual FText GetSourceType() const override; + virtual FText GetSourceMachineName() const override; + virtual FText GetSourceStatus() const override; + + // FTickableGameObject implementation + + virtual void Tick(float DeltaTime) override; + virtual bool IsTickable() const override { return bAnySupported && Client; }; + virtual TStatId GetStatId() const override + { + RETURN_QUICK_DECLARE_CYCLE_STAT(FOculusXRMovementLiveLink, STATGROUP_Tickables); + } + virtual bool IsTickableInEditor() const override { return true; } + virtual bool IsTickableWhenPaused() const override { return true; } + + private: + enum class ESubjectInitializationResult + { + Started = 0, + StartFailed = 1, + NotSupported = 2 + }; + + static constexpr const char* ResultToText[]{ "started", "start_failed", "not_supported" }; + + template + ESubjectInitializationResult InitializeMovementSubject(TOptional& Key, SubjectT& Subject); + void InitializeMovementSubjects(); + template + void UpdateMovementSubject(const TOptional& Key, SubjectT& Subject); + void UpdateMovementSubjects(); + + // LiveLink Data + // The local client to push data updates to + ILiveLinkClient* Client{ nullptr }; + // Our identifier in LiveLink + FGuid SourceGuid; + + // Whenever any of the trackers is supported. + const bool bAnySupported; + + // This subject's keys. Initialized only if a tracker is supported. + TOptional KeyEye; + TOptional KeyFace; + TOptional KeyBody; + + // Subjects + FEyeSubject Eye; + FFaceSubject Face; + FBodySubject Body; + }; +} // namespace MetaXRMovement +#undef LOCTEXT_NAMESPACE diff --git a/Plugins/MetaXR/Source/OculusXRMovement/Private/OculusXRMovementLog.h b/Plugins/MetaXR/Source/OculusXRMovement/Private/OculusXRMovementLog.h new file mode 100644 index 0000000..c507ed1 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRMovement/Private/OculusXRMovementLog.h @@ -0,0 +1,7 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#pragma once + +#include "CoreMinimal.h" + +DECLARE_LOG_CATEGORY_EXTERN(LogOculusXRMovement, Log, All); diff --git a/Plugins/MetaXR/Source/OculusXRMovement/Private/OculusXRMovementModule.cpp b/Plugins/MetaXR/Source/OculusXRMovement/Private/OculusXRMovementModule.cpp new file mode 100644 index 0000000..7010152 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRMovement/Private/OculusXRMovementModule.cpp @@ -0,0 +1,56 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#include "OculusXRMovementModule.h" +#include "OculusXRHMDModule.h" +#include "OculusXRMovementLog.h" + +#define LOCTEXT_NAMESPACE "OculusXRMovement" + +DEFINE_LOG_CATEGORY(LogOculusXRMovement); + +//------------------------------------------------------------------------------------------------- +// FOculusXRMovementModule +//------------------------------------------------------------------------------------------------- + +FOculusXRMovementModule::FOculusXRMovementModule() +{ +} + +void FOculusXRMovementModule::StartupModule() +{ +} + +void FOculusXRMovementModule::ShutdownModule() +{ +} + +TSharedPtr FOculusXRMovementModule::GetLiveLinkSource() +{ + if (!MovementSource.IsValid()) + { + AddLiveLinkSource(); + } + return MovementSource; +} + +bool FOculusXRMovementModule::IsLiveLinkSourceValid() const +{ + return MovementSource.IsValid(); +} + +void FOculusXRMovementModule::AddLiveLinkSource() +{ + if (!MovementSource.IsValid()) + { + MovementSource = MakeShared(); + } +} + +void FOculusXRMovementModule::RemoveLiveLinkSource() +{ + MovementSource.Reset(); +} + +IMPLEMENT_MODULE(FOculusXRMovementModule, OculusXRMovement) + +#undef LOCTEXT_NAMESPACE diff --git a/Plugins/MetaXR/Source/OculusXRMovement/Private/OculusXRMovementModule.h b/Plugins/MetaXR/Source/OculusXRMovement/Private/OculusXRMovementModule.h new file mode 100644 index 0000000..72f1a21 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRMovement/Private/OculusXRMovementModule.h @@ -0,0 +1,39 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#pragma once +#include "ILiveLinkSource.h" + +#include "IOculusXRMovementModule.h" +#include "OculusXRMovement.h" +#include "OculusXRMovementLiveLink.h" + +#define LOCTEXT_NAMESPACE "OculusXRMovement" + +//------------------------------------------------------------------------------------------------- +// FOculusXRMovementModule +//------------------------------------------------------------------------------------------------- + +class FOculusXRMovementModule : public IOculusXRMovementModule +{ +public: + FOculusXRMovementModule(); + + static inline FOculusXRMovementModule& Get() + { + return FModuleManager::LoadModuleChecked("OculusXRMovement"); + } + + virtual void StartupModule() override; + virtual void ShutdownModule() override; + + /* Live link */ + virtual TSharedPtr GetLiveLinkSource() override; + virtual bool IsLiveLinkSourceValid() const override; + virtual void AddLiveLinkSource() override; + virtual void RemoveLiveLinkSource() override; + +private: + TSharedPtr MovementSource{ nullptr }; +}; + +#undef LOCTEXT_NAMESPACE diff --git a/Plugins/MetaXR/Source/OculusXRMovement/Private/OculusXRMovementTypes.cpp b/Plugins/MetaXR/Source/OculusXRMovement/Private/OculusXRMovementTypes.cpp new file mode 100644 index 0000000..758f7bc --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRMovement/Private/OculusXRMovementTypes.cpp @@ -0,0 +1,53 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#include "OculusXRMovementTypes.h" +#include "OculusXRHMDPrivate.h" +#include "OculusXRHMD.h" + +FOculusXRBodyJoint::FOculusXRBodyJoint() + : LocationFlags(0) + , bIsValid(false) + , Orientation(FRotator::ZeroRotator) + , Position(FVector::ZeroVector) +{ +} + +FOculusXRBodyState::FOculusXRBodyState() + : IsActive(false) + , Confidence(0) + , SkeletonChangedCount(0) + , Time(0.f) +{ + Joints.SetNum(static_cast(EOculusXRBoneID::COUNT)); +} + + +FOculusXRFaceState::FOculusXRFaceState() + : bIsValid(false) + , bIsEyeFollowingBlendshapesValid(false) + , Time(0.f) +{ + ExpressionWeights.SetNum(static_cast(EOculusXRFaceExpression::COUNT)); + ExpressionWeightConfidences.SetNum(static_cast(EOculusXRFaceConfidence::COUNT)); +} + +FOculusXRFaceExpressionModifier::FOculusXRFaceExpressionModifier() + : MinValue(0.f) + , MaxValue(1.f) + , Multiplier(1.f) +{ +} + +FOculusXREyeGazeState::FOculusXREyeGazeState() + : Orientation(FRotator::ZeroRotator) + , Position(FVector::ZeroVector) + , Confidence(0.f) + , bIsValid(false) +{ +} + +FOculusXREyeGazesState::FOculusXREyeGazesState() + : Time(0.f) +{ + EyeGazes.SetNum(static_cast(EOculusXREye::COUNT)); +} diff --git a/Plugins/MetaXR/Source/OculusXRMovement/Private/OculusXRTelemetryMovementEvents.h b/Plugins/MetaXR/Source/OculusXRMovement/Private/OculusXRTelemetryMovementEvents.h new file mode 100644 index 0000000..54865de --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRMovement/Private/OculusXRTelemetryMovementEvents.h @@ -0,0 +1,14 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#pragma once + +#include "OculusXRTelemetry.h" + +namespace OculusXRTelemetry::Events +{ + using FMovementSDKLiveLinkCreated = TMarker<191961034>; + using FMovementSDKLiveLinkInit = TMarker<191970472>; + using FMovementSDKBodyStart = TMarker<191958900>; + using FMovementSDKFaceStart = TMarker<191966310>; + using FMovementSDKEyeStart = TMarker<191969182>; +} // namespace OculusXRTelemetry::Events diff --git a/Plugins/MetaXR/Source/OculusXRMovement/Public/IOculusXRMovementModule.h b/Plugins/MetaXR/Source/OculusXRMovement/Public/IOculusXRMovementModule.h new file mode 100644 index 0000000..7c15ef3 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRMovement/Public/IOculusXRMovementModule.h @@ -0,0 +1,59 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#pragma once + +#include "Modules/ModuleManager.h" + +/** + * The public interface to this module. In most cases, this interface is only public to sibling modules + * within this plugin. + */ +class IOculusXRMovementModule : public IModuleInterface +{ + +public: + /** + * Singleton-like access to this module's interface. This is just for convenience! + * Beware of calling this during the shutdown phase, though. Your module might have been unloaded already. + * + * @return Returns singleton instance, loading the module on demand if needed + */ + static inline IOculusXRMovementModule& Get() + { + return FModuleManager::GetModuleChecked("OculusXRMovement"); + } + + /** + * Checks to see if this module is loaded and ready. It is only valid to call Get() if IsAvailable() returns true. + * + * @return True if the module is loaded and ready to use + */ + static inline bool IsAvailable() + { + return FModuleManager::Get().IsModuleLoaded("OculusXRMovement"); + } + + /** + * Returns the LiveLinkSource associated with this IOculusXRMovementModule. + * + * @return Shared pointer to the Meta MovementSDK source. + */ + virtual TSharedPtr GetLiveLinkSource() = 0; + + /** + * Checks if the LiveLinkSource has been created. + * + * @return True if the LiveLinkSource has been created with GetLiveLinkSource or AddLiveLinkSource. + */ + virtual bool IsLiveLinkSourceValid() const = 0; + + /** + * Make sure Meta MovementSDK Live Link source exist. + */ + virtual void AddLiveLinkSource() = 0; + + /** + * Destroy Meta MovementSDK Live Link source. + */ + virtual void RemoveLiveLinkSource() = 0; +}; diff --git a/Plugins/MetaXR/Source/OculusXRMovement/Public/OculusXRBodyTrackingComponent.h b/Plugins/MetaXR/Source/OculusXRMovement/Public/OculusXRBodyTrackingComponent.h new file mode 100644 index 0000000..76456eb --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRMovement/Public/OculusXRBodyTrackingComponent.h @@ -0,0 +1,69 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#pragma once + +#include "CoreMinimal.h" +#include "Components/PoseableMeshComponent.h" + +#include "OculusXRMovementTypes.h" + +#include "OculusXRBodyTrackingComponent.generated.h" + +UENUM(BlueprintType) +enum class EOculusXRBodyTrackingMode : uint8 +{ + PositionAndRotation, + RotationOnly, + NoTracking +}; + +UCLASS(Blueprintable, meta = (BlueprintSpawnableComponent, DisplayName = "OculusXR Body Tracking Component"), ClassGroup = OculusXRHMD) +class OCULUSXRMOVEMENT_API UOculusXRBodyTrackingComponent : public UPoseableMeshComponent +{ + GENERATED_BODY() +public: + UOculusXRBodyTrackingComponent(); + + virtual void BeginPlay() override; + virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override; + virtual void TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override; + + /** + * Restore all bones to their initial transforms + */ + UFUNCTION(BlueprintCallable, Category = "OculusXR|Movement") + void ResetAllBoneTransforms(); + + /** + * How are the results of body tracking applied to the mesh. + */ + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "OculusXR|Movement") + EOculusXRBodyTrackingMode BodyTrackingMode; + + /** + * The bone name associated with each bone ID. + */ + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "OculusXR|Movement") + TMap BoneNames; + + /** + * Do not apply body state to bones if confidence is lower than this value. Confidence is in range [0,1]. + */ + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "OculusXR|Movement", meta = (ClampMin = "0", ClampMax = "1", UIMin = "0", UIMax = "1")) + float ConfidenceThreshold; + +private: + bool InitializeBodyBones(); + + // One meter in unreal world units. + float WorldToMeters; + + // The index of each mapped bone after the discovery and association of bone names. + TMap MappedBoneIndices; + + // Saved body state. + FOculusXRBodyState BodyState; + + // Stop the tracker just once. + static int TrackingInstanceCount; +}; diff --git a/Plugins/MetaXR/Source/OculusXRMovement/Public/OculusXREyeTrackingComponent.h b/Plugins/MetaXR/Source/OculusXRMovement/Public/OculusXREyeTrackingComponent.h new file mode 100644 index 0000000..2fb771b --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRMovement/Public/OculusXREyeTrackingComponent.h @@ -0,0 +1,99 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#pragma once + +#include "CoreMinimal.h" +#include "Components/ActorComponent.h" +#include "Components/PoseableMeshComponent.h" + +#include "OculusXRMovementTypes.h" + +#include "OculusXREyeTrackingComponent.generated.h" + +struct FOculusXREyeTrackingData +{ +public: + FOculusXREyeTrackingData() + : EyeIsMapped(false) + , MappedBoneName(NAME_None) + { + } + + bool EyeIsMapped; + FName MappedBoneName; + FQuat InitialRotation; +}; + +UCLASS(Blueprintable, meta = (BlueprintSpawnableComponent, DisplayName = "OculusXR Eye Tracking Component"), ClassGroup = OculusXRHMD) +class OCULUSXRMOVEMENT_API UOculusXREyeTrackingComponent : public UActorComponent +{ + GENERATED_BODY() +public: + UOculusXREyeTrackingComponent(); + + virtual void BeginPlay() override; + virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override; + virtual void TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override; + + /** + * Reset the rotation values of the eyes to their initial rotation + */ + UFUNCTION(BlueprintCallable, Category = "Oculus|Movement") + void ClearRotationValues(); + + /** + * The name of the poseable mesh component that this component targets for eyes glazes movement. + * This must be the name of a component on this actor. + */ + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "OculusXR|Movement") + FName TargetMeshComponentName; + + /** + * The map of eye to mesh bone that this component supports. + * Names are validated on (@see BeginPlay) so only valid bone names will be targeted. + */ + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "OculusXR|Movement") + TMap EyeToBone; + + /** + * Update the target mesh position when eye state changes + */ + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "OculusXR|Movement") + bool bUpdatePosition; + + /** + * Update the target mesh rotation when eye state changes + */ + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "OculusXR|Movement") + bool bUpdateRotation; + + /** + * Do not accept an eye gaze state if confidence is lower than this value. Confidence is in range [0,1]. + */ + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "OculusXR|Movement") + float ConfidenceThreshold; + + /** + * Bypass eye gaze state validity. + * + * @Note: It doesn't check the confidence (@see ConfidenceThreshold). The eye gaze state can be marked as invalid. This flag bypass that state flag. + */ + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "OculusXR|Movement") + bool bAcceptInvalid; + +private: + bool InitializeEyes(); + + // One meter in unreal world units. + float WorldToMeters; + + // Per eye, eye tracking data + TStaticArray(EOculusXREye::COUNT)> PerEyeData; + + // The mesh component targeted for eyes + UPROPERTY() + UPoseableMeshComponent* TargetPoseableMeshComponent; + + // Stop the tracker just once. + static int TrackingInstanceCount; +}; diff --git a/Plugins/MetaXR/Source/OculusXRMovement/Public/OculusXRFaceTrackingComponent.h b/Plugins/MetaXR/Source/OculusXRMovement/Public/OculusXRFaceTrackingComponent.h new file mode 100644 index 0000000..cffdbf3 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRMovement/Public/OculusXRFaceTrackingComponent.h @@ -0,0 +1,104 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#pragma once + +#include "CoreMinimal.h" +#include "Components/SkeletalMeshComponent.h" +#include "OculusXRMorphTargetsController.h" +#include "OculusXRMovementTypes.h" + +#include "OculusXRFaceTrackingComponent.generated.h" + +UCLASS(Blueprintable, meta = (BlueprintSpawnableComponent, DisplayName = "OculusXR Face Tracking Component"), ClassGroup = OculusXRHMD) +class OCULUSXRMOVEMENT_API UOculusXRFaceTrackingComponent : public UActorComponent +{ + GENERATED_BODY() +public: + UOculusXRFaceTrackingComponent(); + + virtual void BeginPlay() override; + virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override; + virtual void TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override; + + /** + * Set face expression value with expression key and value(0-1). + * + * @param Expression : The expression key that will be modified. + * @param Value : The new value to assign to the expression, 0 will remove all changes. + */ + UFUNCTION(BlueprintCallable, Category = "Components|OculusXRFaceTracking", meta = (UnsafeDuringActorConstruction = "true")) + void SetExpressionValue(EOculusXRFaceExpression Expression, float Value); + + /** + * Get a face expression value given an expression key. + * + * @param Expression : The expression key that will be queried. + */ + UFUNCTION(BlueprintCallable, Category = "Components|OculusXRFaceTracking") + float GetExpressionValue(EOculusXRFaceExpression Expression) const; + + /** + * Clears all face expression values. + */ + UFUNCTION(BlueprintCallable, Category = "Components|OculusXRFaceTracking") + void ClearExpressionValues(); + + /** + * The name of the skinned mesh component that this component targets for facial expression. + * This must be the name of a component on this actor. + */ + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "OculusXR|Movement") + FName TargetMeshComponentName; + + /** + * If the face data is invalid for at least this or longer than this time then all face blendshapes/morph targets are reset to zero. + */ + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "OculusXR|Movement") + float InvalidFaceDataResetTime; + + /** + * The list of expressions that this component supports. + * Names are validated on startup so only valid morph targets on the skeletal mesh will be targeted. + */ + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "OculusXR|Movement") + TMap ExpressionNames; + + /** + * An array of optional expression modifiers that can be applied. + */ + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "OculusXR|Movement") + TArray ExpressionModifiers; + + /** + * This flag determines if the face should be updated or not during the components tick. + */ + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "OculusXR|Movement") + bool bUpdateFace; + + /** + * This flag determines if the face should be modified with Expression Modifiers or not during the components tick. + */ + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "OculusXR|Movement") + bool bUseModifiers; + +private: + bool InitializeFaceTracking(); + + // The mesh component targeted for expressions + UPROPERTY() + USkinnedMeshComponent* TargetMeshComponent; + + // Which mapped expressions are valid + TStaticArray(EOculusXRFaceExpression::COUNT)> ExpressionValid; + + // Morph targets controller + FOculusXRMorphTargetsController MorphTargets; + + FOculusXRFaceState FaceState; + + // Timer that counts up until we reset morph curves if we've failed to get face state + float InvalidFaceStateTimer; + + // Stop the tracker just once. + static int TrackingInstanceCount; +}; diff --git a/Plugins/MetaXR/Source/OculusXRMovement/Public/OculusXRLiveLinkRetargetBodyAsset.h b/Plugins/MetaXR/Source/OculusXRMovement/Public/OculusXRLiveLinkRetargetBodyAsset.h new file mode 100644 index 0000000..58591f9 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRMovement/Public/OculusXRLiveLinkRetargetBodyAsset.h @@ -0,0 +1,143 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#pragma once + +#include "CoreMinimal.h" +#include "LiveLinkRetargetAsset.h" +#include "OculusXRMovementTypes.h" +#include "Containers/StaticArray.h" +#include "BonePose.h" + +#include "OculusXRLiveLinkRetargetBodyAsset.generated.h" + +UENUM(BlueprintType, meta = (DisplayName = "Axis")) +enum class EOculusXRAxis : uint8 +{ + X = 0 UMETA(DisplayName = "X"), + Y = 1 UMETA(DisplayName = "Y"), + Z = 2 UMETA(DisplayName = "Z"), + NegativeX = 3 UMETA(DisplayName = "-X"), + NegativeY = 4 UMETA(DisplayName = "-Y"), + NegativeZ = 5 UMETA(DisplayName = "-Z"), +}; + +UENUM(BlueprintType, meta = (DisplayName = "Retargeting mode")) +enum class EOculusXRRetargetingMode : uint8 +{ + Full UMETA(DisplayName = "Rotations and positions"), + Rotations UMETA(DisplayName = "Only rotations"), + RotationsPlusRoot UMETA(DisplayName = "Rotations and root position"), + RotationsPlusHips UMETA(DisplayName = "Rotations and hips position"), + None UMETA(DisplayName = "Disabled"), +}; + +USTRUCT(BlueprintType, meta = (DisplayName = "Bone local correction")) +struct OCULUSXRMOVEMENT_API FOculusXRBoneCorrection +{ + GENERATED_BODY() + + FOculusXRBoneCorrection() + : PositionOffset(FVector::ZeroVector), RotationOffset(FRotator::ZeroRotator){}; + + /** + * Position offset in local space. + */ + UPROPERTY(EditAnywhere, Category = "OculusXR|Movement") + FVector PositionOffset; + + /** + * Rotation offset in local space. + */ + UPROPERTY(EditAnywhere, Category = "OculusXR|Movement") + FRotator RotationOffset; +}; + +USTRUCT(BlueprintType, meta = (DisplayName = "Correction applied to set of bones")) +struct OCULUSXRMOVEMENT_API FOculusXRBoneCorrectionSet +{ + GENERATED_BODY() + + FOculusXRBoneCorrectionSet(){}; + + /** + * Set of bones to which the correction will be applied. + */ + UPROPERTY(EditAnywhere, Category = "OculusXR|Movement") + TSet Bones; + + /** + * The correction for this set. + */ + UPROPERTY(EditAnywhere, Category = "OculusXR|Movement") + FOculusXRBoneCorrection BoneCorrection; +}; + +UCLASS(Blueprintable, meta = (DisplayName = "MetaXR MovementSDK LiveLink retarget body asset"), ClassGroup = OculusXRHMD) +class OCULUSXRMOVEMENT_API UOculusXRLiveLinkRetargetBodyAsset : public ULiveLinkRetargetAsset +{ + GENERATED_UCLASS_BODY() + + virtual void Initialize() override; + virtual void BuildPoseFromAnimationData(float DeltaTime, const FLiveLinkSkeletonStaticData* InSkeletonData, const FLiveLinkAnimationFrameData* InFrameData, FCompactPose& OutPose) override; + + /** + * Remapping from bone ID to target skeleton's bone name. + */ + UPROPERTY(EditDefaultsOnly, Category = "OculusXR|Movement") + TMap BoneRemapping; + + /** + * Correction applied to all bones. + */ + UPROPERTY(EditDefaultsOnly, Category = "OculusXR|Movement") + FOculusXRBoneCorrection GlobalCorrection; + + /** + * Groups of local bone corrections. + * + * Order matters. A bone can be corrected multiple times. + * Corrections will be applied with the same order as in this array. + */ + UPROPERTY(EditDefaultsOnly, Category = "OculusXR|Movement") + TArray LocalCorrections; + + /** + * Switch between retargeting modes. + */ + UPROPERTY(EditAnywhere, Category = "OculusXR|Movement") + EOculusXRRetargetingMode RetargetingMode; + + /** + * Forward vector axis is the direction towards which the target mesh is oriented. + */ + UPROPERTY(EditDefaultsOnly, Category = "OculusXR|Movement") + EOculusXRAxis ForwardMesh; + +private: + // Scale the source tracking positions. This will be initialized with WorldToMeters value. + float Scale; + + // Movement tracking is oriented towards X axis. + const EOculusXRAxis ForwardTracking{ EOculusXRAxis::X }; + + // Transform from tracking to mesh space. + FTransform TrackingSpaceToMeshSpace; + + // Correction applied to all bones + FTransform GlobalBoneCorrection; + + // Correction applied per bone + TStaticArray(EOculusXRBoneID::COUNT)> LocalBoneCorrections; + + // Target skeleton's bone name per bone id + TStaticArray(EOculusXRBoneID::COUNT)> BoneNames; + + // Latest bone container serial number + uint16 LastBoneContainerSerialNumber; + + // Compact pose indices per bone id + TStaticArray(EOculusXRBoneID::COUNT)> LastSkeletonBoneRemapping{ InPlace, FCompactPoseBoneIndex(INDEX_NONE) }; + + // Recalculate skeleton dependent mappings + void OnBoneContainerChanged(const FBoneContainer& BoneContainer); +}; diff --git a/Plugins/MetaXR/Source/OculusXRMovement/Public/OculusXRLiveLinkRetargetFaceAsset.h b/Plugins/MetaXR/Source/OculusXRMovement/Public/OculusXRLiveLinkRetargetFaceAsset.h new file mode 100644 index 0000000..6110fa2 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRMovement/Public/OculusXRLiveLinkRetargetFaceAsset.h @@ -0,0 +1,60 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#pragma once + +#include "CoreMinimal.h" +#include "Animation/AnimTypes.h" +#include "LiveLinkRetargetAsset.h" +#include "Containers/StaticArray.h" +#include "OculusXRMovementTypes.h" +#include "Misc/EngineVersionComparison.h" + +#include "OculusXRLiveLinkRetargetFaceAsset.generated.h" + +USTRUCT(BlueprintType) +struct OCULUSXRMOVEMENT_API FOculusXRAnimCurveMapping +{ + GENERATED_BODY() + + FOculusXRAnimCurveMapping(){}; + + FOculusXRAnimCurveMapping(const std::initializer_list CurveNamesList) + : CurveNames(CurveNamesList) + { + } + + /** + * Skeleton's animation curve names + */ + UPROPERTY(EditAnywhere, Category = "OculusXR|Movement") + TArray CurveNames; +}; + +UCLASS(Blueprintable, meta = (DisplayName = "MetaXR MovementSDK LiveLink retarget face asset"), ClassGroup = OculusXRHMD) +class OCULUSXRMOVEMENT_API UOculusXRLiveLinkRetargetFaceAsset : public ULiveLinkRetargetAsset +{ + GENERATED_UCLASS_BODY() + + virtual void Initialize() override; + virtual void BuildPoseAndCurveFromBaseData(float DeltaTime, const FLiveLinkBaseStaticData* InBaseStaticData, const FLiveLinkBaseFrameData* InBaseFrameData, FCompactPose& OutPose, FBlendedCurve& OutCurve) override; + + /** + * Map face expression to Skeleton's animation curve mapping names. + */ + UPROPERTY(EditDefaultsOnly, Category = "OculusXR|Movement") + TMap CurveRemapping; + +private: + // Latest skeleton used to build pose + FGuid LastSkeletonGuid; + + // Remapping used for latest used skeleton +#if UE_VERSION_OLDER_THAN(5, 3, 0) + TStaticArray, static_cast(EOculusXRFaceExpression::COUNT)> RemappingForLastSkeleton; +#else + TStaticArray, static_cast(EOculusXRFaceExpression::COUNT)> RemappingForLastSkeleton; +#endif + + // Recalculate skeleton dependent mappings + void OnSkeletonChanged(const USkeleton* Skeleton); +}; diff --git a/Plugins/MetaXR/Source/OculusXRMovement/Public/OculusXRMorphTargetsController.h b/Plugins/MetaXR/Source/OculusXRMovement/Public/OculusXRMorphTargetsController.h new file mode 100644 index 0000000..55e79ca --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRMovement/Public/OculusXRMorphTargetsController.h @@ -0,0 +1,36 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#pragma once + +#include "Components/SkinnedMeshComponent.h" + +/* +* Struct that allows applying morph targets data to an arbitrary skinned mesh component +* instead of relying on the skeletal mesh component. +* +* Usage - In a tick method of your choosing: +* 1) ResetMorphTargetCurves(Component) at the start of the update. +* 2) SetMorphTarget(...) as many times as needed based on your data set. +* 3) ApplyMorphTargets(Component) at the end of the update to apply the morph targets to the anim runtime. +*/ +struct OCULUSXRMOVEMENT_API FOculusXRMorphTargetsController +{ +public: + // Clears active morph targets + void ResetMorphTargetCurves(USkinnedMeshComponent* TargetMeshComponent); + + // Will apply morph target data to the underlying runtime skeletal mesh + void ApplyMorphTargets(USkinnedMeshComponent* TargetMeshComponent); + + // Sets a specific morph target value + void SetMorphTarget(FName MorphTargetName, float Value); + + // Gets a specific morph target value + float GetMorphTarget(FName MorphTargetName) const; + + // Clears all morph target curves data + void ClearMorphTargets(); + + // List of morph targets on this controller + TMap MorphTargetCurves; +}; diff --git a/Plugins/MetaXR/Source/OculusXRMovement/Public/OculusXRMovement.h b/Plugins/MetaXR/Source/OculusXRMovement/Public/OculusXRMovement.h new file mode 100644 index 0000000..cfe633f --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRMovement/Public/OculusXRMovement.h @@ -0,0 +1,41 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#pragma once + +#include "OculusXRMovementTypes.h" + +namespace XRSpaceFlags +{ + static const uint64 XR_SPACE_LOCATION_ORIENTATION_VALID_BIT = 0x00000001; + static const uint64 XR_SPACE_LOCATION_POSITION_VALID_BIT = 0x00000002; + static const uint64 XR_SPACE_LOCATION_ORIENTATION_TRACKED_BIT = 0x00000004; + static const uint64 XR_SPACE_LOCATION_POSITION_TRACKED_BIT = 0x00000008; +} // namespace XRSpaceFlags + +struct OCULUSXRMOVEMENT_API OculusXRMovement +{ + static bool GetBodyState(FOculusXRBodyState& outOculusXRBodyState, float WorldToMeters = 100.0f); + static bool IsBodyTrackingEnabled(); + static bool IsBodyTrackingSupported(); + static bool StartBodyTracking(); + static bool StopBodyTracking(); + static bool StartBodyTrackingByJointSet(EOculusXRBodyJointSet jointSet); + static bool RequestBodyTrackingFidelity(EOculusXRBodyTrackingFidelity fidelity); + static bool ResetBodyTrackingCalibration(); + static bool SuggestBodyTrackingCalibrationOverride(float height); +private: + static bool IsFullBodyTrackingEnabled(); + +public: + static bool GetFaceState(FOculusXRFaceState& outOculusXRFaceState); + static bool IsFaceTrackingEnabled(); + static bool IsFaceTrackingSupported(); + static bool StartFaceTracking(); + static bool StopFaceTracking(); + + static bool GetEyeGazesState(FOculusXREyeGazesState& outOculusXREyeGazesState, float WorldToMeters = 100.0f); + static bool IsEyeTrackingEnabled(); + static bool IsEyeTrackingSupported(); + static bool StartEyeTracking(); + static bool StopEyeTracking(); +}; diff --git a/Plugins/MetaXR/Source/OculusXRMovement/Public/OculusXRMovementFunctionLibrary.h b/Plugins/MetaXR/Source/OculusXRMovement/Public/OculusXRMovementFunctionLibrary.h new file mode 100644 index 0000000..ce4c296 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRMovement/Public/OculusXRMovementFunctionLibrary.h @@ -0,0 +1,71 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#pragma once + +#include "OculusXRMovementTypes.h" +#include "Kismet/BlueprintFunctionLibrary.h" + +#include "OculusXRMovementFunctionLibrary.generated.h" + +UCLASS() +class OCULUSXRMOVEMENT_API UOculusXRMovementFunctionLibrary : public UBlueprintFunctionLibrary +{ + GENERATED_BODY() +public: + UFUNCTION(BlueprintCallable, Category = "OculusXR|Body") + static bool TryGetBodyState(FOculusXRBodyState& outBodyState, float WorldToMeters = 100.0f); + + UFUNCTION(BlueprintCallable, Category = "OculusXR|Body") + static bool IsBodyTrackingEnabled(); + + UFUNCTION(BlueprintCallable, Category = "OculusXR|Body") + static bool IsBodyTrackingSupported(); + + UFUNCTION(BlueprintCallable, Category = "OculusXR|Body") + static bool RequestBodyTrackingFidelity(EOculusXRBodyTrackingFidelity fidelity); + + UFUNCTION(BlueprintCallable, Category = "OculusXR|Body") + static bool ResetBodyTrackingCalibration(); + + UFUNCTION(BlueprintCallable, Category = "OculusXR|Body") + static bool SuggestBodyTrackingCalibrationOverride(float height); + + UFUNCTION(BlueprintCallable, Category = "OculusXR|Body") + static bool StartBodyTrackingByJointSet(EOculusXRBodyJointSet jointSet); + + UFUNCTION(BlueprintCallable, meta = (DeprecatedFunction, DeprecationMessage = "StartBodyTracking is deprecated, use StartBodyTrackingByJointSet."), Category = "OculusXR|Body") + static bool StartBodyTracking(); + + UFUNCTION(BlueprintCallable, Category = "OculusXR|Body") + static bool StopBodyTracking(); + + UFUNCTION(BlueprintCallable, Category = "OculusXR|Face") + static bool TryGetFaceState(FOculusXRFaceState& outFaceState); + + UFUNCTION(BlueprintCallable, Category = "OculusXR|Face") + static bool IsFaceTrackingEnabled(); + + UFUNCTION(BlueprintCallable, Category = "OculusXR|Face") + static bool IsFaceTrackingSupported(); + + UFUNCTION(BlueprintCallable, Category = "OculusXR|Face") + static bool StartFaceTracking(); + + UFUNCTION(BlueprintCallable, Category = "OculusXR|Face") + static bool StopFaceTracking(); + + UFUNCTION(BlueprintCallable, Category = "OculusXR|Eyes") + static bool TryGetEyeGazesState(FOculusXREyeGazesState& outEyeGazesState, float WorldToMeters = 100.0f); + + UFUNCTION(BlueprintCallable, Category = "OculusXR|Eyes") + static bool IsEyeTrackingEnabled(); + + UFUNCTION(BlueprintCallable, Category = "OculusXR|Eyes") + static bool IsEyeTrackingSupported(); + + UFUNCTION(BlueprintCallable, Category = "OculusXR|Eyes") + static bool StartEyeTracking(); + + UFUNCTION(BlueprintCallable, Category = "OculusXR|Eyes") + static bool StopEyeTracking(); +}; diff --git a/Plugins/MetaXR/Source/OculusXRMovement/Public/OculusXRMovementHelpers.h b/Plugins/MetaXR/Source/OculusXRMovement/Public/OculusXRMovementHelpers.h new file mode 100644 index 0000000..e482d5e --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRMovement/Public/OculusXRMovementHelpers.h @@ -0,0 +1,24 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#pragma once + +namespace OculusXRUtility +{ + template + T* FindComponentByName(AActor* Actor, const FName& ComponentName) + { + if (IsValid(Actor) && (ComponentName != NAME_None)) + { + TArray ComponentsOfType; + Actor->GetComponents(ComponentsOfType); + T** FoundComponent = ComponentsOfType.FindByPredicate([Name = ComponentName.ToString()](T* Component) { return Component->GetName().Equals(Name); }); + + if (FoundComponent != nullptr) + { + return *FoundComponent; + } + } + + return nullptr; + } +} // namespace OculusXRUtility diff --git a/Plugins/MetaXR/Source/OculusXRMovement/Public/OculusXRMovementTypes.h b/Plugins/MetaXR/Source/OculusXRMovement/Public/OculusXRMovementTypes.h new file mode 100644 index 0000000..9ed5404 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRMovement/Public/OculusXRMovementTypes.h @@ -0,0 +1,336 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#pragma once + +#include "CoreMinimal.h" +#include "OculusXRMovementTypes.generated.h" + +UENUM(BlueprintType) +enum class EOculusXRBodyJointSet : uint8 +{ + UpperBody = 0, + FullBody = 1 +}; + +UENUM(BlueprintType) +enum class EOculusXRBodyTrackingFidelity : uint8 +{ + Unset = 0 UMETA(Hidden), + Low = 1, + High = 2, +}; + +UENUM(BlueprintType) +enum class EOculusXRBoneID : uint8 +{ + BodyRoot = 0, + BodyHips = 1, + BodySpineLower = 2, + BodySpineMiddle = 3, + BodySpineUpper = 4, + BodyChest = 5, + BodyNeck = 6, + BodyHead = 7, + BodyLeftShoulder = 8, + BodyLeftScapula = 9, + BodyLeftArmUpper = 10, + BodyLeftArmLower = 11, + BodyLeftHandWristTwist = 12, + BodyRightShoulder = 13, + BodyRightScapula = 14, + BodyRightArmUpper = 15, + BodyRightArmLower = 16, + BodyRightHandWristTwist = 17, + BodyLeftHandPalm = 18, + BodyLeftHandWrist = 19, + BodyLeftHandThumbMetacarpal = 20, + BodyLeftHandThumbProximal = 21, + BodyLeftHandThumbDistal = 22, + BodyLeftHandThumbTip = 23, + BodyLeftHandIndexMetacarpal = 24, + BodyLeftHandIndexProximal = 25, + BodyLeftHandIndexIntermediate = 26, + BodyLeftHandIndexDistal = 27, + BodyLeftHandIndexTip = 28, + BodyLeftHandMiddleMetacarpal = 29, + BodyLeftHandMiddleProximal = 30, + BodyLeftHandMiddleIntermediate = 31, + BodyLeftHandMiddleDistal = 32, + BodyLeftHandMiddleTip = 33, + BodyLeftHandRingMetacarpal = 34, + BodyLeftHandRingProximal = 35, + BodyLeftHandRingIntermediate = 36, + BodyLeftHandRingDistal = 37, + BodyLeftHandRingTip = 38, + BodyLeftHandLittleMetacarpal = 39, + BodyLeftHandLittleProximal = 40, + BodyLeftHandLittleIntermediate = 41, + BodyLeftHandLittleDistal = 42, + BodyLeftHandLittleTip = 43, + BodyRightHandPalm = 44, + BodyRightHandWrist = 45, + BodyRightHandThumbMetacarpal = 46, + BodyRightHandThumbProximal = 47, + BodyRightHandThumbDistal = 48, + BodyRightHandThumbTip = 49, + BodyRightHandIndexMetacarpal = 50, + BodyRightHandIndexProximal = 51, + BodyRightHandIndexIntermediate = 52, + BodyRightHandIndexDistal = 53, + BodyRightHandIndexTip = 54, + BodyRightHandMiddleMetacarpal = 55, + BodyRightHandMiddleProximal = 56, + BodyRightHandMiddleIntermediate = 57, + BodyRightHandMiddleDistal = 58, + BodyRightHandMiddleTip = 59, + BodyRightHandRingMetacarpal = 60, + BodyRightHandRingProximal = 61, + BodyRightHandRingIntermediate = 62, + BodyRightHandRingDistal = 63, + BodyRightHandRingTip = 64, + BodyRightHandLittleMetacarpal = 65, + BodyRightHandLittleProximal = 66, + BodyRightHandLittleIntermediate = 67, + BodyRightHandLittleDistal = 68, + BodyRightHandLittleTip = 69, + BodyLeftUpperLeg = 70, + BodyLeftLowerLeg = 71, + BodyLeftFootAnkleTwist = 72, + BodyLeftFootAnkle = 73, + BodyLeftFootSubtalar = 74, + BodyLeftFootTransverse = 75, + BodyLeftFootBall = 76, + BodyRightUpperLeg = 77, + BodyRightLowerLeg = 78, + BodyRightFootAnkleTwist = 79, + BodyRightFootAnkle = 80, + BodyRightFootSubtalar = 81, + BodyRightFootTransverse = 82, + BodyRightFootBall = 83, + COUNT = 84 UMETA(Hidden), + None = 255 UMETA(Hidden), +}; + +USTRUCT(BlueprintType) +struct OCULUSXRMOVEMENT_API FOculusXRBodyJoint +{ + GENERATED_BODY() +public: + FOculusXRBodyJoint(); + + uint64 LocationFlags; + + UPROPERTY(BlueprintReadOnly, Category = "OculusXR|Movement") + bool bIsValid; + + UPROPERTY(BlueprintReadOnly, Category = "OculusXR|Movement") + FRotator Orientation; + + UPROPERTY(BlueprintReadOnly, Category = "OculusXR|Movement") + FVector Position; +}; + +USTRUCT(BlueprintType) +struct OCULUSXRMOVEMENT_API FOculusXRBodyState +{ + GENERATED_BODY() +public: + FOculusXRBodyState(); + + UPROPERTY(BlueprintReadOnly, Category = "OculusXR|Movement") + bool IsActive; + + UPROPERTY(BlueprintReadOnly, Category = "OculusXR|Movement") + float Confidence; + + UPROPERTY(BlueprintReadOnly, Category = "OculusXR|Movement") + int SkeletonChangedCount; + + UPROPERTY(BlueprintReadOnly, Category = "OculusXR|Movement") + float Time; + + UPROPERTY(BlueprintReadOnly, Category = "OculusXR|Movement") + TArray Joints; +}; + + +UENUM(BlueprintType) +enum class EFaceTrackingDataSource : uint8 +{ + Visual = 0 UMETA(DisplayName = "Visual"), + Audio = 1 UMETA(DisplayName = "Audio"), + MAX = 2 UMETA(Hidden), +}; + +UENUM(BlueprintType) +enum class EOculusXRFaceExpression : uint8 +{ + // Removed invalid to make this supported as a uint8 enum class + BrowLowererL = 0, + BrowLowererR = 1, + CheekPuffL = 2, + CheekPuffR = 3, + CheekRaiserL = 4, + CheekRaiserR = 5, + CheekSuckL = 6, + CheekSuckR = 7, + ChinRaiserB = 8, + ChinRaiserT = 9, + DimplerL = 10, + DimplerR = 11, + EyesClosedL = 12, + EyesClosedR = 13, + EyesLookDownL = 14, + EyesLookDownR = 15, + EyesLookLeftL = 16, + EyesLookLeftR = 17, + EyesLookRightL = 18, + EyesLookRightR = 19, + EyesLookUpL = 20, + EyesLookUpR = 21, + InnerBrowRaiserL = 22, + InnerBrowRaiserR = 23, + JawDrop = 24, + JawSidewaysLeft = 25, + JawSidewaysRight = 26, + JawThrust = 27, + LidTightenerL = 28, + LidTightenerR = 29, + LipCornerDepressorL = 30, + LipCornerDepressorR = 31, + LipCornerPullerL = 32, + LipCornerPullerR = 33, + LipFunnelerLB = 34, + LipFunnelerLT = 35, + LipFunnelerRB = 36, + LipFunnelerRT = 37, + LipPressorL = 38, + LipPressorR = 39, + LipPuckerL = 40, + LipPuckerR = 41, + LipStretcherL = 42, + LipStretcherR = 43, + LipSuckLB = 44, + LipSuckLT = 45, + LipSuckRB = 46, + LipSuckRT = 47, + LipTightenerL = 48, + LipTightenerR = 49, + LipsToward = 50, + LowerLipDepressorL = 51, + LowerLipDepressorR = 52, + MouthLeft = 53, + MouthRight = 54, + NoseWrinklerL = 55, + NoseWrinklerR = 56, + OuterBrowRaiserL = 57, + OuterBrowRaiserR = 58, + UpperLidRaiserL = 59, + UpperLidRaiserR = 60, + UpperLipRaiserL = 61, + UpperLipRaiserR = 62, + TongueTipInterdental = 63, + TongueTipAlveolar = 64, + TongueFrontDorsalPalate = 65, + TongueMidDorsalPalate = 66, + TongueBackDorsalVelar = 67, + TongueOut = 68, + TongueRetreat = 69, + COUNT = 70 UMETA(Hidden), +}; + +UENUM(BlueprintType) +enum class EOculusXRFaceConfidence : uint8 +{ + Lower = 0, + Upper = 1, + COUNT = 2, +}; + +USTRUCT(BlueprintType) +struct OCULUSXRMOVEMENT_API FOculusXRFaceState +{ + GENERATED_BODY() +public: + FOculusXRFaceState(); + + UPROPERTY(BlueprintReadOnly, Category = "OculusXR|Movement") + TArray ExpressionWeights; + + UPROPERTY(BlueprintReadOnly, Category = "OculusXR|Movement") + TArray ExpressionWeightConfidences; + + UPROPERTY(BlueprintReadOnly, Category = "OculusXR|Movement") + bool bIsValid; + + UPROPERTY(BlueprintReadOnly, Category = "OculusXR|Movement") + bool bIsEyeFollowingBlendshapesValid; + + UPROPERTY(BlueprintReadOnly, Category = "OculusXR|Movement") + float Time; + + UPROPERTY(BlueprintReadOnly, Category = "OculusXR|Movement") + EFaceTrackingDataSource DataSource; +}; + +USTRUCT(BlueprintType) +struct OCULUSXRMOVEMENT_API FOculusXRFaceExpressionModifier +{ + GENERATED_BODY() +public: + FOculusXRFaceExpressionModifier(); + + UPROPERTY(EditAnywhere, Category = "OculusXR|Movement") + TArray FaceExpressions; + + UPROPERTY(EditAnywhere, Category = "OculusXR|Movement") + float MinValue; + + UPROPERTY(EditAnywhere, Category = "OculusXR|Movement") + float MaxValue; + + UPROPERTY(EditAnywhere, Category = "OculusXR|Movement") + float Multiplier; +}; + +UENUM(BlueprintType) +enum class EOculusXREye : uint8 +{ + Left = 0, + Right = 1, + COUNT = 2, +}; + +USTRUCT(BlueprintType) +struct OCULUSXRMOVEMENT_API FOculusXREyeGazeState +{ + GENERATED_BODY() +public: + FOculusXREyeGazeState(); + + UPROPERTY(BlueprintReadOnly, Category = "OculusXR|Movement") + FRotator Orientation; + + UPROPERTY(BlueprintReadOnly, Category = "OculusXR|Movement") + FVector Position; + + UPROPERTY(BlueprintReadOnly, Category = "OculusXR|Movement") + float Confidence; + + UPROPERTY(BlueprintReadOnly, Category = "OculusXR|Movement") + bool bIsValid; +}; + +USTRUCT(BlueprintType) +struct OCULUSXRMOVEMENT_API FOculusXREyeGazesState +{ + GENERATED_BODY() +public: + FOculusXREyeGazesState(); + + UPROPERTY(BlueprintReadOnly, Category = "OculusXR|Movement") + TArray EyeGazes; + + UPROPERTY(BlueprintReadOnly, Category = "OculusXR|Movement") + float Time; +}; diff --git a/Plugins/MetaXR/Source/OculusXROpenXRHMD/OculusXROpenXRHMD.Build.cs b/Plugins/MetaXR/Source/OculusXROpenXRHMD/OculusXROpenXRHMD.Build.cs new file mode 100644 index 0000000..dece4f5 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXROpenXRHMD/OculusXROpenXRHMD.Build.cs @@ -0,0 +1,131 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +using System; +using System.IO; + +namespace UnrealBuildTool.Rules +{ + public class OculusXROpenXRHMD : ModuleRules + { + public OculusXROpenXRHMD(ReadOnlyTargetRules Target) : base(Target) + { + bUseUnity = true; + + var EngineDir = Path.GetFullPath(Target.RelativeEnginePath); + + PublicIncludePaths.AddRange( + new string[] { + // Relative to Engine\Plugins\OculusXR\Source\OculusOpenXR\Source + Path.Combine(EngineDir, "Plugins/Runtime/OpenXR/Source/OpenXRHMD/Private"), + Path.Combine(EngineDir, "Source/Runtime/Renderer/Private"), + Path.Combine(EngineDir, "Source/Runtime/OpenGLDrv/Private"), + Path.Combine(EngineDir, "Source/Runtime/Engine/Classes/Components"), + Path.Combine(EngineDir, "Source/Runtime/Engine/Classes/Kismet"), + }); + + PublicIncludePathModuleNames.AddRange( + new string[] { + "Launch", + "OpenXRHMD", + }); + + PrivateDependencyModuleNames.AddRange( + new string[] + { + "Core", + "CoreUObject", + "Engine", + "InputCore", + "RHI", + "RHICore", + "RenderCore", + "Renderer", + "Slate", + "SlateCore", + "ImageWrapper", + "MediaAssets", + "Analytics", + "OpenGLDrv", + "VulkanRHI", + "HeadMountedDisplay", + "OculusOpenXRLoader", + "Projects", + }); + + if (Target.Version.MajorVersion < 5 || (Target.Version.MajorVersion == 5 && Target.Version.MinorVersion < 3)) + { + PublicDependencyModuleNames.AddRange( + new string[] + { + "OpenXRHMD", + }); + } + + if (Target.Version.MajorVersion > 5 || (Target.Version.MajorVersion == 5 && Target.Version.MinorVersion >= 3)) + { + PublicDependencyModuleNames.AddRange( + new string[] + { + "XRBase", + }); + } + + if (Target.bBuildEditor == true) + { + PrivateDependencyModuleNames.Add("UnrealEd"); + } + + AddEngineThirdPartyPrivateStaticDependencies(Target, "OpenGL"); + + if (Target.Platform == UnrealTargetPlatform.Win64) + { + // D3D + { + PrivateDependencyModuleNames.AddRange( + new string[] + { + "D3D11RHI", + "D3D12RHI", + }); + + + PublicIncludePaths.AddRange( + new string[] + { + Path.Combine(EngineDir, "Source/Runtime/Windows/D3D11RHI/Private"), + Path.Combine(EngineDir, "Source/Runtime/Windows/D3D11RHI/Private/Windows"), + Path.Combine(EngineDir, "Source/Runtime/D3D12RHI/Private"), + Path.Combine(EngineDir, "Source/Runtime/D3D12RHI/Private/Windows"), + }); + + AddEngineThirdPartyPrivateStaticDependencies(Target, "DX11"); + AddEngineThirdPartyPrivateStaticDependencies(Target, "DX12"); + AddEngineThirdPartyPrivateStaticDependencies(Target, "NVAPI"); + AddEngineThirdPartyPrivateStaticDependencies(Target, "DX11Audio"); + AddEngineThirdPartyPrivateStaticDependencies(Target, "DirectSound"); + AddEngineThirdPartyPrivateStaticDependencies(Target, "NVAftermath"); + AddEngineThirdPartyPrivateStaticDependencies(Target, "IntelMetricsDiscovery"); + AddEngineThirdPartyPrivateStaticDependencies(Target, "IntelExtensionsFramework"); + } + + // Vulkan + { + AddEngineThirdPartyPrivateStaticDependencies(Target, "Vulkan"); + } + } + else if (Target.Platform == UnrealTargetPlatform.Android) + { + PrivateIncludePaths.AddRange( + new string[] + { + }); + + // Vulkan + { + AddEngineThirdPartyPrivateStaticDependencies(Target, "Vulkan"); + } + } + } + } +} diff --git a/Plugins/MetaXR/Source/OculusXROpenXRHMD/Private/OculusXROpenXRHMD.cpp b/Plugins/MetaXR/Source/OculusXROpenXRHMD/Private/OculusXROpenXRHMD.cpp new file mode 100644 index 0000000..6cfdd88 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXROpenXRHMD/Private/OculusXROpenXRHMD.cpp @@ -0,0 +1,142 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +#include "OculusXROpenXRHMD.h" +#include "OpenXRCore.h" +#include "OpenXRPlatformRHI.h" +#include "DefaultSpectatorScreenController.h" +#include "Modules/ModuleManager.h" + +#if PLATFORM_ANDROID +//#include +#include +#endif //PLATFORM_ANDROID + +DEFINE_LOG_CATEGORY(LogOculusOpenXRPlugin); + +bool FOculusXROpenXRHMD::IsStandaloneStereoOnlyDevice() +{ +#if PLATFORM_ANDROID + const bool bIsStandaloneStereoDevice = FAndroidMisc::GetDeviceMake() == FString("Oculus"); +#else + const bool bIsStandaloneStereoDevice = false; +#endif + return bIsStandaloneStereoDevice; +} + +bool FOculusXROpenXRHMD::GetRequiredExtensions(TArray& OutExtensions) +{ + return true; +} + +bool FOculusXROpenXRHMD::GetInteractionProfile(XrInstance InInstance, FString& OutKeyPrefix, XrPath& OutPath, bool& OutHasHaptics) +{ + //UE_LOG(LogOculusOpenXRPlugin, Log, TEXT("Oculus OpenXR GetInteractionProfile")); + return false; // if you return true, make sure OutPath and OutHasHaptics are initialized +} + +bool FOculusXROpenXRHMD::GetSpectatorScreenController(FHeadMountedDisplayBase* InHMDBase, TUniquePtr& OutSpectatorScreenController) +{ +#if PLATFORM_ANDROID + OutSpectatorScreenController = nullptr; + return true; +#else // PLATFORM_ANDROID + OutSpectatorScreenController = MakeUnique(InHMDBase); + return false; +#endif // PLATFORM_ANDROID +} + +void FOculusXROpenXRHMD::AddActions(XrInstance Instance, TFunction& InSubactionPaths)> AddAction) +{ + //UE_LOG(LogOculusOpenXRPlugin, Log, TEXT("Oculus OpenXR AddActions")); + return; +} + +void FOculusXROpenXRHMD::OnEvent(XrSession InSession, const XrEventDataBaseHeader* InHeader) +{ + return; +} + +const void* FOculusXROpenXRHMD::OnCreateInstance(class IOpenXRHMDModule* InModule, const void* InNext) +{ + //UE_LOG(LogOculusOpenXRPlugin, Log, TEXT("Oculus OpenXR OnCreateInstance")); + return InNext; +} + +const void* FOculusXROpenXRHMD::OnGetSystem(XrInstance InInstance, const void* InNext) +{ + //UE_LOG(LogOculusOpenXRPlugin, Log, TEXT("Oculus OpenXR OnGetSystem")); + return InNext; +} + +const void* FOculusXROpenXRHMD::OnCreateSession(XrInstance InInstance, XrSystemId InSystem, const void* InNext) +{ + //UE_LOG(LogOculusOpenXRPlugin, Log, TEXT("Oculus OpenXR OnCreateSession")); +#if PLATFORM_ANDROID + if (GRHISupportsRHIThread && GIsThreadedRendering && GUseRHIThread_InternalUseOnly) + { + SetRHIThreadEnabled(false, false); + } +#endif // PLATFORM_ANDROID + return InNext; +} + +const void* FOculusXROpenXRHMD::OnBeginSession(XrSession InSession, const void* InNext) +{ + //UE_LOG(LogOculusOpenXRPlugin, Log, TEXT("Oculus OpenXR OnBeginSession")); + return InNext; +} + +const void* FOculusXROpenXRHMD::OnBeginFrame(XrSession InSession, XrTime DisplayTime, const void* InNext) +{ + //UE_LOG(LogOculusOpenXRPlugin, Log, TEXT("Oculus OpenXR OnBeginFrame")); + return InNext; +} + +const void* FOculusXROpenXRHMD::OnBeginProjectionView(XrSession InSession, int32 InLayerIndex, int32 InViewIndex, const void* InNext) +{ + //UE_LOG(LogOculusOpenXRPlugin, Log, TEXT("Oculus OpenXR OnBeginProjectionView")); + return InNext; +} + +const void* FOculusXROpenXRHMD::OnBeginDepthInfo(XrSession InSession, int32 InLayerIndex, int32 InViewIndex, const void* InNext) +{ + //UE_LOG(LogOculusOpenXRPlugin, Log, TEXT("Oculus OpenXR OnBeginDepthInfo")); + return InNext; +} + +const void* FOculusXROpenXRHMD::OnEndProjectionLayer(XrSession InSession, int32 InLayerIndex, const void* InNext, XrCompositionLayerFlags& OutFlags) +{ + //UE_LOG(LogOculusOpenXRPlugin, Log, TEXT("Oculus OpenXR OnEndProjectionLayer")); + + // XR_COMPOSITION_LAYER_UNPREMULTIPLIED_ALPHA_BIT is required right now because the Oculus mobile runtime blends using alpha otherwise, + // and we don't have proper inverse alpha support in OpenXR yet (once OpenXR supports inverse alpha, or we change the runtime behavior, remove this) + OutFlags |= XR_COMPOSITION_LAYER_CORRECT_CHROMATIC_ABERRATION_BIT; + OutFlags |= XR_COMPOSITION_LAYER_UNPREMULTIPLIED_ALPHA_BIT; + + return InNext; +} + +#if UE_VERSION_OLDER_THAN(5, 3, 0) +const void* FOculusXROpenXRHMD::OnEndFrame(XrSession InSession, XrTime DisplayTime, const TArray InColorImages, const TArray InDepthImages, const void* InNext) +#else +const void* FOculusXROpenXRHMD::OnEndFrame(XrSession InSession, XrTime DisplayTime, const void* InNext) +#endif +{ + //UE_LOG(LogOculusOpenXRPlugin, Log, TEXT("Oculus OpenXR OnEndFrame")); + return InNext; +} + +const void* FOculusXROpenXRHMD::OnSyncActions(XrSession InSession, const void* InNext) +{ + //UE_LOG(LogOculusOpenXRPlugin, Log, TEXT("Oculus OpenXR OnSyncActions")); + return InNext; +} + +void FOculusXROpenXRHMD::PostSyncActions(XrSession InSession) +{ + //UE_LOG(LogOculusOpenXRPlugin, Log, TEXT("Oculus OpenXR PostSyncActions")); + return; +} + +IMPLEMENT_MODULE(FOculusXROpenXRHMD, OculusXROpenXRHMD) diff --git a/Plugins/MetaXR/Source/OculusXROpenXRHMD/Private/OculusXROpenXRHMD.h b/Plugins/MetaXR/Source/OculusXROpenXRHMD/Private/OculusXROpenXRHMD.h new file mode 100644 index 0000000..694bbb0 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXROpenXRHMD/Private/OculusXROpenXRHMD.h @@ -0,0 +1,61 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +#pragma once +#include "CoreMinimal.h" +#include "Misc/EngineVersionComparison.h" +#include "IOculusXROpenXRHMDPlugin.h" + +DECLARE_LOG_CATEGORY_EXTERN(LogOculusOpenXRPlugin, Log, All); + +class FOculusXROpenXRHMD : public IOculusXROpenXRHMDPlugin +{ +private: + void* LoaderHandle; + +public: + FOculusXROpenXRHMD() + : LoaderHandle(nullptr) + { + } + + virtual ~FOculusXROpenXRHMD() + { + } + + virtual void StartupModule() override + { + RegisterOpenXRExtensionModularFeature(); + } + + virtual void ShutdownModule() override + { + if (LoaderHandle) + { + FPlatformProcess::FreeDllHandle(LoaderHandle); + LoaderHandle = nullptr; + } + } + + virtual bool IsStandaloneStereoOnlyDevice() override; + virtual bool GetRequiredExtensions(TArray& OutExtensions) override; + virtual bool GetInteractionProfile(XrInstance InInstance, FString& OutKeyPrefix, XrPath& OutPath, bool& OutHasHaptics) override; + virtual bool GetSpectatorScreenController(FHeadMountedDisplayBase* InHMDBase, TUniquePtr& OutSpectatorScreenController) override; + virtual void AddActions(XrInstance Instance, TFunction& InSubactionPaths)> AddAction) override; + virtual void OnEvent(XrSession InSession, const XrEventDataBaseHeader* InHeader) override; + virtual const void* OnCreateInstance(class IOpenXRHMDModule* InModule, const void* InNext) override; + virtual const void* OnGetSystem(XrInstance InInstance, const void* InNext) override; + virtual const void* OnCreateSession(XrInstance InInstance, XrSystemId InSystem, const void* InNext) override; + virtual const void* OnBeginSession(XrSession InSession, const void* InNext) override; + virtual const void* OnBeginFrame(XrSession InSession, XrTime DisplayTime, const void* InNext) override; + virtual const void* OnBeginProjectionView(XrSession InSession, int32 InLayerIndex, int32 InViewIndex, const void* InNext) override; + virtual const void* OnBeginDepthInfo(XrSession InSession, int32 InLayerIndex, int32 InViewIndex, const void* InNext) override; + virtual const void* OnEndProjectionLayer(XrSession InSession, int32 InLayerIndex, const void* InNext, XrCompositionLayerFlags& OutFlags) override; +#if UE_VERSION_OLDER_THAN(5, 3, 0) + virtual const void* OnEndFrame(XrSession InSession, XrTime DisplayTime, const TArray InColorImages, const TArray InDepthImages, const void* InNext) override; +#else + virtual const void* OnEndFrame(XrSession InSession, XrTime DisplayTime, const void* InNext) override; +#endif + virtual const void* OnSyncActions(XrSession InSession, const void* InNext) override; + virtual void PostSyncActions(XrSession InSession) override; +}; diff --git a/Plugins/MetaXR/Source/OculusXROpenXRHMD/Public/IOculusXROpenXRHMDPlugin.h b/Plugins/MetaXR/Source/OculusXROpenXRHMD/Public/IOculusXROpenXRHMDPlugin.h new file mode 100644 index 0000000..0df1a64 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXROpenXRHMD/Public/IOculusXROpenXRHMDPlugin.h @@ -0,0 +1,9 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +#pragma once +#include "IOpenXRExtensionPlugin.h" + +class IOculusXROpenXRHMDPlugin : public IOpenXRExtensionPlugin, public IModuleInterface +{ +}; diff --git a/Plugins/MetaXR/Source/OculusXRPassthrough/OculusXRPassthrough.Build.cs b/Plugins/MetaXR/Source/OculusXRPassthrough/OculusXRPassthrough.Build.cs new file mode 100644 index 0000000..00548d6 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRPassthrough/OculusXRPassthrough.Build.cs @@ -0,0 +1,38 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +using System; +using System.IO; + +namespace UnrealBuildTool.Rules +{ + public class OculusXRPassthrough : ModuleRules + { + public OculusXRPassthrough(ReadOnlyTargetRules Target) : base(Target) + { + bUseUnity = true; + + PrivateDependencyModuleNames.AddRange( + new string[] + { + "Core", + "CoreUObject", + "Engine", + "ProceduralMeshComponent", + "OculusXRHMD", + "OVRPluginXR", + "HeadMountedDisplay", + }); + + PublicIncludePaths.AddRange(new string[] { + "Runtime/Engine/Classes/Components", + "Runtime/Engine/Classes/Kismet", + }); + + PrivateIncludePaths.AddRange(new string[] { + // Relative to Engine\Plugins\Runtime\Oculus\OculusVR\Source + "OculusXRHMD/Private", + }); + } + } +} diff --git a/Plugins/MetaXR/Source/OculusXRPassthrough/Private/OculusXRPassthroughColorLut.cpp b/Plugins/MetaXR/Source/OculusXRPassthrough/Private/OculusXRPassthroughColorLut.cpp new file mode 100644 index 0000000..24ede85 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRPassthrough/Private/OculusXRPassthroughColorLut.cpp @@ -0,0 +1,278 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#include "OculusXRPassthroughColorLut.h" +#include "OculusXRPassthroughLayerComponent.h" +#include "OculusXRHMDPrivate.h" +#include "Math/UnrealMathUtility.h" +#include "GenericPlatform/GenericPlatformMath.h" +#include "UObject/ObjectSaveContext.h" +#include "OculusXRHMD.h" +#include "TextureResource.h" + +namespace +{ + ovrpPassthroughColorLutChannels ToOVRPColorLutChannels(EColorLutChannels InColorLutChannels) + { + switch (InColorLutChannels) + { + case ColorLutChannels_RGB: + return ovrpPassthroughColorLutChannels_Rgb; + case ColorLutChannels_RGBA: + return ovrpPassthroughColorLutChannels_Rgba; + default: + return ovrpPassthroughColorLutChannels_Invalid; + } + } + + TArray ColorArrayToColorData(const TArray& InColorArray, bool IgnoreAlphaChannel) + { + TArray Data; + const size_t ElementSize = IgnoreAlphaChannel ? 3 : 4; + Data.SetNum(InColorArray.Num() * ElementSize); + uint8* Dest = Data.GetData(); + for (size_t i = 0; i < InColorArray.Num(); i++) + { + Data[i * ElementSize + 0] = InColorArray[i].R; + Data[i * ElementSize + 1] = InColorArray[i].G; + Data[i * ElementSize + 2] = InColorArray[i].B; + + if (!IgnoreAlphaChannel) + { + Data[i * ElementSize + 3] = InColorArray[i].A; + } + } + + return Data; + } + + bool IsTextureDataValid(const FLutTextureData& Data) + { + return Data.Data.Num() > 0 && Data.Resolution > 0; + } +} // namespace + +void UOculusXRPassthroughColorLut::SetLutFromArray(const TArray& InColorArray, bool InIgnoreAlphaChannel) +{ + const int32 Size = InColorArray.Num(); + const int32 Resolution = FPlatformMath::RoundToInt(FPlatformMath::Pow(Size, 1.0 / 3)); + if (Resolution > GetMaxResolution()) + { + UE_LOG(LogOculusPassthrough, Warning, TEXT("Setting array ignored: Resoluton is exceeding maximum resoluton of %d."), GetMaxResolution()); + return; + } + if (Resolution * Resolution * Resolution != Size) + { + UE_LOG(LogOculusPassthrough, Warning, TEXT("Setting array ignored: Provided array size is not cube.")); + return; + } + + /* Check if size if power of 2 */ + if ((Size & (Size - 1)) != 0) + { + UE_LOG(LogOculusPassthrough, Warning, TEXT("Setting array ignored: Provided array does not result in a resolution that is a power of two.")); + return; + } + + ColorLutType = EColorLutType::Array; + + const TArray& Data = ColorArrayToColorData(InColorArray, InIgnoreAlphaChannel); + + if (LutHandle == 0) + { + LutHandle = CreateLutObject(Data, Resolution); + return; + } + + if (InIgnoreAlphaChannel == IgnoreAlphaChannel && Resolution == ColorArrayResolution) + { + UpdateLutObject(LutHandle, Data); + return; + } + + DestroyLutObject(LutHandle); + LutHandle = CreateLutObject(Data, Resolution); + + IgnoreAlphaChannel = InIgnoreAlphaChannel; + ColorArrayResolution = Resolution; +} + +uint64 UOculusXRPassthroughColorLut::GetHandle() +{ + if (LutHandle == 0 && ColorLutType == EColorLutType::TextureLUT && IsTextureDataValid(StoredTextureData)) + { + LutHandle = CreateLutObject(StoredTextureData.Data, StoredTextureData.Resolution); + } + + return LutHandle; +} + +void UOculusXRPassthroughColorLut::PreSave(FObjectPreSaveContext ObjectSaveContext) +{ + Super::PreSave(ObjectSaveContext); +#if WITH_EDITOR + StoredTextureData = TextureToColorData(LutTexture); +#endif +} + +FLutTextureData UOculusXRPassthroughColorLut::TextureToColorData(class UTexture2D* InLutTexture) const +{ + + if (ColorLutType != EColorLutType::TextureLUT) + { + return FLutTextureData(); + } + + if (InLutTexture == nullptr) + { + UE_LOG(LogOculusPassthrough, Warning, TEXT("Ignoring provided LUT texture. Provided texture is NULL.")); + return FLutTextureData(); + } + + if (InLutTexture->LODGroup != TextureGroup::TEXTUREGROUP_ColorLookupTable) + { + UE_LOG(LogOculusPassthrough, Warning, TEXT("Ignoring provided LUT texture. Provided texture is not LUT texture.")); + return FLutTextureData(); + } + + if (InLutTexture->GetPlatformData()->Mips.Num() <= 0) + { + if (IsTextureDataValid(StoredTextureData)) + { + // We do not need to save it again. Use previously saved data. + return StoredTextureData; + } + return FLutTextureData(); + } + + const uint32 TextureWidth = InLutTexture->GetImportedSize().X; + const uint32 TextureHeight = InLutTexture->GetImportedSize().Y; + + uint32 ColorMapSize; + uint32 SlicesPerRow; + + if (TextureWidth == TextureHeight) + { + float EdgeLength = FPlatformMath::Pow(TextureWidth, 2.0f / 3.0f); + ColorMapSize = FPlatformMath::RoundToInt(EdgeLength); + if (FPlatformMath::Abs(EdgeLength - ColorMapSize) > ZERO_ANIMWEIGHT_THRESH) + { + UE_LOG(LogOculusPassthrough, Warning, TEXT("LUT width and height are equal but don't correspond to an 'exploded cube'")); + return FLutTextureData(); + } + + SlicesPerRow = FPlatformMath::Sqrt(ColorMapSize * 1.0f); + } + else + { + if (TextureWidth != TextureHeight * TextureHeight) + { + UE_LOG(LogOculusPassthrough, Warning, TEXT("For rectangular LUTs, the width is expected to be equal to edgeLength^2")); + return FLutTextureData(); + } + ColorMapSize = TextureHeight; + SlicesPerRow = TextureHeight; + } + + FTexture2DMipMap& MipMap = InLutTexture->GetPlatformData()->Mips[0]; + FByteBulkData* BulkData = &MipMap.BulkData; + const FColor* FormatedImageData = reinterpret_cast(BulkData->Lock(LOCK_READ_ONLY)); + + TArray Colors; + Colors.SetNum(ColorMapSize * ColorMapSize * ColorMapSize); + + for (uint32 bi = 0; bi < ColorMapSize; bi++) + { + uint32 bi_row = bi % SlicesPerRow; + uint32 bi_col = bi / SlicesPerRow; + for (uint32 gi = 0; gi < ColorMapSize; gi++) + { + for (uint32 ri = 0; ri < ColorMapSize; ri++) + { + uint32 sX = ri + bi_row * ColorMapSize; + uint32 sY = gi + bi_col * ColorMapSize; + Colors[bi * ColorMapSize * ColorMapSize + gi * ColorMapSize + ri] = FormatedImageData[sX + sY * TextureWidth]; + } + } + } + BulkData->Unlock(); + return FLutTextureData(ColorArrayToColorData(Colors, IgnoreAlphaChannel), ColorMapSize); +} + +uint64 UOculusXRPassthroughColorLut::CreateLutObject(const TArray& InData, uint32 Resolution) const +{ + ovrpPassthroughColorLutData OVRPData; + OVRPData.Buffer = InData.GetData(); + OVRPData.BufferSize = InData.Num(); + const EColorLutChannels Channels = IgnoreAlphaChannel ? EColorLutChannels::ColorLutChannels_RGB : EColorLutChannels::ColorLutChannels_RGBA; + ovrpPassthroughColorLut Handle; + if (OVRP_FAILURE(FOculusXRHMDModule::GetPluginWrapper().CreatePassthroughColorLut( + ToOVRPColorLutChannels(Channels), + Resolution, + OVRPData, + &Handle))) + { + UE_LOG(LogTemp, Error, TEXT("Failed creating passthrough color lut.")); + return 0; + } + return Handle; +} + +void UOculusXRPassthroughColorLut::UpdateLutObject(uint64 Handle, const TArray& InData) const +{ + if (Handle == 0) + { + return; + } + + ovrpPassthroughColorLutData OVRPData; + OVRPData.Buffer = InData.GetData(); + OVRPData.BufferSize = InData.Num(); + + if (OVRP_FAILURE(FOculusXRHMDModule::GetPluginWrapper().UpdatePassthroughColorLut( + Handle, + OVRPData))) + { + UE_LOG(LogTemp, Error, TEXT("Failed updating passthrough color lut data.")); + return; + } +} + +void UOculusXRPassthroughColorLut::DestroyLutObject(uint64 Handle) const +{ + if (Handle == 0) + { + return; + } + if (OVRP_FAILURE(FOculusXRHMDModule::GetPluginWrapper().DestroyPassthroughColorLut(Handle))) + { + UE_LOG(LogTemp, Error, TEXT("Failed to destroy passthrough color lut.")); + } +} + +void UOculusXRPassthroughColorLut::BeginDestroy() +{ + Super::BeginDestroy(); + DestroyLutObject(LutHandle); +} + +int UOculusXRPassthroughColorLut::GetMaxResolution() +{ + if (MaxResolution > -1) + { + return MaxResolution; + } + + ovrpInsightPassthroughCapabilities PassthroughCapabilites; + PassthroughCapabilites.Fields = + static_cast( + ovrpInsightPassthroughCapabilityFields::ovrpInsightPassthroughCapabilityFields_Flags | ovrpInsightPassthroughCapabilityFields::ovrpInsightPassthroughCapabilityFields_MaxColorLutResolution); + + if (OVRP_FAILURE(FOculusXRHMDModule::GetPluginWrapper().GetPassthroughCapabilities(&PassthroughCapabilites))) + { + UE_LOG(LogTemp, Error, TEXT("Failed to fetch passthrough capabilities.")); + // Default MAX resoulution is 64. + return 64; + } + MaxResolution = PassthroughCapabilites.MaxColorLutResolution; + return MaxResolution; +} diff --git a/Plugins/MetaXR/Source/OculusXRPassthrough/Private/OculusXRPassthroughLayerComponent.cpp b/Plugins/MetaXR/Source/OculusXRPassthrough/Private/OculusXRPassthroughLayerComponent.cpp new file mode 100644 index 0000000..342ccfa --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRPassthrough/Private/OculusXRPassthroughLayerComponent.cpp @@ -0,0 +1,647 @@ +// @lint-ignore-every LICENSELINT +// Copyright 1998-2020 Epic Games, Inc. All Rights Reserved. + +#include "OculusXRPassthroughLayerComponent.h" + +#include "Engine/StaticMesh.h" +#include "Components/StaticMeshComponent.h" +#include "ProceduralMeshComponent.h" +#include "OculusXRHMD.h" +#include "OculusXRPassthroughLayerShapes.h" +#include "Curves/CurveLinearColor.h" +#include "StaticMeshResources.h" + +DEFINE_LOG_CATEGORY(LogOculusPassthrough); + +void UOculusXRStereoLayerShapeReconstructed::ApplyShape(IStereoLayers::FLayerDesc& LayerDesc) +{ + const FEdgeStyleParameters EdgeStyleParameters( + bEnableEdgeColor, + bEnableColorMap, + TextureOpacityFactor, + Brightness, + Contrast, + Posterize, + Saturation, + EdgeColor, + ColorScale, + ColorOffset, + ColorMapType, + GetColorArray(bUseColorMapCurve, ColorMapCurve), + GenerateColorLutDescription(LutWeight, ColorLUTSource, ColorLUTTarget)); + LayerDesc.SetShape(EdgeStyleParameters, LayerOrder); +} + +void UOculusXRStereoLayerShapeUserDefined::ApplyShape(IStereoLayers::FLayerDesc& LayerDesc) +{ + //If there is no user geometry, set the layer hidden to avoid unnecessary cost + if (UserGeometryList.IsEmpty()) + LayerDesc.Flags |= IStereoLayers::LAYER_FLAG_HIDDEN; + + const FEdgeStyleParameters EdgeStyleParameters( + bEnableEdgeColor, + bEnableColorMap, + TextureOpacityFactor, + Brightness, + Contrast, + Posterize, + Saturation, + EdgeColor, + ColorScale, + ColorOffset, + ColorMapType, + GetColorArray(bUseColorMapCurve, ColorMapCurve), + GenerateColorLutDescription(LutWeight, ColorLUTSource, ColorLUTTarget)); + LayerDesc.SetShape(UserGeometryList, EdgeStyleParameters, LayerOrder); +} + +void UOculusXRStereoLayerShapeUserDefined::AddGeometry(const FString& MeshName, OculusXRHMD::FOculusPassthroughMeshRef PassthroughMesh, FTransform Transform, bool bUpdateTransform) +{ + FUserDefinedGeometryDesc UserDefinedGeometryDesc( + MeshName, + PassthroughMesh, + Transform, + bUpdateTransform); + + UserGeometryList.Add(UserDefinedGeometryDesc); +} + +void UOculusXRStereoLayerShapeUserDefined::RemoveGeometry(const FString& MeshName) +{ + UserGeometryList.RemoveAll([MeshName](const FUserDefinedGeometryDesc& Desc) { + return Desc.MeshName == MeshName; + }); +} + +UOculusXRPassthroughLayerComponent::UOculusXRPassthroughLayerComponent(const FObjectInitializer& ObjectInitializer) + : Super(ObjectInitializer) +{ +} + +void UOculusXRPassthroughLayerComponent::DestroyComponent(bool bPromoteChildren) +{ + Super::DestroyComponent(bPromoteChildren); +#ifdef WITH_OCULUS_BRANCH + IStereoLayers* StereoLayers; + if (LayerId && GEngine->StereoRenderingDevice.IsValid() && (StereoLayers = GEngine->StereoRenderingDevice->GetStereoLayers()) != nullptr) + { + StereoLayers->DestroyLayer(LayerId); + LayerId = 0; + } +#endif +} + +void UOculusXRPassthroughLayerComponent::TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) +{ +#ifndef WITH_OCULUS_BRANCH + if (Texture == nullptr && !LayerRequiresTexture()) + { + // UStereoLayerComponent hides components without textures + Texture = GEngine->DefaultTexture; + } +#endif + UpdatePassthroughObjects(); + Super::TickComponent(DeltaTime, TickType, ThisTickFunction); +} + +void UOculusXRPassthroughLayerComponent::UpdatePassthroughObjects() +{ + UOculusXRStereoLayerShapeUserDefined* UserShape = Cast(Shape); + if (UserShape) + { + bool bDirty = false; + for (FUserDefinedGeometryDesc& Entry : UserShape->GetUserGeometryList()) + { + if (Entry.bUpdateTransform) + { + const UMeshComponent** MeshComponent = PassthroughComponentMap.Find(Entry.MeshName); + if (MeshComponent) + { + Entry.Transform = (*MeshComponent)->GetComponentTransform(); + bDirty = true; + } + } + } + if (bDirty) + { + MarkStereoLayerDirty(); + } + } +} + +OculusXRHMD::FOculusPassthroughMeshRef UOculusXRPassthroughLayerComponent::CreatePassthroughMesh(UProceduralMeshComponent* ProceduralMeshComponent) +{ + if (!ProceduralMeshComponent) + { + UE_LOG(LogOculusPassthrough, Error, TEXT("Passthrough Procedural Mesh is nullptr")); + return nullptr; + } + + TArray Triangles; + TArray Vertices; + int32 NumSections = ProceduralMeshComponent->GetNumSections(); + int VertexOffset = 0; //Each section start with vertex IDs of 0, in order to create a single mesh from all sections we need to offset those IDs by the amount of previous vertices + for (int32 s = 0; s < NumSections; ++s) + { + FProcMeshSection* ProcMeshSection = ProceduralMeshComponent->GetProcMeshSection(s); + for (int32 i = 0; i < ProcMeshSection->ProcIndexBuffer.Num(); ++i) + { + Triangles.Add(VertexOffset + ProcMeshSection->ProcIndexBuffer[i]); + } + + for (int32 i = 0; i < ProcMeshSection->ProcVertexBuffer.Num(); ++i) + { + Vertices.Add(ProcMeshSection->ProcVertexBuffer[i].Position); + } + + VertexOffset += ProcMeshSection->ProcVertexBuffer.Num(); + } + + OculusXRHMD::FOculusPassthroughMeshRef PassthroughMesh = new OculusXRHMD::FOculusPassthroughMesh(Vertices, Triangles); + return PassthroughMesh; +} + +OculusXRHMD::FOculusPassthroughMeshRef UOculusXRPassthroughLayerComponent::CreatePassthroughMesh(UStaticMeshComponent* StaticMeshComponent) +{ + if (!StaticMeshComponent) + { + UE_LOG(LogOculusPassthrough, Error, TEXT("Passthrough Static Mesh is nullptr")); + return nullptr; + } + + UStaticMesh* Mesh = StaticMeshComponent->GetStaticMesh(); + + if (!Mesh || !Mesh->GetRenderData()) + { + UE_LOG(LogOculusPassthrough, Error, TEXT("Passthrough Static Mesh has no Renderdata")); + return nullptr; + } + + if (Mesh->GetNumLODs() == 0) + { + UE_LOG(LogOculusPassthrough, Error, TEXT("Passthrough Static Mesh has no LODs")); + return nullptr; + } + + if (!Mesh->bAllowCPUAccess) + { + UE_LOG(LogOculusPassthrough, Error, TEXT("Passthrough Static Mesh Requires CPU Access")); + return nullptr; + } + + const int32 LODIndex = 0; + FStaticMeshLODResources& LOD = Mesh->GetRenderData()->LODResources[LODIndex]; + + TArray Triangles; + const int32 NumIndices = LOD.IndexBuffer.GetNumIndices(); + for (int32 i = 0; i < NumIndices; ++i) + { + Triangles.Add(LOD.IndexBuffer.GetIndex(i)); + } + + TArray Vertices; + const int32 NumVertices = LOD.VertexBuffers.PositionVertexBuffer.GetNumVertices(); + for (int32 i = 0; i < NumVertices; ++i) + { + Vertices.Add((FVector)LOD.VertexBuffers.PositionVertexBuffer.VertexPosition(i)); + } + + OculusXRHMD::FOculusPassthroughMeshRef PassthroughMesh = new OculusXRHMD::FOculusPassthroughMesh(Vertices, Triangles); + return PassthroughMesh; +} + +void UOculusXRPassthroughLayerComponent::AddSurfaceGeometry(AStaticMeshActor* StaticMeshActor, bool updateTransform) +{ + if (StaticMeshActor) + { + UStaticMeshComponent* StaticMeshComponent = StaticMeshActor->GetStaticMeshComponent(); + if (StaticMeshComponent) + AddStaticSurfaceGeometry(StaticMeshComponent, updateTransform); + } +} + +void UOculusXRPassthroughLayerComponent::AddStaticSurfaceGeometry(UStaticMeshComponent* StaticMeshComponent, bool updateTransform) +{ + if (!StaticMeshComponent) + return; + + UOculusXRStereoLayerShapeUserDefined* UserShape = Cast(Shape); + if (!UserShape) + return; + + OculusXRHMD::FOculusPassthroughMeshRef PassthroughMesh = CreatePassthroughMesh(StaticMeshComponent); + if (!PassthroughMesh) + return; + + const FString MeshName = StaticMeshComponent->GetFullName(); + const FTransform Transform = StaticMeshComponent->GetComponentTransform(); + UserShape->AddGeometry(MeshName, PassthroughMesh, Transform, updateTransform); + + PassthroughComponentMap.Add(MeshName, StaticMeshComponent); + MarkStereoLayerDirty(); +} + +void UOculusXRPassthroughLayerComponent::AddProceduralSurfaceGeometry(UProceduralMeshComponent* ProceduralMeshComponent, bool updateTransform) +{ + if (!ProceduralMeshComponent) + return; + + UOculusXRStereoLayerShapeUserDefined* UserShape = Cast(Shape); + if (!UserShape) + return; + + OculusXRHMD::FOculusPassthroughMeshRef PassthroughMesh = CreatePassthroughMesh(ProceduralMeshComponent); + if (!PassthroughMesh) + return; + + const FString MeshName = ProceduralMeshComponent->GetFullName(); + const FTransform Transform = ProceduralMeshComponent->GetComponentTransform(); + UserShape->AddGeometry(MeshName, PassthroughMesh, Transform, updateTransform); + + PassthroughComponentMap.Add(MeshName, ProceduralMeshComponent); + MarkStereoLayerDirty(); +} + +void UOculusXRPassthroughLayerComponent::RemoveSurfaceGeometry(AStaticMeshActor* StaticMeshActor) +{ + if (StaticMeshActor) + RemoveSurfaceGeometryComponent(StaticMeshActor->GetStaticMeshComponent()); +} + +void UOculusXRPassthroughLayerComponent::RemoveStaticSurfaceGeometry(UStaticMeshComponent* StaticMeshComponent) +{ + RemoveSurfaceGeometryComponent(StaticMeshComponent); +} + +void UOculusXRPassthroughLayerComponent::RemoveProceduralSurfaceGeometry(UProceduralMeshComponent* ProceduralMeshComponent) +{ + RemoveSurfaceGeometryComponent(ProceduralMeshComponent); +} + +void UOculusXRPassthroughLayerComponent::RemoveSurfaceGeometryComponent(UMeshComponent* MeshComponent) +{ + if (!MeshComponent) + return; + + UOculusXRStereoLayerShapeUserDefined* UserShape = Cast(Shape); + if (!UserShape) + return; + + const FString MeshName = MeshComponent->GetFullName(); + + UserShape->RemoveGeometry(MeshName); + PassthroughComponentMap.Remove(MeshName); + + MarkStereoLayerDirty(); +} + +bool UOculusXRPassthroughLayerComponent::IsSurfaceGeometry(AStaticMeshActor* StaticMeshActor) const +{ + return StaticMeshActor ? IsSurfaceGeometryComponent(StaticMeshActor->GetStaticMeshComponent()) : false; +} + +bool UOculusXRPassthroughLayerComponent::IsSurfaceGeometryComponent(const UMeshComponent* MeshComponent) const +{ + return MeshComponent ? PassthroughComponentMap.Contains(MeshComponent->GetFullName()) : false; +} + +void UOculusXRPassthroughLayerComponent::MarkPassthroughStyleForUpdate() +{ + bPassthroughStyleNeedsUpdate = true; +} + +#if WITH_EDITOR +bool UOculusXRPassthroughLayerComponent::CanEditChange(const FProperty* InProperty) const +{ + if (!Super::CanEditChange(InProperty)) + return false; + + if (!(Shape && Shape.IsA(UOculusXRPassthroughLayerBase::StaticClass()))) + { + return true; + } + + const FName PropertyName = InProperty->GetFName(); + if (PropertyName == GET_MEMBER_NAME_CHECKED(UOculusXRPassthroughLayerComponent, Texture) + || PropertyName == GET_MEMBER_NAME_CHECKED(UOculusXRPassthroughLayerComponent, bQuadPreserveTextureRatio) + || PropertyName == GET_MEMBER_NAME_CHECKED(UOculusXRPassthroughLayerComponent, QuadSize) + || PropertyName == GET_MEMBER_NAME_CHECKED(UOculusXRPassthroughLayerComponent, UVRect) + || PropertyName == GET_MEMBER_NAME_CHECKED(UOculusXRPassthroughLayerComponent, StereoLayerType)) + { + return false; + } + + return true; +} +#endif // WITH_EDITOR + +bool UOculusXRPassthroughLayerComponent::LayerRequiresTexture() +{ + const bool bIsPassthroughShape = Shape && (Shape->IsA() || Shape->IsA()); + return !bIsPassthroughShape; +} + +void UOculusXRPassthroughLayerBase::SetTextureOpacity(float InOpacity) +{ + if (TextureOpacityFactor == InOpacity) + { + return; + } + + TextureOpacityFactor = InOpacity; + MarkStereoLayerDirty(); +} + +void UOculusXRPassthroughLayerBase::EnableEdgeColor(bool bInEnableEdgeColor) +{ + if (bEnableEdgeColor == bInEnableEdgeColor) + { + return; + } + bEnableEdgeColor = bInEnableEdgeColor; + MarkStereoLayerDirty(); +} + +void UOculusXRPassthroughLayerBase::EnableColorMap(bool bInEnableColorMap) +{ + if (bEnableColorMap == bInEnableColorMap) + { + return; + } + bEnableColorMap = bInEnableColorMap; + MarkStereoLayerDirty(); +} + +void UOculusXRPassthroughLayerBase::SetEdgeRenderingColor(FLinearColor InEdgeColor) +{ + if (EdgeColor == InEdgeColor) + { + return; + } + EdgeColor = InEdgeColor; + MarkStereoLayerDirty(); +} + +void UOculusXRPassthroughLayerBase::EnableColorMapCurve(bool bInEnableColorMapCurve) +{ + if (bUseColorMapCurve == bInEnableColorMapCurve) + { + return; + } + bUseColorMapCurve = bInEnableColorMapCurve; + ColorArray = GenerateColorArray(bUseColorMapCurve, ColorMapCurve); + MarkStereoLayerDirty(); +} + +void UOculusXRPassthroughLayerBase::SetColorMapCurve(UCurveLinearColor* InColorMapCurve) +{ + if (ColorMapCurve == InColorMapCurve) + { + return; + } + ColorMapCurve = InColorMapCurve; + ColorArray = GenerateColorArray(bUseColorMapCurve, ColorMapCurve); + MarkStereoLayerDirty(); +} + +void UOculusXRPassthroughLayerBase::SetColorMapType(EOculusXRColorMapType InColorMapType) +{ + if (ColorMapType == InColorMapType) + { + return; + } + ColorMapType = InColorMapType; + ColorArray = GenerateColorArray(bUseColorMapCurve, ColorMapCurve); + MarkStereoLayerDirty(); +} + +void UOculusXRPassthroughLayerBase::SetColorArray(const TArray& InColorArray) +{ + if (InColorArray.Num() == 0) + { + return; + } + + if (ColorMapType != ColorMapType_GrayscaleToColor) + { + UE_LOG(LogOculusPassthrough, Warning, TEXT("SetColorArray is ignored for color map types other than Grayscale to Color.")); + return; + } + + if (bUseColorMapCurve) + { + UE_LOG(LogOculusPassthrough, Warning, TEXT("UseColorMapCurve is enabled on the layer. Automatic disable and use the Array for color lookup")); + } + bUseColorMapCurve = false; + + ColorArray = InColorArray; + MarkStereoLayerDirty(); +} + +void UOculusXRPassthroughLayerBase::ClearColorMap() +{ + ColorArray.Empty(); +} + +void UOculusXRPassthroughLayerBase::SetColorMapControls(float InContrast, float InBrightness, float InPosterize) +{ + if (ColorMapType != ColorMapType_Grayscale && ColorMapType != ColorMapType_GrayscaleToColor) + { + UE_LOG(LogOculusPassthrough, Warning, TEXT("SetColorMapControls is ignored for color map types other than Grayscale and Grayscale to color.")); + return; + } + Contrast = FMath::Clamp(InContrast, -1.0f, 1.0f); + Brightness = FMath::Clamp(InBrightness, -1.0f, 1.0f); + Posterize = FMath::Clamp(InPosterize, 0.0f, 1.0f); + + MarkStereoLayerDirty(); +} + +void UOculusXRPassthroughLayerBase::SetBrightnessContrastSaturation(float InContrast, float InBrightness, float InSaturation) +{ + if (ColorMapType != ColorMapType_ColorAdjustment) + { + UE_LOG(LogOculusPassthrough, Warning, TEXT("SetBrightnessContrastSaturation is ignored for color map types other than Color Adjustment.")); + return; + } + Contrast = FMath::Clamp(InContrast, -1.0f, 1.0f); + Brightness = FMath::Clamp(InBrightness, -1.0f, 1.0f); + Saturation = FMath::Clamp(InSaturation, -1.0f, 1.0f); + + MarkStereoLayerDirty(); +} + +void UOculusXRPassthroughLayerBase::SetColorScaleAndOffset(FLinearColor InColorScale, FLinearColor InColorOffset) +{ + if (ColorScale == InColorScale && ColorOffset == InColorOffset) + { + return; + } + ColorScale = InColorScale; + ColorOffset = InColorOffset; + MarkStereoLayerDirty(); +} + +void UOculusXRPassthroughLayerBase::SetLayerPlacement(EOculusXRPassthroughLayerOrder InLayerOrder) +{ + if (LayerOrder == InLayerOrder) + { + UE_LOG(LogOculusPassthrough, Warning, TEXT("Same layer order as before, no change needed")); + return; + } + + LayerOrder = InLayerOrder; + this->MarkStereoLayerDirty(); +} + +void UOculusXRPassthroughLayerBase::SetColorLUTSource(class UOculusXRPassthroughColorLut* InColorLUTSource) +{ + if (ColorMapType != ColorMapType_ColorLut && ColorMapType != ColorMapType_ColorLut_Interpolated) + { + UE_LOG(LogOculusPassthrough, Warning, TEXT("SetColorLUT is ignored for color map types other than Color LUT.")); + return; + } + + if (InColorLUTSource == ColorLUTSource) + { + UE_LOG(LogOculusPassthrough, Warning, TEXT("Same color LUT source as before, no change needed")); + return; + } + + ColorLUTSource = InColorLUTSource; + MarkStereoLayerDirty(); +} + +void UOculusXRPassthroughLayerBase::SetColorLUTTarget(class UOculusXRPassthroughColorLut* InColorLUTTarget) +{ + if (ColorMapType != ColorMapType_ColorLut_Interpolated) + { + UE_LOG(LogOculusPassthrough, Warning, TEXT("SetColorLUTTarget is ignored for color map types other than Interpolated Color LUT.")); + return; + } + + if (InColorLUTTarget == ColorLUTTarget) + { + UE_LOG(LogOculusPassthrough, Warning, TEXT("Same color LUT source as before, no change needed")); + return; + } + + ColorLUTTarget = InColorLUTTarget; + MarkStereoLayerDirty(); +} + +void UOculusXRPassthroughLayerBase::SetColorLUTWeight(float InWeight) +{ + if (ColorMapType != ColorMapType_ColorLut && ColorMapType != ColorMapType_ColorLut_Interpolated) + { + UE_LOG(LogOculusPassthrough, Warning, TEXT("SetWeight is ignored for color map types other than Color LUT.")); + return; + } + + if (LutWeight == InWeight) + { + UE_LOG(LogOculusPassthrough, Warning, TEXT("Same lut weight as before, no change needed")); + return; + } + + LutWeight = InWeight; + MarkStereoLayerDirty(); +} + +void UOculusXRPassthroughLayerBase::RemoveColorLut() +{ + ColorLUTSource = nullptr; + ColorLUTTarget = nullptr; + MarkStereoLayerDirty(); +} + +TArray UOculusXRPassthroughLayerBase::GenerateColorArrayFromColorCurve(const UCurveLinearColor* InColorMapCurve) const +{ + if (InColorMapCurve == nullptr) + { + return TArray(); + } + + TArray NewColorArray; + constexpr uint32 TotalEntries = 256; + NewColorArray.Empty(); + NewColorArray.SetNum(TotalEntries); + + for (int32 Index = 0; Index < TotalEntries; ++Index) + { + const float Alpha = ((float)Index / TotalEntries); + NewColorArray[Index] = InColorMapCurve->GetLinearColorValue(Alpha); + } + return NewColorArray; +} + +TArray UOculusXRPassthroughLayerBase::GetOrGenerateNeutralColorArray() +{ + if (NeutralColorArray.Num() == 0) + { + const uint32 TotalEntries = 256; + NeutralColorArray.SetNum(TotalEntries); + + for (int32 Index = 0; Index < TotalEntries; ++Index) + { + NeutralColorArray[Index] = FLinearColor((float)Index / TotalEntries, (float)Index / TotalEntries, (float)Index / TotalEntries); + } + } + + return NeutralColorArray; +} + +TArray UOculusXRPassthroughLayerBase::GenerateColorArray(bool bInUseColorMapCurve, const UCurveLinearColor* InColorMapCurve) +{ + TArray NewColorArray; + if (bInUseColorMapCurve) + { + NewColorArray = GenerateColorArrayFromColorCurve(InColorMapCurve); + } + + // Check for existing Array, otherwise generate a neutral one + if (NewColorArray.Num() == 0) + { + NewColorArray = GetOrGenerateNeutralColorArray(); + } + + return NewColorArray; +} + +TArray UOculusXRPassthroughLayerBase::GetColorArray(bool bInUseColorMapCurve, const UCurveLinearColor* InColorMapCurve) +{ + if (ColorArray.Num() == 0) + { + if (bInUseColorMapCurve) + { + return GenerateColorArray(bInUseColorMapCurve, InColorMapCurve); + } + return GetOrGenerateNeutralColorArray(); + } + + return ColorArray; +} + +FColorLutDesc UOculusXRPassthroughLayerBase::GenerateColorLutDescription(float InLutWeight, UOculusXRPassthroughColorLut* InLutSource, UOculusXRPassthroughColorLut* InLutTarget) +{ + TArray ColorLuts; + if (InLutSource != nullptr && InLutSource->ColorLutType != EColorLutType::None) + { + uint64 ColorLutHandle = InLutSource->GetHandle(); + if (ColorLutHandle != 0) + { + ColorLuts.Add(ColorLutHandle); + } + } + + if (ColorMapType == EOculusXRColorMapType::ColorMapType_ColorLut_Interpolated && ColorLuts.Num() > 0 && InLutSource->ColorLutType != EColorLutType::None) + { + uint64 ColorLutHandle = InLutTarget->GetHandle(); + if (ColorLutHandle != 0) + { + ColorLuts.Add(ColorLutHandle); + } + } + + return FColorLutDesc(ColorLuts, InLutWeight); +} diff --git a/Plugins/MetaXR/Source/OculusXRPassthrough/Private/OculusXRPassthroughModule.cpp b/Plugins/MetaXR/Source/OculusXRPassthrough/Private/OculusXRPassthroughModule.cpp new file mode 100644 index 0000000..50027f0 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRPassthrough/Private/OculusXRPassthroughModule.cpp @@ -0,0 +1,25 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#include "OculusXRPassthroughModule.h" + +#define LOCTEXT_NAMESPACE "OculusXRPassthrough" + +//------------------------------------------------------------------------------------------------- +// FOculusXRPassthroughModule +//------------------------------------------------------------------------------------------------- + +FOculusXRPassthroughModule::FOculusXRPassthroughModule() +{ +} + +void FOculusXRPassthroughModule::StartupModule() +{ +} + +void FOculusXRPassthroughModule::ShutdownModule() +{ +} + +IMPLEMENT_MODULE(FOculusXRPassthroughModule, OculusXRPassthrough) + +#undef LOCTEXT_NAMESPACE diff --git a/Plugins/MetaXR/Source/OculusXRPassthrough/Private/OculusXRPassthroughModule.h b/Plugins/MetaXR/Source/OculusXRPassthrough/Private/OculusXRPassthroughModule.h new file mode 100644 index 0000000..4c6740c --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRPassthrough/Private/OculusXRPassthroughModule.h @@ -0,0 +1,26 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#pragma once +#include "IOculusXRPassthroughModule.h" + +#define LOCTEXT_NAMESPACE "OculusXRPassthrough" + +//------------------------------------------------------------------------------------------------- +// FOculusXRPassthroughModule +//------------------------------------------------------------------------------------------------- + +class FOculusXRPassthroughModule : public IOculusXRPassthroughModule +{ +public: + FOculusXRPassthroughModule(); + + static inline FOculusXRPassthroughModule& Get() + { + return FModuleManager::LoadModuleChecked("OculusXRPassthrough"); + } + + virtual void StartupModule() override; + virtual void ShutdownModule() override; +}; + +#undef LOCTEXT_NAMESPACE diff --git a/Plugins/MetaXR/Source/OculusXRPassthrough/Public/IOculusXRPassthroughModule.h b/Plugins/MetaXR/Source/OculusXRPassthrough/Public/IOculusXRPassthroughModule.h new file mode 100644 index 0000000..39d90ae --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRPassthrough/Public/IOculusXRPassthroughModule.h @@ -0,0 +1,35 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#pragma once +#include "Modules/ModuleInterface.h" +#include "Modules/ModuleManager.h" + +/** + * The public interface to this module. In most cases, this interface is only public to sibling modules + * within this plugin. + */ +class IOculusXRPassthroughModule : public IModuleInterface +{ + +public: + /** + * Singleton-like access to this module's interface. This is just for convenience! + * Beware of calling this during the shutdown phase, though. Your module might have been unloaded already. + * + * @return Returns singleton instance, loading the module on demand if needed + */ + static inline IOculusXRPassthroughModule& Get() + { + return FModuleManager::GetModuleChecked("OculusXRPassthrough"); + } + + /** + * Checks to see if this module is loaded and ready. It is only valid to call Get() if IsAvailable() returns true. + * + * @return True if the module is loaded and ready to use + */ + static inline bool IsAvailable() + { + return FModuleManager::Get().IsModuleLoaded("OculusXRPassthrough"); + } +}; diff --git a/Plugins/MetaXR/Source/OculusXRPassthrough/Public/OculusXRPassthroughColorLut.h b/Plugins/MetaXR/Source/OculusXRPassthrough/Public/OculusXRPassthroughColorLut.h new file mode 100644 index 0000000..1669133 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRPassthrough/Public/OculusXRPassthroughColorLut.h @@ -0,0 +1,80 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#pragma once + +#include "CoreMinimal.h" +#include "UObject/ObjectMacros.h" +#include "Engine/Texture2D.h" + +#include "OculusXRPassthroughColorLut.generated.h" + +enum EColorLutChannels +{ + ColorLutChannels_RGB, + ColorLutChannels_RGBA +}; + +USTRUCT() +struct FLutTextureData +{ + GENERATED_BODY() +public: + UPROPERTY() + TArray Data; + + UPROPERTY() + uint32 Resolution; + + FLutTextureData() + : Data{}, Resolution(0) {} + + FLutTextureData(const TArray& InData, uint32 InResolution) + : Data(InData), Resolution(InResolution) {} +}; + +UENUM(BlueprintType) +enum class EColorLutType : uint8 +{ + None = 0 UMETA(DisplayName = "None"), + TextureLUT = 1 UMETA(DisplayName = "Texture"), + Array = 2 UMETA(Hidden) +}; + +UCLASS(BlueprintType, CollapseCategories, meta = (DisplayName = "Passthrough Color LUT")) +class OCULUSXRPASSTHROUGH_API UOculusXRPassthroughColorLut : public UObject +{ + GENERATED_BODY() +public: + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Passthrough Color LUT") + EColorLutType ColorLutType = EColorLutType::None; + +#if WITH_EDITORONLY_DATA + /** Color LUT texture.*/ + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Passthrough Color LUT", meta = (EditCondition = "ColorLutType == EColorLutType::TextureLUT", EditConditionHides)) + UTexture2D* LutTexture; +#endif + /** If alpha channel should be ignored.*/ + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Passthrough Color LUT", meta = (EditCondition = "ColorLutType == EColorLutType::TextureLUT", EditConditionHides)) + bool IgnoreAlphaChannel = false; + + /** Generate color LUT from array. Array should have format of exploded cube. Its size should be power of 2. */ + UFUNCTION(BlueprintCallable, Category = "Passthrough Color LUT") + void SetLutFromArray(const TArray& InColorArray, bool InIgnoreAlphaChannel); + + uint64 GetHandle(); + virtual void PreSave(FObjectPreSaveContext ObjectSaveContext) override; + + void BeginDestroy() override; + +private: + UPROPERTY() + FLutTextureData StoredTextureData; + uint64 LutHandle = 0; + int32 ColorArrayResolution = 0; + int MaxResolution = -1; + FLutTextureData TextureToColorData(class UTexture2D* InLutTexture) const; + uint64 CreateLutObject(const TArray& InData, uint32 Resolution) const; + void UpdateLutObject(uint64 Handle, const TArray& InData) const; + void DestroyLutObject(uint64 Handle) const; + int GetMaxResolution(); +}; diff --git a/Plugins/MetaXR/Source/OculusXRPassthrough/Public/OculusXRPassthroughLayerComponent.h b/Plugins/MetaXR/Source/OculusXRPassthrough/Public/OculusXRPassthroughLayerComponent.h new file mode 100644 index 0000000..f6f20cd --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRPassthrough/Public/OculusXRPassthroughLayerComponent.h @@ -0,0 +1,259 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. +// OculusEventComponent.h: Component to handle receiving events from Oculus HMDs + +#pragma once + +#include "CoreMinimal.h" +#include "Engine/StaticMeshActor.h" +#include "UObject/ObjectMacros.h" +#include "Components/StereoLayerComponent.h" +#include "OculusXRPassthroughLayerShapes.h" +#include "OculusXRPassthroughColorLut.h" +#include "OculusXRHMDRuntimeSettings.h" +#include "OculusXRPassthroughLayerComponent.generated.h" + +DECLARE_LOG_CATEGORY_EXTERN(LogOculusPassthrough, Log, All); + +UCLASS(Abstract, meta = (DisplayName = "Passthrough Layer Base")) +class OCULUSXRPASSTHROUGH_API UOculusXRPassthroughLayerBase : public UStereoLayerShape +{ + GENERATED_BODY() +public: + /** Ordering of passthrough layer in relation to scene rendering */ + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Passthrough Properties", DisplayName = "Layer Placement") + TEnumAsByte LayerOrder; + + /** Opacity of the (main) passthrough texture. */ + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Passthrough Properties", meta = (UIMin = 0.0, UIMax = 1.0, ClampMin = 0.0, ClampMax = 1.0)) + float TextureOpacityFactor = 1.0f; + + /** Enable edge color */ + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Passthrough Properties", meta = (DisplayName = "Enable Edge Rendering")) + bool bEnableEdgeColor = false; + + /** Color of the passthrough edge rendering effect. */ + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Passthrough Properties") + FLinearColor EdgeColor; + + /** Enable color mapping */ + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Passthrough Properties") + bool bEnableColorMap = false; + + /** Type of colormapping to perform */ + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Passthrough Properties", meta = (EditCondition = "bEnableColorMap", EditConditionHides)) + TEnumAsByte ColorMapType; + + /** Whether to use color map curve or gradient*/ + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Passthrough Properties", meta = (EditCondition = "bEnableColorMap && ColorMapType == 1", EditConditionHides)) + bool bUseColorMapCurve = false; + + /** Passthrough color mapping gradient converts grayscale to color*/ + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Passthrough Properties", meta = (EditCondition = "bEnableColorMap && bUseColorMapCurve && ColorMapType == 1", EditConditionHides)) + UCurveLinearColor* ColorMapCurve; + + /** Contrast setting for color mapping*/ + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Passthrough Properties", meta = (ClampMin = "-1", ClampMax = "1", EditCondition = "bEnableColorMap && ColorMapType > 0 && ColorMapType < 4", EditConditionHides)) + float Contrast = 0.0f; + + /** Brightness setting for color mapping*/ + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Passthrough Properties", meta = (ClampMin = "-1", ClampMax = "1", EditCondition = "bEnableColorMap && ColorMapType > 0 && ColorMapType < 4", EditConditionHides)) + float Brightness = 0.0f; + + /** Posterize setting for grayscale and grayscale to color mapping*/ + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Passthrough Properties", meta = (ClampMin = "0", ClampMax = "1", EditCondition = "bEnableColorMap && ColorMapType > 0 && ColorMapType < 3", EditConditionHides)) + float Posterize = 0.0f; + + /** Saturation setting for color adjustment mapping*/ + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Passthrough Properties", meta = (ClampMin = "-1", ClampMax = "1", EditCondition = "bEnableColorMap && ColorMapType == 3", EditConditionHides)) + float Saturation = 0.0f; + + /** Color LUT Weight. It is used to combine LUT with Passthrough if one LUT is provided. If two LUTs are provided LutWeight will be used to blend them. */ + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Passthrough Properties", meta = (ClampMin = "0", ClampMax = "1", EditCondition = "bEnableColorMap && ColorMapType > 3", EditConditionHides)) + float LutWeight = 1.0f; + + /** + * Color LUT properties. If only ColorLUTSource is provided it will be blended with passthrough layer using following formula: + * Result = ColorLUTSource * LutWeight + Passthrough * (1 - LutWeight ) + */ + UPROPERTY(EditAnywhere, Category = "Passthrough Properties", meta = (EditCondition = "bEnableColorMap && ColorMapType > 3", EditConditionHides)) + UOculusXRPassthroughColorLut* ColorLUTSource; + + /** + * Color LUT properties. If two LUTs are provided they will be blended using following formula: + * Result = ColorLUTsSource * ( 1 - LutWeight ) + ColorLUTsTarget * LutWeight + */ + UPROPERTY(EditAnywhere, Category = "Passthrough Properties", meta = (EditCondition = "bEnableColorMap && ColorMapType > 4", EditConditionHides)) + UOculusXRPassthroughColorLut* ColorLUTTarget; + + /** Color value that will be multiplied to the current color map*/ + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Passthrough Properties", meta = (EditCondition = "bEnableColorMap", EditConditionHides)) + FLinearColor ColorScale = FLinearColor::White; + + /** Color value that will be added to the current color map*/ + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Passthrough Properties", meta = (EditCondition = "bEnableColorMap", EditConditionHides)) + FLinearColor ColorOffset = FLinearColor::Black; + + UFUNCTION(BlueprintCallable, Category = "Components|Stereo Layer") + void SetTextureOpacity(float InOpacity); + + UFUNCTION(BlueprintCallable, Category = "Components|Stereo Layer") + void EnableEdgeColor(bool bInEnableEdgeColor); + + UFUNCTION(BlueprintCallable, Category = "Components|Stereo Layer") + void EnableColorMap(bool bInEnableColorMap); + + UFUNCTION(BlueprintCallable, Category = "Components|Stereo Layer") + void EnableColorMapCurve(bool bInEnableColorMapCurve); + + UFUNCTION(BlueprintCallable, Category = "Components|Stereo Layer") + void SetEdgeRenderingColor(FLinearColor InEdgeColor); + + /** Set color map controls for grayscale and grayscale to rgb color mapping*/ + UFUNCTION(BlueprintCallable, Category = "Components|Stereo Layer") + void SetColorMapControls(float InContrast = 0, float InBrightness = 0, float InPosterize = 0); + + /** Set color map controls for color adjustment color mapping */ + UFUNCTION(BlueprintCallable, Category = "Components|Stereo Layer") + void SetBrightnessContrastSaturation(float InContrast = 0, float InBrightness = 0, float InSaturation = 0); + + UFUNCTION(BlueprintCallable, Category = "Components|Stereo Layer") + void SetColorScaleAndOffset(FLinearColor InColorScale = FLinearColor::White, FLinearColor InColorOffset = FLinearColor::Black); + + /** Set color curve that will be added to the color map in grayscale modes --> will be converted into a gradient*/ + UFUNCTION(BlueprintCallable, Category = "Components|Stereo Layer") + void SetColorMapCurve(UCurveLinearColor* InColorMapCurve); + + UFUNCTION(BlueprintCallable, Category = "Components|Stereo Layer") + void SetColorMapType(EOculusXRColorMapType InColorMapType); + + /** Set color map array directly instead through a color curve*/ + UFUNCTION(BlueprintCallable, Category = "Components|Stereo Layer") + void SetColorArray(const TArray& InColorArray); + + UFUNCTION(BlueprintCallable, Category = "Components|Stereo Layer") + void ClearColorMap(); + + UFUNCTION(BlueprintCallable, Category = "Passthrough Properties") + void SetLayerPlacement(EOculusXRPassthroughLayerOrder InLayerOrder); + + /** + * Sets Color LUT source. + * If ColorMapType is "Color LUT", then source will be blended with passthrough + * using folowing formula: + * Result = ColorLUTSource * LutWeight + Passthrough * (1 - LutWeight ) + * If ColorMapType is "Interpolated Color LUT", then source will be blended with color LUT target + * using folowing formula: + * Result = ColorLUTSource * ( 1 - LutWeight ) + ColorLUTTarget * LutWeight + */ + UFUNCTION(BlueprintCallable, Category = "Components|Stereo Layer") + void SetColorLUTSource(class UOculusXRPassthroughColorLut* InColorLUTSource); + + /** + * Sets Color LUT target. + * If ColorMapType is "Interpolated Color LUT", then target will be blended with passthrough + * using folowing formula: + * Result = ColorLUTSource * ( 1 - LutWeight ) + ColorLUTTarget * LutWeight + * Note: If ColorLUTSource is not specified, Color LUT will be not be applied to the Passthrough layer. + */ + UFUNCTION(BlueprintCallable, Category = "Components|Stereo Layer") + void SetColorLUTTarget(class UOculusXRPassthroughColorLut* InColorLUTTarget); + + /** Sets LUT weight. */ + UFUNCTION(BlueprintCallable, Category = "Components|Stereo Layer") + void SetColorLUTWeight(float InWeight = 1.0f); + + /** Removes color grading if any is active. */ + UFUNCTION(BlueprintCallable, Category = "Components|Stereo Layer") + void RemoveColorLut(); + +protected: + TArray ColorArray; + TArray NeutralColorArray; + TArray GenerateColorArrayFromColorCurve(const UCurveLinearColor* InColorMapCurve) const; + TArray GetOrGenerateNeutralColorArray(); + TArray GenerateColorArray(bool bInUseColorMapCurve, const UCurveLinearColor* InColorMapCurve); + TArray GetColorArray(bool bInUseColorMapCurve, const UCurveLinearColor* InColorMapCurve); + FColorLutDesc GenerateColorLutDescription(float InLutWeight, UOculusXRPassthroughColorLut* InLutSource, UOculusXRPassthroughColorLut* InLutTarget); +}; + +/* Reconstructed Passthrough Layer*/ +UCLASS(meta = (DisplayName = "Reconstructed Passthrough Layer")) +class OCULUSXRPASSTHROUGH_API UOculusXRStereoLayerShapeReconstructed : public UOculusXRPassthroughLayerBase +{ + GENERATED_BODY() +public: + virtual void ApplyShape(IStereoLayers::FLayerDesc& LayerDesc) override; +}; + +/* User Defined Passthrough Layer*/ +UCLASS(meta = (DisplayName = "User Defined Passthrough Layer")) +class OCULUSXRPASSTHROUGH_API UOculusXRStereoLayerShapeUserDefined : public UOculusXRPassthroughLayerBase +{ + GENERATED_BODY() +public: + void AddGeometry(const FString& MeshName, OculusXRHMD::FOculusPassthroughMeshRef PassthroughMesh, FTransform Transform, bool bUpdateTransform); + void RemoveGeometry(const FString& MeshName); + + virtual void ApplyShape(IStereoLayers::FLayerDesc& LayerDesc) override; + TArray& GetUserGeometryList() { return UserGeometryList; }; + +private: + TArray UserGeometryList; +}; + +class UProceduralMeshComponent; + +UCLASS(Blueprintable, meta = (BlueprintSpawnableComponent), ClassGroup = OculusXRHMD) +class OCULUSXRPASSTHROUGH_API UOculusXRPassthroughLayerComponent : public UStereoLayerComponent +{ + GENERATED_UCLASS_BODY() + +public: + void DestroyComponent(bool bPromoteChildren) override; + + void TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override; + + void UpdatePassthroughObjects(); + + UFUNCTION(BlueprintCallable, Category = "Passthrough", meta = (DeprecatedFunction, DeprecationMessage = "Please use AddStaticSurfaceGeometry instead")) + void AddSurfaceGeometry(AStaticMeshActor* StaticMeshActor, bool updateTransform); + UFUNCTION(BlueprintCallable, Category = "Passthrough") + void AddStaticSurfaceGeometry(UStaticMeshComponent* StaticMeshComponent, bool updateTransform); + UFUNCTION(BlueprintCallable, Category = "Passthrough") + void AddProceduralSurfaceGeometry(UProceduralMeshComponent* ProceduralMeshComponent, bool updateTransform); + + UFUNCTION(BlueprintCallable, Category = "Passthrough", meta = (DeprecatedFunction, DeprecationMessage = "Please use RemoveStaticSurfaceGeometry instead")) + void RemoveSurfaceGeometry(AStaticMeshActor* StaticMeshActor); + UFUNCTION(BlueprintCallable, Category = "Passthrough") + void RemoveStaticSurfaceGeometry(UStaticMeshComponent* StaticMeshComponent); + UFUNCTION(BlueprintCallable, Category = "Passthrough") + void RemoveProceduralSurfaceGeometry(UProceduralMeshComponent* ProceduralMeshComponent); + + UFUNCTION(BlueprintCallable, Category = "Passthrough", meta = (DeprecatedFunction, DeprecationMessage = "Please use IsSurfaceGeometryComponent instead")) + bool IsSurfaceGeometry(AStaticMeshActor* StaticMeshActor) const; + UFUNCTION(BlueprintPure, Category = "Passthrough") + bool IsSurfaceGeometryComponent(const UMeshComponent* MeshComponent) const; + + // Manually mark the stereo layer passthrough effect for updating + UFUNCTION(BlueprintCallable, Category = "Components|Stereo Layer") + void MarkPassthroughStyleForUpdate(); + +#if WITH_EDITOR + virtual bool CanEditChange(const FProperty* InProperty) const override; +#endif // WITH_EDITOR + +protected: + virtual bool LayerRequiresTexture(); + virtual void RemoveSurfaceGeometryComponent(UMeshComponent* MeshComponent); + + UPROPERTY(Transient) + TMap PassthroughComponentMap; + +private: + OculusXRHMD::FOculusPassthroughMeshRef CreatePassthroughMesh(UProceduralMeshComponent* ProceduralMeshComponent); + OculusXRHMD::FOculusPassthroughMeshRef CreatePassthroughMesh(UStaticMeshComponent* StaticMeshComponent); + + /** Passthrough style needs to be marked for update **/ + bool bPassthroughStyleNeedsUpdate; +}; diff --git a/Plugins/MetaXR/Source/OculusXRProjectSetupTool/OculusXRProjectSetupTool.Build.cs b/Plugins/MetaXR/Source/OculusXRProjectSetupTool/OculusXRProjectSetupTool.Build.cs new file mode 100644 index 0000000..f9c952b --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRProjectSetupTool/OculusXRProjectSetupTool.Build.cs @@ -0,0 +1,50 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +using UnrealBuildTool; + +public class OculusXRProjectSetupTool : ModuleRules +{ + public OculusXRProjectSetupTool(ReadOnlyTargetRules Target) : base(Target) + { + + bUseUnity = true; + + PrivateIncludePaths.AddRange( + new string[] { + "OculusXRHMD/Private", + }); + + PublicDependencyModuleNames.AddRange( + new string[] + { + "Core", + "CoreUObject", + "Engine" + } + ); + + PrivateDependencyModuleNames.AddRange( + new string[] + { + "Projects", + "UnrealEd", + "LevelEditor", + "Slate", + "SlateCore", + "EditorStyle", + "EngineSettings", + "OculusXRHMD", + "OculusXRMovement", + "OculusXRPassthrough", + "OculusXRAnchors", + "OculusXRScene", + "AndroidRuntimeSettings", + "LauncherServices", + "ToolWidgets", + "WorkspaceMenuStructure", + "PluginBrowser", + "ToolMenus" + } + ); + } +} diff --git a/Plugins/MetaXR/Source/OculusXRProjectSetupTool/Private/OculusXRPSTEvents.h b/Plugins/MetaXR/Source/OculusXRProjectSetupTool/Private/OculusXRPSTEvents.h new file mode 100644 index 0000000..e52044a --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRProjectSetupTool/Private/OculusXRPSTEvents.h @@ -0,0 +1,31 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#pragma once + +#include "OculusXRTelemetry.h" + +namespace OculusXRTelemetry::Events +{ + using FProjectSetupToolIgnore = TMarker<191964172>; + using FProjectSetupToolFix = TMarker<191966457>; + using FProjectSetupToolOption = TMarker<191964194>; + using FProjectSetupToolSummary = TMarker<191966987>; + using FProjectSetupToolOpen = TMarker<191967598>; + using FProjectSetupToolClose = TMarker<191957393>; + using FProjectSetupToolNext = TMarker<191956372>; + using FProjectSetupToolPrev = TMarker<191956161>; + using FProjectSetupToolTutorialClose = TMarker<191962723>; +} // namespace OculusXRTelemetry::Events + +namespace OculusXRTelemetry::Annotations +{ + constexpr const char* Uid = "Uid"; + constexpr const char* Level = "Level"; + constexpr const char* Type = "Type"; + constexpr const char* Value = "Value"; + constexpr const char* BuildTargetGroup = "BuildTargetGroup"; + constexpr const char* Count = "Count"; + constexpr const char* Group = "Group"; + constexpr const char* Origin = "Origin"; + constexpr const char* TutorialCompleted = "TutorialCompleted"; +} // namespace OculusXRTelemetry::Annotations diff --git a/Plugins/MetaXR/Source/OculusXRProjectSetupTool/Private/OculusXRPSTUtils.h b/Plugins/MetaXR/Source/OculusXRProjectSetupTool/Private/OculusXRPSTUtils.h new file mode 100644 index 0000000..ed99600 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRProjectSetupTool/Private/OculusXRPSTUtils.h @@ -0,0 +1,139 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#pragma once +#include "CoreMinimal.h" + +#define OCULUSXR_UPDATE_SETTINGS(SettingsClass, PropertyName, PropertyValue) \ + { \ + SettingsClass* Settings = GetMutableDefault(); \ + Settings->PropertyName = PropertyValue; \ + Settings->UpdateSinglePropertyInConfigFile( \ + Settings->GetClass()->FindPropertyByName( \ + GET_MEMBER_NAME_CHECKED(SettingsClass, PropertyName)), \ + Settings->GetDefaultConfigFilename()); \ + } + +namespace OculusXRPSTUtils +{ + /** + * Return if there is a component of a given type in the world. + */ + template + bool IsComponentOfTypeInWorld() + { + for (TObjectIterator Iterator; Iterator;) + { + return true; + } + + return false; + } + + inline const char* ToString(ESetupRuleSeverity Severity) + { + switch (Severity) + { + case ESetupRuleSeverity::Critical: + return "critical"; + case ESetupRuleSeverity::Performance: + return "performance"; + case ESetupRuleSeverity::Warning: + return "warning"; + default: + UE_LOG(LogTemp, Error, TEXT("Not covered Severity enum. %d"), Severity); + check(false); + } + return ""; + } + + inline const char* ToString(ESetupRuleCategory Category) + { + switch (Category) + { + case ESetupRuleCategory::Compatibility: + return "Compatibility"; + case ESetupRuleCategory::Rendering: + return "Rendering"; + case ESetupRuleCategory::Quality: + return "Quality"; + case ESetupRuleCategory::Physics: + return "Physics"; + case ESetupRuleCategory::Plugins: + return "Plugins"; + case ESetupRuleCategory::Features: + return "Features"; + case ESetupRuleCategory::Miscellaneous: + return "Miscellaneous"; + default: + UE_LOG(LogTemp, Error, TEXT("Not covered Category enum. %d"), Category); + check(false); + } + return ""; + } + + inline const char* ToString(ESetupRulePlatform Platform) + { + FString Result = ""; + if ((Platform & ESetupRulePlatform::MetaLink) == ESetupRulePlatform::MetaLink) + Result += " PC Link"; + if ((Platform & ESetupRulePlatform::MetaQuest_2) == ESetupRulePlatform::MetaQuest_2) + Result += " Quest 2"; + if ((Platform & ESetupRulePlatform::MetaQuest_3) == ESetupRulePlatform::MetaQuest_3) + Result += " Quest 3"; + if ((Platform & ESetupRulePlatform::MetaQuest_Pro) == ESetupRulePlatform::MetaQuest_Pro) + Result += " Quest Pro"; + return TCHAR_TO_ANSI(*Result); + } + + inline const char* GetDisplayName(ESetupRulePlatform Platform) + { + if ((Platform & MetaQuest_All) == MetaQuest_All) + return "All Quest"; + if ((Platform & ESetupRulePlatform::MetaLink) == ESetupRulePlatform::MetaLink) + return "PC Link"; + if ((Platform & ESetupRulePlatform::MetaQuest_2) == ESetupRulePlatform::MetaQuest_2) + return "Quest 2"; + if ((Platform & ESetupRulePlatform::MetaQuest_3) == ESetupRulePlatform::MetaQuest_3) + return "Quest 3"; + if ((Platform & ESetupRulePlatform::MetaQuest_Pro) == ESetupRulePlatform::MetaQuest_Pro) + return "Quest Pro"; + return ""; + } + + inline void SetBrushStyle(const TSharedPtr& Style, const ESetupRulePlatform Platform) + { + FString RelativePath = "PlatformQuest3"; // Quest3 and All Quest + FVector2d Size{ 32.f, 32.f }; + if (Platform == ESetupRulePlatform::MetaLink) + { + RelativePath = "PlatformDesktop"; + Size = { 16.f, 16.f }; + } + + if (Platform == ESetupRulePlatform::MetaQuest_Pro || Platform == ESetupRulePlatform::MetaQuest_2) + { + RelativePath = "PlatformQuest2"; + } + + Style->Set(GetDisplayName(Platform), + new FSlateVectorImageBrush(Style->RootToContentDir(RelativePath, TEXT(".svg")), + Size)); + } + inline bool ShouldRuleBeSkipped(const SetupRulePtr& Rule, ESetupRulePlatform Platform, const TSet& Severities) + { + return !Rule->IsValid() || Rule->IsIgnored() || !Severities.Contains(Rule->GetSeverity()) || (Rule->GetPlatform() & Platform) != Platform; + } + + inline void LogErrorForUnAppliedRules(const TArray& UnAppliedRules) + { + if (!UnAppliedRules.IsEmpty()) + { + UE_LOG(LogProjectSetupTool, Error, TEXT("Following critical rules are not applied:\n%s"), + *FString::JoinBy( + UnAppliedRules, + TEXT("\n"), + [](const SetupRulePtr Rule) { return Rule->GetDisplayName().ToString(); })); + UE_LOG(LogProjectSetupTool, Error, TEXT("To fix them open `Tools > Meta XR Project Setup Tool`")); + } + } +} // namespace OculusXRPSTUtils diff --git a/Plugins/MetaXR/Source/OculusXRProjectSetupTool/Private/OculusXRProjectSetupToolModule.cpp b/Plugins/MetaXR/Source/OculusXRProjectSetupTool/Private/OculusXRProjectSetupToolModule.cpp new file mode 100644 index 0000000..2f2910c --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRProjectSetupTool/Private/OculusXRProjectSetupToolModule.cpp @@ -0,0 +1,400 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#include "OculusXRProjectSetupToolModule.h" +#include "CoreMinimal.h" +#include "OculusXRPSTEvents.h" +#include "OculusXRPSTSettings.h" +#include "OculusXRPSTUtils.h" +#include "OculusXRRuleProcessorSubsystem.h" +#include "OculusXRTelemetry.h" +#include "WorkspaceMenuStructure.h" +#include "WorkspaceMenuStructureModule.h" +#include "Brushes/SlateImageBrush.h" +#include "Styling/SlateStyle.h" +#include "Interfaces/IPluginManager.h" +#include "Styling/SlateStyleRegistry.h" +#include "Widget/OculusXRProjectSetupToolWidget.h" +#include "Widget/OculusXRStatusBarWidget.h" +#include "Interfaces/IMainFrameModule.h" +#include "Widget/OculusXRProjectTutorialWidget.h" + +DEFINE_LOG_CATEGORY(LogProjectSetupTool); +#define LOCTEXT_NAMESPACE "OculusXRProjectSetupToolModule" + +IMPLEMENT_MODULE(FOculusXRProjectSetupToolModule, OculusXRProjectSetupTool) + +/** Style set */ +TSharedPtr IconStyle = nullptr; + +const char* MetaLogo = "ProjectSetupTool.MetaLogo"; +const FName ProjectSetupToolTabName = FName("OculusXRProjectSetupTool"); +/** + * Perform module initialization + */ +void FOculusXRProjectSetupToolModule::StartupModule() +{ + UE_LOG(LogProjectSetupTool, Display, TEXT("StartupModule: OculusXRProjectSetupTool")); + RegisterConsoleCommands(); + + // Prepare the main project setup tool tab + if (IsRunningCommandlet()) + { + return; + } + RegisterStyleWithStyleRegistry(); + RegisterProjectSetupToolWithTabManager(); + RegisterStatusBarWidgetWithToolMenu(); +} + +/** + * Perform module cleanup + */ +void FOculusXRProjectSetupToolModule::ShutdownModule() +{ + UnregisterConsoleCommands(); + if (IsRunningCommandlet()) + { + return; + } + + UnregisterStyleWithStyleRegistry(); + FGlobalTabmanager::Get()->UnregisterNomadTabSpawner(ProjectSetupToolTabName); +} + +/** + * Show the project setup tool + */ +void FOculusXRProjectSetupToolModule::ShowProjectSetupTool(const FString& Origin) +{ +#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST) + FGlobalTabmanager::Get()->TryInvokeTab(ProjectSetupToolTabName); + TriggerOrigin = Origin; +#endif +} + +#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST) + +TSharedPtr FOculusXRProjectSetupToolModule::GetSlateStyle() +{ + return IconStyle; +} + +/** + * Register console commands + */ +void FOculusXRProjectSetupToolModule::RegisterConsoleCommands() +{ + ConsoleCommands.Add(IConsoleManager::Get().RegisterConsoleCommand(TEXT("vr.oculus.ApplyRule"), TEXT("Applies a rule.\n"), FConsoleCommandWithArgsDelegate::CreateStatic(&FOculusXRProjectSetupToolModule::ProcessApplyRuleCommand), ECVF_Default)); + + ConsoleCommands.Add(IConsoleManager::Get().RegisterConsoleCommand(TEXT("vr.oculus.IsRuleApplied"), TEXT("Determines whether a rule is applied.\n"), FConsoleCommandWithArgsDelegate::CreateStatic(&FOculusXRProjectSetupToolModule::ProcessIsRuleAppliedCommand), ECVF_Default)); + + ConsoleCommands.Add(IConsoleManager::Get().RegisterConsoleCommand(TEXT("vr.oculus.ListAppliedRules"), TEXT("Lists all applied rules.\n"), FConsoleCommandDelegate::CreateStatic(&FOculusXRProjectSetupToolModule::ProcessListAppliedRulesCommand), ECVF_Default)); + + ConsoleCommands.Add(IConsoleManager::Get().RegisterConsoleCommand(TEXT("vr.oculus.ListRules"), TEXT("Lists all registered rules.\n"), FConsoleCommandDelegate::CreateStatic(&FOculusXRProjectSetupToolModule::ProcessListRulesCommand), ECVF_Default)); +} + +/** + * Unregister console commands + */ +void FOculusXRProjectSetupToolModule::UnregisterConsoleCommands() +{ + for (const auto ConsoleCommand : ConsoleCommands) + { + IConsoleManager::Get().UnregisterConsoleObject(ConsoleCommand); + } +} + +/** + * Register styles + */ +void FOculusXRProjectSetupToolModule::RegisterStyleWithStyleRegistry() const +{ + const FString PluginContentRoot = IPluginManager::Get().FindPlugin("OculusXR")->GetBaseDir() / TEXT("Resources"); + + IconStyle = MakeShared("OculusXRProjectSetupToolStyle"); + IconStyle->SetContentRoot(PluginContentRoot); + IconStyle->Set(MetaLogo, + new FSlateVectorImageBrush(IconStyle->RootToContentDir("MetaLogo", TEXT(".svg")), + FVector2D(32.0f, 32.0f))); + + IconStyle->Set("ProjectSetupTool.MetaQuestBackground", + new FSlateImageBrush(IconStyle->RootToContentDir("MetaQuestBackground", TEXT(".png")), + FVector2D(480.f, 570.f))); + + IconStyle->Set("ProjectSetupTool.RedDot", + new FSlateVectorImageBrush(IconStyle->RootToContentDir("RedDot", TEXT(".svg")), + FVector2D(32.0f, 32.0f))); + + IconStyle->Set("ProjectSetupTool.YellowDot", + new FSlateVectorImageBrush(IconStyle->RootToContentDir("YellowDot", TEXT(".svg")), + FVector2D(32.0f, 32.0f))); + + IconStyle->Set("ProjectSetupTool.GreenDot", + new FSlateVectorImageBrush(IconStyle->RootToContentDir("GreenDot", TEXT(".svg")), + FVector2D(32.0f, 32.0f))); + + IconStyle->Set("ProjectSetupTool.GreyDot", + new FSlateVectorImageBrush(IconStyle->RootToContentDir("GreyDot", TEXT(".svg")), + FVector2D(32.0f, 32.0f))); + + IconStyle->Set("ProjectSetupTool.WhiteDot", + new FSlateVectorImageBrush(IconStyle->RootToContentDir("WhiteDot", TEXT(".svg")), + FVector2D(32.0f, 32.0f))); + + OculusXRPSTUtils::SetBrushStyle(IconStyle, ESetupRulePlatform::MetaLink); + OculusXRPSTUtils::SetBrushStyle(IconStyle, ESetupRulePlatform::MetaQuest_2); + OculusXRPSTUtils::SetBrushStyle(IconStyle, ESetupRulePlatform::MetaQuest_3); + OculusXRPSTUtils::SetBrushStyle(IconStyle, ESetupRulePlatform::MetaQuest_Pro); + OculusXRPSTUtils::SetBrushStyle(IconStyle, MetaQuest_All); + + FSlateStyleRegistry::RegisterSlateStyle(*IconStyle.Get()); +} + +/** + * Unregister styles + */ +void FOculusXRProjectSetupToolModule::UnregisterStyleWithStyleRegistry() const +{ + if (IconStyle.IsValid()) + { + FSlateStyleRegistry::UnRegisterSlateStyle(*IconStyle.Get()); + IconStyle.Reset(); + } +} + +/** + * Register tab widget + */ +void FOculusXRProjectSetupToolModule::RegisterProjectSetupToolWithTabManager() +{ + FGlobalTabmanager::Get()->RegisterNomadTabSpawner( + ProjectSetupToolTabName, + FOnSpawnTab::CreateRaw(this, + &FOculusXRProjectSetupToolModule::OnSpawnProjectSetupToolTab)) + .SetDisplayName(LOCTEXT("ProjectSetupToolTab_Title", "Meta XR Project Setup Tool")) + .SetTooltipText(LOCTEXT("ProjectSetupToolTab_Tooltip", "Meta XR Project Setup tool")) + .SetGroup(WorkspaceMenu::GetMenuStructure().GetToolsCategory()) + .SetIcon(FSlateIcon(IconStyle->GetStyleSetName(), MetaLogo)); +} + +/** + * Register status bar widget + */ +void FOculusXRProjectSetupToolModule::RegisterStatusBarWidgetWithToolMenu() const +{ + UToolMenu* Menu = UToolMenus::Get()->ExtendMenu(TEXT("LevelEditor.StatusBar.ToolBar")); + + FToolMenuSection& ProjectSetupToolSection = Menu->AddSection(TEXT("ProjectSetupTool"), FText::GetEmpty(), FToolMenuInsert(NAME_None, EToolMenuInsertType::First)); + + ProjectSetupToolSection.AddEntry( + FToolMenuEntry::InitWidget(TEXT("ProjectSetupTool"), SNew(SOculusXRStatusBarWidget), FText::GetEmpty(), true, false)); +} + +/** + * Process 'ApplyRule' console command + */ +void FOculusXRProjectSetupToolModule::ProcessApplyRuleCommand(const TArray& Arguments) +{ + if (Arguments.Num() != 1) + { + UE_LOG(LogProjectSetupTool, Warning, TEXT("Expected only 1 argument")); + } + + const UOculusXRRuleProcessorSubsystem* RuleProcessorSubsystem = GEngine->GetEngineSubsystem(); + const FString& ConsoleRuleId = Arguments[0]; + const auto& Rule = RuleProcessorSubsystem->GetRule(FName(ConsoleRuleId)); + + if (Rule != nullptr) + { + bool ShouldRestart; + Rule->Apply(ShouldRestart); + + UE_LOG(LogProjectSetupTool, Display, TEXT("Applied rule <%s>"), *ConsoleRuleId); + } + else + { + UE_LOG(LogProjectSetupTool, Warning, TEXT("Cannot apply unknown rule <%s>"), *ConsoleRuleId); + } +} + +/** + * Process 'IsRuleApplied' console command + */ +void FOculusXRProjectSetupToolModule::ProcessIsRuleAppliedCommand(const TArray& Arguments) +{ + if (Arguments.Num() != 1) + { + UE_LOG(LogProjectSetupTool, Warning, TEXT("Expected only 1 argument")); + } + + const UOculusXRRuleProcessorSubsystem* RuleProcessorSubsystem = GEngine->GetEngineSubsystem(); + const FString& ConsoleRuleId = Arguments[0]; + const auto& Rule = RuleProcessorSubsystem->GetRule(FName(ConsoleRuleId)); + if (Rule != nullptr) + { + UE_LOG(LogProjectSetupTool, Display, TEXT("Rule <%s> is %s"), *ConsoleRuleId, Rule->IsApplied() ? TEXT("applied") : TEXT("not applied")); + } + else + { + UE_LOG(LogProjectSetupTool, Warning, TEXT("Cannot query unknown rule <%s>"), *ConsoleRuleId); + } +} + +/** + * Process 'ListAppliedRules' console command + */ +void FOculusXRProjectSetupToolModule::ProcessListAppliedRulesCommand() +{ + const UOculusXRRuleProcessorSubsystem* RuleProcessorSubsystem = GEngine->GetEngineSubsystem(); + + uint32 Index = 0; + + for (auto& Rule : RuleProcessorSubsystem->GetRules()) + { + if (Rule->IsApplied()) + { + UE_LOG(LogProjectSetupTool, Display, TEXT("Applied rule <%s>"), *(Rule->GetId().ToString())); + ++Index; + } + } + UE_LOG(LogProjectSetupTool, Display, TEXT("There are %d applied rules"), Index); +} + +/** + * Process 'ListRules' console command + */ +void FOculusXRProjectSetupToolModule::ProcessListRulesCommand() +{ + const UOculusXRRuleProcessorSubsystem* RuleProcessorSubsystem = GEngine->GetEngineSubsystem(); + + UE_LOG(LogProjectSetupTool, Display, TEXT("There are %d registered rules"), RuleProcessorSubsystem->GetRules().Num()); + UE_LOG(LogProjectSetupTool, Display, TEXT("|%60hs|%60hs|%20hs|%20hs|%10hs|"), "Rule id", "Display Name", + "Category", "Severity", "Is Ignored"); + + for (const auto& RegisteredRule : RuleProcessorSubsystem->GetRules()) + { + UE_LOG( + LogProjectSetupTool, + Display, + TEXT("|%60ls|%60s|%20hs|%20hs|%10hs|"), + *RegisteredRule->GetId().ToString(), + *RegisteredRule->GetDisplayName().ToString(), + OculusXRPSTUtils::ToString(RegisteredRule->GetCategory()), + OculusXRPSTUtils::ToString(RegisteredRule->GetSeverity()), + RegisteredRule->IsIgnored() ? "yes" : "no"); + } +} + +void FOculusXRProjectSetupToolModule::ProcessIgnoreRuleCommand(const TArray& Arguments) +{ + if (Arguments.Num() != 1) + { + UE_LOG(LogProjectSetupTool, Warning, TEXT("Expected only 1 argument")); + } + + const UOculusXRRuleProcessorSubsystem* RuleProcessorSubsystem = GEngine->GetEngineSubsystem(); + const FString& ConsoleRuleId = Arguments[0]; + const auto& Rule = RuleProcessorSubsystem->GetRule(FName(ConsoleRuleId)); + if (Rule != nullptr) + { + Rule->SetIgnoreRule(true); + } + else + { + UE_LOG(LogProjectSetupTool, Warning, TEXT("Cannot query unknown rule <%s>"), *ConsoleRuleId); + } +} +void FOculusXRProjectSetupToolModule::ProcessUnIgnoreRuleCommand(const TArray& Arguments) +{ + if (Arguments.Num() != 1) + { + UE_LOG(LogProjectSetupTool, Warning, TEXT("Expected only 1 argument")); + } + + const UOculusXRRuleProcessorSubsystem* RuleProcessorSubsystem = GEngine->GetEngineSubsystem(); + const FString& ConsoleRuleId = Arguments[0]; + const auto& Rule = RuleProcessorSubsystem->GetRule(FName(ConsoleRuleId)); + if (Rule != nullptr) + { + Rule->SetIgnoreRule(false); + } + else + { + UE_LOG(LogProjectSetupTool, Warning, TEXT("Cannot query unknown rule <%s>"), *ConsoleRuleId); + } +} +void FOculusXRProjectSetupToolModule::ProcessUnIgnoreAllRulesCommand() +{ + const UOculusXRRuleProcessorSubsystem* RuleProcessorSubsystem = GEngine->GetEngineSubsystem(); + + for (const auto& Rule : RuleProcessorSubsystem->GetRules()) + { + Rule->SetIgnoreRule(false); + } +} + +void FOculusXRProjectSetupToolModule::OnWidgetClosed() +{ + const auto& Platform = static_cast(GetMutableDefault()->CurrentPlatform); + const OculusXRTelemetry::TScopedMarker CloseEvent; + const auto& Annotated = CloseEvent + .AddAnnotation(OculusXRTelemetry::Annotations::BuildTargetGroup, OculusXRPSTUtils::ToString(Platform)) + .AddAnnotation(OculusXRTelemetry::Annotations::Origin, TCHAR_TO_ANSI(*TriggerOrigin)); +} + +/** + * Spawn the project setup tool tab + */ +TSharedRef FOculusXRProjectSetupToolModule::OnSpawnProjectSetupToolTab(const FSpawnTabArgs& SpawnTabArgs) +{ + SpawnTutorialWindowIfNeeded(); + const auto& Platform = static_cast(GetMutableDefault()->CurrentPlatform); + const OculusXRTelemetry::TScopedMarker OpenEvent; + const auto& Annotated = OpenEvent + .AddAnnotation(OculusXRTelemetry::Annotations::BuildTargetGroup, OculusXRPSTUtils::ToString(Platform)) + .AddAnnotation(OculusXRTelemetry::Annotations::Origin, TCHAR_TO_ANSI(*TriggerOrigin)); + TriggerOrigin = "Menu"; + TSharedRef DockTab = SNew(SDockTab) + .TabRole(ETabRole::NomadTab) + .OnTabClosed(SDockTab::FOnTabClosedCallback::CreateLambda([this](TSharedRef) { + OnWidgetClosed(); + })) + .Label(NSLOCTEXT("MetaXRProjectSetupTool", "MetaXRPSTTitle", "Meta XR Project Setup Tool")) + [SNew(SOculusXRProjectSetupToolWidget)]; + + DockTab->SetTabIcon(IconStyle->GetBrush(MetaLogo)); + return DockTab; +} + +void FOculusXRProjectSetupToolModule::SpawnTutorialWindowIfNeeded() const +{ + const auto Settings = GetMutableDefault(); + if (Settings->bShowGuidedTutorial) + { + TSharedPtr ParentWindow; + + if (FModuleManager::Get().IsModuleLoaded("MainFrame")) + { + const IMainFrameModule& MainFrame = FModuleManager::LoadModuleChecked("MainFrame"); + ParentWindow = MainFrame.GetParentWindow(); + } + const TSharedRef Window = SNew(SWindow) + .Title(LOCTEXT("Meta XR Project Setup Tool", "Meta XR Project Setup Tool")) + .SizingRule(ESizingRule::Autosized) + .SupportsMaximize(false) + .SupportsMinimize(false)[SNew(SOculusXRTutorialWindow)]; + + Window->SetOnWindowClosed(FOnWindowClosed::CreateLambda([](const TSharedRef&) { + auto Settings = GetMutableDefault(); + Settings->bShowGuidedTutorial = false; + Settings->SaveConfig(); + const OculusXRTelemetry::TScopedMarker ClosedEvent; + const auto& Annotated = ClosedEvent + .AddAnnotation(OculusXRTelemetry::Annotations::TutorialCompleted, Settings->bGuidedTutorialComplete ? "true" : "false"); + })); + FSlateApplication::Get().AddModalWindow(Window, ParentWindow, false); + } +} + +#endif +#undef LOCTEXT_NAMESPACE diff --git a/Plugins/MetaXR/Source/OculusXRProjectSetupTool/Private/OculusXRProjectSetupToolModule.h b/Plugins/MetaXR/Source/OculusXRProjectSetupTool/Private/OculusXRProjectSetupToolModule.h new file mode 100644 index 0000000..b047046 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRProjectSetupTool/Private/OculusXRProjectSetupToolModule.h @@ -0,0 +1,62 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#pragma once + +#include "CoreMinimal.h" +#include "IOculusXRProjectSetupModule.h" + +DECLARE_LOG_CATEGORY_EXTERN(LogProjectSetupTool, Log, All); + +/** + * The module for the implementation of the Project Setup Tool + */ +class FOculusXRProjectSetupToolModule : public IOculusXRProjectSetupToolModule +{ +public: + /** + * IModuleInterface implementation + */ + virtual void StartupModule() override; + virtual void ShutdownModule() override; + + /** Show the project setup tool window */ + virtual void ShowProjectSetupTool(const FString& Origin) override; + +#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST) + static TSharedPtr GetSlateStyle(); + +private: + /** Register and unregister console commands */ + void RegisterConsoleCommands(); + void UnregisterConsoleCommands(); + + /** Register and unregister styles */ + void RegisterStyleWithStyleRegistry() const; + void UnregisterStyleWithStyleRegistry() const; + + /** Register tool extensions */ + void RegisterProjectSetupToolWithTabManager(); + void RegisterStatusBarWidgetWithToolMenu() const; + + /** Process functions for all the console commands */ + static void ProcessApplyRuleCommand(const TArray& Arguments); + static void ProcessIsRuleAppliedCommand(const TArray& Arguments); + static void ProcessListAppliedRulesCommand(); + static void ProcessListRulesCommand(); + static void ProcessIgnoreRuleCommand(const TArray& Arguments); + static void ProcessUnIgnoreRuleCommand(const TArray& Arguments); + static void ProcessUnIgnoreAllRulesCommand(); + + void OnWidgetClosed(); + void SpawnTutorialWindowIfNeeded() const; + + /** Spawn function for creating the project setup tool tab */ + TSharedRef OnSpawnProjectSetupToolTab(const FSpawnTabArgs& SpawnTabArgs); + + /** All registered console commands */ + TArray ConsoleCommands{}; + + /** If PST is triggered from toolbar*/ + FString TriggerOrigin = "Menu"; +#endif +}; diff --git a/Plugins/MetaXR/Source/OculusXRProjectSetupTool/Private/OculusXRRuleProcessorSubsystem.cpp b/Plugins/MetaXR/Source/OculusXRProjectSetupTool/Private/OculusXRRuleProcessorSubsystem.cpp new file mode 100644 index 0000000..120e7a9 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRProjectSetupTool/Private/OculusXRRuleProcessorSubsystem.cpp @@ -0,0 +1,292 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#include "OculusXRRuleProcessorSubsystem.h" + +#include "LightComponentBase.h" +#include "OculusXRProjectSetupToolModule.h" +#include "OculusXRPSTEvents.h" +#include "OculusXRPSTSettings.h" +#include "OculusXRPSTUtils.h" +#include "OculusXRTelemetry.h" +#include "Developer/LauncherServices/Public/ILauncherServicesModule.h" +#include "Rules/OculusXRAnchorsRules.h" +#include "Rules/OculusXRCompatibilityRules.h" +#include "Rules/OculusXRMovementRules.h" +#include "Rules/OculusXRPassthroughRules.h" +#include "Rules/OculusXRRenderingRules.h" +#include "Rules/OculusXRPluginRules.h" + +/** + * Initialize the subsystem. USubsystem override + */ +void UOculusXRRuleProcessorSubsystem::Initialize(FSubsystemCollectionBase& Collection) +{ + Super::Initialize(Collection); + + PopulateDynamicLights(); + + // Register rules + RegisterRules(OculusXRRenderingRules::RenderingRules_Table); + RegisterRules(OculusXRPluginRules::PluginRules_Table); + RegisterRules(OculusXRCompatibilityRules::CompatibilityRules_Table); + RegisterRules(OculusXRPassthroughRules::PassthroughRules_Table); + RegisterRules(OculusXRMovementRules::MovementRules_Table); + RegisterRules(OculusXRAnchorsRules::AnchorRules_Table); + + // Register on Launcher Callback + ILauncherServicesModule& ProjectLauncherServicesModule = FModuleManager::LoadModuleChecked( + "LauncherServices"); + LauncherCallbackHandle = ProjectLauncherServicesModule.OnCreateLauncherDelegate.AddUObject( + this, &UOculusXRRuleProcessorSubsystem::OnLauncherCreated); + // Show errors after play in editor is over. + FEditorDelegates::PrePIEEnded.AddUObject(this, &UOculusXRRuleProcessorSubsystem::OnPIEEnded); + + // Update if rules are ignored. Note: At time of the rules construction it is early to fetch settings + const auto& IgnoredRules = GetMutableDefault()->IgnoredRules; + for (const auto& Rule : Rules) + { + Rule->SetIgnoreRule(IgnoredRules.Contains(Rule->GetId()), false); + } + + SendSummaryEvent(); +} + +/** + * De-initializes the subsystem. USubsystem override + */ +void UOculusXRRuleProcessorSubsystem::Deinitialize() +{ + SendSummaryEvent(); + Super::Deinitialize(); + if (LauncherCallbackHandle.IsValid()) + { + ILauncherServicesModule& ProjectLauncherServicesModule = FModuleManager::LoadModuleChecked< + ILauncherServicesModule>( + "LauncherServices"); + ProjectLauncherServicesModule.OnCreateLauncherDelegate.Remove(LauncherCallbackHandle); + LauncherCallbackHandle.Reset(); + } +} + +/** + * Register a rule + */ +bool UOculusXRRuleProcessorSubsystem::RegisterRule(const SetupRulePtr& Rule) +{ + if (Rule == nullptr) + { + UE_LOG(LogProjectSetupTool, Error, TEXT("RegisterRule: Cannot register nullptr")); + return false; + } + bool bIsAlreadyRegistred = false; + Rules.Add(Rule, &bIsAlreadyRegistred); + if (bIsAlreadyRegistred) + { + UE_LOG(LogProjectSetupTool, Warning, TEXT("RegisterRule: rule with id <%s> has already been registered"), + *(Rule->GetId().ToString())); + return false; + } + + UE_LOG(LogProjectSetupTool, Display, TEXT("RegisterRule: added rule with id <%s>"), *(Rule->GetId().ToString())); + + return true; +} + +/** + * Unregister a rule + */ +bool UOculusXRRuleProcessorSubsystem::UnregisterRule(const SetupRulePtr& Rule) +{ + if (Rule == nullptr) + { + UE_LOG(LogProjectSetupTool, Error, TEXT("RegisterRule: Cannot deregister nullptr")); + return false; + } + const auto Id = Rule->GetId(); + if (!Rules.Contains(Id)) + { + UE_LOG(LogProjectSetupTool, Warning, TEXT("UnregisterRule: rule with id <%s> has not been registered"), + *Id.ToString()); + return false; + } + + UE_LOG(LogProjectSetupTool, Display, TEXT("UnregisterRule: removed rule with id <%s>"), *Id.ToString()); + + Rules.Remove(Id); + return true; +} + +/** + * Unregister all rules + */ +void UOculusXRRuleProcessorSubsystem::UnregisterAllRules() +{ + UE_LOG(LogProjectSetupTool, Display, TEXT("UnregisterRule: removed all rules")); + + Rules.Empty(); +} + +/** + * Fetch all rules + */ +const TSet& UOculusXRRuleProcessorSubsystem::GetRules() const +{ + return Rules; +} + +/** + * Fetch rule with given `Id` + */ +SetupRulePtr UOculusXRRuleProcessorSubsystem::GetRule(const FName& Id) const +{ + const auto Found = Rules.Find(Id); + if (Found == nullptr) + { + return nullptr; + } + + return *Found; +} + +bool UOculusXRRuleProcessorSubsystem::DynamicLightsExistInProject() const +{ + return DynamicLights.Num() > 0; +} + +void UOculusXRRuleProcessorSubsystem::SendSummaryEvent() +{ + SendSummaryEvent(ESetupRulePlatform::MetaLink); + SendSummaryEvent(ESetupRulePlatform::MetaQuest_2); + SendSummaryEvent(ESetupRulePlatform::MetaQuest_3); + SendSummaryEvent(ESetupRulePlatform::MetaQuest_Pro); +} + +void UOculusXRRuleProcessorSubsystem::SendSummaryEvent(ESetupRulePlatform Platform) const +{ + const auto& Status = UnAppliedRulesStatus(Platform); + const char* Level = Status.PendingRequiredRulesCount > 0 ? "Critical" : "Recommended"; + const char* Value = TCHAR_TO_ANSI(*FString::FromInt(Status.PendingRequiredRulesCount > 0 ? Status.PendingRequiredRulesCount : Status.PendingRecommendedRulesCount)); + const char* Total = TCHAR_TO_ANSI( + *FString::FromInt(Status.PendingRequiredRulesCount + Status.PendingRecommendedRulesCount)); + const OculusXRTelemetry::TScopedMarker SummaryEvent; + const auto& CriticalAnnotated = SummaryEvent + .AddAnnotation(OculusXRTelemetry::Annotations::Level, Level) + .AddAnnotation(OculusXRTelemetry::Annotations::Value, Value) + .AddAnnotation(OculusXRTelemetry::Annotations::Count, Total) + .AddAnnotation(OculusXRTelemetry::Annotations::BuildTargetGroup, OculusXRPSTUtils::ToString(Platform)); +} + +void UOculusXRRuleProcessorSubsystem::Refresh() +{ + PopulateDynamicLights(); + SendSummaryEvent(); +} + +UOculusXRRuleProcessorSubsystem::RuleStatus UOculusXRRuleProcessorSubsystem::UnAppliedRulesStatus( + ESetupRulePlatform Platform) const +{ + RuleStatus Status{}; + for (const auto& Rule : Rules) + { + if (Rule->IsApplied()) + { + continue; + } + if (OculusXRPSTUtils::ShouldRuleBeSkipped(Rule, Platform, { ESetupRuleSeverity::Critical, ESetupRuleSeverity::Performance, ESetupRuleSeverity::Warning })) + { + continue; + } + + if (Rule->GetSeverity() == ESetupRuleSeverity::Critical) + { + ++Status.PendingRequiredRulesCount; + } + else + { + ++Status.PendingRecommendedRulesCount; + } + } + return Status; +} + +void UOculusXRRuleProcessorSubsystem::PopulateDynamicLights() +{ + DynamicLights.Empty(); + + for (TObjectIterator LightItr; LightItr; ++LightItr) + { + const AActor* owner = LightItr->GetOwner(); + if (owner != nullptr && (owner->IsRootComponentStationary() || owner->IsRootComponentMovable()) && !owner->IsHiddenEd() && LightItr->IsVisible() && owner->IsEditable() && owner->IsSelectable() && LightItr->GetWorld() == GEditor->GetEditorWorldContext().World()) + { + DynamicLights.Add(LightItr->GetFullGroupName(false), TWeakObjectPtr(*LightItr)); + } + } +} + +void UOculusXRRuleProcessorSubsystem::RegisterRules(const TArray& InRules) +{ + for (const auto& Rule : InRules) + { + if (!RegisterRule(Rule)) + { + UE_LOG(LogProjectSetupTool, Error, TEXT("Cannot register rule <%s>"), *Rule->GetId().ToString()); + } + } +} + +void UOculusXRRuleProcessorSubsystem::OnLauncherCreated(ILauncherRef Launcher) +{ + // Add callback for when launcher worker is started + Launcher->FLauncherWorkerStartedDelegate.AddUObject( + this, &UOculusXRRuleProcessorSubsystem::OnLauncherWorkerStarted); +} + +void UOculusXRRuleProcessorSubsystem::OnLauncherWorkerStarted(ILauncherWorkerPtr LauncherWorker, + ILauncherProfileRef Profile) +{ + if (!GetMutableDefault()->bStopBuildOnUnAppliedCriticalItems) + { + return; + } + + const TArray Platforms = Profile.Get().GetCookedPlatforms(); + ESetupRulePlatform RulePlatforms = ESetupRulePlatform::None; + if (Platforms.Contains("Android_ASTC")) + { + RulePlatforms |= MetaQuest_All; + } + + if (Platforms.Contains("Windows")) + { + RulePlatforms |= ESetupRulePlatform::MetaLink; + } + + const auto& UnAppliedRules = UnAppliedRulesForPlatform(RulePlatforms, { ESetupRuleSeverity::Critical }); + + OculusXRPSTUtils::LogErrorForUnAppliedRules(UnAppliedRules); + if (!UnAppliedRules.IsEmpty()) + { + LauncherWorker->Cancel(); + } +} + +void UOculusXRRuleProcessorSubsystem::OnPIEEnded(bool bIsSimulating) +{ + const auto& UnAppliedRules = UnAppliedRulesForPlatform(ESetupRulePlatform::MetaLink, { ESetupRuleSeverity::Critical }); + + OculusXRPSTUtils::LogErrorForUnAppliedRules(UnAppliedRules); +} + +TArray UOculusXRRuleProcessorSubsystem::UnAppliedRulesForPlatform(ESetupRulePlatform Platform, const TSet& Severities) const +{ + TArray UnAppliedRules = {}; + for (const auto Rule : Rules) + { + if (!OculusXRPSTUtils::ShouldRuleBeSkipped(Rule, Platform, Severities) && !Rule->IsApplied()) + { + UnAppliedRules.Add(Rule); + } + } + + return UnAppliedRules; +} diff --git a/Plugins/MetaXR/Source/OculusXRProjectSetupTool/Private/OculusXRSetupRule.cpp b/Plugins/MetaXR/Source/OculusXRProjectSetupTool/Private/OculusXRSetupRule.cpp new file mode 100644 index 0000000..fd71373 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRProjectSetupTool/Private/OculusXRSetupRule.cpp @@ -0,0 +1,96 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#include "OculusXRSetupRule.h" + +#include "OculusXRPSTEvents.h" +#include "OculusXRPSTSettings.h" +#include "OculusXRPSTUtils.h" + +ISetupRule::ISetupRule( + const FName& InId, + const FText& InDisplayName, + const FText& InDescription, + const ESetupRuleCategory InCategory, + const ESetupRuleSeverity InSeverity, + const ESetupRulePlatform InPlatform) + : Id(InId), DisplayName(InDisplayName), Description(InDescription), Category(InCategory), Severity(InSeverity), Platform(InPlatform) +{ +} + +void ISetupRule::Apply(bool& ShouldRestartEditor) +{ + const OculusXRTelemetry::TScopedMarker FixedEvent; + const auto& Annotated = FixedEvent + .AddAnnotation(OculusXRTelemetry::Annotations::Uid, TCHAR_TO_ANSI(*Id.ToString())) + .AddAnnotation(OculusXRTelemetry::Annotations::Level, OculusXRPSTUtils::ToString(Severity)) + .AddAnnotation(OculusXRTelemetry::Annotations::Group, OculusXRPSTUtils::ToString(Category)) + .AddAnnotation(OculusXRTelemetry::Annotations::BuildTargetGroup, OculusXRPSTUtils::ToString(static_cast(Platform))) + .AddAnnotation(OculusXRTelemetry::Annotations::Value, "true"); + ApplyImpl(ShouldRestartEditor); +} + +bool ISetupRule::IsValid() +{ + return true; +} + +bool ISetupRule::IsIgnored() const +{ + return bIsIgnored; +} + +void ISetupRule::SetIgnoreRule(bool bIgnore, bool bSendMetrics) +{ + if (bSendMetrics) + { + const OculusXRTelemetry::TScopedMarker IgnoreEvent; + const auto& Annotated = IgnoreEvent + .AddAnnotation(OculusXRTelemetry::Annotations::Uid, TCHAR_TO_ANSI(*Id.ToString())) + .AddAnnotation(OculusXRTelemetry::Annotations::Level, OculusXRPSTUtils::ToString(Severity)) + .AddAnnotation(OculusXRTelemetry::Annotations::Group, OculusXRPSTUtils::ToString(Category)) + .AddAnnotation(OculusXRTelemetry::Annotations::BuildTargetGroup, OculusXRPSTUtils::ToString(static_cast(Platform))) + .AddAnnotation(OculusXRTelemetry::Annotations::Value, bIgnore ? "true" : "false"); + } + + if (bIsIgnored == bIgnore) + { + return; + } + bIsIgnored = bIgnore; + + if (bIgnore) + { + GetMutableDefault()->IgnoredRules.Add(Id); + } + else + { + GetMutableDefault()->IgnoredRules.Remove(Id); + } + GetMutableDefault()->SaveConfig(); +} + +const FName& ISetupRule::GetId() const +{ + return Id; +} +FText ISetupRule::GetDisplayName() const +{ + return DisplayName; +} +FText ISetupRule::GetDescription() const +{ + return Description; +} +ESetupRuleCategory ISetupRule::GetCategory() const +{ + return Category; +} +ESetupRuleSeverity ISetupRule::GetSeverity() const +{ + return Severity; +} + +ESetupRulePlatform ISetupRule::GetPlatform() const +{ + return Platform; +} diff --git a/Plugins/MetaXR/Source/OculusXRProjectSetupTool/Private/Rules/OculusXRAnchorsRules.cpp b/Plugins/MetaXR/Source/OculusXRProjectSetupTool/Private/Rules/OculusXRAnchorsRules.cpp new file mode 100644 index 0000000..113f625 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRProjectSetupTool/Private/Rules/OculusXRAnchorsRules.cpp @@ -0,0 +1,49 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#include "OculusXRAnchorsRules.h" +#include "CoreMinimal.h" +#include "OculusXRHMDRuntimeSettings.h" +#include "OculusXRAnchorComponents.h" +#include "OculusXRPSTUtils.h" +#include "OculusXRSceneActor.h" + +namespace OculusXRAnchorsRules +{ + bool FEnableAnchorSupportRule::IsApplied() const + { + const UOculusXRHMDRuntimeSettings* Settings = GetMutableDefault(); + + return Settings->bAnchorSupportEnabled; + } + + void FEnableAnchorSupportRule::ApplyImpl(bool& OutShouldRestartEditor) + { + OCULUSXR_UPDATE_SETTINGS(UOculusXRHMDRuntimeSettings, bAnchorSupportEnabled, true); + OutShouldRestartEditor = false; + } + + bool FEnableAnchorSupportRule::IsValid() + { + return OculusXRPSTUtils::IsComponentOfTypeInWorld() || OculusXRPSTUtils::IsComponentOfTypeInWorld(); + } + + bool FEnableSceneSupportRule::IsApplied() const + { + const UOculusXRHMDRuntimeSettings* Settings = GetMutableDefault(); + + return Settings->bSceneSupportEnabled; + } + + void FEnableSceneSupportRule::ApplyImpl(bool& OutShouldRestartEditor) + { + OCULUSXR_UPDATE_SETTINGS(UOculusXRHMDRuntimeSettings, bSceneSupportEnabled, true); + OutShouldRestartEditor = false; + } + + bool FEnableSceneSupportRule::IsValid() + { + return OculusXRPSTUtils::IsComponentOfTypeInWorld(); + } +} // namespace OculusXRAnchorsRules + +#undef LOCTEXT_NAMESPACE diff --git a/Plugins/MetaXR/Source/OculusXRProjectSetupTool/Private/Rules/OculusXRAnchorsRules.h b/Plugins/MetaXR/Source/OculusXRProjectSetupTool/Private/Rules/OculusXRAnchorsRules.h new file mode 100644 index 0000000..01b75b3 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRProjectSetupTool/Private/Rules/OculusXRAnchorsRules.h @@ -0,0 +1,49 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#pragma once +#include "OculusXRSetupRule.h" + +/* + * Collection of rules related to anchors. Can be extended as needed + */ +namespace OculusXRAnchorsRules +{ + class FEnableAnchorSupportRule final : public ISetupRule + { + public: + FEnableAnchorSupportRule() + : ISetupRule( + "Feature_EnableAnchorSupport", + NSLOCTEXT("OculusXRAnchorsRules", "EnableAnchorSupport_DisplayName", "Enable Anchor Support"), + NSLOCTEXT("OculusXRAnchorsRules", "EnableAnchorSupport_Description", "Anchor support must be enabled when using anchor features"), + ESetupRuleCategory::Features, + ESetupRuleSeverity::Critical) {} + virtual bool IsApplied() const override; + virtual bool IsValid() override; + + protected: + virtual void ApplyImpl(bool& OutShouldRestartEditor) override; + }; + + class FEnableSceneSupportRule final : public ISetupRule + { + public: + FEnableSceneSupportRule() + : ISetupRule( + "Feature_EnableSceneSupport", + NSLOCTEXT("OculusXRAnchorsRules", "EnableSceneSupport_DisplayName", "Enable Scene Support"), + NSLOCTEXT("OculusXRAnchorsRules", "EnableSceneSupport_Description", "Scene support must be enabled when using scene features"), + ESetupRuleCategory::Features, + ESetupRuleSeverity::Critical) {} + virtual bool IsApplied() const override; + virtual bool IsValid() override; + + protected: + virtual void ApplyImpl(bool& OutShouldRestartEditor) override; + }; + + inline TArray AnchorRules_Table{ + MakeShared(), + MakeShared() + }; +} // namespace OculusXRAnchorsRules diff --git a/Plugins/MetaXR/Source/OculusXRProjectSetupTool/Private/Rules/OculusXRCompatibilityRules.cpp b/Plugins/MetaXR/Source/OculusXRProjectSetupTool/Private/Rules/OculusXRCompatibilityRules.cpp new file mode 100644 index 0000000..0b4df4a --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRProjectSetupTool/Private/Rules/OculusXRCompatibilityRules.cpp @@ -0,0 +1,187 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#include "OculusXRCompatibilityRules.h" +#include "CoreMinimal.h" +#include "AndroidRuntimeSettings.h" +#include "GeneralProjectSettings.h" +#include "OculusXRRuleProcessorSubsystem.h" +#include "GameFramework/InputSettings.h" +#include "OculusXRHMDRuntimeSettings.h" +#include "OculusXRPSTUtils.h" + +#define LOCTEXT_NAMESPACE "OculusXRCompatibilityRules" +namespace +{ + constexpr int32 MinimumAndroidAPILevel = 32; + constexpr int32 TargetAndroidAPILevel = 32; +} // namespace + +namespace OculusXRCompatibilityRules +{ + + FUseAndroidSDKMinimumRule::FUseAndroidSDKMinimumRule() + : ISetupRule( + "Compatibility_UseAndroidSDKMinimum", + LOCTEXT("UseAndroidSDKMinimum_DisplayName", "Use Android SDK Minimum Version"), + FText::Format( + LOCTEXT("UseAndroidSDKMinimum_Description", "Minimum Android API level must be at least {0}."), + MinimumAndroidAPILevel), + ESetupRuleCategory::Compatibility, + ESetupRuleSeverity::Critical, + MetaQuest_All) {} + + bool FUseAndroidSDKMinimumRule::IsApplied() const + { + const UAndroidRuntimeSettings* Settings = GetMutableDefault(); + + return Settings->MinSDKVersion >= MinimumAndroidAPILevel; + } + + void FUseAndroidSDKMinimumRule::ApplyImpl(bool& OutShouldRestartEditor) + { + OCULUSXR_UPDATE_SETTINGS(UAndroidRuntimeSettings, MinSDKVersion, MinimumAndroidAPILevel); + OutShouldRestartEditor = false; + } + + FUseAndroidSDKTargetRule::FUseAndroidSDKTargetRule() + : ISetupRule( + "Compatibility_UseAndroidSDKTarget", + LOCTEXT("UseAndroidSDKTarget_DisplayName", "Use Android SDK Target Version"), + FText::Format( + LOCTEXT("UseAndroidSDKTarget_Description", "Target Android API level must be at least {0}."), + TargetAndroidAPILevel), + ESetupRuleCategory::Compatibility, + ESetupRuleSeverity::Critical, + MetaQuest_All) {} + + bool FUseAndroidSDKTargetRule::IsApplied() const + { + const UAndroidRuntimeSettings* Settings = GetMutableDefault(); + + return Settings->TargetSDKVersion >= TargetAndroidAPILevel; + } + + void FUseAndroidSDKTargetRule::ApplyImpl(bool& OutShouldRestartEditor) + { + OCULUSXR_UPDATE_SETTINGS(UAndroidRuntimeSettings, TargetSDKVersion, TargetAndroidAPILevel); + OutShouldRestartEditor = false; + } + + bool FUseArm64CPURule::IsApplied() const + { + const UAndroidRuntimeSettings* Settings = GetMutableDefault(); + + return Settings->bBuildForArm64 && !Settings->bBuildForX8664; + } + + void FUseArm64CPURule::ApplyImpl(bool& OutShouldRestartEditor) + { + OCULUSXR_UPDATE_SETTINGS(UAndroidRuntimeSettings, bBuildForArm64, true); + OCULUSXR_UPDATE_SETTINGS(UAndroidRuntimeSettings, bBuildForX8664, false); + OutShouldRestartEditor = false; + } + bool FEnablePackageForMetaQuestRule::IsApplied() const + { + const UAndroidRuntimeSettings* Settings = GetMutableDefault(); + + return Settings->bPackageForMetaQuest; + } + + void FEnablePackageForMetaQuestRule::ApplyImpl(bool& OutShouldRestartEditor) + { + OCULUSXR_UPDATE_SETTINGS(UAndroidRuntimeSettings, bPackageForMetaQuest, true); + OutShouldRestartEditor = false; + } + + bool FQuest2SupportedDeviceRule::IsApplied() const + { + const UOculusXRHMDRuntimeSettings* Settings = GetMutableDefault(); + + return Settings->SupportedDevices.Contains(EOculusXRSupportedDevices::Quest2); + } + + void FQuest2SupportedDeviceRule::ApplyImpl(bool& OutShouldRestartEditor) + { + UOculusXRHMDRuntimeSettings* Settings = GetMutableDefault(); + + Settings->SupportedDevices.Add(EOculusXRSupportedDevices::Quest2); + // UpdateSinglePropertyInConfigFile does not support arrays + Settings->SaveConfig(CPF_Config, *Settings->GetDefaultConfigFilename()); + OutShouldRestartEditor = false; + } + + bool FQuestProSupportedDeviceRule::IsApplied() const + { + const UOculusXRHMDRuntimeSettings* Settings = GetMutableDefault(); + + return Settings->SupportedDevices.Contains(EOculusXRSupportedDevices::QuestPro); + } + + void FQuestProSupportedDeviceRule::ApplyImpl(bool& OutShouldRestartEditor) + { + UOculusXRHMDRuntimeSettings* Settings = GetMutableDefault(); + + Settings->SupportedDevices.Add(EOculusXRSupportedDevices::QuestPro); + // UpdateSinglePropertyInConfigFile does not support arrays + Settings->SaveConfig(CPF_Config, *Settings->GetDefaultConfigFilename()); + OutShouldRestartEditor = false; + } + + bool FQuest3SupportedDeviceRule::IsApplied() const + { + const UOculusXRHMDRuntimeSettings* Settings = GetMutableDefault(); + + return Settings->SupportedDevices.Contains(EOculusXRSupportedDevices::Quest3); + } + + void FQuest3SupportedDeviceRule::ApplyImpl(bool& OutShouldRestartEditor) + { + UOculusXRHMDRuntimeSettings* Settings = GetMutableDefault(); + + Settings->SupportedDevices.Add(EOculusXRSupportedDevices::Quest3); + // UpdateSinglePropertyInConfigFile does not support arrays + Settings->SaveConfig(CPF_Config, *Settings->GetDefaultConfigFilename()); + OutShouldRestartEditor = false; + } + + bool FEnableFullscreenRule::IsApplied() const + { + const UAndroidRuntimeSettings* Settings = GetMutableDefault(); + + return Settings->bFullScreen; + } + + void FEnableFullscreenRule::ApplyImpl(bool& OutShouldRestartEditor) + { + OCULUSXR_UPDATE_SETTINGS(UAndroidRuntimeSettings, bFullScreen, true); + OutShouldRestartEditor = false; + } + + bool FEnableStartInVRRule::IsApplied() const + { + const UGeneralProjectSettings* Settings = GetDefault(); + + return Settings->bStartInVR != 0; + } + + void FEnableStartInVRRule::ApplyImpl(bool& OutShouldRestartEditor) + { + OCULUSXR_UPDATE_SETTINGS(UGeneralProjectSettings, bStartInVR, true); + OutShouldRestartEditor = false; + } + + bool FDisableTouchInterfaceRule::IsApplied() const + { + const UInputSettings* Settings = GetDefault(); + + return Settings->DefaultTouchInterface.IsNull(); + } + + void FDisableTouchInterfaceRule::ApplyImpl(bool& OutShouldRestartEditor) + { + OCULUSXR_UPDATE_SETTINGS(UInputSettings, DefaultTouchInterface, nullptr); + OutShouldRestartEditor = false; + } +} // namespace OculusXRCompatibilityRules + +#undef LOCTEXT_NAMESPACE diff --git a/Plugins/MetaXR/Source/OculusXRProjectSetupTool/Private/Rules/OculusXRCompatibilityRules.h b/Plugins/MetaXR/Source/OculusXRProjectSetupTool/Private/Rules/OculusXRCompatibilityRules.h new file mode 100644 index 0000000..da8c3d8 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRProjectSetupTool/Private/Rules/OculusXRCompatibilityRules.h @@ -0,0 +1,176 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#pragma once +#include "OculusXRSetupRule.h" + +// Collection of rules related to compatibility. Can be extended as needed +namespace OculusXRCompatibilityRules +{ + + class FUseAndroidSDKMinimumRule final : public ISetupRule + { + public: + FUseAndroidSDKMinimumRule(); + virtual bool IsApplied() const override; + + protected: + virtual void ApplyImpl(bool& OutShouldRestartEditor) override; + }; + + class FUseAndroidSDKTargetRule final : public ISetupRule + { + public: + FUseAndroidSDKTargetRule(); + virtual bool IsApplied() const override; + + protected: + virtual void ApplyImpl(bool& OutShouldRestartEditor) override; + }; + + class FUseArm64CPURule final : public ISetupRule + { + public: + FUseArm64CPURule() + : ISetupRule( + "Compatibility_UseArm64CPU", + NSLOCTEXT("OculusXRCompatibilityRules", "UseArm64CPU_DisplayName", "Use Arm64 CPU Architecture"), + NSLOCTEXT("OculusXRCompatibilityRules", "UseArm64CPU_Description", "Meta Quest store requires 64-bit applications"), + ESetupRuleCategory::Compatibility, + ESetupRuleSeverity::Critical, + MetaQuest_All) {} + virtual bool IsApplied() const override; + + protected: + virtual void ApplyImpl(bool& OutShouldRestartEditor) override; + }; + + class FEnablePackageForMetaQuestRule final : public ISetupRule + { + public: + FEnablePackageForMetaQuestRule() + : ISetupRule( + "Compatibility_UsePackageForMetaQuest", + NSLOCTEXT("OculusXRCompatibilityRules", "UsePackageForQuest_DisplayName", "Enable Package for Meta Quest devices"), + NSLOCTEXT("OculusXRCompatibilityRules", "UsePackageForQuest_Description", "\"Package for Meta Quest devices\" must be enabled."), + ESetupRuleCategory::Compatibility, + ESetupRuleSeverity::Critical, + MetaQuest_All) {} + virtual bool IsApplied() const override; + + protected: + virtual void ApplyImpl(bool& OutShouldRestartEditor) override; + }; + + class FQuest2SupportedDeviceRule final : public ISetupRule + { + public: + FQuest2SupportedDeviceRule() + : ISetupRule( + "Compatibility_UsePackageForQuest2", + NSLOCTEXT("OculusXRCompatibilityRules", "UsePackageForQuest_DisplayName", "Use Package for Quest2"), + NSLOCTEXT("OculusXRCompatibilityRules", "UsePackageForQuest_Description", "Meta Quest2 must be added to \"Supported Meta Quest Devices\"."), + ESetupRuleCategory::Compatibility, + ESetupRuleSeverity::Critical, + ESetupRulePlatform::MetaQuest_2) {} + virtual bool IsApplied() const override; + + protected: + virtual void ApplyImpl(bool& OutShouldRestartEditor) override; + }; + + class FQuestProSupportedDeviceRule final : public ISetupRule + { + public: + FQuestProSupportedDeviceRule() + : ISetupRule( + "Compatibility_UsePackageForQuestPro", + NSLOCTEXT("OculusXRCompatibilityRules", "UsePackageForQuest_DisplayName", "Use Package for QuestPro"), + NSLOCTEXT("OculusXRCompatibilityRules", "UsePackageForQuest_Description", "Meta QuestPro must be added to \"Supported Meta Quest Devices\"."), + ESetupRuleCategory::Compatibility, + ESetupRuleSeverity::Critical, + ESetupRulePlatform::MetaQuest_Pro) {} + virtual bool IsApplied() const override; + + protected: + virtual void ApplyImpl(bool& OutShouldRestartEditor) override; + }; + + class FQuest3SupportedDeviceRule final : public ISetupRule + { + public: + FQuest3SupportedDeviceRule() + : ISetupRule( + "Compatibility_UsePackageForQuest3", + NSLOCTEXT("OculusXRCompatibilityRules", "UsePackageForQuest_DisplayName", "Use Package for Quest3"), + NSLOCTEXT("OculusXRCompatibilityRules", "UsePackageForQuest_Description", "Meta Quest3 must be added to \"Supported Meta Quest Devices\"."), + ESetupRuleCategory::Compatibility, + ESetupRuleSeverity::Critical, + ESetupRulePlatform::MetaQuest_3) {} + virtual bool IsApplied() const override; + + protected: + virtual void ApplyImpl(bool& OutShouldRestartEditor) override; + }; + + class FEnableFullscreenRule final : public ISetupRule + { + public: + FEnableFullscreenRule() + : ISetupRule( + "Compatibility_EnableFullscreen", + NSLOCTEXT("OculusXRCompatibilityRules", "EnableFullscreen_DisplayName", "Enable Fullscreen"), + NSLOCTEXT("OculusXRCompatibilityRules", "EnableFullscreen_Description", "Android fullscreen must be enabled for VR"), + ESetupRuleCategory::Compatibility, + ESetupRuleSeverity::Warning, + MetaQuest_All) {} + virtual bool IsApplied() const override; + + protected: + virtual void ApplyImpl(bool& OutShouldRestartEditor) override; + }; + + class FEnableStartInVRRule final : public ISetupRule + { + public: + FEnableStartInVRRule() + : ISetupRule( + "Compatibility_EnableStartInVR", + NSLOCTEXT("OculusXRCompatibilityRules", "EnableStartInVR_DisplayName", "Enable Start in VR"), + NSLOCTEXT("OculusXRCompatibilityRules", "EnableStartInVR_Description", "Enable the \"Start in VR\" setting to ensure your app starts in VR. (You can also ignore this and pass -vr at the command line"), + ESetupRuleCategory::Compatibility, + ESetupRuleSeverity::Warning) {} + virtual bool IsApplied() const override; + + protected: + virtual void ApplyImpl(bool& OutShouldRestartEditor) override; + }; + + class FDisableTouchInterfaceRule final : public ISetupRule + { + public: + FDisableTouchInterfaceRule() + : ISetupRule( + "Compatibility_DisableTouchInterface", + NSLOCTEXT("OculusXRCompatibilityRules", "DisableTouchInterface_DisplayName", "Disable Touch Interface"), + NSLOCTEXT("OculusXRCompatibilityRules", "DisableTouchInterface_Description", "Touch interface will interfere with correct VR input behavior"), + ESetupRuleCategory::Compatibility, + ESetupRuleSeverity::Critical) {} + virtual bool IsApplied() const override; + + protected: + virtual void ApplyImpl(bool& OutShouldRestartEditor) override; + }; + + inline TArray CompatibilityRules_Table{ + MakeShared(), + MakeShared(), + MakeShared(), + MakeShared(), + MakeShared(), + MakeShared(), + MakeShared(), + MakeShared(), + MakeShared(), + MakeShared() + }; +} // namespace OculusXRCompatibilityRules diff --git a/Plugins/MetaXR/Source/OculusXRProjectSetupTool/Private/Rules/OculusXRMovementRules.cpp b/Plugins/MetaXR/Source/OculusXRProjectSetupTool/Private/Rules/OculusXRMovementRules.cpp new file mode 100644 index 0000000..1bf6052 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRProjectSetupTool/Private/Rules/OculusXRMovementRules.cpp @@ -0,0 +1,69 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#include "OculusXRMovementRules.h" +#include "CoreMinimal.h" +#include "OculusXRHMDRuntimeSettings.h" +#include "OculusXRPSTUtils.h" +#include "OculusXRBodyTrackingComponent.h" +#include "OculusXREyeTrackingComponent.h" +#include "OculusXRFaceTrackingComponent.h" +#include "OculusXRProjectSetupToolModule.h" +#include "OculusXRRuleProcessorSubsystem.h" + +namespace OculusXRMovementRules +{ + bool FEnableBodyTrackingRule::IsApplied() const + { + const UOculusXRHMDRuntimeSettings* Settings = GetMutableDefault(); + return Settings->bBodyTrackingEnabled; + } + + void FEnableBodyTrackingRule::ApplyImpl(bool& OutShouldRestartEditor) + { + OCULUSXR_UPDATE_SETTINGS(UOculusXRHMDRuntimeSettings, bBodyTrackingEnabled, true); + OutShouldRestartEditor = false; + } + + bool FEnableBodyTrackingRule::IsValid() + { + return OculusXRPSTUtils::IsComponentOfTypeInWorld(); + } + + bool FEnableFaceTrackingRule::IsApplied() const + { + const UOculusXRHMDRuntimeSettings* Settings = GetMutableDefault(); + + return Settings->bFaceTrackingEnabled; + } + + void FEnableFaceTrackingRule::ApplyImpl(bool& OutShouldRestartEditor) + { + OCULUSXR_UPDATE_SETTINGS(UOculusXRHMDRuntimeSettings, bFaceTrackingEnabled, true); + OutShouldRestartEditor = false; + } + + bool FEnableFaceTrackingRule::IsValid() + { + return OculusXRPSTUtils::IsComponentOfTypeInWorld(); + } + + bool FEnableEyeTrackingRule::IsApplied() const + { + const UOculusXRHMDRuntimeSettings* Settings = GetMutableDefault(); + + return Settings->bEyeTrackingEnabled; + } + + void FEnableEyeTrackingRule::ApplyImpl(bool& OutShouldRestartEditor) + { + OCULUSXR_UPDATE_SETTINGS(UOculusXRHMDRuntimeSettings, bEyeTrackingEnabled, true); + OutShouldRestartEditor = false; + } + + bool FEnableEyeTrackingRule::IsValid() + { + return OculusXRPSTUtils::IsComponentOfTypeInWorld(); + } +} // namespace OculusXRMovementRules + +#undef LOCTEXT_NAMESPACE diff --git a/Plugins/MetaXR/Source/OculusXRProjectSetupTool/Private/Rules/OculusXRMovementRules.h b/Plugins/MetaXR/Source/OculusXRProjectSetupTool/Private/Rules/OculusXRMovementRules.h new file mode 100644 index 0000000..7a0461c --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRProjectSetupTool/Private/Rules/OculusXRMovementRules.h @@ -0,0 +1,67 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#pragma once +#include "OculusXRSetupRule.h" + +/* + * Collection of rules related to movement SDK. Can be extended as needed + */ +namespace OculusXRMovementRules +{ + class FEnableBodyTrackingRule final : public ISetupRule + { + public: + FEnableBodyTrackingRule() + : ISetupRule( + "Feature_EnableBodyTracking", + NSLOCTEXT("OculusXRMovementRules", "EnableBodyTracking_DisplayName", "Enable Body Tracking"), + NSLOCTEXT("OculusXRMovementRules", "EnableBodyTracking_Description", "Body tracking must be enabled when using body tracking features"), + ESetupRuleCategory::Features, + ESetupRuleSeverity::Critical) {} + virtual bool IsApplied() const override; + virtual bool IsValid() override; + + protected: + virtual void ApplyImpl(bool& OutShouldRestartEditor) override; + }; + + class FEnableFaceTrackingRule final : public ISetupRule + { + public: + FEnableFaceTrackingRule() + : ISetupRule( + "Feature_EnableFaceTracking", + NSLOCTEXT("OculusXRMovementRules", "EnableFaceTracking_DisplayName", "Enable Face Tracking"), + NSLOCTEXT("OculusXRMovementRules", "EnableFaceTracking_Description", "Face tracking must be enabled when using face tracking features"), + ESetupRuleCategory::Features, + ESetupRuleSeverity::Critical) {} + virtual bool IsApplied() const override; + virtual bool IsValid() override; + + protected: + virtual void ApplyImpl(bool& OutShouldRestartEditor) override; + }; + + class FEnableEyeTrackingRule final : public ISetupRule + { + public: + FEnableEyeTrackingRule() + : ISetupRule( + "Feature_EnableEyeTracking", + NSLOCTEXT("OculusXRMovementRules", "EnableEyeTracking_DisplayName", "Enable Eye Tracking"), + NSLOCTEXT("OculusXRMovementRules", "EnableEyeTracking_Description", "Eye tracking must be enabled when using eye tracking features"), + ESetupRuleCategory::Features, + ESetupRuleSeverity::Critical) {} + virtual bool IsApplied() const override; + virtual bool IsValid() override; + + protected: + virtual void ApplyImpl(bool& OutShouldRestartEditor) override; + }; + + inline TArray MovementRules_Table{ + MakeShared(), + MakeShared(), + MakeShared() + }; +} // namespace OculusXRMovementRules diff --git a/Plugins/MetaXR/Source/OculusXRProjectSetupTool/Private/Rules/OculusXRPassthroughRules.cpp b/Plugins/MetaXR/Source/OculusXRProjectSetupTool/Private/Rules/OculusXRPassthroughRules.cpp new file mode 100644 index 0000000..320ea2d --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRProjectSetupTool/Private/Rules/OculusXRPassthroughRules.cpp @@ -0,0 +1,50 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#include "OculusXRPassthroughRules.h" +#include "CoreMinimal.h" +#include "OculusXRHMDRuntimeSettings.h" +#include "OculusXRPSTUtils.h" +#include "OculusXRPassthroughLayerComponent.h" +#include "OculusXRProjectSetupToolModule.h" +#include "OculusXRRuleProcessorSubsystem.h" +#include "Engine/RendererSettings.h" + +namespace OculusXRPassthroughRules +{ + bool FEnablePassthroughRule::IsApplied() const + { + const UOculusXRHMDRuntimeSettings* Settings = GetMutableDefault(); + + return Settings->bInsightPassthroughEnabled; + } + + void FEnablePassthroughRule::ApplyImpl(bool& OutShouldRestartEditor) + { + OCULUSXR_UPDATE_SETTINGS(UOculusXRHMDRuntimeSettings, bInsightPassthroughEnabled, true); + OutShouldRestartEditor = false; + } + + bool FEnablePassthroughRule::IsValid() + { + return OculusXRPSTUtils::IsComponentOfTypeInWorld(); + } + + bool FAllowAlphaToneMapperPassthroughRule::IsApplied() const + { + URendererSettings* Settings = GetMutableDefault(); + return Settings->bEnableAlphaChannelInPostProcessing == EAlphaChannelMode::AllowThroughTonemapper; + } + + bool FAllowAlphaToneMapperPassthroughRule::IsValid() + { + return OculusXRPSTUtils::IsComponentOfTypeInWorld(); + } + + void FAllowAlphaToneMapperPassthroughRule::ApplyImpl(bool& OutShouldRestartEditor) + { + OCULUSXR_UPDATE_SETTINGS(URendererSettings, bEnableAlphaChannelInPostProcessing, EAlphaChannelMode::AllowThroughTonemapper); + OutShouldRestartEditor = true; + } +} // namespace OculusXRPassthroughRules + +#undef LOCTEXT_NAMESPACE diff --git a/Plugins/MetaXR/Source/OculusXRProjectSetupTool/Private/Rules/OculusXRPassthroughRules.h b/Plugins/MetaXR/Source/OculusXRProjectSetupTool/Private/Rules/OculusXRPassthroughRules.h new file mode 100644 index 0000000..368c109 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRProjectSetupTool/Private/Rules/OculusXRPassthroughRules.h @@ -0,0 +1,49 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#pragma once +#include "OculusXRSetupRule.h" + +/* + * Collection of rules related to passthrough. Can be extended as needed + */ +namespace OculusXRPassthroughRules +{ + class FEnablePassthroughRule final : public ISetupRule + { + public: + FEnablePassthroughRule() + : ISetupRule( + "Feature_EnablePassthrough", + NSLOCTEXT("OculusXRPassthroughRules", "EnablePassthrough_DisplayName", "Enable Passthrough"), + NSLOCTEXT("OculusXRPassthroughRules", "EnablePassthrough_Description", "Passthrough must be enabled when using passthrough features"), + ESetupRuleCategory::Features, + ESetupRuleSeverity::Critical) {} + virtual bool IsApplied() const override; + virtual bool IsValid() override; + + protected: + virtual void ApplyImpl(bool& OutShouldRestartEditor) override; + }; + + class FAllowAlphaToneMapperPassthroughRule final : public ISetupRule + { + public: + FAllowAlphaToneMapperPassthroughRule() + : ISetupRule( + "Feature_AllowAlphaToneMapperPassthrough", + NSLOCTEXT("OculusXRPassthroughRules", "AllowAlphaToneMapperPassthrough_DisplayName", "Enable passing alpha channel through tonemapper"), + NSLOCTEXT("OculusXRPassthroughRules", "AllowAlphaToneMapperPassthrough_Description", "For passthrough to work over Link alpha channel must be passed through tonemapper."), + ESetupRuleCategory::Features, + ESetupRuleSeverity::Warning) {} + virtual bool IsApplied() const override; + virtual bool IsValid() override; + + protected: + virtual void ApplyImpl(bool& OutShouldRestartEditor) override; + }; + + inline TArray PassthroughRules_Table{ + MakeShared(), + MakeShared() + }; +} // namespace OculusXRPassthroughRules diff --git a/Plugins/MetaXR/Source/OculusXRProjectSetupTool/Private/Rules/OculusXRPluginRules.cpp b/Plugins/MetaXR/Source/OculusXRProjectSetupTool/Private/Rules/OculusXRPluginRules.cpp new file mode 100644 index 0000000..2940e07 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRProjectSetupTool/Private/Rules/OculusXRPluginRules.cpp @@ -0,0 +1,80 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#include "OculusXRPluginRules.h" +#include "CoreMinimal.h" +#include "OculusXRHMDRuntimeSettings.h" +#include "OculusXRPSTUtils.h" +#include "Editor/GameProjectGeneration/Public/GameProjectGenerationModule.h" +#include "Interfaces/IPluginManager.h" +#include "Interfaces/IProjectManager.h" + +namespace OculusXRPluginRules +{ + namespace + { + bool IsPluginEnabled(const FString& PluginName) + { + const auto Plugin = IPluginManager::Get().FindPlugin(PluginName); + if (!Plugin) + { + return false; + } + + return Plugin->IsEnabled(); + } + + bool DisablePlugin(const FString& PluginName) + { + FText FailMessage; + bool bSuccess = IProjectManager::Get().SetPluginEnabled( + PluginName, false, FailMessage); + const bool bIsProjectDirty = IProjectManager::Get().IsCurrentProjectDirty(); + if (bSuccess && bIsProjectDirty) + { + FGameProjectGenerationModule::Get().TryMakeProjectFileWriteable(FPaths::GetProjectFilePath()); + bSuccess = IProjectManager::Get().SaveCurrentProjectToDisk(FailMessage); + } + if (!bSuccess) + { + FMessageDialog::Open(EAppMsgType::Ok, FailMessage); + } + + return bSuccess && !bIsProjectDirty; + } + } // namespace + bool FUseRecommendedXRAPIRule::IsApplied() const + { + const UOculusXRHMDRuntimeSettings* Settings = GetMutableDefault(); + return Settings->XrApi == EOculusXRXrApi::OVRPluginOpenXR; + } + + void FUseRecommendedXRAPIRule::ApplyImpl(bool& OutShouldRestartEditor) + { + OCULUSXR_UPDATE_SETTINGS(UOculusXRHMDRuntimeSettings, XrApi, EOculusXRXrApi::OVRPluginOpenXR); + OutShouldRestartEditor = false; + } + + bool FDisableOculusVRRule::IsApplied() const + { + return bApplied || !IsPluginEnabled(PluginName); + } + + void FDisableOculusVRRule::ApplyImpl(bool& OutShouldRestartEditor) + { + OutShouldRestartEditor = DisablePlugin(PluginName); + bApplied = OutShouldRestartEditor; + } + + bool FDisableSteamVRRule::IsApplied() const + { + return bApplied || !IsPluginEnabled(PluginName); + } + + void FDisableSteamVRRule::ApplyImpl(bool& OutShouldRestartEditor) + { + OutShouldRestartEditor = DisablePlugin(PluginName); + bApplied = OutShouldRestartEditor; + } +} // namespace OculusXRPluginRules + +#undef LOCTEXT_NAMESPACE diff --git a/Plugins/MetaXR/Source/OculusXRProjectSetupTool/Private/Rules/OculusXRPluginRules.h b/Plugins/MetaXR/Source/OculusXRProjectSetupTool/Private/Rules/OculusXRPluginRules.h new file mode 100644 index 0000000..f1592ba --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRProjectSetupTool/Private/Rules/OculusXRPluginRules.h @@ -0,0 +1,71 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#pragma once +#include "OculusXRSetupRule.h" + +// Collection of rules related to plugins. Can be extended as needed +namespace OculusXRPluginRules +{ + class FUseRecommendedXRAPIRule final : public ISetupRule + { + public: + FUseRecommendedXRAPIRule() + : ISetupRule("Plugin_UseRecommendedXRAPI", + NSLOCTEXT("OculusXRPluginRules", "UseRecommendedXRAPI_DisplayName", "Use Recommended XR API"), + NSLOCTEXT("OculusXRPluginRules", "UseRecommendedXRAPI_Description", "It is currently recommended to use OVRPlugin + OpenXR for the XR API"), + ESetupRuleCategory::Plugins, + ESetupRuleSeverity::Warning) {} + + virtual bool IsApplied() const override; + + protected: + virtual void ApplyImpl(bool& OutShouldRestartEditor) override; + }; + + class FDisableOculusVRRule final : public ISetupRule + { + public: + FDisableOculusVRRule() + : ISetupRule("Plugin_DisableOculusVR", + NSLOCTEXT("OculusXRPluginRules", "DisableOculusVR_DisplayName", "Disable OculusVR Plugin"), + NSLOCTEXT("OculusXRPluginRules", "DisableOculusVR_Description", "The OculusVR plugin is deprecated and should be disabled"), + ESetupRuleCategory::Plugins, + ESetupRuleSeverity::Warning) {} + + virtual bool IsApplied() const override; + + protected: + virtual void ApplyImpl(bool& OutShouldRestartEditor) override; + + private: + FString PluginName = "OculusVR"; + bool bApplied = false; + }; + + class FDisableSteamVRRule final : public ISetupRule + { + public: + FDisableSteamVRRule() + : ISetupRule("Plugin_DisableSteamVR", + NSLOCTEXT("OculusXRPluginRules", "DisableSteamVR_DisplayName", "Disable SteamVR Plugin"), + NSLOCTEXT("OculusXRPluginRules", "DisableSteamVR_Description", "The SteamVR plugin is deprecated and should be disabled"), + ESetupRuleCategory::Plugins, + ESetupRuleSeverity::Warning) {} + + virtual bool IsApplied() const override; + + protected: + virtual void ApplyImpl(bool& OutShouldRestartEditor) override; + + private: + FString PluginName = "SteamVR"; + bool bApplied = false; + }; + + // All defined plugin rules. Add new rules to this table for them to be auto-registered + inline TArray PluginRules_Table{ + MakeShared(), + MakeShared(), + MakeShared() + }; +} // namespace OculusXRPluginRules diff --git a/Plugins/MetaXR/Source/OculusXRProjectSetupTool/Private/Rules/OculusXRRenderingRules.cpp b/Plugins/MetaXR/Source/OculusXRProjectSetupTool/Private/Rules/OculusXRRenderingRules.cpp new file mode 100644 index 0000000..7c590fe --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRProjectSetupTool/Private/Rules/OculusXRRenderingRules.cpp @@ -0,0 +1,246 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#include "OculusXRRenderingRules.h" +#include "CoreMinimal.h" +#include "AndroidRuntimeSettings.h" +#include "EngineUtils.h" +#include "OculusXRHMDRuntimeSettings.h" +#include "OculusXRPSTUtils.h" +#include "OculusXRRuleProcessorSubsystem.h" +#include "Engine/PostProcessVolume.h" +#include "Engine/RendererSettings.h" + +namespace OculusXRRenderingRules +{ + bool FUseVulkanRule::IsApplied() const + { + const UAndroidRuntimeSettings* Settings = GetMutableDefault(); + + return Settings->bSupportsVulkan && !Settings->bBuildForES31; + } + + void FUseVulkanRule::ApplyImpl(bool& OutShouldRestartEditor) + { + OCULUSXR_UPDATE_SETTINGS(UAndroidRuntimeSettings, bSupportsVulkan, true); + OCULUSXR_UPDATE_SETTINGS(UAndroidRuntimeSettings, bBuildForES31, false); + OutShouldRestartEditor = false; + } + + bool FUseHalfPrecisionFloatRule::IsApplied() const + { + const URendererSettings* Settings = GetMutableDefault(); + + return Settings->MobileFloatPrecisionMode == EMobileFloatPrecisionMode::Half; + } + + void FUseHalfPrecisionFloatRule::ApplyImpl(bool& OutShouldRestartEditor) + { + OCULUSXR_UPDATE_SETTINGS(URendererSettings, MobileFloatPrecisionMode, EMobileFloatPrecisionMode::Half); + OutShouldRestartEditor = true; + } + + bool FEnableInstancedStereoRule::IsApplied() const + { + const URendererSettings* Settings = GetMutableDefault(); + return Settings->bMultiView != 0; + } + + void FEnableInstancedStereoRule::ApplyImpl(bool& OutShouldRestartEditor) + { + OCULUSXR_UPDATE_SETTINGS(URendererSettings, bMultiView, 1); + OutShouldRestartEditor = true; + } + + bool FEnableForwardShadingRule::IsApplied() const + { + const URendererSettings* Settings = GetMutableDefault(); + + return Settings->MobileShadingPath == EMobileShadingPath::Forward; + } + + void FEnableForwardShadingRule::ApplyImpl(bool& OutShouldRestartEditor) + { + OCULUSXR_UPDATE_SETTINGS(URendererSettings, MobileShadingPath, EMobileShadingPath::Forward); + OutShouldRestartEditor = true; + } + + bool FEnableMSAARule::IsApplied() const + { + const URendererSettings* Settings = GetMutableDefault(); + return Settings->MobileAntiAliasing == EMobileAntiAliasingMethod::MSAA + && Settings->MSAASampleCount == ECompositingSampleCount::Four; + } + + void FEnableMSAARule::ApplyImpl(bool& OutShouldRestartEditor) + { + OCULUSXR_UPDATE_SETTINGS(URendererSettings, MobileAntiAliasing, EMobileAntiAliasingMethod::MSAA); + OCULUSXR_UPDATE_SETTINGS(URendererSettings, MSAASampleCount, ECompositingSampleCount::Four); + + OutShouldRestartEditor = false; + } + + bool FEnableOcclusionCullingRule::IsApplied() const + { + const URendererSettings* Settings = GetMutableDefault(); + + return Settings->bOcclusionCulling; + } + + void FEnableOcclusionCullingRule::ApplyImpl(bool& OutShouldRestartEditor) + { + OCULUSXR_UPDATE_SETTINGS(URendererSettings, bOcclusionCulling, 1); + OutShouldRestartEditor = false; + } + + bool FEnableDynamicFoveationRule::IsApplied() const + { + const UOculusXRHMDRuntimeSettings* Settings = GetMutableDefault(); + + return Settings->bDynamicFoveatedRendering; + } + + void FEnableDynamicFoveationRule::ApplyImpl(bool& OutShouldRestartEditor) + { + OCULUSXR_UPDATE_SETTINGS(UOculusXRHMDRuntimeSettings, bDynamicFoveatedRendering, true); + OutShouldRestartEditor = false; + } + +#ifdef WITH_OCULUS_BRANCH + bool FEnableDynamicResolutionRule::IsApplied() const + { + const UOculusXRHMDRuntimeSettings* Settings = GetMutableDefault(); + + return Settings->bDynamicResolution; + } + + void FEnableDynamicResolutionRule::ApplyImpl(bool& OutShouldRestartEditor) + { + OCULUSXR_UPDATE_SETTINGS(UOculusXRHMDRuntimeSettings, bDynamicResolution, true); + OutShouldRestartEditor = false; + } +#endif + + bool FDisableLensFlareRule::IsApplied() const + { + const URendererSettings* Settings = GetMutableDefault(); + for (TActorIterator ActorItr(GEditor->GetEditorWorldContext().World()); ActorItr; ++ActorItr) + { + if (ActorItr->Settings.LensFlareIntensity > 0.0f) + { + return false; + } + } + return Settings->bDefaultFeatureLensFlare == 0; + } + + void FDisableLensFlareRule::ApplyImpl(bool& OutShouldRestartEditor) + { + OCULUSXR_UPDATE_SETTINGS(URendererSettings, bDefaultFeatureLensFlare, false); + + for (TActorIterator ActorItr(GEditor->GetEditorWorldContext().World()); ActorItr; ++ActorItr) + { + ActorItr->Settings.LensFlareIntensity = 0.0f; + } + GetMutableDefault()->SaveConfig(); + OutShouldRestartEditor = false; + } + + bool FDisablePostProcessingRule::IsApplied() const + { + const URendererSettings* Settings = GetMutableDefault(); + + return Settings->bMobilePostProcessing == 0; + } + + void FDisablePostProcessingRule::ApplyImpl(bool& OutShouldRestartEditor) + { + OCULUSXR_UPDATE_SETTINGS(URendererSettings, bMobilePostProcessing, 0); + OutShouldRestartEditor = true; + } + + bool FDisableAmbientOcclusionRule::IsApplied() const + { + const URendererSettings* Settings = GetMutableDefault(); + + return Settings->bMobileAmbientOcclusion == 0; + } + + void FDisableAmbientOcclusionRule::ApplyImpl(bool& OutShouldRestartEditor) + { + OCULUSXR_UPDATE_SETTINGS(URendererSettings, bMobileAmbientOcclusion, 0); + OutShouldRestartEditor = true; + } + + bool FEnableMultiViewRule::IsApplied() const + { + return GetMutableDefault()->bMobileMultiView != 0; + } + + void FEnableMultiViewRule::ApplyImpl(bool& OutShouldRestartEditor) + { + OCULUSXR_UPDATE_SETTINGS(URendererSettings, bMobileMultiView, 1); + OutShouldRestartEditor = true; + } + + bool FEnableStaticLightingRule::IsApplied() const + { + return GetMutableDefault()->bAllowStaticLighting; + } + + void FEnableStaticLightingRule::ApplyImpl(bool& OutShouldRestartEditor) + { + OCULUSXR_UPDATE_SETTINGS(URendererSettings, bAllowStaticLighting, true); + OutShouldRestartEditor = true; + } + + bool FDisableMobileShaderStaticAndCSMShadowReceiversRule::IsApplied() const + { + return !GetMutableDefault()->bMobileEnableStaticAndCSMShadowReceivers; + } + + void FDisableMobileShaderStaticAndCSMShadowReceiversRule::ApplyImpl(bool& OutShouldRestartEditor) + { + OCULUSXR_UPDATE_SETTINGS(URendererSettings, bMobileEnableStaticAndCSMShadowReceivers, false); + OutShouldRestartEditor = false; + } + + bool FDisableMobileShaderStaticAndCSMShadowReceiversRule::IsValid() + { + const UOculusXRRuleProcessorSubsystem* RuleProcessorSubsystem = GEngine->GetEngineSubsystem(); + return !RuleProcessorSubsystem->DynamicLightsExistInProject(); + } + + bool FDisableMobileShaderAllowDistanceFieldShadowsRule::IsApplied() const + { + return !GetMutableDefault()->bMobileAllowDistanceFieldShadows; + } + + void FDisableMobileShaderAllowDistanceFieldShadowsRule::ApplyImpl(bool& OutShouldRestartEditor) + { + OCULUSXR_UPDATE_SETTINGS(URendererSettings, bMobileAllowDistanceFieldShadows, false); + OutShouldRestartEditor = true; + } + + bool FDisableMobileShaderAllowDistanceFieldShadowsRule::IsValid() + { + const UOculusXRRuleProcessorSubsystem* RuleProcessorSubsystem = GEngine->GetEngineSubsystem(); + return !RuleProcessorSubsystem->DynamicLightsExistInProject(); + } + + bool FDisableMobileShaderAllowMovableDirectionalLightsRule::IsApplied() const + { + return !GetMutableDefault()->bMobileAllowMovableDirectionalLights; + } + + void FDisableMobileShaderAllowMovableDirectionalLightsRule::ApplyImpl(bool& OutShouldRestartEditor) + { + OCULUSXR_UPDATE_SETTINGS(URendererSettings, bMobileAllowMovableDirectionalLights, false); + OutShouldRestartEditor = true; + } + + bool FDisableMobileShaderAllowMovableDirectionalLightsRule::IsValid() + { + const UOculusXRRuleProcessorSubsystem* RuleProcessorSubsystem = GEngine->GetEngineSubsystem(); + return !RuleProcessorSubsystem->DynamicLightsExistInProject(); + } +} // namespace OculusXRRenderingRules diff --git a/Plugins/MetaXR/Source/OculusXRProjectSetupTool/Private/Rules/OculusXRRenderingRules.h b/Plugins/MetaXR/Source/OculusXRProjectSetupTool/Private/Rules/OculusXRRenderingRules.h new file mode 100644 index 0000000..32e8433 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRProjectSetupTool/Private/Rules/OculusXRRenderingRules.h @@ -0,0 +1,293 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#pragma once + +#include "OculusXRSetupRule.h" + +// Collection of rules related to rendering. Can be extended as needed +namespace OculusXRRenderingRules +{ + class FUseVulkanRule final : public ISetupRule + { + public: + FUseVulkanRule() + : ISetupRule("Rendering_UseVulkan", + NSLOCTEXT("OculusXRRenderingRules", "UseVulkan_DisplayName", "Use Vulkan Rendering Backend"), + NSLOCTEXT("OculusXRRenderingRules", "UseVulkan_Description", "Oculus recommends using Vulkan as the rendering backend for all mobile apps."), + ESetupRuleCategory::Rendering, + ESetupRuleSeverity::Performance, + MetaQuest_All) {} + virtual bool IsApplied() const override; + + protected: + virtual void ApplyImpl(bool& OutShouldRestartEditor) override; + }; + + class FUseHalfPrecisionFloatRule final : public ISetupRule + { + public: + FUseHalfPrecisionFloatRule() + : ISetupRule("Rendering_UseHalfPrecisionFloat", + NSLOCTEXT("OculusXRRenderingRules", "UseHalfPrecisionFloat_DisplayName", "Use Half Precision Float"), + NSLOCTEXT("OculusXRRenderingRules", "UseHalfPrecisionFloat_Description", "Half precision float provides increased shader performance."), + ESetupRuleCategory::Rendering, + ESetupRuleSeverity::Performance, + MetaQuest_All) {} + virtual bool IsApplied() const override; + + protected: + virtual void ApplyImpl(bool& OutShouldRestartEditor) override; + }; + + class FEnableInstancedStereoRule final : public ISetupRule + { + public: + FEnableInstancedStereoRule() + : ISetupRule("Rendering_EnableInstancedStereo", + NSLOCTEXT("OculusXRRenderingRules", "EnableInstancedStereo_DisplayName", "Enable Instanced Stereo"), + NSLOCTEXT("OculusXRRenderingRules", "EnableInstancedStereo_Description", "Instanced stereo substantially reduces draw calls, and improves rendering performance."), + ESetupRuleCategory::Rendering, + ESetupRuleSeverity::Performance, + ESetupRulePlatform::MetaLink) {} + virtual bool IsApplied() const override; + + protected: + virtual void ApplyImpl(bool& OutShouldRestartEditor) override; + }; + + class FEnableForwardShadingRule final : public ISetupRule + { + public: + FEnableForwardShadingRule() + : ISetupRule("Rendering_EnableForwardShading", + NSLOCTEXT("OculusXRRenderingRules", "EnableForwardShading_DisplayName", "Enable Forward Shading"), + NSLOCTEXT("OculusXRRenderingRules", "EnableForwardShading_Description", "Forward shading is often better suited for VR rendering."), + ESetupRuleCategory::Rendering, + ESetupRuleSeverity::Performance, + ESetupRulePlatform::MetaQuest_2) {} + virtual bool IsApplied() const override; + + protected: + virtual void ApplyImpl(bool& OutShouldRestartEditor) override; + }; + + class FEnableMSAARule final : public ISetupRule + { + public: + FEnableMSAARule() + : ISetupRule("Rendering_EnableMSAA", + NSLOCTEXT("OculusXRRenderingRules", "EnableMSAA_DisplayName", "Enable MSAA"), + NSLOCTEXT("OculusXRRenderingRules", "EnableMSAA_Description", "MSAA provides higher quality antialiasing at a reasonable cost."), + ESetupRuleCategory::Rendering, + ESetupRuleSeverity::Performance, + MetaQuest_All) {} + virtual bool IsApplied() const override; + + protected: + virtual void ApplyImpl(bool& OutShouldRestartEditor) override; + }; + + class FEnableOcclusionCullingRule final : public ISetupRule + { + public: + FEnableOcclusionCullingRule() + : ISetupRule("Rendering_EnableOcclusionCulling", + NSLOCTEXT("OculusXRRenderingRules", "EnableOcclusionCulling_DisplayName", "Enable Occlusion Culling"), + NSLOCTEXT("OculusXRRenderingRules", "EnableOcclusionCulling_Description", "Occlusion culling can provide significant performance gains."), + ESetupRuleCategory::Rendering, + ESetupRuleSeverity::Performance) {} + virtual bool IsApplied() const override; + + protected: + virtual void ApplyImpl(bool& OutShouldRestartEditor) override; + }; + + class FEnableDynamicFoveationRule final : public ISetupRule + { + public: + FEnableDynamicFoveationRule() + : ISetupRule("Rendering_EnableDynamicFoveation", + NSLOCTEXT("OculusXRRenderingRules", "EnableDynamicFoveation_DisplayName", "Enable Dynamic Foveation"), + NSLOCTEXT("OculusXRRenderingRules", "EnableDynamicFoveation_Description", "Dynamic foveated rendering significantly reduces rendering cost."), + ESetupRuleCategory::Rendering, + ESetupRuleSeverity::Performance, + MetaQuest_All) {} + virtual bool IsApplied() const override; + + protected: + virtual void ApplyImpl(bool& OutShouldRestartEditor) override; + }; + +#ifdef WITH_OCULUS_BRANCH + class FEnableDynamicResolutionRule final : public ISetupRule + { + public: + FEnableDynamicResolutionRule() + : ISetupRule("Rendering_EnableDynamicResolution", + NSLOCTEXT("OculusXRRenderingRules", "EnableDynamicResolution_DisplayName", "Enable Dynamic Resolution"), + NSLOCTEXT("OculusXRRenderingRules", "EnableDynamicResolution_Description", "Dynamic resolution rendering significantly reduces rendering cost."), + ESetupRuleCategory::Rendering, + ESetupRuleSeverity::Performance, + MetaQuest_All) {} + virtual bool IsApplied() const override; + + protected: + virtual void ApplyImpl(bool& OutShouldRestartEditor) override; + }; +#endif + + class FDisableLensFlareRule final : public ISetupRule + { + public: + FDisableLensFlareRule() + : ISetupRule("Rendering_DisableLensFlare", + NSLOCTEXT("OculusXRRenderingRules", "DisableLensFlare_DisplayName", "Disable Lens Flare"), + NSLOCTEXT("OculusXRRenderingRules", "DisableLensFlare_Description", "Lens flare can be expensive and exhibit visible artifacts in VR."), + ESetupRuleCategory::Rendering, + ESetupRuleSeverity::Performance) {} + virtual bool IsApplied() const override; + + protected: + virtual void ApplyImpl(bool& OutShouldRestartEditor) override; + }; + + class FDisablePostProcessingRule final : public ISetupRule + { + public: + FDisablePostProcessingRule() + : ISetupRule("Rendering_DisablePostProcessing", + NSLOCTEXT("OculusXRRenderingRules", "DisablePostProcessing_DisplayName", "Disable Post Processing"), + NSLOCTEXT("OculusXRRenderingRules", "DisablePostProcessing_Description", "Mobile HDR has performance and stability issues in VR. We strongly recommend disabling it."), + ESetupRuleCategory::Rendering, + ESetupRuleSeverity::Performance, + MetaQuest_All) {} + virtual bool IsApplied() const override; + + protected: + virtual void ApplyImpl(bool& OutShouldRestartEditor) override; + }; + + class FDisableAmbientOcclusionRule final : public ISetupRule + { + public: + FDisableAmbientOcclusionRule() + : ISetupRule("Rendering_DisableAmbientOcclusion", + NSLOCTEXT("OculusXRRenderingRules", "DisableAmbientOcclusion_DisplayName", "Disable Ambient Occlusion"), + NSLOCTEXT("OculusXRRenderingRules", "DisableAmbientOcclusion_Description", "Ambient occlusion has performance issues. We recommend disabling it."), + ESetupRuleCategory::Rendering, + ESetupRuleSeverity::Performance, + MetaQuest_All) {} + virtual bool IsApplied() const override; + + protected: + virtual void ApplyImpl(bool& OutShouldRestartEditor) override; + }; + + class FEnableMultiViewRule final : public ISetupRule + { + public: + FEnableMultiViewRule() + : ISetupRule("Rendering_EnableMultiView", + NSLOCTEXT("OculusXRRenderingRules", "EnableMultiView_DisplayName", "Enable Mobile Multiveiw"), + NSLOCTEXT("OculusXRRenderingRules", "EnableMultiView_Description", "Enable mobile multi-view and direct mobile multi-view to significantly reduce CPU overhead."), + ESetupRuleCategory::Rendering, + ESetupRuleSeverity::Performance, + MetaQuest_All) {} + virtual bool IsApplied() const override; + + protected: + virtual void ApplyImpl(bool& OutShouldRestartEditor) override; + }; + + class FEnableStaticLightingRule final : public ISetupRule + { + public: + FEnableStaticLightingRule() + : ISetupRule("Rendering_EnableStaticLighting", + NSLOCTEXT("OculusXRRenderingRules", "EnableStaticLighting_DisplayName", "Enable Static Lighting"), + NSLOCTEXT("OculusXRRenderingRules", "EnableStaticLighting_Description", "Static lighting should be disallowed only if project is intended to be 100% dynamically lit."), + ESetupRuleCategory::Rendering, + ESetupRuleSeverity::Performance, + All_Platforms) {} + virtual bool IsApplied() const override; + + protected: + virtual void ApplyImpl(bool& OutShouldRestartEditor) override; + }; + + class FDisableMobileShaderStaticAndCSMShadowReceiversRule final : public ISetupRule + { + public: + FDisableMobileShaderStaticAndCSMShadowReceiversRule() + : ISetupRule( + "Rendering_MobileShaderStaticAndCSMShadowReceivers", + NSLOCTEXT("OculusXRRenderingRules", "MobileShaderStaticAndCSMShadowReceivers_DisplayName", "Disable Support Combined Static and CSM Shadowing"), + NSLOCTEXT("OculusXRRenderingRules", "MobileShaderStaticAndCSMShadowReceivers_Description", "The project does not contain any stationary lights. Support Combined Static and CSM Shadowing can be disabled to reduce shader permutations."), + ESetupRuleCategory::Rendering, + ESetupRuleSeverity::Performance) {} + + virtual bool IsApplied() const override; + virtual bool IsValid() override; + + protected: + virtual void ApplyImpl(bool& OutShouldRestartEditor) override; + }; + + class FDisableMobileShaderAllowDistanceFieldShadowsRule final : public ISetupRule + { + public: + FDisableMobileShaderAllowDistanceFieldShadowsRule() + : ISetupRule("Rendering_MobileShaderAllowDistanceFieldShadows", + NSLOCTEXT("OculusXRRenderingRules", "MobileShaderAllowDistanceFieldShadows_DisplayName", "Disable Support Support Distance Field Shadows"), + NSLOCTEXT("OculusXRRenderingRules", "MobileShaderAllowDistanceFieldShadows_Description", "The project does not contain any stationary lights. Support Support Distance Field Shadows can be disabled to reduce shader permutations."), + ESetupRuleCategory::Rendering, + ESetupRuleSeverity::Performance, + MetaQuest_All) {} + + virtual bool IsApplied() const override; + virtual bool IsValid() override; + + protected: + virtual void ApplyImpl(bool& OutShouldRestartEditor) override; + }; + + class FDisableMobileShaderAllowMovableDirectionalLightsRule final : public ISetupRule + { + public: + FDisableMobileShaderAllowMovableDirectionalLightsRule() + : ISetupRule("Rendering_MobileShaderAllowMovableDirectionalLights", + NSLOCTEXT("OculusXRRenderingRules", "MobileShaderAllowMovableDirectionalLights_DisplayName", "Disable Support Movable Directional Lights"), + NSLOCTEXT("OculusXRRenderingRules", "MobileShaderAllowMovableDirectionalLights_Description", "The project does not contain any movable lights. Support Movable Directional Lights can be disabled to reduce shader permutations."), + ESetupRuleCategory::Rendering, + ESetupRuleSeverity::Performance, + MetaQuest_All) {} + + virtual bool IsApplied() const override; + virtual bool IsValid() override; + + protected: + virtual void ApplyImpl(bool& OutShouldRestartEditor) override; + }; + + // All defined rendering rules. Add new rules to this table for them to be auto-registered + inline TArray RenderingRules_Table{ + MakeShared(), + MakeShared(), + MakeShared(), + MakeShared(), + MakeShared(), + MakeShared(), + MakeShared(), +#ifdef WITH_OCULUS_BRANCH + MakeShared(), +#endif + MakeShared(), + MakeShared(), + MakeShared(), + MakeShared(), + MakeShared(), + MakeShared(), + MakeShared(), + MakeShared() + }; +} // namespace OculusXRRenderingRules diff --git a/Plugins/MetaXR/Source/OculusXRProjectSetupTool/Private/Tests/OculusXRProjectSetupTool.spec.cpp b/Plugins/MetaXR/Source/OculusXRProjectSetupTool/Private/Tests/OculusXRProjectSetupTool.spec.cpp new file mode 100644 index 0000000..16382dc --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRProjectSetupTool/Private/Tests/OculusXRProjectSetupTool.spec.cpp @@ -0,0 +1,169 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#include "Misc/AutomationTest.h" +#include "OculusXRRuleProcessorSubsystem.h" +#include "OculusXRSetupRule.h" +#include "Rules/OculusXRAnchorsRules.h" +#include "Rules/OculusXRCompatibilityRules.h" +#include "Rules/OculusXRMovementRules.h" +#include "Rules/OculusXRPassthroughRules.h" +#include "Rules/OculusXRPluginRules.h" +#include "Rules/OculusXRRenderingRules.h" + +namespace +{ + const char* TestRule_Id = "test_id"; + const FText TestRule_DisName = FText::FromString("Test Display"); + const FText TestRule_Desc = FText::FromString("Test Desc"); +} // namespace + +BEGIN_DEFINE_SPEC(FOculusXRProjectSetupToolSpec, TEXT("Project Setup Tool"), EAutomationTestFlags::ProductFilter | EAutomationTestFlags::ApplicationContextMask) +UOculusXRRuleProcessorSubsystem* ProcessorSubsystem; +bool bShouldRestartEditor = false; +TSet RulesThatRequireRestart = { + FName("Feature_AllowAlphaToneMapperPassthrough"), + FName("Rendering_DisableAmbientOcclusion"), + FName("Rendering_DisablePostProcessing"), + FName("Rendering_EnableForwardShading"), + FName("Rendering_EnableInstancedStereo"), + FName("Rendering_EnableMultiView"), + FName("Rendering_EnableStaticLighting"), + FName("Rendering_MobileShaderAllowDistanceFieldShadows"), + FName("Rendering_MobileShaderAllowMovableDirectionalLights"), + FName("Rendering_UseHalfPrecisionFloat") +}; + +void Setup(); +END_DEFINE_SPEC(FOculusXRProjectSetupToolSpec) + +void FOculusXRProjectSetupToolSpec::Setup() +{ + BeforeEach([this] { + ProcessorSubsystem = GEngine->GetEngineSubsystem(); + bShouldRestartEditor = false; + }); +} + +class FMockRule : public ISetupRule +{ +public: + FMockRule() + : ISetupRule(TestRule_Id, TestRule_DisName, TestRule_Desc, ESetupRuleCategory::Miscellaneous, ESetupRuleSeverity::Warning) + { + } + + virtual bool IsApplied() const override + { + return bIsApplied; + } + +protected: + virtual void ApplyImpl(bool& ShouldRestartEditor) override + { + bIsApplied = true; + } + +private: + bool bIsApplied = false; +}; + +void FOculusXRProjectSetupToolSpec::Define() +{ + Describe(TEXT("Rule Processor"), [this] { + Setup(); + + It(TEXT("Rule registered and unregistered successfully"), [this] { + const auto RuleNum = ProcessorSubsystem->GetRules().Num(); + const SetupRulePtr mockRule = MakeShared(); + TestTrue(TEXT("Rule added"), ProcessorSubsystem->RegisterRule(mockRule)); + TestEqual(TEXT("After rule is added"), ProcessorSubsystem->GetRules().Num(), RuleNum + 1); + + TestTrue(TEXT("Rule removed"), ProcessorSubsystem->UnregisterRule(mockRule)); + TestEqual(TEXT("After rule is removed"), ProcessorSubsystem->GetRules().Num(), RuleNum); + }); + + It(TEXT("Rule applied"), [this] { + const SetupRulePtr mockRule = MakeShared(); + + // apply rule + TestFalse(TEXT("Rule is not applied yet"), mockRule->IsApplied()); + mockRule->Apply(bShouldRestartEditor); + + TestTrue(TEXT("Rule applied"), mockRule->IsApplied()); + }); + + It(TEXT("Rule ignored"), [this] { + const SetupRulePtr mockRule = MakeShared(); + // ignore rule + TestFalse(TEXT("Rule is not ignored yet"), mockRule->IsIgnored()); + mockRule->SetIgnoreRule(true); + TestTrue(TEXT("Rule ignored"), mockRule->IsIgnored()); + }); + }); + + Describe(TEXT("Rendering rules"), [this] { + for (auto Rule : OculusXRRenderingRules::RenderingRules_Table) + { + It(TEXT("Test " + Rule->GetId().ToString()), [this, Rule] { + Rule->Apply(bShouldRestartEditor); + TestTrue(TEXT("Rule is applied"), Rule->IsApplied()); + TestEqual(TEXT("Restart is pending"), RulesThatRequireRestart.Contains(Rule->GetId()), bShouldRestartEditor); + }); + } + }); + + Describe(TEXT("Plugin rules"), [this] { + for (auto Rule : OculusXRPluginRules::PluginRules_Table) + { + It(TEXT("Test " + Rule->GetId().ToString()), [this, Rule] { + Rule->Apply(bShouldRestartEditor); + TestTrue(TEXT("Rule is applied"), Rule->IsApplied()); + TestEqual(TEXT("Restart is pending"), RulesThatRequireRestart.Contains(Rule->GetId()), bShouldRestartEditor); + }); + } + }); + + Describe(TEXT("Compatibility rules"), [this] { + for (auto Rule : OculusXRCompatibilityRules::CompatibilityRules_Table) + { + It(TEXT("Test " + Rule->GetId().ToString()), [this, Rule] { + Rule->Apply(bShouldRestartEditor); + TestTrue(TEXT("Rule is applied"), Rule->IsApplied()); + TestEqual(TEXT("Restart is pending"), RulesThatRequireRestart.Contains(Rule->GetId()), bShouldRestartEditor); + }); + } + }); + + Describe(TEXT("Anchor rules"), [this] { + for (auto Rule : OculusXRAnchorsRules::AnchorRules_Table) + { + It(TEXT("Test " + Rule->GetId().ToString()), [this, Rule] { + Rule->Apply(bShouldRestartEditor); + TestTrue(TEXT("Rule is applied"), Rule->IsApplied()); + TestEqual(TEXT("Restart is pending"), RulesThatRequireRestart.Contains(Rule->GetId()), bShouldRestartEditor); + }); + } + }); + + Describe(TEXT("Movement rules"), [this] { + for (auto Rule : OculusXRMovementRules::MovementRules_Table) + { + It(TEXT("Test " + Rule->GetId().ToString()), [this, Rule] { + Rule->Apply(bShouldRestartEditor); + TestTrue(TEXT("Rule is applied"), Rule->IsApplied()); + TestEqual(TEXT("Restart is pending"), RulesThatRequireRestart.Contains(Rule->GetId()), bShouldRestartEditor); + }); + } + }); + + Describe(TEXT("Passthrough rules"), [this] { + for (auto Rule : OculusXRPassthroughRules::PassthroughRules_Table) + { + It(TEXT("Test " + Rule->GetId().ToString()), [this, Rule] { + Rule->Apply(bShouldRestartEditor); + TestTrue(TEXT("Rule is applied"), Rule->IsApplied()); + TestEqual(TEXT("Restart is pending"), RulesThatRequireRestart.Contains(Rule->GetId()), bShouldRestartEditor); + }); + } + }); +} diff --git a/Plugins/MetaXR/Source/OculusXRProjectSetupTool/Private/Widget/OculusXRProjectSetupToolWidget.cpp b/Plugins/MetaXR/Source/OculusXRProjectSetupTool/Private/Widget/OculusXRProjectSetupToolWidget.cpp new file mode 100644 index 0000000..ce1d848 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRProjectSetupTool/Private/Widget/OculusXRProjectSetupToolWidget.cpp @@ -0,0 +1,1026 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#pragma once + +#include "OculusXRProjectSetupToolWidget.h" + +#include "DetailColumnSizeData.h" +#include "OculusXRProjectSetupToolModule.h" +#include "OculusXRPSTEvents.h" +#include "OculusXRPSTSettings.h" +#include "OculusXRPSTUtils.h" +#include "OculusXRTelemetry.h" +#include "SWarningOrErrorBox.h" +#include "Widgets/Layout/SScrollBox.h" +#include "Widgets/Input/SButton.h" +#include "Styling/SlateStyle.h" + +#define LOCTEXT_NAMESPACE "OculusXRProjectSetupToolWidget" + +/** + * Construct the layout for the project setup tool tab + * + * @param InArgs [in] the arguments associated with this tool + */ +void SOculusXRProjectSetupToolWidget::Construct(const FArguments& InArgs) +{ + Refresh(); + + // Populate the platform filter + PlatformFilters.Add(MetaQuest_All); + PlatformFilters.Add(ESetupRulePlatform::MetaLink); + PlatformFilters.Add(ESetupRulePlatform::MetaQuest_3); + PlatformFilters.Add(ESetupRulePlatform::MetaQuest_Pro); + PlatformFilters.Add(ESetupRulePlatform::MetaQuest_2); + + const auto Settings = GetMutableDefault(); + + UpdateActiveTimer(Settings->bBackGroundChecks); + + // Apply the starting platform filter. + const auto& Platform = static_cast(Settings->CurrentPlatform); + CurrentPlatformFilterIndex = PlatformFilters.Find(Platform); + + if (CurrentPlatformFilterIndex == INDEX_NONE) + { + CurrentPlatformFilterIndex = 0; + } + + // Setup the column information for the layout + ColumnSizeData = MakeShared(); + ColumnSizeData->SetValueColumnWidth(0.75f); + ColumnSizeData->SetRightColumnMinWidth(150); + + // Construct the layout + + RootContainerWidget = SNew(SVerticalBox); + + BuildLayout(RootContainerWidget); + + ChildSlot + [RootContainerWidget.ToSharedRef()]; +} + +/** + * Build the layout for the main window + */ +void SOculusXRProjectSetupToolWidget::BuildLayout(const TSharedPtr& RootContainer) +{ + // Clear all existing contents + RootContainer->ClearChildren(); + + const TSharedPtr HeaderContainer = SNew(SVerticalBox); + // Section to contain the title bar + BuildTitleSectionLayout(HeaderContainer); + + // Section to contain the filters + BuildFilterSectionLayout(HeaderContainer, CurrentPlatformFilterIndex); + + const TSharedPtr RulesContainer = SNew(SScrollBox); + // Section to contain the required rules + BuildRequiredRulesSectionLayout(RulesContainer); + + // Section to contain the recommended rules + BuildRecommendedRulesSectionLayout(RulesContainer); + + // Section to contain the applied rules + BuildAppliedRulesSectionLayout(RulesContainer); + + // Section to contain the ignored rules + BuildIgnoredRulesSectionLayout(RulesContainer); + + RootContainer->AddSlot() + .AutoHeight() + .Padding(0) + [HeaderContainer.ToSharedRef()]; + + RootContainer->AddSlot() + .Padding(0) + [RulesContainer.ToSharedRef()]; + + // Section to show warning about restarting editor + RootContainer->AddSlot() + .AutoHeight() + [SNew(SVerticalBox) + + SVerticalBox::Slot() + .AutoHeight() + .Padding(FMargin(18.0f, 20.0f, 18.0f, 16.0f)) + [SNew(SWarningOrErrorBox) + .Visibility(this, &SOculusXRProjectSetupToolWidget::OnRestartEditorNoticeVisibility) + .MessageStyle(EMessageStyle::Warning) + .Message(LOCTEXT("PluginSettingsRestartNotice", "You must restart Unreal Editor for your changes to take effect.")) + [SNew(SButton) + .OnClicked(this, &SOculusXRProjectSetupToolWidget::OnRestartEditorButtonClicked) + .TextStyle(FAppStyle::Get(), "NormalText") + .Text(LOCTEXT("PluginSettingsRestartEditor", "Restart Now"))]]]; +} + +/** + * Build the title section layout + */ +void SOculusXRProjectSetupToolWidget::BuildTitleSectionLayout(const TSharedPtr& RootContainer) +{ + const TSharedPtr TitleWidget = SNew(SHorizontalBox) + .Clipping(EWidgetClipping::OnDemand); + + ProjectStatusWidget = SNew(STextBlock) + .Font(FAppStyle::Get().GetFontStyle(TEXT("DetailsView.CategoryFontStyle"))) + .TextStyle(FAppStyle::Get(), "DetailsView.CategoryTextStyle") + .Text(FText()); + + UpdateProjectStatus(); + + TitleWidget->AddSlot() + .HAlign(HAlign_Left) + .VAlign(VAlign_Center) + .Padding(8, 0, 0, 0) + [ProjectStatusWidget.ToSharedRef()]; + + const TSharedPtr ButtonWidget = SNew(SHorizontalBox); + + auto Settings = GetMutableDefault(); + FMenuBuilder DetailViewOptions(true, nullptr); + + DetailViewOptions.AddMenuEntry( + LOCTEXT("BackGroundChecks", "Enable background rule checks"), + LOCTEXT("BackGroundChecks_ToolTip", "If enabled background rule validity will be performed every 30 seconds."), + FSlateIcon(), + FUIAction( + FExecuteAction::CreateLambda([Settings] { + Settings->bBackGroundChecks = !Settings->bBackGroundChecks; + Settings->SaveConfig(); + const OculusXRTelemetry::TScopedMarker OptionEvent; + const auto& Annotated = OptionEvent + .AddAnnotation(OculusXRTelemetry::Annotations::Uid, "bBackGroundChecks") + .AddAnnotation(OculusXRTelemetry::Annotations::Value, + Settings->bBackGroundChecks ? "true" : "false"); + }), + FCanExecuteAction(), + FIsActionChecked::CreateLambda([Settings]() -> bool { + return Settings->bBackGroundChecks; + })), + NAME_None, + EUserInterfaceActionType::ToggleButton); + + DetailViewOptions.AddMenuEntry( + LOCTEXT("StopBuildOnUnappliedRequredItem", "Stop build on unapplied items"), + LOCTEXT("StopBuildOnUnappliedRequredItem_ToolTip", "Stop build if required items are not applied or ignored."), + FSlateIcon(), + FUIAction( + FExecuteAction::CreateLambda([Settings] { + Settings->bStopBuildOnUnAppliedCriticalItems = !Settings->bStopBuildOnUnAppliedCriticalItems; + Settings->SaveConfig(); + const OculusXRTelemetry::TScopedMarker OptionEvent; + const auto& Annotated = OptionEvent + .AddAnnotation(OculusXRTelemetry::Annotations::Uid, "bStopBuildOnUnAppliedCriticalItems") + .AddAnnotation(OculusXRTelemetry::Annotations::Value, + Settings->bStopBuildOnUnAppliedCriticalItems ? "true" : "false"); + }), + FCanExecuteAction(), + FIsActionChecked::CreateLambda([Settings]() -> bool { + return Settings->bStopBuildOnUnAppliedCriticalItems; + })), + NAME_None, + EUserInterfaceActionType::ToggleButton); + + ButtonWidget->AddSlot() + .HAlign(HAlign_Center) + .VAlign(VAlign_Center) + .Padding(FMargin(8.f, 0.f, 8.f, 0.f)) + [SNew(SComboButton) + .ContentPadding(0) + .HasDownArrow(false) + .ForegroundColor(FSlateColor::UseForeground()) + .ComboButtonStyle(FAppStyle::Get(), "SimpleComboButton") + .AddMetaData(FTagMetaData(TEXT("ViewOptions"))) + .MenuContent() + [DetailViewOptions.MakeWidget()] + .ButtonContent() + [SNew(SHorizontalBox) + + SHorizontalBox::Slot() + .AutoWidth() + .HAlign(HAlign_Center) + [SNew(SImage) + .Image(FAppStyle::Get().GetBrush("Icons.Toolbar.Settings")) + .ColorAndOpacity(FSlateColor::UseForeground())]]]; + + // Top level container for the whole row + const TSharedPtr RowWidget = SNew(SHorizontalBox); + + RowWidget->AddSlot() + .HAlign(HAlign_Left) + [TitleWidget.ToSharedRef()]; + + RowWidget->AddSlot() + .HAlign(HAlign_Right) + [ButtonWidget.ToSharedRef()]; + + // Add into the root container + RootContainer->AddSlot() + .AutoHeight() + .Padding(0) + [SNew(SBorder) + .BorderImage(FAppStyle::Get().GetBrush("DetailsView.GridLine")) + .Padding(FMargin(0, 0, 0, 1)) + [SNew(SHorizontalBox) + + + SHorizontalBox::Slot() + [SNew(SBorder) + .BorderImage(FAppStyle::Get().GetBrush("DetailsView.CategoryTop")) + .BorderBackgroundColor(FSlateColor(FLinearColor::White)) + .Padding(0) + [SNew(SBox) + .MinDesiredHeight(26.0f) + [RowWidget.ToSharedRef()]]]]]; +} + +/** + * Build the filter section layout + */ +void SOculusXRProjectSetupToolWidget::BuildFilterSectionLayout(const TSharedPtr& RootContainer, const uint32 PlatformFilterIndex) +{ + // Top level container for the whole row + const TSharedPtr RowWidget = SNew(SHorizontalBox); + + uint32 index = 0; + + for (const auto& Platform : PlatformFilters) + { + const FSlateBrush* BorderBrush = FAppStyle::Get().GetBrush("DetailsView.GridLine"); + + if (index == PlatformFilterIndex) + { + BorderBrush = FAppStyle::Get().GetBrush("DetailsView.CategoryTop"); + } + + ++index; + + RowWidget->AddSlot() + .Padding(FMargin(0, 1, 1, 1)) + [SNew(SBorder) + .BorderImage(BorderBrush) + [SNew(SHorizontalBox) + + SHorizontalBox::Slot() + [SNew(SButton) + .HAlign(HAlign_Center) + .VAlign(VAlign_Center) + .ContentPadding(0) + .ButtonStyle(FCoreStyle::Get(), "NoBorder") + .OnClicked(this, &SOculusXRProjectSetupToolWidget::OnPlatformFilterChanged, Platform) + [SNew(SHorizontalBox) + + SHorizontalBox::Slot() + .Padding(0, 3, 3, 3) + [SNew(SImage) + .Image( + FOculusXRProjectSetupToolModule::GetSlateStyle() + ->GetBrush(OculusXRPSTUtils::GetDisplayName( + Platform))) + .ColorAndOpacity(FSlateColor::UseForeground())] + + SHorizontalBox::Slot() + .Padding(3, 0, 0, 0) + .AutoWidth() + .VAlign(VAlign_Center) + [SNew(STextBlock) + .Text(FText::FromString(OculusXRPSTUtils::GetDisplayName(Platform)))]]]]]; + } + + // Add into the root container + RootContainer->AddSlot() + .AutoHeight() + .Padding(0) + [SNew(SBorder) + .BorderImage(FAppStyle::Get().GetBrush("DetailsView.GridLine")) + .Padding(FMargin(0, 0, 0, 1)) + [SNew(SHorizontalBox) + + SHorizontalBox::Slot() + [SNew(SBorder) + .BorderImage(FAppStyle::Get().GetBrush("DetailsView.CategoryTop")) + .BorderBackgroundColor(FSlateColor(FLinearColor::White)) + .Padding(0) + [SNew(SBox) + .MinDesiredHeight(26.0f) + [RowWidget.ToSharedRef()]]]]]; +} + +/** + * Build a container for a rules section + */ +TSharedPtr SOculusXRProjectSetupToolWidget::BuildRulesContainerLayout(const TSharedPtr& RootContainer, ERulesSection Section, const FText& SectionTitle) +{ + // Top level container for the whole row + const TSharedPtr TitleAndExpanderWidget = SNew(SHorizontalBox) + .Clipping(EWidgetClipping::OnDemand); + + TitleAndExpanderWidget->AddSlot() + .HAlign(HAlign_Left) + .VAlign(VAlign_Center) + .Padding(8, 0, 8, 0) + .AutoWidth() + [SNew(SHorizontalBox) + .Visibility_Static(&SOculusXRProjectSetupToolWidget::OnHeaderExpanderVisibility, Section) + + SHorizontalBox::Slot() + [SNew(SButton) + .ButtonStyle(FCoreStyle::Get(), "NoBorder") + .VAlign(VAlign_Center) + .HAlign(HAlign_Center) + .ClickMethod(EButtonClickMethod::MouseDown) + .OnClicked(this, &SOculusXRProjectSetupToolWidget::OnHeaderExpanderClicked, Section) + .ContentPadding(0) + .IsFocusable(false) + [SNew(SImage) + .Image(this, &SOculusXRProjectSetupToolWidget::GetHeaderExpanderImage, Section) + .ColorAndOpacity(FSlateColor::UseSubduedForeground())]]]; + + TitleAndExpanderWidget->AddSlot() + .HAlign(HAlign_Left) + .VAlign(VAlign_Center) + .Padding(0, 0, 0, 0) + [SNew(STextBlock) + .Font(FAppStyle::Get().GetFontStyle(TEXT("DetailsView.CategoryFontStyle"))) + .TextStyle(FAppStyle::Get(), "DetailsView.CategoryTextStyle") + .Text(SectionTitle)]; + + const TSharedPtr EmptyDescriptionWidget = SNew(SHorizontalBox); + const TSharedPtr ButtonWidget = SNew(SHorizontalBox); + + if (Section == ERulesSection::Required || Section == ERulesSection::Recommended) + { + ButtonWidget->AddSlot() + .Padding(FMargin(6, 3, 3, 3)) + [SNew(SButton) + .HAlign(HAlign_Center) + .VAlign(VAlign_Center) + .ButtonStyle(&FAppStyle::Get().GetWidgetStyle("PrimaryButton")) + .Text(LOCTEXT("ApplyAllRules", "Apply All")) + .OnClicked(this, &SOculusXRProjectSetupToolWidget::OnApplyAllRulesClicked, Section) + .IsEnabled_Raw(this, &SOculusXRProjectSetupToolWidget::OnApplyAllRulesEnabled, Section)]; + + // This is not actually needed but we add it to ensure correct alignment + ButtonWidget->AddSlot() + .AutoWidth() + .VAlign(VAlign_Center) + .Padding(FMargin(4.f, 0.f, 8.f, 0.f)) + [SNew(SComboButton) + .ContentPadding(0) + .Visibility_Lambda([this]() -> EVisibility { return EVisibility::Hidden; }) + .HasDownArrow(false) + .ForegroundColor(FSlateColor::UseForeground()) + .ComboButtonStyle(FAppStyle::Get(), "SimpleComboButton") + .ButtonContent() + [SNew(SHorizontalBox) + + SHorizontalBox::Slot() + .AutoWidth() + .HAlign(HAlign_Center) + [SNew(SImage) + .Image(FAppStyle::Get().GetBrush("PropertyWindow.Button_Ellipsis")) + .ColorAndOpacity(FSlateColor::UseForeground())]]]; + } + + // Splitter so each row can contain Name | Description | Buttons + const TSharedPtr Splitter = SNew(SSplitter) + .Style(FAppStyle::Get(), "DetailsView.Splitter") + .PhysicalSplitterHandleSize(1.0f) + .HitDetectionSplitterHandleSize(5.0f); + + // Add the widgets to the splitter + Splitter->AddSlot() + .Value(ColumnSizeData->GetNameColumnWidth()) + .OnSlotResized(ColumnSizeData->GetOnNameColumnResized()) + [TitleAndExpanderWidget.ToSharedRef()]; + + Splitter->AddSlot() + .Value(ColumnSizeData->GetValueColumnWidth()) + .OnSlotResized(ColumnSizeData->GetOnValueColumnResized()) + [EmptyDescriptionWidget.ToSharedRef()]; + + Splitter->AddSlot() + .Value(ColumnSizeData->GetRightColumnWidth()) + .OnSlotResized(ColumnSizeData->GetOnRightColumnResized()) + .MinSize(ColumnSizeData->GetRightColumnMinWidth()) + [ButtonWidget.ToSharedRef()]; + + // Top level container for the whole row + const TSharedPtr RowWidget = SNew(SBox) + .Padding(0) + [Splitter.ToSharedRef()]; + // Add into the root container + RootContainer->AddSlot() + .Padding(0) + [SNew(SBorder) + .BorderImage(FAppStyle::Get().GetBrush("DetailsView.GridLine")) + .Padding(FMargin(0, 0, 0, 1)) + [SNew(SHorizontalBox) + + + SHorizontalBox::Slot() + [SNew(SBorder) + .BorderImage(FAppStyle::Get().GetBrush("DetailsView.CategoryTop")) + .BorderBackgroundColor(FSlateColor(FLinearColor::White)) + .Padding(0) + [SNew(SBox) + .MinDesiredHeight(26.0f) + [RowWidget.ToSharedRef()]]]]]; + + // Contents + TSharedPtr SectionContentContainer = SNew(SVerticalBox); + + RootContainer->AddSlot() + .Padding(0) + [SectionContentContainer.ToSharedRef()]; + + return SectionContentContainer; +} + +/** + * Build the layout for a single row (filter or rule row) + */ +void SOculusXRProjectSetupToolWidget::BuildRowItemLayout(const TSharedPtr& SectionContentContainer, ERulesSection Section, const SetupRulePtr& Rule, const uint32 PlatformFilterIndex) +{ + // RowWidget -> Splitter -> (NameWidget | DescriptionWidget | ButtonWidget) + const bool bShouldHideApplyButton = Section == ERulesSection::Applied; + const FSlateBrush* IconBrush = nullptr; + + if (Rule != nullptr) + { + if (Section == ERulesSection::Applied) + { + IconBrush = FAppStyle::Get().GetBrush("Icons.SuccessWithColor"); + } + else if (Rule->GetSeverity() == ESetupRuleSeverity::Critical) + { + IconBrush = FAppStyle::Get().GetBrush("Icons.ErrorWithColor"); + } + else + { + IconBrush = FAppStyle::Get().GetBrush("Icons.WarningWithColor"); + } + } + + // Name widget + const TSharedPtr NameWidget = SNew(SHorizontalBox) + .Clipping(EWidgetClipping::OnDemand); + + if (IconBrush != nullptr) + { + NameWidget->AddSlot() + .HAlign(HAlign_Left) + .VAlign(VAlign_Center) + .Padding(8, 0, 8, 0) + .AutoWidth() + [SNew(SImage) + .Image(IconBrush)]; + } + + NameWidget->AddSlot() + .HAlign(HAlign_Left) + .VAlign(VAlign_Center) + .Padding(0, 0, 0, 0) + [SNew(STextBlock) + .Font(FAppStyle::Get().GetFontStyle(TEXT("PropertyWindow.NormalFont"))) + .ColorAndOpacity(FSlateColor::UseStyle()) + .Text(Rule != nullptr ? Rule->GetDisplayName() : FText::GetEmpty())]; + + // Description widget + const TSharedPtr DescriptionWidget = SNew(SHorizontalBox) + .Clipping(EWidgetClipping::OnDemand); + + DescriptionWidget->AddSlot() + .VAlign(VAlign_Center) + .Padding(6, 0) + [SNew(STextBlock) + .Font(FAppStyle::Get().GetFontStyle(TEXT("PropertyWindow.NormalFont"))) + .ColorAndOpacity(FSlateColor::UseStyle()) + .Text(Rule != nullptr ? Rule->GetDescription() : FText::GetEmpty())]; + + // Button widget. There are two buttons slots that are customised based on section + const TSharedPtr ButtonWidget = SNew(SHorizontalBox); + + ButtonWidget->AddSlot() + .Padding(FMargin(6, 3, 3, 3)) + [SNew(SButton) + .HAlign(HAlign_Center) + .VAlign(VAlign_Center) + .Text(LOCTEXT("ApplyRule", "Apply")) + .Visibility_Lambda([bShouldHideApplyButton]() -> EVisibility { return bShouldHideApplyButton ? EVisibility::Hidden : EVisibility::Visible; }) + .OnClicked(this, &SOculusXRProjectSetupToolWidget::OnApplyRuleClicked, Rule) + .IsEnabled_Static(&SOculusXRProjectSetupToolWidget::OnApplyRuleEnabled, Section)]; + + FMenuBuilder EllipsisMenuBuilder(true, nullptr); + + const auto IgnoreButtonText = Section == ERulesSection::Ignored ? LOCTEXT("UnignoreRule", "Unignore") : LOCTEXT("IgnoreRule", "Ignore"); + const auto IgnoreButtonTooltip = Section == ERulesSection::Ignored ? LOCTEXT("UnignoreRule_Tooltip", "Unignore this rule") : LOCTEXT("IgnoreRule_Tooltip", "Ignore this rule"); + const FString SupportURL(TEXT("https://forums.oculusvr.com/developer")); + + EllipsisMenuBuilder.AddMenuEntry( + IgnoreButtonText, + IgnoreButtonTooltip, + FSlateIcon(), + FUIAction( + FExecuteAction::CreateRaw(this, &SOculusXRProjectSetupToolWidget::OnIgnoreRuleClicked, Rule, Section), + FCanExecuteAction::CreateStatic(&SOculusXRProjectSetupToolWidget::OnIgnoreRuleEnabled, Section))); + + EllipsisMenuBuilder.AddMenuEntry( + LOCTEXT("SupportButton", "Support"), + LOCTEXT("SupportButton_ToolTip", "Get more information about this rule."), + FSlateIcon(FAppStyle::GetAppStyleSetName(), "Icons.Comment"), + FUIAction( + FExecuteAction::CreateLambda([SupportURL] { FPlatformProcess::LaunchURL(*SupportURL, nullptr, nullptr); }), + FCanExecuteAction())); + + ButtonWidget->AddSlot() + .AutoWidth() + .VAlign(VAlign_Center) + .Padding(FMargin(4.f, 0.f, 8.f, 0.f)) + [SNew(SComboButton) + .ContentPadding(0) + .HasDownArrow(false) + .Visibility_Lambda([bShouldHideApplyButton]() -> EVisibility { return bShouldHideApplyButton ? EVisibility::Hidden : EVisibility::Visible; }) + .ForegroundColor(FSlateColor::UseForeground()) + .ComboButtonStyle(FAppStyle::Get(), "SimpleComboButton") + .AddMetaData(FTagMetaData(TEXT("ViewOptions"))) + .MenuContent() + [EllipsisMenuBuilder.MakeWidget()] + .ButtonContent() + [SNew(SHorizontalBox) + + SHorizontalBox::Slot() + .AutoWidth() + .HAlign(HAlign_Center) + [SNew(SImage) + .Image(FAppStyle::Get().GetBrush("PropertyWindow.Button_Ellipsis")) + .ColorAndOpacity(FSlateColor::UseForeground())]]]; + + // Splitter so each row can contain Name | Description | Buttons + const TSharedPtr Splitter = SNew(SSplitter) + .Style(FAppStyle::Get(), "DetailsView.Splitter") + .PhysicalSplitterHandleSize(1.0f) + .HitDetectionSplitterHandleSize(5.0f); + + // Add the widgets to the splitter + Splitter->AddSlot() + .Value(ColumnSizeData->GetNameColumnWidth()) + .OnSlotResized(ColumnSizeData->GetOnNameColumnResized()) + [NameWidget.ToSharedRef()]; + + Splitter->AddSlot() + .Value(ColumnSizeData->GetValueColumnWidth()) + .OnSlotResized(ColumnSizeData->GetOnValueColumnResized()) + [DescriptionWidget.ToSharedRef()]; + + Splitter->AddSlot() + .Value(ColumnSizeData->GetRightColumnWidth()) + .OnSlotResized(ColumnSizeData->GetOnRightColumnResized()) + .MinSize(ColumnSizeData->GetRightColumnMinWidth()) + [ButtonWidget.ToSharedRef()]; + + // Top level container for the whole row + const TSharedPtr RowWidget = SNew(SBorder) + .BorderImage(FAppStyle::Get().GetBrush("DetailsView.CategoryMiddle")) + .BorderBackgroundColor(FAppStyle::Get().GetSlateColor("Colors.Panel")) + .Padding(0) + [Splitter.ToSharedRef()]; + + // Add a slot into the content container for this item and add the row widget to it + SectionContentContainer->AddSlot() + .AutoHeight() + [SNew(SBorder) + .BorderImage(FAppStyle::Get().GetBrush("DetailsView.GridLine")) + .Padding(FMargin(0, 0, 0, 1)) + .Clipping(EWidgetClipping::ClipToBounds) + .Visibility(this, &SOculusXRProjectSetupToolWidget::OnRowVisibility, Section, PlatformFilters[CurrentPlatformFilterIndex], Rule) + [SNew(SBox) + .MinDesiredHeight(26.0f) + [SNew(SHorizontalBox) + + SHorizontalBox::Slot() + .HAlign(HAlign_Fill) + .VAlign(VAlign_Fill) + [SNew(SBorder) + .BorderImage(FAppStyle::Get().GetBrush("DetailsView.Highlight")) + .Padding(0) + [SNew(SBorder) + .BorderImage(FAppStyle::Get().GetBrush("DetailsView.CategoryMiddle")) + .BorderBackgroundColor(FAppStyle::Get().GetSlateColor("Colors.Panel")) + .Padding(0) + [RowWidget.ToSharedRef()]]]]]]; +} + +/** + * Build the layout for the required rules + */ +void SOculusXRProjectSetupToolWidget::BuildRequiredRulesSectionLayout(const TSharedPtr& RootContainer) +{ + const UOculusXRRuleProcessorSubsystem* RuleProcessorSubsystem = GEngine->GetEngineSubsystem(); + + if (RuleProcessorSubsystem == nullptr) + { + return; + } + + const TSharedPtr SectionContentContainer = BuildRulesContainerLayout(RootContainer, ERulesSection::Required, LOCTEXT("RequiredRules_Title", "Required Rules")); + + for (const auto& Rule : RuleProcessorSubsystem->GetRules()) + { + if (Rule->GetSeverity() == ESetupRuleSeverity::Critical) + { + BuildRowItemLayout(SectionContentContainer, ERulesSection::Required, Rule, 0); + } + } +} + +/** + * Build the layout for the recommended rules + */ +void SOculusXRProjectSetupToolWidget::BuildRecommendedRulesSectionLayout(const TSharedPtr& RootContainer) +{ + const UOculusXRRuleProcessorSubsystem* RuleProcessorSubsystem = GEngine->GetEngineSubsystem(); + + if (RuleProcessorSubsystem == nullptr) + { + return; + } + + const TSharedPtr SectionContentContainer = BuildRulesContainerLayout(RootContainer, ERulesSection::Recommended, LOCTEXT("RecommendedRules_Title", "Recommended Rules")); + + for (const auto& Rule : RuleProcessorSubsystem->GetRules()) + { + if (Rule->GetSeverity() < ESetupRuleSeverity::Critical) + { + BuildRowItemLayout(SectionContentContainer, ERulesSection::Recommended, Rule, 0); + } + } +} + +/** + * Build the layout for the applied rules + */ +void SOculusXRProjectSetupToolWidget::BuildAppliedRulesSectionLayout(const TSharedPtr& RootContainer) +{ + const UOculusXRRuleProcessorSubsystem* RuleProcessorSubsystem = GEngine->GetEngineSubsystem(); + + if (RuleProcessorSubsystem == nullptr) + { + return; + } + + const TSharedPtr SectionContentContainer = BuildRulesContainerLayout(RootContainer, ERulesSection::Applied, LOCTEXT("AppliedRules_Title", "Applied Rules")); + + // Add all rules and let the visibility function take care of which ones to show + + for (const auto& Rule : RuleProcessorSubsystem->GetRules()) + { + BuildRowItemLayout(SectionContentContainer, ERulesSection::Applied, Rule, 0); + } +} + +/** + * Build the layout for the ignored rules + */ +void SOculusXRProjectSetupToolWidget::BuildIgnoredRulesSectionLayout(const TSharedPtr& RootContainer) +{ + const UOculusXRRuleProcessorSubsystem* RuleProcessorSubsystem = GEngine->GetEngineSubsystem(); + + if (RuleProcessorSubsystem == nullptr) + { + return; + } + + const TSharedPtr SectionContentContainer = BuildRulesContainerLayout(RootContainer, ERulesSection::Ignored, LOCTEXT("IgnoredRules_Title", "Ignored Rules")); + + // Add all rules and let the visibility function take care of which ones to show + + for (const auto& Rule : RuleProcessorSubsystem->GetRules()) + { + BuildRowItemLayout(SectionContentContainer, ERulesSection::Ignored, Rule, 0); + } +} + +/** + * Is an un-applied rule visible? + */ +EVisibility SOculusXRProjectSetupToolWidget::OnRowVisibility(ERulesSection Section, ESetupRulePlatform CurrentPlatform, SetupRulePtr Rule) const +{ + if (Section == ERulesSection::Filter) + { + return EVisibility::Visible; + } + + if (!BIsSectionExpanded[static_cast(Section)]) + { + return EVisibility::Collapsed; + } + + if (Rule == nullptr) + { + return EVisibility::Collapsed; + } + + if (!Rule->IsValid()) + { + return EVisibility::Collapsed; + } + + if ((Rule->GetPlatform() & CurrentPlatform) != CurrentPlatform) + { + return EVisibility::Collapsed; + } + + switch (Section) + { + case ERulesSection::Required: + case ERulesSection::Recommended: + { + if (Rule->IsApplied()) + { + return EVisibility::Collapsed; + } + + return Rule->IsIgnored() ? EVisibility::Collapsed : EVisibility::Visible; + } + + case ERulesSection::Applied: + { + return Rule->IsApplied() ? EVisibility::Visible : EVisibility::Collapsed; + } + + case ERulesSection::Ignored: + { + // Applied rules always show in the Applied section even if ignored + + if (Rule->IsApplied()) + { + return EVisibility::Collapsed; + } + + return Rule->IsIgnored() ? EVisibility::Visible : EVisibility::Collapsed; + } + + default: + { + break; + } + } + + return EVisibility::Collapsed; +} + +EVisibility SOculusXRProjectSetupToolWidget::OnRestartEditorNoticeVisibility() const +{ + return bShowButtonToRestart ? EVisibility::Visible : EVisibility::Collapsed; +} + +FReply SOculusXRProjectSetupToolWidget::OnRestartEditorButtonClicked() +{ + bShowButtonToRestart = false; + FUnrealEdMisc::Get().RestartEditor(false); + return FReply::Handled(); +} + +void SOculusXRProjectSetupToolWidget::Refresh() +{ + UOculusXRRuleProcessorSubsystem* RuleProcessorSubsystem = GEngine->GetEngineSubsystem(); + + if (RuleProcessorSubsystem != nullptr) + { + RuleProcessorSubsystem->Refresh(); + } +} + +void SOculusXRProjectSetupToolWidget::UpdateActiveTimer(bool Register) +{ + if (!Register) + { + if (!ActiveTimerHandle.IsValid()) + { + return; + } + UnRegisterActiveTimer(ActiveTimerHandle.Pin().ToSharedRef()); + return; + } + + if (ActiveTimerHandle.IsValid()) + { + UnRegisterActiveTimer(ActiveTimerHandle.Pin().ToSharedRef()); + } + + ActiveTimerHandle = RegisterActiveTimer( + 30.f, + FWidgetActiveTimerDelegate::CreateLambda([this](double /*InCurrentTime*/, float /*InDeltaTime*/) { + Refresh(); + UpdateProjectStatus(); + return EActiveTimerReturnType::Continue; + })); +} + +/** + * Apply a new platform filter + */ +FReply SOculusXRProjectSetupToolWidget::OnPlatformFilterChanged(ESetupRulePlatform ItemSelected) +{ + const UOculusXRRuleProcessorSubsystem* RuleProcessorSubsystem = GEngine->GetEngineSubsystem(); + + if (RuleProcessorSubsystem == nullptr) + { + return FReply::Handled(); + } + + const int32 Index = PlatformFilters.Find(ItemSelected); + + if (Index != INDEX_NONE) + { + CurrentPlatformFilterIndex = Index; + GetMutableDefault()->CurrentPlatform = static_cast(ItemSelected); + BuildLayout(RootContainerWidget); + } + + return FReply::Handled(); +} + +/** + * Apply rule button callback + */ +FReply SOculusXRProjectSetupToolWidget::OnApplyRuleClicked(SetupRulePtr Rule) +{ + if (Rule == nullptr) + { + return FReply::Handled(); + } + bool bShouldRestartEditor = false; + Rule->Apply(bShouldRestartEditor); + bShowButtonToRestart |= bShouldRestartEditor; + UpdateProjectStatus(); + return FReply::Handled(); +} + +/** + * Apply rule enabled callback + */ +bool SOculusXRProjectSetupToolWidget::OnApplyRuleEnabled(ERulesSection Section) +{ + return Section != ERulesSection::Applied && Section != ERulesSection::Ignored; +} + +/** + * Ignore/Unignore rule button callback + */ +void SOculusXRProjectSetupToolWidget::OnIgnoreRuleClicked(SetupRulePtr Rule, ERulesSection Section) +{ + if (Rule == nullptr) + { + return; + } + + if (Section != ERulesSection::Ignored) + { + Rule->SetIgnoreRule(true); + } + else + { + Rule->SetIgnoreRule(false); + } + + UpdateProjectStatus(); +} + +/** + * Apply rule button callback + */ +FReply SOculusXRProjectSetupToolWidget::OnApplyAllRulesClicked(ERulesSection Section) +{ + bool bShouldRestartEditor = false; + + const UOculusXRRuleProcessorSubsystem* RuleProcessorSubsystem = GEngine->GetEngineSubsystem(); + + for (auto& Rule : RuleProcessorSubsystem->GetRules()) + { + // Only apply rules that are critical and are in the required section or non-critical and are in the recommended section + bool bShouldApplyRule = Rule->GetSeverity() == ESetupRuleSeverity::Critical && Section == ERulesSection::Required; + bShouldApplyRule = bShouldApplyRule || Rule->GetSeverity() != ESetupRuleSeverity::Critical && Section == ERulesSection::Recommended; + // Only apply rules that in the current platform + bShouldApplyRule = bShouldApplyRule && (Rule->GetPlatform() & PlatformFilters[CurrentPlatformFilterIndex]) == PlatformFilters[CurrentPlatformFilterIndex]; + // Only apply rules that are valid + bShouldApplyRule = bShouldApplyRule && Rule->IsValid(); + // Only apply rules that are not applied yet + bShouldApplyRule = bShouldApplyRule && !Rule->IsApplied(); + // Only apply rules that are not ignored + bShouldApplyRule = bShouldApplyRule && !Rule->IsIgnored(); + if (!bShouldApplyRule) + { + continue; + } + + Rule->Apply(bShouldRestartEditor); + bShowButtonToRestart |= bShouldRestartEditor; + } + + UpdateProjectStatus(); + + return FReply::Handled(); +} + +/** + * Apply rule enabled callback + */ +bool SOculusXRProjectSetupToolWidget::OnApplyAllRulesEnabled(ERulesSection Section) const +{ + switch (Section) + { + case ERulesSection::Required: + return RuleStatus.PendingRequiredRulesCount > 0; + case ERulesSection::Recommended: + return RuleStatus.PendingRecommendedRulesCount > 0; + default: + return false; + } +} + +/** + * Ignore rule enabled callback + */ +bool SOculusXRProjectSetupToolWidget::OnIgnoreRuleEnabled(ERulesSection Section) +{ + return Section != ERulesSection::Applied; +} + +/** + * Expander visibility + */ +EVisibility SOculusXRProjectSetupToolWidget::OnHeaderExpanderVisibility(ERulesSection Section) +{ + return Section == ERulesSection::Filter ? EVisibility::Collapsed : EVisibility::Visible; +} + +/** + * Expander image + */ +const FSlateBrush* SOculusXRProjectSetupToolWidget::GetHeaderExpanderImage(ERulesSection Section) const +{ + const bool bIsHeaderExpanded = BIsSectionExpanded[static_cast(Section)]; + + FName ResourceName; + if (bIsHeaderExpanded) + { + static const FName ExpandedName = "TreeArrow_Expanded"; + ResourceName = ExpandedName; + } + else + { + static const FName CollapsedName = "TreeArrow_Collapsed"; + ResourceName = CollapsedName; + } + + return FAppStyle::Get().GetBrush(ResourceName); +} + +/** + * Expander clicked + */ +FReply SOculusXRProjectSetupToolWidget::OnHeaderExpanderClicked(ERulesSection Section) +{ + const uint8 index = static_cast(Section); + BIsSectionExpanded[index] = !BIsSectionExpanded[index]; + return FReply::Handled(); +} + +void SOculusXRProjectSetupToolWidget::UpdateProjectStatus() +{ + const UOculusXRRuleProcessorSubsystem* RuleProcessorSubsystem = GEngine->GetEngineSubsystem(); + + if (RuleProcessorSubsystem != nullptr) + { + RuleStatus = RuleProcessorSubsystem->UnAppliedRulesStatus(PlatformFilters[CurrentPlatformFilterIndex]); + } + + UpdateProjectStatusString(); +} + +/** + * Build the project status string + */ +void SOculusXRProjectSetupToolWidget::UpdateProjectStatusString() const +{ + if (ProjectStatusWidget == nullptr) + { + return; + } + + FString Status; + + if (RuleStatus.PendingRequiredRulesCount == 0 && RuleStatus.PendingRecommendedRulesCount == 0) + { + Status = TEXT("Current Project Status: All rules have been applied"); + } + else if (RuleStatus.PendingRequiredRulesCount == 0) + { + Status = FString::Printf(TEXT("Current Project Status: There are %d recommended rules to apply"), RuleStatus.PendingRecommendedRulesCount); + } + else if (RuleStatus.PendingRecommendedRulesCount == 0) + { + Status = FString::Printf(TEXT("Current Project Status: There are %d required rules to apply"), RuleStatus.PendingRequiredRulesCount); + } + else + { + Status = FString::Printf(TEXT("Current Project Status: There are %d required rules and %d recommended rules to apply"), RuleStatus.PendingRequiredRulesCount, RuleStatus.PendingRecommendedRulesCount); + } + + ProjectStatusWidget->SetText(FText::FromString(Status)); +} + +#undef LOCTEXT_NAMESPACE diff --git a/Plugins/MetaXR/Source/OculusXRProjectSetupTool/Private/Widget/OculusXRProjectSetupToolWidget.h b/Plugins/MetaXR/Source/OculusXRProjectSetupTool/Private/Widget/OculusXRProjectSetupToolWidget.h new file mode 100644 index 0000000..84db337 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRProjectSetupTool/Private/Widget/OculusXRProjectSetupToolWidget.h @@ -0,0 +1,119 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#pragma once + +#include "CoreMinimal.h" + +#include "DetailColumnSizeData.h" +#include "Widgets/DeclarativeSyntaxSupport.h" +#include "Widgets/SCompoundWidget.h" +#include "Widgets/Layout/SScrollBox.h" +#include "OculusXRRuleProcessorSubsystem.h" + +class FActiveTimerHandle; +/** + * Slate widget for the Project Setup Tool main tab + */ +class SOculusXRProjectSetupToolWidget : public SCompoundWidget +{ + SLATE_BEGIN_ARGS(SOculusXRProjectSetupToolWidget) {} + SLATE_END_ARGS() + + /** Construct the slate layout for the widget */ + + void Construct(const FArguments& InArgs); + +private: + enum class ERulesSection : uint8 + { + Filter, + Required, + Recommended, + Applied, + Ignored + }; + + /** Build the main layout */ + void BuildLayout(const TSharedPtr& RootContainer); + + /** Build the title section layout*/ + void BuildTitleSectionLayout(const TSharedPtr& RootContainer); + + /** Build the filter section layout */ + void BuildFilterSectionLayout(const TSharedPtr& RootContainer, const uint32 PlatformFilterIndex); + + /** Build a container for a rules section */ + TSharedPtr BuildRulesContainerLayout(const TSharedPtr& RootContainer, ERulesSection Section, const FText& SectionTitle); + + /** Build a single rules item */ + void BuildRowItemLayout(const TSharedPtr& SectionContentContainer, ERulesSection Section, const SetupRulePtr& Rule, const uint32 PlatformFilterIndex); + + /** Build the rules section layouts */ + void BuildRequiredRulesSectionLayout(const TSharedPtr& RootContainer); + void BuildRecommendedRulesSectionLayout(const TSharedPtr& RootContainer); + void BuildAppliedRulesSectionLayout(const TSharedPtr& RootContainer); + void BuildIgnoredRulesSectionLayout(const TSharedPtr& RootContainer); + + /** Platform filter callbacks */ + FReply OnPlatformFilterChanged(ESetupRulePlatform ItemSelected); + + /** Button handling callbacks */ + FReply OnApplyRuleClicked(SetupRulePtr Rule); + static bool OnApplyRuleEnabled(ERulesSection Section); + + FReply OnApplyAllRulesClicked(ERulesSection Section); + bool OnApplyAllRulesEnabled(ERulesSection Section) const; + + void OnIgnoreRuleClicked(SetupRulePtr Rule, ERulesSection Section); + static bool OnIgnoreRuleEnabled(ERulesSection Section); + + /** Rule visibility callback */ + EVisibility OnRowVisibility(ERulesSection Section, ESetupRulePlatform CurrentPlatform, SetupRulePtr Rule) const; + + /** Expander callbacks */ + const FSlateBrush* GetHeaderExpanderImage(ERulesSection Section) const; + static EVisibility OnHeaderExpanderVisibility(ERulesSection Section); + FReply OnHeaderExpanderClicked(ERulesSection Section); + + /** Restart Editor Notice Visibility */ + EVisibility OnRestartEditorNoticeVisibility() const; + /** Restart Editor Button Clicked */ + FReply OnRestartEditorButtonClicked(); + + /** Perform refresh */ + static void Refresh(); + + /** Register/Unregister timer */ + void UpdateActiveTimer(bool Register); + + /** Update the status of rules */ + void UpdateProjectStatus(); + + /** Update the status string */ + void UpdateProjectStatusString() const; + + /** Root container */ + TSharedPtr RootContainerWidget{}; + + /** Column size data */ + TSharedPtr ColumnSizeData{}; + + /** Platform filter */ + TArray PlatformFilters{}; + uint32 CurrentPlatformFilterIndex{}; + + /** Active timer handle */ + TWeakPtr ActiveTimerHandle; + + /** Restart pending after rule application */ + bool bShowButtonToRestart = false; + + /** Expanded/collapsed state for each section */ + TArray BIsSectionExpanded{ true, true, true, true, true }; + + /** Status string */ + TSharedPtr ProjectStatusWidget; + + /** Rules status */ + UOculusXRRuleProcessorSubsystem::RuleStatus RuleStatus{}; +}; diff --git a/Plugins/MetaXR/Source/OculusXRProjectSetupTool/Private/Widget/OculusXRProjectTutorialWidget.cpp b/Plugins/MetaXR/Source/OculusXRProjectSetupTool/Private/Widget/OculusXRProjectTutorialWidget.cpp new file mode 100644 index 0000000..ad5b9c3 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRProjectSetupTool/Private/Widget/OculusXRProjectTutorialWidget.cpp @@ -0,0 +1,331 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#pragma once + +#include "OculusXRProjectTutorialWidget.h" + +#include "OculusXRProjectSetupToolModule.h" +#include "OculusXRPSTEvents.h" +#include "OculusXRPSTSettings.h" +#include "OculusXRTelemetry.h" +#include "Widgets/Layout/SScrollBox.h" +#include "Widgets/Input/SButton.h" +#include "Styling/SlateStyle.h" +#include "Styling/SlateStyleMacros.h" + +#define LOCTEXT_NAMESPACE "OculusXRProjectTutorialWidget" + +static constexpr int32 NumTutorialPages = 3; + +/** + * Construct the layout for the project setup tool tab + * + * @param InArgs [in] the arguments associated with this tool + */ +void SOculusXRTutorialWindow::Construct(const FArguments& InArgs) +{ + // Construct the layout + RootContainerWidget = SNew(SVerticalBox); + + BuildGuidedTutorialLayout(RootContainerWidget); + + ChildSlot + [SNew(SBox) + .WidthOverride(1080) + .HeightOverride(600) + [RootContainerWidget.ToSharedRef()]]; +} + +/** + * Build the guided tutorial layout + */ +void SOculusXRTutorialWindow::BuildGuidedTutorialLayout(const TSharedPtr& RootContainer) +{ + // Construct the row of buttons + const TSharedPtr PreviousNextWidget = SNew(SHorizontalBox); + + PreviousNextWidget->AddSlot() + .AutoWidth() + [SNew(SButton) + .OnClicked(this, &SOculusXRTutorialWindow::OnPreviousClicked) + .IsEnabled(this, &SOculusXRTutorialWindow::OnPreviousEnabled) + .Text(LOCTEXT("Previous", "Previous"))]; + + PreviousNextWidget->AddSlot() + .AutoWidth() + .Padding(10, 0, 0, 0) + [SNew(SButton) + .OnClicked(this, &SOculusXRTutorialWindow::OnNextClicked) + .IsEnabled(this, &SOculusXRTutorialWindow::OnNextEnabled) + .Text(LOCTEXT("Next", "Next"))]; + + const TSharedPtr SkipWidget = SNew(SHorizontalBox); + + SkipWidget->AddSlot() + .AutoWidth() + [SNew(SButton) + .OnClicked(this, &SOculusXRTutorialWindow::OnSkipClicked) + .ButtonStyle(&FAppStyle::Get().GetWidgetStyle("PrimaryButton")) + .Text_Lambda([this]() { + if (GuidedTutorialPageIndex == NumTutorialPages - 1) + { + return LOCTEXT("Close", "Close"); + } + return LOCTEXT("Skip", "Skip"); + })]; + + const TSharedPtr PaginationWidget = SNew(SHorizontalBox); + + for (int i = 0; i < NumTutorialPages; ++i) + { + PaginationWidget->AddSlot() + .Padding(4.0f, 0.0f) + [SNew(SImage) + .DesiredSizeOverride(FVector2D(8.0f, 8.0f)) + .Image_Raw(this, &SOculusXRTutorialWindow::GetPaginationImageForIndex, i)]; + } + + const TSharedPtr ButtonsWidget = SNew(SHorizontalBox); + + ButtonsWidget->AddSlot() + .HAlign(HAlign_Left) + [PreviousNextWidget.ToSharedRef()]; + + ButtonsWidget->AddSlot() + .Padding(0.0f, 7.0f) + .HAlign(HAlign_Center) + [PaginationWidget.ToSharedRef()]; + + ButtonsWidget->AddSlot() + .HAlign(HAlign_Right) + [SkipWidget.ToSharedRef()]; + + // Construct the text widget + const TSharedPtr TextWidget = SNew(SVerticalBox); + AddTutorialPage1(TextWidget); + AddTutorialPage2(TextWidget); + AddTutorialPage3(TextWidget); + + // Construct the image panel + const TSharedPtr ImagePanel = SNew(SOverlay); + + ImagePanel->AddSlot() + [SNew(SImage) + .Image(FOculusXRProjectSetupToolModule::GetSlateStyle()->GetBrush("ProjectSetupTool.MetaQuestBackground"))]; + + // Construct the instruction panel + const TSharedPtr InstructionsPanel = SNew(SOverlay); + + InstructionsPanel->AddSlot() + [SNew(SVerticalBox) + + SVerticalBox::Slot() + .Padding(40) + .VAlign(VAlign_Center) + [TextWidget.ToSharedRef()]]; + + InstructionsPanel->AddSlot() + [SNew(SVerticalBox) + + SVerticalBox::Slot() + .Padding(40, 20) + .VAlign(VAlign_Bottom) + [ButtonsWidget.ToSharedRef()]]; + + // Construct the main panel + + const TSharedPtr MainPanel = SNew(SHorizontalBox); + + MainPanel->AddSlot() + [ImagePanel.ToSharedRef()]; + + MainPanel->AddSlot() + [InstructionsPanel.ToSharedRef()]; + + // Add to the root container + + RootContainer->AddSlot() + [MainPanel.ToSharedRef()]; +} + +/** + * Previous button clicked + */ +FReply SOculusXRTutorialWindow::OnPreviousClicked() +{ + --GuidedTutorialPageIndex; + + if (GuidedTutorialPageIndex < 0) + { + GuidedTutorialPageIndex = 0; + } + + const OculusXRTelemetry::TScopedMarker Previous; + const auto& Annotated = Previous + .AddAnnotation(OculusXRTelemetry::Annotations::Value, + TCHAR_TO_ANSI(*FString::FromInt(GuidedTutorialPageIndex))); + + return FReply::Handled(); +} + +/** + * Previous button enabled + */ +bool SOculusXRTutorialWindow::OnPreviousEnabled() const +{ + return GuidedTutorialPageIndex > 0; +} + +/** + * Next button clicked + */ +FReply SOculusXRTutorialWindow::OnNextClicked() +{ + ++GuidedTutorialPageIndex; + + if (GuidedTutorialPageIndex == NumTutorialPages - 1) + { + GetMutableDefault()->bGuidedTutorialComplete = true; + GetMutableDefault()->SaveConfig(); + } + const OculusXRTelemetry::TScopedMarker NextEvent; + const auto& Annotated = NextEvent + .AddAnnotation(OculusXRTelemetry::Annotations::Value, + TCHAR_TO_ANSI(*FString::FromInt(GuidedTutorialPageIndex))); + return FReply::Handled(); +} + +/** + * Next button enabled + */ +bool SOculusXRTutorialWindow::OnNextEnabled() const +{ + return GuidedTutorialPageIndex < NumTutorialPages - 1; +} + +/** + * Skip button clicked + */ +FReply SOculusXRTutorialWindow::OnSkipClicked() const +{ + FSlateApplication::Get().FindWidgetWindow(AsShared())->RequestDestroyWindow(); + return FReply::Handled(); +} + +/** + * Get the image to use for the pagination indicator + */ +const FSlateBrush* SOculusXRTutorialWindow::GetPaginationImageForIndex(int32 PageIndex) const +{ + if (PageIndex == GuidedTutorialPageIndex) + { + return FOculusXRProjectSetupToolModule::GetSlateStyle()->GetBrush("ProjectSetupTool.WhiteDot"); + } + + return FOculusXRProjectSetupToolModule::GetSlateStyle()->GetBrush("ProjectSetupTool.GreyDot"); +} + +void SOculusXRTutorialWindow::AddTutorialPage1(const TSharedPtr& TextWidget) const +{ + TextWidget->AddSlot() + .AutoHeight() + [SNew(STextBlock) + .AutoWrapText(true) + .Font(DEFAULT_FONT("Regular", 24)) + .Visibility_Lambda([this]() { return GuidedTutorialPageIndex == 0 ? EVisibility::Visible : EVisibility::Collapsed; }) + .Text(LOCTEXT("Title1", "Welcome to the Meta XR Project Setup Tool"))]; + + TextWidget->AddSlot() + .AutoHeight() + .Padding(0, 20, 0, 0) + [SNew(STextBlock) + .AutoWrapText(true) + .Font(DEFAULT_FONT("Regular", 12)) + .Visibility_Lambda([this]() { return GuidedTutorialPageIndex == 0 ? EVisibility::Visible : EVisibility::Collapsed; }) + .Text(LOCTEXT("Body1", + "The Unreal Project Setup Tool can help you quickly configure projects using the Meta XR Plugin. This tool guides you through the necessary steps so you can start developing faster. The Unreal Project Setup Tool tests a registry of rules called Configuration Tasks. We provide default rules to make your project Quest Ready."))]; +} + +void SOculusXRTutorialWindow::AddTutorialPage2(const TSharedPtr& TextWidget) const +{ + + TextWidget->AddSlot() + .AutoHeight() + [SNew(STextBlock) + .AutoWrapText(true) + .Font(DEFAULT_FONT("Regular", 24)) + .Visibility_Lambda([this]() { return GuidedTutorialPageIndex == 1 ? EVisibility::Visible : EVisibility::Collapsed; }) + .Text(LOCTEXT("Title2", "Here are the key things to know about Unreal Project Setup Tool"))]; + + TextWidget->AddSlot() + .AutoHeight() + .Padding(0, 10, 0, 0) + [SNew(STextBlock) + .AutoWrapText(true) + .Font(DEFAULT_FONT("Bold", 12)) + .Visibility_Lambda([this]() { return GuidedTutorialPageIndex == 1 ? EVisibility::Visible : EVisibility::Collapsed; }) + .Text(LOCTEXT("Body2.1", "Actions"))]; + TextWidget->AddSlot() + .AutoHeight() + .Padding(0, 3, 0, 0) + [SNew(STextBlock) + .AutoWrapText(true) + .Font(DEFAULT_FONT("Regular", 12)) + .Visibility_Lambda([this]() { return GuidedTutorialPageIndex == 1 ? EVisibility::Visible : EVisibility::Collapsed; }) + .Text(LOCTEXT("Body2.2", "A Configuration Task is regularly checked for its validation. You can interact directly with a Task in the following ways."))]; + + TextWidget->AddSlot() + .AutoHeight() + .Padding(0, 3, 0, 0) + [SNew(STextBlock) + .AutoWrapText(true) + .Font(DEFAULT_FONT("Bold", 12)) + .Visibility_Lambda([this]() { return GuidedTutorialPageIndex == 1 ? EVisibility::Visible : EVisibility::Collapsed; }) + .Text(LOCTEXT("Body2.3", "Fix/Apply"))]; + + TextWidget->AddSlot() + .AutoHeight() + .Padding(0, 3, 0, 0) + [SNew(STextBlock) + .AutoWrapText(true) + .Font(DEFAULT_FONT("Regular", 12)) + .Visibility_Lambda([this]() { return GuidedTutorialPageIndex == 1 ? EVisibility::Visible : EVisibility::Collapsed; }) + .Text(LOCTEXT("Body2.3", "Manually call the fix delegate for this Task in order to resolve the issue. This action is only available for tasks that are not already validated."))]; + + TextWidget->AddSlot() + .AutoHeight() + .Padding(0, 3, 0, 0) + [SNew(STextBlock) + .AutoWrapText(true) + .Font(DEFAULT_FONT("Bold", 12)) + .Visibility_Lambda([this]() { return GuidedTutorialPageIndex == 1 ? EVisibility::Visible : EVisibility::Collapsed; }) + .Text(LOCTEXT("Body2.4", "Ignore / Unignore"))]; + + TextWidget->AddSlot() + .AutoHeight() + .Padding(0, 3, 0, 0) + [SNew(STextBlock) + .AutoWrapText(true) + .Font(DEFAULT_FONT("Regular", 12)) + .Visibility_Lambda([this]() { return GuidedTutorialPageIndex == 1 ? EVisibility::Visible : EVisibility::Collapsed; }) + .Text(LOCTEXT("Body2.5", "This moves the task to another category that will get ignored for both checks and fixes. This gives the control back to developers who may not want to be forced to follow some guidelines or even requirements in some specific cases."))]; +} + +void SOculusXRTutorialWindow::AddTutorialPage3(const TSharedPtr& TextWidget) const +{ + TextWidget->AddSlot() + .AutoHeight() + [SNew(STextBlock) + .AutoWrapText(true) + .Font(DEFAULT_FONT("Bold", 24)) + .Visibility_Lambda([this]() { return GuidedTutorialPageIndex == 2 ? EVisibility::Visible : EVisibility::Collapsed; }) + .Text(LOCTEXT("Title3", "You’re good to go! Start developing faster with Unreal Project Setup Tool"))]; + + TextWidget->AddSlot() + .AutoHeight() + .Padding(0, 20, 0, 0) + [SNew(STextBlock) + .AutoWrapText(true) + .Font(DEFAULT_FONT("Regular", 12)) + .Visibility_Lambda([this]() { return GuidedTutorialPageIndex == 2 ? EVisibility::Visible : EVisibility::Collapsed; }) + .Text(LOCTEXT("Body3", "You can check Unreal Project Setup Tool from the Tools menu bar, Meta XR Plugin Settings Page or from the Meta icon on the bottom bar. The tool proactively checks for configuration changes."))]; +} +#undef LOCTEXT_NAMESPACE diff --git a/Plugins/MetaXR/Source/OculusXRProjectSetupTool/Private/Widget/OculusXRProjectTutorialWidget.h b/Plugins/MetaXR/Source/OculusXRProjectSetupTool/Private/Widget/OculusXRProjectTutorialWidget.h new file mode 100644 index 0000000..053bccc --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRProjectSetupTool/Private/Widget/OculusXRProjectTutorialWidget.h @@ -0,0 +1,46 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#pragma once + +#include "CoreMinimal.h" + +#include "Widgets/DeclarativeSyntaxSupport.h" +#include "Widgets/SCompoundWidget.h" +#include "Widgets/Layout/SScrollBox.h" + +class FActiveTimerHandle; +/** + * Slate widget for the tutorial + */ +class SOculusXRTutorialWindow : public SCompoundWidget +{ + SLATE_BEGIN_ARGS(SOculusXRTutorialWindow) {} + SLATE_END_ARGS() + + /** Construct the slate layout for the widget */ + void Construct(const FArguments& InArgs); + +private: + /** Build the guided tutorial layout */ + void BuildGuidedTutorialLayout(const TSharedPtr& RootContainer); + + FReply OnPreviousClicked(); + bool OnPreviousEnabled() const; + + FReply OnNextClicked(); + bool OnNextEnabled() const; + + FReply OnSkipClicked() const; + + const FSlateBrush* GetPaginationImageForIndex(int32 PageIndex) const; + + void AddTutorialPage1(const TSharedPtr& TextWidget) const; + void AddTutorialPage2(const TSharedPtr& TextWidget) const; + void AddTutorialPage3(const TSharedPtr& TextWidget) const; + + /** Root container */ + TSharedPtr RootContainerWidget{}; + + /** Current tutorial page */ + int32 GuidedTutorialPageIndex = 0; +}; diff --git a/Plugins/MetaXR/Source/OculusXRProjectSetupTool/Private/Widget/OculusXRStatusBarWidget.cpp b/Plugins/MetaXR/Source/OculusXRProjectSetupTool/Private/Widget/OculusXRStatusBarWidget.cpp new file mode 100644 index 0000000..d5b2573 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRProjectSetupTool/Private/Widget/OculusXRStatusBarWidget.cpp @@ -0,0 +1,77 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#pragma once + +#include "OculusXRStatusBarWidget.h" + +#include "OculusXRProjectSetupToolModule.h" +#include "OculusXRRuleProcessorSubsystem.h" + +#define LOCTEXT_NAMESPACE "OculusXRStatusBarWidget" + +/** + * Construct the layout for the status bar widget + * + * @param InArgs [in] the arguments associated with this tool + */ +void SOculusXRStatusBarWidget::Construct(const FArguments& InArgs) +{ + ChildSlot + [SNew(SHorizontalBox) + + SHorizontalBox::Slot() + [SNew(SButton) + .HAlign(HAlign_Center) + .VAlign(VAlign_Center) + .ButtonStyle(FAppStyle::Get(), "SimpleButton") + .ToolTipText(LOCTEXT("StatusBarWidget_Tooltip", "Launch Meta XR Project Setup tool")) + .OnClicked_Lambda([]() -> FReply { + IOculusXRProjectSetupToolModule::Get().ShowProjectSetupTool("Toolbar"); + return FReply::Handled(); + }) + .ContentPadding(0) + [SNew(SOverlay) + + SOverlay::Slot() + [SNew(SHorizontalBox) + + SHorizontalBox::Slot() + .AutoWidth() + [SNew(SImage) + .Image(FOculusXRProjectSetupToolModule::GetSlateStyle()->GetBrush("ProjectSetupTool.MetaLogo")) + .DesiredSizeOverride(FVector2D(22.0f, 22.0f))]] + + SOverlay::Slot() + [SNew(SHorizontalBox) + + SHorizontalBox::Slot() + .AutoWidth() + .Padding(16, 4, -2, 10) + [SNew(SImage) + .Image_Static(SOculusXRStatusBarWidget::GetDotImage) + .DesiredSizeOverride(FVector2D(8.0f, 8.0f))]]]]]; +} + +/** + * Determine the correct image to use + */ +const FSlateBrush* SOculusXRStatusBarWidget::GetDotImage() +{ + const UOculusXRRuleProcessorSubsystem* RuleProcessorSubsystem = GEngine->GetEngineSubsystem(); + + if (RuleProcessorSubsystem == nullptr) + { + return FOculusXRProjectSetupToolModule::GetSlateStyle()->GetBrush("ProjectSetupTool.GreenDot"); + } + + const auto& RuleStatus = RuleProcessorSubsystem->UnAppliedRulesStatus(MetaQuest_All); + + if (RuleStatus.PendingRequiredRulesCount > 0) + { + return FOculusXRProjectSetupToolModule::GetSlateStyle()->GetBrush("ProjectSetupTool.RedDot"); + } + + if (RuleStatus.PendingRecommendedRulesCount > 0) + { + return FOculusXRProjectSetupToolModule::GetSlateStyle()->GetBrush("ProjectSetupTool.YellowDot"); + } + + return FOculusXRProjectSetupToolModule::GetSlateStyle()->GetBrush("ProjectSetupTool.GreenDot"); +} + +#undef LOCTEXT_NAMESPACE diff --git a/Plugins/MetaXR/Source/OculusXRProjectSetupTool/Private/Widget/OculusXRStatusBarWidget.h b/Plugins/MetaXR/Source/OculusXRProjectSetupTool/Private/Widget/OculusXRStatusBarWidget.h new file mode 100644 index 0000000..38c48b4 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRProjectSetupTool/Private/Widget/OculusXRStatusBarWidget.h @@ -0,0 +1,27 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#pragma once + +#include "CoreMinimal.h" + +#include "Widgets/DeclarativeSyntaxSupport.h" +#include "Widgets/SCompoundWidget.h" + +/** + * Slate widget for the widget used to show any outstanding issues in the status bar + */ +class SOculusXRStatusBarWidget : public SCompoundWidget +{ + SLATE_BEGIN_ARGS(SOculusXRStatusBarWidget) {} + SLATE_END_ARGS() + + /** Construct the slate layout for the widget */ + + void Construct(const FArguments& InArgs); + +private: + /** + * Determine the correct image to use + */ + static const FSlateBrush* GetDotImage(); +}; diff --git a/Plugins/MetaXR/Source/OculusXRProjectSetupTool/Public/IOculusXRProjectSetupModule.h b/Plugins/MetaXR/Source/OculusXRProjectSetupTool/Public/IOculusXRProjectSetupModule.h new file mode 100644 index 0000000..3d93c1a --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRProjectSetupTool/Public/IOculusXRProjectSetupModule.h @@ -0,0 +1,29 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#pragma once +#include "Modules/ModuleManager.h" + +//------------------------------------------------------------------------------------------------- +// IOculusXRProjectSetupToolModule +//------------------------------------------------------------------------------------------------- + +/** + * The public interface to this module. + */ +class IOculusXRProjectSetupToolModule : public IModuleInterface +{ +public: + /** + * Singleton-like access to this module's interface. This is just for convenience! + * Beware of calling this during the shutdown phase, though. Your module might have been unloaded already. + * + * @return Returns singleton instance, loading the module on demand if needed + */ + static inline IOculusXRProjectSetupToolModule& Get() + { + return FModuleManager::LoadModuleChecked("OculusXRProjectSetupTool"); + } + + /** Show the project setup tool window */ + virtual void ShowProjectSetupTool(const FString& Origin) = 0; +}; diff --git a/Plugins/MetaXR/Source/OculusXRProjectSetupTool/Public/OculusXRPSTSettings.h b/Plugins/MetaXR/Source/OculusXRProjectSetupTool/Public/OculusXRPSTSettings.h new file mode 100644 index 0000000..f9089f9 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRProjectSetupTool/Public/OculusXRPSTSettings.h @@ -0,0 +1,52 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#pragma once + +#include "CoreMinimal.h" +#include "OculusXRSetupRule.h" +#include "OculusXRPSTSettings.generated.h" + +/** + * Meta XR Project Setup tool Settings + */ +UCLASS(config = EditorPerProjectUserSettings) +class OCULUSXRPROJECTSETUPTOOL_API UOculusXRPSTSettings : public UObject +{ + GENERATED_BODY() +public: + /** + * @brief Ignored rules by developer + */ + UPROPERTY(config) + TSet IgnoredRules = {}; + + /** + * @brief Selected platform for development + */ + UPROPERTY(config) + uint32 CurrentPlatform = static_cast(MetaQuest_All); + + /** + * @brief If tools should periodically check if list of rules and rules' status + */ + UPROPERTY(config, EditAnywhere, Category = MetaXR) + bool bBackGroundChecks = true; + + /** + * @brief If build should fail if critical rule is not applied + */ + UPROPERTY(config, EditAnywhere, Category = MetaXR) + bool bStopBuildOnUnAppliedCriticalItems = false; + + /** + * @brief If guided tutorial has been completed/skipped + */ + UPROPERTY(config, EditAnywhere, Category = MetaXR) + bool bGuidedTutorialComplete = false; + + /** + * @brief If guided tutorial showed + */ + UPROPERTY(config, EditAnywhere, Category = MetaXR) + bool bShowGuidedTutorial = true; +}; diff --git a/Plugins/MetaXR/Source/OculusXRProjectSetupTool/Public/OculusXRRuleProcessorSubsystem.h b/Plugins/MetaXR/Source/OculusXRProjectSetupTool/Public/OculusXRRuleProcessorSubsystem.h new file mode 100644 index 0000000..4bc7b29 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRProjectSetupTool/Public/OculusXRRuleProcessorSubsystem.h @@ -0,0 +1,100 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#pragma once + +#include "CoreMinimal.h" +#include "OculusXRSetupRule.h" +#include "Developer/LauncherServices/Public/ILauncher.h" +#include "Subsystems/EngineSubsystem.h" +#include "OculusXRRuleProcessorSubsystem.generated.h" + +/** + * The rule processor handles registration and querying of rules + */ +UCLASS() +class OCULUSXRPROJECTSETUPTOOL_API UOculusXRRuleProcessorSubsystem final : public UEngineSubsystem +{ + GENERATED_BODY() + +public: + struct RuleStatus + { + unsigned PendingRequiredRulesCount = 0; + unsigned PendingRecommendedRulesCount = 0; + }; + /** + * Initialize the subsystem. USubsystem override + */ + virtual void Initialize(FSubsystemCollectionBase& Collection) override; + + /** + * De-initializes the subsystem. USubsystem override + */ + virtual void Deinitialize() override; + + /** + * Register a rule + * + * @return true if successfully registered + */ + bool RegisterRule(const SetupRulePtr& Rule); + + /** + * Unregister a rule + * + * @return true if successfully unregistered + */ + bool UnregisterRule(const SetupRulePtr& Rule); + + /** + * Unregister all rules + */ + void UnregisterAllRules(); + + /** + * Fetch all rules + */ + const TSet& GetRules() const; + + /** + * Fetch rule with given `Id` + */ + SetupRulePtr GetRule(const FName& Id) const; + + /** + * Returns if there are dynamic lights in project + */ + bool DynamicLightsExistInProject() const; + + void SendSummaryEvent(); + + void SendSummaryEvent(ESetupRulePlatform Platform) const; + /** + * Refresh state + */ + void Refresh(); + + /** + * Returns number of not applied critical and recommended rules + */ + RuleStatus UnAppliedRulesStatus(ESetupRulePlatform Platform) const; + +private: + void PopulateDynamicLights(); + void RegisterRules(const TArray& Rules); + + //** A set containing all the registered rules + TSet Rules = {}; + + // Dynamic lights in project + TMap> DynamicLights; + + // Launcher handles + FDelegateHandle LauncherCallbackHandle; + void OnLauncherCreated(ILauncherRef Launcher); + void OnLauncherWorkerStarted(ILauncherWorkerPtr LauncherWorker, ILauncherProfileRef Profile); + + void OnPIEEnded(bool bIsSimulating); + + TArray UnAppliedRulesForPlatform(ESetupRulePlatform Platform, const TSet& Severities) const; +}; diff --git a/Plugins/MetaXR/Source/OculusXRProjectSetupTool/Public/OculusXRSetupRule.h b/Plugins/MetaXR/Source/OculusXRProjectSetupTool/Public/OculusXRSetupRule.h new file mode 100644 index 0000000..c826333 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRProjectSetupTool/Public/OculusXRSetupRule.h @@ -0,0 +1,145 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#pragma once + +#include "CoreMinimal.h" + +/** + * Rule categories + */ +enum class ESetupRuleCategory : uint8 +{ + Compatibility = 0, + Rendering = 1, + Quality = 2, + Physics = 3, + Plugins = 4, + Features = 5, + Miscellaneous = 6 +}; + +/** + * Rule severities + */ +enum class ESetupRuleSeverity : uint8 +{ + Warning = 0, + Performance = 1, + Critical = 2 +}; + +/** + * Rule platforms + */ + +UENUM() +enum class ESetupRulePlatform : uint32 +{ + //None + None = 0, + // Link + MetaLink = 0x1 UMETA(DisplayName = "Link"), + + // Quest + MetaQuest_2 = 0x2 UMETA(DisplayName = "Quest 2"), + MetaQuest_3 = 0x4 UMETA(DisplayName = "Quest 3"), + MetaQuest_Pro = 0x8 UMETA(DisplayName = "Quest Pro") +}; + +ENUM_CLASS_FLAGS(ESetupRulePlatform) + +static constexpr ESetupRulePlatform MetaQuest_All = ESetupRulePlatform::MetaQuest_2 | ESetupRulePlatform::MetaQuest_3 | ESetupRulePlatform::MetaQuest_Pro; + +static constexpr ESetupRulePlatform All_Platforms = MetaQuest_All | ESetupRulePlatform::MetaLink; + +class OCULUSXRPROJECTSETUPTOOL_API ISetupRule +{ +public: + ISetupRule( + const FName& InId, + const FText& InDisplayName, + const FText& InDescription, + const ESetupRuleCategory InCategory, + const ESetupRuleSeverity InSeverity, + const ESetupRulePlatform InPlatform = All_Platforms); + virtual ~ISetupRule() = default; + virtual bool IsApplied() const = 0; + + // Returns true if rule is valid. For example, Rule that checks if passthrough enabled is checked and can be applied only if PassthroughComponent is added. + virtual bool IsValid(); + + bool IsIgnored() const; + void SetIgnoreRule(bool bIgnore, bool bSendMetrics = true); + + const FName& GetId() const; + FText GetDisplayName() const; + FText GetDescription() const; + + ESetupRuleCategory GetCategory() const; + ESetupRuleSeverity GetSeverity() const; + ESetupRulePlatform GetPlatform() const; + + void Apply(bool& OutShouldRestartEditor); + +protected: + virtual void ApplyImpl(bool& OutShouldRestartEditor) = 0; + +private: + /** Id for the rule */ + FName Id; + + /** Display name of the rule */ + FText DisplayName; + + /** Description of the rule */ + FText Description; + + /** Category of the rule */ + ESetupRuleCategory Category; + + /** Severity of the rule */ + ESetupRuleSeverity Severity; + + /** Platforms the rule applies to */ + ESetupRulePlatform Platform; + + /** Is rule ignored */ + bool bIsIgnored = false; +}; + +typedef TSharedPtr SetupRulePtr; + +/** + * Setup rule symbol database hash. + */ +struct FSetupRuleKeyFunc +{ + enum + { + bAllowDuplicateKeys = 0 + }; + typedef TCallTraits::ParamType KeyInitType; + typedef TCallTraits::ParamType ElementInitType; + + /** + * @return The key used to index the given element. + */ + static FORCEINLINE KeyInitType GetSetKey(ElementInitType Element) + { + return Element->GetId(); + } + + /** + * @return True if the keys match. + */ + static FORCEINLINE bool Matches(KeyInitType A, KeyInitType B) + { + return A == B; + } + + /** Calculates a hash index for a key. */ + static FORCEINLINE uint32 GetKeyHash(KeyInitType Key) + { + return GetTypeHash(Key); + } +}; diff --git a/Plugins/MetaXR/Source/OculusXRScene/OculusXRScene.Build.cs b/Plugins/MetaXR/Source/OculusXRScene/OculusXRScene.Build.cs new file mode 100644 index 0000000..6a987f9 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRScene/OculusXRScene.Build.cs @@ -0,0 +1,37 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +namespace UnrealBuildTool.Rules +{ + public class OculusXRScene : ModuleRules + { + public OculusXRScene(ReadOnlyTargetRules Target) : base(Target) + { + bUseUnity = true; + + PrivateDependencyModuleNames.AddRange( + new string[] + { + "Core", + "CoreUObject", + "Engine", + "OculusXRHMD", + "OculusXRAnchors", + "OVRPluginXR", + "ProceduralMeshComponent", + }); + + PrivateIncludePaths.AddRange( + new string[] { + // Relative to Engine\Plugins\Runtime\Oculus\OculusVR\Source + "OculusXRHMD/Private", + "OculusXRAnchors/Private" + }); + + PublicIncludePaths.AddRange( + new string[] { + "Runtime/Engine/Classes/Components", + }); + } + } +} diff --git a/Plugins/MetaXR/Source/OculusXRScene/Private/OculusXRScene.cpp b/Plugins/MetaXR/Source/OculusXRScene/Private/OculusXRScene.cpp new file mode 100644 index 0000000..e66c943 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRScene/Private/OculusXRScene.cpp @@ -0,0 +1,17 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#include "OculusXRScene.h" +#include "OculusXRSceneModule.h" +#include "OculusXRHMDPrivate.h" +#include "OculusXRHMD.h" +#include "OculusXRPluginWrapper.h" + +#define LOCTEXT_NAMESPACE "OculusXRScene" + +namespace OculusXRScene +{ + + +} // namespace OculusXRScene + +#undef LOCTEXT_NAMESPACE diff --git a/Plugins/MetaXR/Source/OculusXRScene/Private/OculusXRSceneActor.cpp b/Plugins/MetaXR/Source/OculusXRScene/Private/OculusXRSceneActor.cpp new file mode 100644 index 0000000..89a3925 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRScene/Private/OculusXRSceneActor.cpp @@ -0,0 +1,757 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +#include "OculusXRSceneActor.h" +#include "OculusXRSceneModule.h" +#include "OculusXRHMDModule.h" +#include "OculusXRHMD.h" +#include "OculusXRAnchorManager.h" +#include "OculusXRAnchorTypes.h" +#include "OculusXRAnchorBPFunctionLibrary.h" +#include "OculusXRSceneDelegates.h" +#include "OculusXRDelegates.h" +#include "Components/StaticMeshComponent.h" +#include "Engine/AssetManager.h" +#include "Engine/StaticMesh.h" +#include "Engine/StaticMeshActor.h" +#include "Engine/World.h" +#include "GameFramework/WorldSettings.h" +#include "ProceduralMeshComponent.h" +#include "OculusXRSceneGlobalMeshComponent.h" + +#define LOCTEXT_NAMESPACE "OculusXRSceneActor" + +////////////////////////////////////////////////////////////////////////// +// ASceneActor + +AOculusXRSceneActor::AOculusXRSceneActor(const FObjectInitializer& ObjectInitializer) + : Super(ObjectInitializer) +{ + ResetStates(); + + // Create required components + RoomLayoutManagerComponent = CreateDefaultSubobject(TEXT("OculusXRRoomLayoutManagerComponent")); + + // Following are the semantic labels we want to support default properties for. User can always add new ones through the properties panel if needed. + const FString default2DSemanticClassifications[] = { + TEXT("WALL_FACE"), + TEXT("CEILING"), + TEXT("FLOOR"), + TEXT("COUCH"), + TEXT("TABLE"), + TEXT("DOOR_FRAME"), + TEXT("WINDOW_FRAME"), + TEXT("WALL_ART"), + TEXT("INVISIBLE_WALL_FACE"), + TEXT("OTHER") + }; + + const FString default3DSemanticClassifications[] = { + TEXT("COUCH"), + TEXT("TABLE"), + TEXT("SCREEN"), + TEXT("BED"), + TEXT("LAMP"), + TEXT("PLANT"), + TEXT("STORAGE"), + TEXT("OTHER") + }; + + FOculusXRSpawnedSceneAnchorProperties spawnedAnchorProps; + spawnedAnchorProps.ActorComponent = nullptr; + spawnedAnchorProps.StaticMesh = nullptr; + + // Setup initial scene plane and volume properties + for (auto& semanticLabel2D : default2DSemanticClassifications) + { + FOculusXRSpawnedSceneAnchorProperties& props = ScenePlaneSpawnedSceneAnchorProperties.Add(semanticLabel2D, spawnedAnchorProps); + props.ForceParallelToFloor = (semanticLabel2D != "WALL_FACE"); + } + + for (auto& semanticLabel3D : default3DSemanticClassifications) + { + FOculusXRSpawnedSceneAnchorProperties& props = SceneVolumeSpawnedSceneAnchorProperties.Add(semanticLabel3D, spawnedAnchorProps); + props.ForceParallelToFloor = true; + } +} + +void AOculusXRSceneActor::ResetStates() +{ + bCaptureFlowWasLaunched = false; + ClearScene(); +} + +void AOculusXRSceneActor::BeginPlay() +{ + Super::BeginPlay(); + + // Create a scene component as root so we can attach spawned actors to it + USceneComponent* rootSceneComponent = NewObject(this, USceneComponent::StaticClass()); + rootSceneComponent->SetMobility(EComponentMobility::Static); + rootSceneComponent->RegisterComponent(); + SetRootComponent(rootSceneComponent); + + SceneGlobalMeshComponent = FindComponentByClass(); + + // Register delegates + RoomLayoutManagerComponent->OculusXRRoomLayoutSceneCaptureCompleteNative.AddUObject(this, &AOculusXRSceneActor::SceneCaptureComplete_Handler); + + // Make an initial request to query for the room layout if bPopulateSceneOnBeginPlay was set to true + if (bPopulateSceneOnBeginPlay) + { + PopulateScene(); + } + +} + +void AOculusXRSceneActor::EndPlay(EEndPlayReason::Type Reason) +{ + // Unregister delegates + RoomLayoutManagerComponent->OculusXRRoomLayoutSceneCaptureCompleteNative.RemoveAll(this); + + // Calling ResetStates will reset member variables to their default values (including the request IDs). + ResetStates(); + + + Super::EndPlay(Reason); +} + +void AOculusXRSceneActor::Tick(float DeltaTime) +{ + Super::Tick(DeltaTime); +} + +bool AOculusXRSceneActor::IsValidUuid(const FOculusXRUUID& Uuid) +{ + return Uuid.UUIDBytes != nullptr; +} + +void AOculusXRSceneActor::LaunchCaptureFlow() +{ + UE_LOG(LogOculusXRScene, Verbose, TEXT("Launch capture flow")); + + if (RoomLayoutManagerComponent) + { + UE_LOG(LogOculusXRScene, Verbose, TEXT("Launch capture flow -- RoomLayoutManagerComponent")); + + const bool bResult = RoomLayoutManagerComponent->LaunchCaptureFlow(); + if (!bResult) + { + UE_LOG(LogOculusXRScene, Error, TEXT("LaunchCaptureFlow() failed!")); + } + } +} + +void AOculusXRSceneActor::LaunchCaptureFlowIfNeeded() +{ +#if WITH_EDITOR + UE_LOG(LogOculusXRScene, Display, TEXT("Scene Capture does not work over Link. Please capture a scene with the HMD in standalone mode, then access the scene model over Link.")); +#else + // Depending on LauchCaptureFlowWhenMissingScene, we might not want to launch Capture Flow + if (LauchCaptureFlowWhenMissingScene != EOculusXRLaunchCaptureFlowWhenMissingScene::NEVER) + { + if (LauchCaptureFlowWhenMissingScene == EOculusXRLaunchCaptureFlowWhenMissingScene::ALWAYS || (!bCaptureFlowWasLaunched && LauchCaptureFlowWhenMissingScene == EOculusXRLaunchCaptureFlowWhenMissingScene::ONCE)) + { + LaunchCaptureFlow(); + } + } +#endif +} + +AActor* AOculusXRSceneActor::SpawnActorWithSceneComponent(const FOculusXRUInt64& Space, const FOculusXRUInt64& RoomSpaceID, const TArray& SemanticClassifications, UClass* sceneAnchorComponentInstanceClass) +{ + FActorSpawnParameters actorSpawnParams; + actorSpawnParams.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn; + AActor* Anchor = GetWorld()->SpawnActor(AActor::StaticClass(), FVector::ZeroVector, FRotator::ZeroRotator, actorSpawnParams); + + USceneComponent* rootComponent = NewObject(Anchor, USceneComponent::StaticClass()); + rootComponent->SetMobility(EComponentMobility::Movable); + rootComponent->RegisterComponent(); + Anchor->SetRootComponent(rootComponent); + rootComponent->SetWorldLocation(FVector::ZeroVector); + + Anchor->AttachToActor(this, FAttachmentTransformRules::KeepRelativeTransform); + +#if WITH_EDITOR + if (SemanticClassifications.Num() > 0) + { + Anchor->SetActorLabel(FString::Join(SemanticClassifications, TEXT("-")), false); + } +#endif + + UOculusXRSceneAnchorComponent* sceneAnchorComponent = NewObject(Anchor, sceneAnchorComponentInstanceClass); + sceneAnchorComponent->RegisterComponent(); + + sceneAnchorComponent->SetHandle(Space); + sceneAnchorComponent->SemanticClassifications = SemanticClassifications; + sceneAnchorComponent->RoomSpaceID = RoomSpaceID; + + EOculusXRAnchorResult::Type Result; + OculusXRAnchors::FOculusXRAnchors::SetAnchorComponentStatus(sceneAnchorComponent, EOculusXRSpaceComponentType::Locatable, true, 0.0f, FOculusXRAnchorSetComponentStatusDelegate(), Result); + + return Anchor; +} + +AActor* AOculusXRSceneActor::SpawnOrUpdateSceneAnchor(AActor* Anchor, const FOculusXRUInt64& Space, const FOculusXRUInt64& RoomSpaceID, const FVector& BoundedPos, const FVector& BoundedSize, const TArray& SemanticClassifications, const EOculusXRSpaceComponentType AnchorComponentType) +{ + if (Space.Value == 0) + { + UE_LOG(LogOculusXRScene, Error, TEXT("AOculusXRSceneActor::SpawnOrUpdateSceneAnchor Invalid Space handle.")); + return Anchor; + } + + if (!(AnchorComponentType == EOculusXRSpaceComponentType::ScenePlane || AnchorComponentType == EOculusXRSpaceComponentType::SceneVolume)) + { + UE_LOG(LogOculusXRScene, Error, TEXT("AOculusXRSceneActor::SpawnOrUpdateSceneAnchor Anchor doesn't have ScenePlane or SceneVolume component active.")); + return Anchor; + } + + if (0 == SemanticClassifications.Num()) + { + UE_LOG(LogOculusXRScene, Error, TEXT("AOculusXRSceneActor::SpawnOrUpdateSceneAnchor No semantic classification found.")); + return Anchor; + } + + FOculusXRSpawnedSceneAnchorProperties* foundProperties = (AnchorComponentType == EOculusXRSpaceComponentType::ScenePlane) ? ScenePlaneSpawnedSceneAnchorProperties.Find(SemanticClassifications[0]) : SceneVolumeSpawnedSceneAnchorProperties.Find(SemanticClassifications[0]); + + if (!foundProperties) + { + UE_LOG(LogOculusXRScene, Warning, TEXT("AOculusXRSceneActor::SpawnOrUpdateSceneAnchor Scene object has an unknown semantic label. Will not be spawned.")); + return Anchor; + } + + TSoftClassPtr* sceneAnchorComponentClassPtrRef = &foundProperties->ActorComponent; + TSoftObjectPtr* staticMeshObjPtrRef = &foundProperties->StaticMesh; + + UClass* sceneAnchorComponentInstanceClass = sceneAnchorComponentClassPtrRef->LoadSynchronous(); + if (!sceneAnchorComponentInstanceClass) + { + UE_LOG(LogOculusXRScene, Error, TEXT("AOculusXRSceneActor::SpawnOrUpdateSceneAnchor Scene anchor component class is invalid! Cannot spawn actor to populate the scene.")); + return Anchor; + } + + if (!Anchor) + { + Anchor = SpawnActorWithSceneComponent(Space, RoomSpaceID, SemanticClassifications, sceneAnchorComponentInstanceClass); + } + + if (staticMeshObjPtrRef && staticMeshObjPtrRef->IsPending()) + { + staticMeshObjPtrRef->LoadSynchronous(); + } + UStaticMesh* refStaticMesh = staticMeshObjPtrRef ? staticMeshObjPtrRef->Get() : nullptr; + if (refStaticMesh == nullptr) + { + UE_LOG(LogOculusXRScene, Warning, TEXT("AOculusXRSceneActor::SpawnOrUpdateSceneAnchor Spawn scene anchor mesh is invalid for %s!"), *SemanticClassifications[0]); + return Anchor; + } + + UStaticMeshComponent* staticMeshComponent = NewObject(Anchor, UStaticMeshComponent::StaticClass()); + staticMeshComponent->RegisterComponent(); + staticMeshComponent->SetStaticMesh(refStaticMesh); + staticMeshComponent->AttachToComponent(Anchor->GetRootComponent(), FAttachmentTransformRules::KeepWorldTransform); + const float worldToMeters = GetWorld()->GetWorldSettings()->WorldToMeters; + FVector offset(0.0f, BoundedSize.Y / 2.0f, BoundedSize.Z / 2.0f); + staticMeshComponent->SetRelativeLocation(foundProperties->AddOffset + ((BoundedPos + offset) * worldToMeters), false, nullptr, ETeleportType::ResetPhysics); + + // Setup scale based on bounded size and the actual size of the mesh + UStaticMesh* staticMesh = staticMeshComponent->GetStaticMesh(); + FBoxSphereBounds staticMeshBounds; + staticMeshBounds.BoxExtent = FVector{ 1.f, 1.f, 1.f }; + if (staticMesh) + { + staticMeshBounds = staticMesh->GetBounds(); + } + + staticMeshComponent->SetRelativeScale3D(FVector( + (BoundedSize.X < UE_SMALL_NUMBER) ? 1 : (BoundedSize.X / (staticMeshBounds.BoxExtent.X * 2.f)) * worldToMeters, + (BoundedSize.Y < UE_SMALL_NUMBER) ? 1 : (BoundedSize.Y / (staticMeshBounds.BoxExtent.Y * 2.f)) * worldToMeters, + (BoundedSize.Z < UE_SMALL_NUMBER) ? 1 : (BoundedSize.Z / (staticMeshBounds.BoxExtent.Z * 2.f)) * worldToMeters)); + + return Anchor; +} + + +bool AOculusXRSceneActor::IsScenePopulated() +{ + if (!RootComponent) + { + return false; + } + + return RootComponent->GetNumChildrenComponents() > 0; +} + +bool AOculusXRSceneActor::IsRoomLayoutValid() +{ + return true; +} + +void AOculusXRSceneActor::PopulateScene() +{ + if (!RootComponent) + { + return; + } + + const EOculusXRAnchorResult::Type result = QueryAllRooms(); + if (!UOculusXRAnchorBPFunctionLibrary::IsAnchorResultSuccess(result)) + { + UE_LOG(LogOculusXRScene, Error, TEXT("PopulateScene Failed to query available rooms")); + } +} + +void AOculusXRSceneActor::ClearScene() +{ + if (!RootComponent) + return; + + TArray childrenComponents = RootComponent->GetAttachChildren(); + for (USceneComponent* SceneComponent : childrenComponents) + { + Cast(SceneComponent->GetOuter())->Destroy(); + } + + bRoomLayoutIsValid = false; + bFoundCapturedScene = false; +} + +void AOculusXRSceneActor::SetVisibilityToAllSceneAnchors(const bool bIsVisible) +{ + if (!RootComponent) + return; + + TArray childrenComponents = RootComponent->GetAttachChildren(); + for (USceneComponent* sceneComponent : childrenComponents) + { + sceneComponent->SetVisibility(bIsVisible, true); + } +} + +void AOculusXRSceneActor::SetVisibilityToSceneAnchorsBySemanticLabel(const FString SemanticLabel, const bool bIsVisible) +{ + FString label = SemanticLabel; + if (SemanticLabel == TEXT("DESK")) + { + label = TEXT("TABLE"); + UE_LOG(LogOculusXRScene, Warning, TEXT("XR Scene Actor semantic lable 'DESK' is deprecated, use 'TABLE' instead.")); + } + + if (!RootComponent) + return; + + TArray childrenComponents = RootComponent->GetAttachChildren(); + for (USceneComponent* sceneComponent : childrenComponents) + { + UObject* outerObject = sceneComponent->GetOuter(); + if (!outerObject) + { + continue; + } + + AActor* outerActor = Cast(outerObject); + if (!outerActor) + { + continue; + } + + UActorComponent* sceneAnchorComponent = outerActor->GetComponentByClass(UOculusXRSceneAnchorComponent::StaticClass()); + if (!sceneAnchorComponent) + { + continue; + } + + if (Cast(sceneAnchorComponent)->SemanticClassifications.Contains(label)) + { + sceneComponent->SetVisibility(bIsVisible, true); + } + } +} + +TArray AOculusXRSceneActor::GetActorsBySemanticLabel(const FString SemanticLabel) +{ + FString label = SemanticLabel; + if (SemanticLabel == TEXT("DESK")) + { + label = TEXT("TABLE"); + UE_LOG(LogOculusXRScene, Warning, TEXT("XR Scene Actor semantic lable 'DESK' is deprecated, use 'TABLE' instead.")); + } + + TArray actors; + + if (!RootComponent) + return actors; + + TArray childrenComponents = RootComponent->GetAttachChildren(); + for (USceneComponent* sceneComponent : childrenComponents) + { + UObject* outerObject = sceneComponent->GetOuter(); + if (!outerObject) + { + continue; + } + + AActor* outerActor = Cast(outerObject); + if (!outerActor) + { + continue; + } + + UActorComponent* sceneAnchorComponent = outerActor->GetComponentByClass(UOculusXRSceneAnchorComponent::StaticClass()); + if (!sceneAnchorComponent) + { + continue; + } + + if (Cast(sceneAnchorComponent)->SemanticClassifications.Contains(label)) + { + actors.Add(outerActor); + } + } + + return actors; +} + +TArray AOculusXRSceneActor::GetRoomLayouts() const +{ + TArray layouts; + RoomLayouts.GenerateValueArray(layouts); + return layouts; +} + +EOculusXRAnchorResult::Type AOculusXRSceneActor::QueryAllRooms() +{ + FOculusXRSpaceQueryInfo queryInfo; + queryInfo.MaxQuerySpaces = MaxQueries; + queryInfo.FilterType = EOculusXRSpaceQueryFilterType::FilterByComponentType; + queryInfo.ComponentFilter.Add(EOculusXRSpaceComponentType::RoomLayout); + + EOculusXRAnchorResult::Type anchorQueryResult; + OculusXRAnchors::FOculusXRAnchors::QueryAnchorsAdvanced(queryInfo, + FOculusXRAnchorQueryDelegate::CreateUObject(this, &AOculusXRSceneActor::RoomLayoutQueryComplete), anchorQueryResult); + + return anchorQueryResult; +} + +void AOculusXRSceneActor::RoomLayoutQueryComplete(EOculusXRAnchorResult::Type AnchorResult, const TArray& QueryResults) +{ + UE_LOG(LogOculusXRScene, Verbose, TEXT("RoomLayoutQueryComplete (Result = %d)"), AnchorResult); + + for (auto& QueryElement : QueryResults) + { + UE_LOG(LogOculusXRScene, Verbose, TEXT("RoomLayoutQueryComplete -- Query Element (space = %llu, uuid = %s"), QueryElement.Space.Value, *BytesToHex(QueryElement.UUID.UUIDBytes, OCULUSXR_UUID_SIZE)); + + FOculusXRRoomLayout roomLayout; + const bool bGetRoomLayoutResult = RoomLayoutManagerComponent->GetRoomLayout(QueryElement.Space.Value, roomLayout, MaxQueries); + if (!bGetRoomLayoutResult) + { + UE_LOG(LogOculusXRScene, Error, TEXT("RoomLayoutQueryComplete -- Failed to get room layout for space (space = %llu, uuid = %s"), + QueryElement.Space.Value, *BytesToHex(QueryElement.UUID.UUIDBytes, OCULUSXR_UUID_SIZE)); + continue; + } + + roomLayout.RoomAnchorHandle = QueryElement.Space; + roomLayout.RoomUuid = QueryElement.UUID; + + + // If we're only loading the active room we start that floor check query here, otherwise do the room query + if (bActiveRoomOnly) + { + QueryFloorForActiveRoom(QueryElement.Space, roomLayout); + } + else + { + StartSingleRoomQuery(QueryElement.Space, roomLayout); + } + } +} + +EOculusXRAnchorResult::Type AOculusXRSceneActor::QueryRoomUUIDs(const FOculusXRUInt64 RoomSpaceID, const TArray& RoomUUIDs) +{ + EOculusXRAnchorResult::Type startAnchorQueryResult; + OculusXRAnchors::FOculusXRAnchors::QueryAnchors( + RoomUUIDs, + EOculusXRSpaceStorageLocation::Local, + FOculusXRAnchorQueryDelegate::CreateUObject(this, &AOculusXRSceneActor::SceneRoomQueryComplete, RoomSpaceID), + startAnchorQueryResult); + + return startAnchorQueryResult; +} + +void AOculusXRSceneActor::SceneRoomQueryComplete(EOculusXRAnchorResult::Type AnchorResult, const TArray& QueryResults, const FOculusXRUInt64 RoomSpaceID) +{ + if (!UOculusXRAnchorBPFunctionLibrary::IsAnchorResultSuccess(AnchorResult)) + { + return; + } + + bool bOutPending = false; + for (auto& AnchorQueryElement : QueryResults) + { + if (SceneGlobalMeshComponent) + { + TArray semanticClassifications; + GetSemanticClassifications(AnchorQueryElement.Space.Value, semanticClassifications); + UE_LOG(LogOculusXRScene, Log, TEXT("SpatialAnchor Scene label is %s"), semanticClassifications.Num() > 0 ? *semanticClassifications[0] : TEXT("unknown")); + if (semanticClassifications.Contains(UOculusXRSceneGlobalMeshComponent::GlobalMeshSemanticLabel)) + { + bool bIsTriangleMesh = false; + EOculusXRAnchorResult::Type result = OculusXRAnchors::FOculusXRAnchorManager::GetSpaceComponentStatus( + AnchorQueryElement.Space.Value, EOculusXRSpaceComponentType::TriangleMesh, bIsTriangleMesh, bOutPending); + + if (!UOculusXRAnchorBPFunctionLibrary::IsAnchorResultSuccess(result) || !bIsTriangleMesh) + { + UE_LOG(LogOculusXRScene, Error, TEXT("SpatialAnchorQueryResult_Handler Failed to load Triangle Mesh Component for a GLOBAL_MESH")); + continue; + } + + UClass* sceneAnchorComponentInstanceClass = SceneGlobalMeshComponent->GetAnchorComponentClass(); + + AActor* globalMeshAnchor = SpawnActorWithSceneComponent(AnchorQueryElement.Space.Value, RoomSpaceID, semanticClassifications, sceneAnchorComponentInstanceClass); + + SceneGlobalMeshComponent->CreateMeshComponent(AnchorQueryElement.Space, globalMeshAnchor, RoomLayoutManagerComponent); + continue; + } + } + + bool bIsScenePlane = false; + bool bIsSceneVolume = false; + EOculusXRAnchorResult::Type isPlaneResult = OculusXRAnchors::FOculusXRAnchorManager::GetSpaceComponentStatus( + AnchorQueryElement.Space.Value, EOculusXRSpaceComponentType::ScenePlane, bIsScenePlane, bOutPending); + + EOculusXRAnchorResult::Type isVolumeResult = OculusXRAnchors::FOculusXRAnchorManager::GetSpaceComponentStatus( + AnchorQueryElement.Space.Value, EOculusXRSpaceComponentType::SceneVolume, bIsSceneVolume, bOutPending); + + bool bIsPlaneResultSuccess = UOculusXRAnchorBPFunctionLibrary::IsAnchorResultSuccess(isPlaneResult); + bool bIsVolumeResultSuccess = UOculusXRAnchorBPFunctionLibrary::IsAnchorResultSuccess(isVolumeResult); + + AActor* anchor = nullptr; + + if (bIsPlaneResultSuccess && bIsScenePlane) + { + EOculusXRAnchorResult::Type Result; + FVector scenePlanePos; + FVector scenePlaneSize; + bool ResultSuccess = OculusXRAnchors::FOculusXRAnchors::GetSpaceScenePlane(AnchorQueryElement.Space.Value, scenePlanePos, scenePlaneSize, Result); + if (ResultSuccess) + { + UE_LOG(LogOculusXRScene, Log, TEXT("SpatialAnchorQueryResult_Handler ScenePlane pos = [%.2f, %.2f, %.2f], size = [%.2f, %.2f, %.2f]."), + scenePlanePos.X, scenePlanePos.Y, scenePlanePos.Z, + scenePlaneSize.X, scenePlaneSize.Y, scenePlaneSize.Z); + + TArray semanticClassifications; + GetSemanticClassifications(AnchorQueryElement.Space.Value, semanticClassifications); + + UE_LOG(LogOculusXRScene, Log, TEXT("SpatialAnchor ScenePlane label is %s"), semanticClassifications.Num() > 0 ? *semanticClassifications[0] : TEXT("unknown")); + + anchor = SpawnOrUpdateSceneAnchor(anchor, AnchorQueryElement.Space, RoomSpaceID, scenePlanePos, scenePlaneSize, semanticClassifications, EOculusXRSpaceComponentType::ScenePlane); + if (!anchor) + { + UE_LOG(LogOculusXRScene, Error, TEXT("SpatialAnchorQueryResult_Handler Failed to spawn scene anchor.")); + } + } + else + { + UE_LOG(LogOculusXRScene, Error, TEXT("SpatialAnchorQueryResult_Handler Failed to get bounds for ScenePlane space.")); + } + } + + if (bIsVolumeResultSuccess && bIsSceneVolume) + { + EOculusXRAnchorResult::Type Result; + FVector sceneVolumePos; + FVector sceneVolumeSize; + bool ResultSuccess = OculusXRAnchors::FOculusXRAnchors::GetSpaceSceneVolume(AnchorQueryElement.Space.Value, sceneVolumePos, sceneVolumeSize, Result); + if (ResultSuccess) + { + UE_LOG(LogOculusXRScene, Log, TEXT("SpatialAnchorQueryResult_Handler SceneVolume pos = [%.2f, %.2f, %.2f], size = [%.2f, %.2f, %.2f]."), + sceneVolumePos.X, sceneVolumePos.Y, sceneVolumePos.Z, + sceneVolumeSize.X, sceneVolumeSize.Y, sceneVolumeSize.Z); + + TArray semanticClassifications; + GetSemanticClassifications(AnchorQueryElement.Space.Value, semanticClassifications); + + UE_LOG(LogOculusXRScene, Log, TEXT("SpatialAnchor SceneVolume label is %s"), semanticClassifications.Num() > 0 ? *semanticClassifications[0] : TEXT("unknown")); + + anchor = SpawnOrUpdateSceneAnchor(anchor, AnchorQueryElement.Space, RoomSpaceID, sceneVolumePos, sceneVolumeSize, semanticClassifications, EOculusXRSpaceComponentType::SceneVolume); + if (!anchor) + { + UE_LOG(LogOculusXRScene, Error, TEXT("SpatialAnchorQueryResult_Handler Failed to spawn scene anchor.")); + } + } + else + { + UE_LOG(LogOculusXRScene, Error, TEXT("SpatialAnchorQueryResult_Handler Failed to get bounds for SceneVolume space.")); + } + } + } +} + +void AOculusXRSceneActor::StartSingleRoomQuery(FOculusXRUInt64 RoomSpaceID, FOculusXRRoomLayout RoomLayout) +{ + EOculusXRAnchorResult::Type startQueryResult = QueryRoomUUIDs(RoomSpaceID, RoomLayout.RoomObjectUUIDs); + if (UOculusXRAnchorBPFunctionLibrary::IsAnchorResultSuccess(startQueryResult)) + { + RoomLayouts.Add(RoomSpaceID, std::move(RoomLayout)); + } +} + +EOculusXRAnchorResult::Type AOculusXRSceneActor::QueryFloorForActiveRoom(FOculusXRUInt64 RoomSpaceID, FOculusXRRoomLayout RoomLayout) +{ + EOculusXRAnchorResult::Type anchorQueryResult; + OculusXRAnchors::FOculusXRAnchors::QueryAnchors( + TArray({ RoomLayout.FloorUuid }), + EOculusXRSpaceStorageLocation::Local, + FOculusXRAnchorQueryDelegate::CreateUObject(this, &AOculusXRSceneActor::ActiveRoomFloorQueryComplete, RoomSpaceID, RoomLayout), + anchorQueryResult); + + return anchorQueryResult; +} + +void AOculusXRSceneActor::ActiveRoomFloorQueryComplete(EOculusXRAnchorResult::Type AnchorResult, const TArray& QueryResults, FOculusXRUInt64 RoomSpaceID, FOculusXRRoomLayout RoomLayout) +{ + if (QueryResults.Num() != 1) + { + UE_LOG(LogOculusXRScene, Error, TEXT("Wrong number of elements returned from query for floor UUID. Result count (%d), UUID (%s), Room Space ID (%llu)"), QueryResults.Num(), *RoomLayout.FloorUuid.ToString(), RoomSpaceID.Value); + return; + } + + const FOculusXRSpaceQueryResult& floorQueryResult = QueryResults[0]; + + TArray semanticClassifications; + GetSemanticClassifications(floorQueryResult.Space.Value, semanticClassifications); + if (!semanticClassifications.Contains("FLOOR")) + { + UE_LOG(LogOculusXRScene, Error, TEXT("Queried floor in room doesn't contain a floor semantic label. UUID (%s), Room Space ID (%llu)"), *RoomLayout.FloorUuid.ToString(), RoomSpaceID.Value); + return; + } + + EOculusXRAnchorResult::Type getBoundaryResult; + TArray boundaryVertices; + if (!OculusXRAnchors::FOculusXRAnchors::GetSpaceBoundary2D(floorQueryResult.Space.Value, boundaryVertices, getBoundaryResult)) + { + UE_LOG(LogOculusXRScene, Error, TEXT("Failed to get space boundary vertices for floor. UUID (%s), Room Space ID (%llu)"), *RoomLayout.FloorUuid.ToString(), RoomSpaceID.Value); + return; + } + + OculusXRHMD::FOculusXRHMD* HMD = OculusXRHMD::FOculusXRHMD::GetOculusXRHMD(); + check(HMD); + + OculusXRHMD::FPose headPose; + HMD->GetCurrentPose(OculusXRHMD::ToExternalDeviceId(ovrpNode_Head), headPose.Orientation, headPose.Position); + + TArray convertedBoundaryPoints; + + FTransform floorTransform; + if (!UOculusXRAnchorBPFunctionLibrary::GetAnchorTransformByHandle(floorQueryResult.Space, floorTransform)) + { + UE_LOG(LogOculusXRScene, Error, TEXT("Failed to get the floor anchor transform. Floor Space ID (%llu)"), floorQueryResult.Space.Value); + return; + } + + // Convert the boundary vertices to game engine world space + for (auto& it : boundaryVertices) + { + FVector pos = floorTransform.TransformPosition(FVector(0, it.X * HMD->GetWorldToMetersScale(), it.Y * HMD->GetWorldToMetersScale())); + convertedBoundaryPoints.Add(pos); + } + + // Create the new 2D boundary + TArray new2DBoundary; + for (auto& it : convertedBoundaryPoints) + { + new2DBoundary.Add(FVector2f(it.X, it.Y)); + } + + // Check if inside poly + if (!PointInPolygon2D(FVector2f(headPose.Position.X, headPose.Position.Y), new2DBoundary)) + { + UE_LOG(LogOculusXRScene, Verbose, TEXT("Floor failed active room check. UUID (%s), Room Space ID (%llu)"), *RoomLayout.FloorUuid.ToString(), RoomSpaceID.Value); + return; + } + + StartSingleRoomQuery(RoomSpaceID, RoomLayout); +} + +bool AOculusXRSceneActor::PointInPolygon2D(FVector2f PointToTest, const TArray& PolyVerts) const +{ + if (PolyVerts.Num() < 3) + { + return false; + } + + int collision = 0; + float x = PointToTest.X; + float y = PointToTest.Y; + + int vertCount = PolyVerts.Num(); + for (int i = 0; i < vertCount; i++) + { + float x1 = PolyVerts[i].X; + float y1 = PolyVerts[i].Y; + + float x2 = PolyVerts[(i + 1) % vertCount].X; + float y2 = PolyVerts[(i + 1) % vertCount].Y; + + if (y < y1 != y < y2 && x < x1 + ((y - y1) / (y2 - y1)) * (x2 - x1)) + { + collision += (y1 < y2) ? 1 : -1; + } + } + + return collision != 0; +} + +void AOculusXRSceneActor::GetSemanticClassifications(uint64 Space, TArray& OutSemanticLabels) const +{ + EOculusXRAnchorResult::Type SemanticLabelAnchorResult; + bool Result = OculusXRAnchors::FOculusXRAnchors::GetSpaceSemanticClassification(Space, OutSemanticLabels, SemanticLabelAnchorResult); + if (Result) + { + UE_LOG(LogOculusXRScene, Verbose, TEXT("GetSemanticClassifications -- Space (%llu) Classifications:"), Space); + for (FString& label : OutSemanticLabels) + { + UE_LOG(LogOculusXRScene, Verbose, TEXT("%s"), *label); + } + } + else + { + UE_LOG(LogOculusXRScene, Error, TEXT("SpatialAnchorQueryResult_Handler Failed to get semantic classification space.")); + } +} + +// DELEGATE HANDLERS +void AOculusXRSceneActor::SceneCaptureComplete_Handler(FOculusXRUInt64 RequestId, bool bResult) +{ + if (!bResult) + { + UE_LOG(LogOculusXRScene, Error, TEXT("Scene Capture Complete failed!")); + return; + } + + // Mark that we already launched Capture Flow and try to query spatial anchors again + bCaptureFlowWasLaunched = true; + + ClearScene(); + PopulateScene(); +} + +void AOculusXRSceneActor::PostLoad() +{ + Super::PostLoad(); + + FOculusXRSpawnedSceneAnchorProperties desk; + if (ScenePlaneSpawnedSceneAnchorProperties.RemoveAndCopyValue(TEXT("DESK"), desk)) + { + UE_LOG(LogOculusXRScene, Log, TEXT("Running XR Scene Actor plane semantic lable migration: 'DESK' to 'TABLE'")); + ScenePlaneSpawnedSceneAnchorProperties[TEXT("TABLE")] = desk; + } + + if (SceneVolumeSpawnedSceneAnchorProperties.RemoveAndCopyValue(TEXT("DESK"), desk)) + { + UE_LOG(LogOculusXRScene, Log, TEXT("Running XR Scene Actor volume semantic lable migration: 'DESK' to 'TABLE'")); + SceneVolumeSpawnedSceneAnchorProperties[TEXT("TABLE")] = desk; + } +} + +#undef LOCTEXT_NAMESPACE diff --git a/Plugins/MetaXR/Source/OculusXRScene/Private/OculusXRSceneAnchorComponent.cpp b/Plugins/MetaXR/Source/OculusXRScene/Private/OculusXRSceneAnchorComponent.cpp new file mode 100644 index 0000000..137ce38 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRScene/Private/OculusXRSceneAnchorComponent.cpp @@ -0,0 +1,21 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#include "OculusXRSceneAnchorComponent.h" + +#include "Engine/StaticMeshActor.h" + +UOculusXRSceneAnchorComponent::UOculusXRSceneAnchorComponent(const FObjectInitializer& ObjectInitializer) + : Super(ObjectInitializer) +{ + bUpdateHeadSpaceTransform = false; +} + +void UOculusXRSceneAnchorComponent::TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) +{ + Super::TickComponent(DeltaTime, TickType, ThisTickFunction); + + if (GetHandle().Value == 0) + { + return; + } +} diff --git a/Plugins/MetaXR/Source/OculusXRScene/Private/OculusXRSceneDelegates.cpp b/Plugins/MetaXR/Source/OculusXRScene/Private/OculusXRSceneDelegates.cpp new file mode 100644 index 0000000..f613e79 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRScene/Private/OculusXRSceneDelegates.cpp @@ -0,0 +1,5 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#include "OculusXRSceneDelegates.h" + + diff --git a/Plugins/MetaXR/Source/OculusXRScene/Private/OculusXRSceneEventHandling.cpp b/Plugins/MetaXR/Source/OculusXRScene/Private/OculusXRSceneEventHandling.cpp new file mode 100644 index 0000000..a267a99 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRScene/Private/OculusXRSceneEventHandling.cpp @@ -0,0 +1,38 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#include "OculusXRSceneEventHandling.h" + +#include "OculusXRHMD.h" +#include "IOculusXRSceneModule.h" +#include "OculusXRSceneDelegates.h" +#include "OculusXRSceneEventDelegates.h" + +namespace OculusXRScene +{ + template + void GetEventData(ovrpEventDataBuffer& Buffer, T& OutEventData) + { + unsigned char* BufData = Buffer.EventData; + BufData -= sizeof(Buffer.EventType); // Offset buffer data to get to the actual event payload + + memcpy(&OutEventData, BufData, sizeof(T)); + } + + void FOculusXRSceneEventHandling::OnPollEvent(ovrpEventDataBuffer* EventDataBuffer, bool& EventPollResult) + { + ovrpEventDataBuffer& buf = *EventDataBuffer; + EventPollResult = true; + + switch (buf.EventType) + { + + + case ovrpEventType_None: + default: + { + EventPollResult = false; + break; + } + } + } +} // namespace OculusXRScene diff --git a/Plugins/MetaXR/Source/OculusXRScene/Private/OculusXRSceneEventHandling.h b/Plugins/MetaXR/Source/OculusXRScene/Private/OculusXRSceneEventHandling.h new file mode 100644 index 0000000..1b24e37 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRScene/Private/OculusXRSceneEventHandling.h @@ -0,0 +1,19 @@ +/* +Copyright (c) Meta Platforms, Inc. and affiliates. +All rights reserved. + +This source code is licensed under the license found in the +LICENSE file in the root directory of this source tree. +*/ +#pragma once + +#include "CoreMinimal.h" +#include "OculusXRHMDPrivate.h" + +namespace OculusXRScene +{ + struct OCULUSXRSCENE_API FOculusXRSceneEventHandling + { + static void OnPollEvent(ovrpEventDataBuffer* EventDataBuffer, bool& EventPollResult); + }; +} // namespace OculusXRScene diff --git a/Plugins/MetaXR/Source/OculusXRScene/Private/OculusXRSceneFunctionLibrary.cpp b/Plugins/MetaXR/Source/OculusXRScene/Private/OculusXRSceneFunctionLibrary.cpp new file mode 100644 index 0000000..6382b9b --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRScene/Private/OculusXRSceneFunctionLibrary.cpp @@ -0,0 +1,11 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#include "OculusXRSceneFunctionLibrary.h" +#include "OculusXRAnchorBPFunctionLibrary.h" + +#include "OculusXRScene.h" +#include "OculusXRSceneSubsystem.h" +#include "OculusXRHMDPrivate.h" +#include "OculusXRHMD.h" + + diff --git a/Plugins/MetaXR/Source/OculusXRScene/Private/OculusXRSceneGlobalMeshComponent.cpp b/Plugins/MetaXR/Source/OculusXRScene/Private/OculusXRSceneGlobalMeshComponent.cpp new file mode 100644 index 0000000..93e9034 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRScene/Private/OculusXRSceneGlobalMeshComponent.cpp @@ -0,0 +1,67 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#include "OculusXRSceneGlobalMeshComponent.h" +#include "OculusXRSceneModule.h" +#include "OculusXRRoomLayoutManagerComponent.h" +#include "ProceduralMeshComponent.h" +#include "Engine/World.h" +#include "GameFramework/WorldSettings.h" +#include "Materials/MaterialInterface.h" + +const FString UOculusXRSceneGlobalMeshComponent::GlobalMeshSemanticLabel = TEXT("GLOBAL_MESH"); + +UOculusXRSceneGlobalMeshComponent::UOculusXRSceneGlobalMeshComponent(const FObjectInitializer& ObjectInitializer) + : Super(ObjectInitializer) +{ +} + +void UOculusXRSceneGlobalMeshComponent::TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) +{ + Super::TickComponent(DeltaTime, TickType, ThisTickFunction); +} + +bool UOculusXRSceneGlobalMeshComponent::HasCollision() const +{ + return Collision; +} + +bool UOculusXRSceneGlobalMeshComponent::IsVisible() const +{ + return Visible; +} + +UClass* UOculusXRSceneGlobalMeshComponent::GetAnchorComponentClass() const +{ + UClass* sceneAnchorComponentInstanceClass = SceneAnchorComponent ? SceneAnchorComponent.LoadSynchronous() : nullptr; + return sceneAnchorComponentInstanceClass; +} + +void UOculusXRSceneGlobalMeshComponent::CreateMeshComponent(const FOculusXRUInt64& Space, AActor* GlobalMeshAnchor, const UOculusXRRoomLayoutManagerComponent* RoomLayoutManagerComponent) const +{ + bool hasCollision = HasCollision(); + UProceduralMeshComponent* proceduralMeshComponent = NewObject(GlobalMeshAnchor); + proceduralMeshComponent->RegisterComponent(); + + bool bLoaded = RoomLayoutManagerComponent->LoadTriangleMesh(Space.Value, proceduralMeshComponent, hasCollision); + ensure(bLoaded); + UMaterialInterface* refMaterial = Material; + if (refMaterial != nullptr) + { + UE_LOG(LogOculusXRScene, Verbose, TEXT("GLOBAL MESH Set Material %s"), *refMaterial->GetName()); + proceduralMeshComponent->SetMaterial(0, refMaterial); + } + if (hasCollision) + { + FName refCollisionProfile = CollisionProfileName.Name; + proceduralMeshComponent->SetCollisionProfileName(refCollisionProfile); + UE_LOG(LogOculusXRScene, Verbose, TEXT("GLOBAL MESH Set Collision Profile %s"), *refCollisionProfile.ToString()); + } + GlobalMeshAnchor->AddOwnedComponent(proceduralMeshComponent); + proceduralMeshComponent->AttachToComponent(GlobalMeshAnchor->GetRootComponent(), FAttachmentTransformRules::KeepWorldTransform); + proceduralMeshComponent->SetRelativeLocation(FVector::ZeroVector, false, nullptr, ETeleportType::ResetPhysics); + + proceduralMeshComponent->SetVisibility(IsVisible()); + + const float worldToMeters = GetWorld()->GetWorldSettings()->WorldToMeters; + proceduralMeshComponent->SetRelativeScale3D(FVector(worldToMeters, worldToMeters, worldToMeters)); +} diff --git a/Plugins/MetaXR/Source/OculusXRScene/Private/OculusXRSceneModule.cpp b/Plugins/MetaXR/Source/OculusXRScene/Private/OculusXRSceneModule.cpp new file mode 100644 index 0000000..6613171 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRScene/Private/OculusXRSceneModule.cpp @@ -0,0 +1,44 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +#include "OculusXRSceneModule.h" + +#if OCULUS_SCENE_SUPPORTED_PLATFORMS +#include "OculusXRHMDModule.h" + +#include "OculusXRHMD.h" +#include "OculusXRSceneEventHandling.h" + +DEFINE_LOG_CATEGORY(LogOculusXRScene); + +#define LOCTEXT_NAMESPACE "OculusXRScene" + +//------------------------------------------------------------------------------------------------- +// FOculusXRSceneModule +//------------------------------------------------------------------------------------------------- +void FOculusXRSceneModule::StartupModule() +{ + if (!GEngine) + { + return; + } + + OculusXRHMD::FOculusXRHMD* HMD = OculusXRHMD::FOculusXRHMD::GetOculusXRHMD(); + if (!HMD) + { + UE_LOG(LogOculusXRScene, Warning, TEXT("Unable to retrieve OculusXRHMD, cannot add event polling delegates.")); + return; + } + + HMD->AddEventPollingDelegate(OculusXRHMD::FOculusXRHMDEventPollingDelegate::CreateStatic(&OculusXRScene::FOculusXRSceneEventHandling::OnPollEvent)); +} + +void FOculusXRSceneModule::ShutdownModule() +{ +} + +#endif // OCULUS_SCENE_SUPPORTED_PLATFORMS + +IMPLEMENT_MODULE(FOculusXRSceneModule, OculusXRScene) + +#undef LOCTEXT_NAMESPACE diff --git a/Plugins/MetaXR/Source/OculusXRScene/Private/OculusXRSceneModule.h b/Plugins/MetaXR/Source/OculusXRScene/Private/OculusXRSceneModule.h new file mode 100644 index 0000000..ed33331 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRScene/Private/OculusXRSceneModule.h @@ -0,0 +1,37 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +#pragma once +#include "IOculusXRSceneModule.h" + +#define LOCTEXT_NAMESPACE "OculusXRScene" + +//------------------------------------------------------------------------------------------------- +// FOculusXRSceneModule +//------------------------------------------------------------------------------------------------- + +#if OCULUS_SCENE_SUPPORTED_PLATFORMS + +DECLARE_LOG_CATEGORY_EXTERN(LogOculusXRScene, Log, All); + +class FOculusXRSceneModule : public IOculusXRSceneModule +{ +public: + virtual ~FOculusXRSceneModule() = default; + + // IModuleInterface interface + virtual void StartupModule() override; + virtual void ShutdownModule() override; + +private: +}; + +#else // OCULUS_SCENE_SUPPORTED_PLATFORMS + +class FOculusXRSceneModule : public FDefaultModuleImpl +{ +}; + +#endif // OCULUS_SCENE_SUPPORTED_PLATFORMS + +#undef LOCTEXT_NAMESPACE diff --git a/Plugins/MetaXR/Source/OculusXRScene/Private/OculusXRSceneSubsystem.cpp b/Plugins/MetaXR/Source/OculusXRScene/Private/OculusXRSceneSubsystem.cpp new file mode 100644 index 0000000..942d86e --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRScene/Private/OculusXRSceneSubsystem.cpp @@ -0,0 +1,43 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#pragma once + +#include "OculusXRSceneSubsystem.h" +#include "OculusXRSceneTypes.h" +#include "OculusXRScene.h" +#include "OculusXRSceneDelegates.h" +#include "OculusXRAnchorBPFunctionLibrary.h" +#include "OculusXRHMD.h" +#include "OculusXRHMDRuntimeSettings.h" + +UOculusXRSceneSubsystem::UOculusXRSceneSubsystem() +{ +} + +bool UOculusXRSceneSubsystem::ShouldCreateSubsystem(UObject* Outer) const +{ + return false; +} + +void UOculusXRSceneSubsystem::Initialize(FSubsystemCollectionBase& Collection) +{ +} + +void UOculusXRSceneSubsystem::Deinitialize() +{ +} + +ETickableTickType UOculusXRSceneSubsystem::GetTickableTickType() const +{ + return IsTemplate() ? ETickableTickType::Never : FTickableGameObject::GetTickableTickType(); +} + +bool UOculusXRSceneSubsystem::IsAllowedToTick() const +{ + return false; +} + +void UOculusXRSceneSubsystem::Tick(float DeltaTime) +{ +} + diff --git a/Plugins/MetaXR/Source/OculusXRScene/Public/IOculusXRSceneModule.h b/Plugins/MetaXR/Source/OculusXRScene/Public/IOculusXRSceneModule.h new file mode 100644 index 0000000..d361ba9 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRScene/Public/IOculusXRSceneModule.h @@ -0,0 +1,37 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +#pragma once +#include "Modules/ModuleManager.h" + +#define OCULUS_SCENE_SUPPORTED_PLATFORMS (PLATFORM_WINDOWS && WINVER > 0x0502) || (PLATFORM_ANDROID_ARM || PLATFORM_ANDROID_ARM64) + +/** + * The public interface to this module. In most cases, this interface is only public to sibling modules + * within this plugin. + */ +class IOculusXRSceneModule : public IModuleInterface +{ + +public: + /** + * Singleton-like access to this module's interface. This is just for convenience! + * Beware of calling this during the shutdown phase, though. Your module might have been unloaded already. + * + * @return Returns singleton instance, loading the module on demand if needed + */ + static inline IOculusXRSceneModule& Get() + { + return FModuleManager::LoadModuleChecked("OculusXRScene"); + } + + /** + * Checks to see if this module is loaded and ready. It is only valid to call Get() if IsAvailable() returns true. + * + * @return True if the module is loaded and ready to use + */ + static inline bool IsAvailable() + { + return FModuleManager::Get().IsModuleLoaded("OculusXRScene"); + } +}; diff --git a/Plugins/MetaXR/Source/OculusXRScene/Public/OculusXRScene.h b/Plugins/MetaXR/Source/OculusXRScene/Public/OculusXRScene.h new file mode 100644 index 0000000..436616c --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRScene/Public/OculusXRScene.h @@ -0,0 +1,14 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#pragma once + +#include "OculusXRAnchorTypes.h" +#include "OculusXRSceneTypes.h" + +namespace OculusXRScene +{ + struct OCULUSXRSCENE_API FOculusXRScene + { + + }; +} // namespace OculusXRScene diff --git a/Plugins/MetaXR/Source/OculusXRScene/Public/OculusXRSceneActor.h b/Plugins/MetaXR/Source/OculusXRScene/Public/OculusXRSceneActor.h new file mode 100644 index 0000000..13c0ecf --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRScene/Public/OculusXRSceneActor.h @@ -0,0 +1,178 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. +#pragma once + +#include "GameFramework/Actor.h" +#include "OculusXRRoomLayoutManagerComponent.h" +#include "OculusXRAnchorComponent.h" +#include "OculusXRFunctionLibrary.h" +#include "OculusXRSceneAnchorComponent.h" +#include "OculusXRSceneTypes.h" +#include "OculusXRSceneActor.generated.h" + +/** EOculusXRLaunchCaptureFlowWhenMissingScene +* Used to dictate whether the actor should launch the Capture Flow application when a scene is not detected on the device. +* The Actor will check if a scene capture is either non-existent or invalid (ie. missing walls/ceiling/floor) before checking if Capture Flow +* should be launched. +* +* NEVER: will never launch Flow Capture. +* ONCE: will only launch it once. If the actor still doesn't detect that a scene was captured, it will not launch Capture Flow again. +* ALWAYS: will always re-launch Flow Capture if a scene was not detected on the device. +*/ +UENUM(BlueprintType) +enum EOculusXRLaunchCaptureFlowWhenMissingScene +{ + NEVER UMETA(DisplayName = "Never"), + ONCE UMETA(DisplayName = "Once"), + ALWAYS UMETA(DisplayName = "Always") +}; + +/** FOculusXRSpawnedSceneAnchorProperties +* Properties/Components that a spawned scene anchor will use. +*/ +USTRUCT(BlueprintType) +struct FOculusXRSpawnedSceneAnchorProperties +{ + GENERATED_BODY() + + UPROPERTY(EditAnywhere, Category = "Spawned Scene Anchor Properties") + TSoftClassPtr ActorComponent = TSoftClassPtr(FSoftClassPath(UOculusXRSceneAnchorComponent::StaticClass())); + + UPROPERTY(EditAnywhere, Category = "Spawned Scene Anchor Properties") + TSoftObjectPtr StaticMesh; + + UPROPERTY(EditAnywhere, Category = "Spawned Scene Anchor Properties", Meta = (DeprecatedProperty, DeprecationMessage = "This property is deprecated. Alignment is done automatically at lower level.")) + bool ForceParallelToFloor = false; + + UPROPERTY(EditAnywhere, Category = "Spawned Scene Anchor Properties") + FVector AddOffset = FVector::ZeroVector; +}; + +/** +* AOculusXRSceneActor +* The purpose of this actor is to be able to spawn "scene anchor" actors. +* +* Each actor type (based on their semantic label) can be configured to be spawned with a specific mesh and actor component. +* +* Overall, it provides a simple interface to be able to quickly get a captured scene from Capture Flow populated at runtime. +* It also provides a basic and flexible template to making use of the OculusAnchorSDK and UOculusXRRoomLayoutManagerComponent +* to drive the actor's logic. This removes the need for the developer to implement a system from scratch that makes use of +* the native methods and components. +* +* TLDR: +* - This actor populates a captured scene (created in Capture Flow) by spawning child actors with predefined actor and mesh components. +* - Can be used as is, or can be derived or modified as needed depending on the application's needs. +*/ +UCLASS(ClassGroup = OculusXRScene) +class OCULUSXRSCENE_API AOculusXRSceneActor : public AActor +{ + GENERATED_BODY() +public: + + UFUNCTION(BlueprintCallable, Category = "OculusXR|Scene Actor") + void LaunchCaptureFlow(); + + UFUNCTION(BlueprintCallable, Category = "OculusXR|Scene Actor") + bool IsScenePopulated(); + + UFUNCTION(BlueprintCallable, Category = "OculusXR|Scene Actor", Meta = (DeprecatedFunction, DeprecationMessage = "Is Room Layout Valid is deprecated and no longer returns any value but true. Please validate your room configuration in the way your application requires.")) + bool IsRoomLayoutValid(); + + UFUNCTION(BlueprintCallable, Category = "OculusXR|Scene Actor") + void PopulateScene(); + + UFUNCTION(BlueprintCallable, Category = "OculusXR|Scene Actor") + void ClearScene(); + + UFUNCTION(BlueprintCallable, Category = "OculusXR|Scene Actor") + void SetVisibilityToAllSceneAnchors(const bool bIsVisible); + + UFUNCTION(BlueprintCallable, Category = "OculusXR|Scene Actor") + void SetVisibilityToSceneAnchorsBySemanticLabel(const FString SemanticLabel, const bool bIsVisible); + + UFUNCTION(BlueprintCallable, Category = "OculusXR|Scene Actor") + TArray GetActorsBySemanticLabel(const FString SemanticLabel); + + UFUNCTION(BlueprintPure, BlueprintCallable, Category = "OculusXR|Scene Actor") + TArray GetRoomLayouts() const; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "OculusXR|Scene Actor") + TEnumAsByte LauchCaptureFlowWhenMissingScene = EOculusXRLaunchCaptureFlowWhenMissingScene::ALWAYS; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "OculusXR|Scene Actor", meta = (UIMin = 1, ClampMin = 1, UIMax = 1024, ClampMax = 1024)) + int32 MaxQueries = 64; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "OculusXR|Scene Actor") + bool bPopulateSceneOnBeginPlay = true; + + // If true then when the scene model is loaded we will only attempt to populate the room the user is standing in. + // Otherwise all rooms and all scene anchors will be loaded. + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "OculusXR|Scene Actor") + bool bActiveRoomOnly = true; + + UPROPERTY(EditAnywhere, Category = "OculusXR|Scene Actor") + TMap ScenePlaneSpawnedSceneAnchorProperties; + + UPROPERTY(EditAnywhere, Category = "OculusXR|Scene Actor") + TMap SceneVolumeSpawnedSceneAnchorProperties; + + +public: + AOculusXRSceneActor(const FObjectInitializer& ObjectInitializer); + + virtual void BeginPlay() override; + virtual void EndPlay(EEndPlayReason::Type Reason) override; + virtual void Tick(float DeltaTime) override; + + virtual void PostLoad() override; + +private: + EOculusXRAnchorResult::Type QueryAllRooms(); + void RoomLayoutQueryComplete(EOculusXRAnchorResult::Type AnchorResult, const TArray& QueryResults); + + EOculusXRAnchorResult::Type QueryRoomUUIDs(const FOculusXRUInt64 RoomSpaceID, const TArray& RoomUUIDs); + void SceneRoomQueryComplete(EOculusXRAnchorResult::Type AnchorResult, const TArray& QueryResults, const FOculusXRUInt64 RoomSpaceID); + + void StartSingleRoomQuery(FOculusXRUInt64 RoomSpaceID, FOculusXRRoomLayout RoomLayout); + EOculusXRAnchorResult::Type QueryFloorForActiveRoom(FOculusXRUInt64 RoomSpaceID, FOculusXRRoomLayout RoomLayout); + void ActiveRoomFloorQueryComplete(EOculusXRAnchorResult::Type AnchorResult, const TArray& QueryResults, FOculusXRUInt64 RoomSpaceID, FOculusXRRoomLayout RoomLayout); + bool PointInPolygon2D(FVector2f PointToTest, const TArray& PolyVerts) const; + + void GetSemanticClassifications(uint64 Space, TArray& OutSemanticLabels) const; + + // Scene capture event handler + void SceneCaptureComplete_Handler(FOculusXRUInt64 RequestId, bool bResult); + + // Launches Capture Flow if (based on LauchCaptureFlowWhenMissingScene member value) + void LaunchCaptureFlowIfNeeded(); + + // Resets states of the Actor + void ResetStates(); + + // Validates UUID + bool IsValidUuid(const FOculusXRUUID& Uuid); + + // Helper method to spawn an actor for anchor + AActor* SpawnActorWithSceneComponent(const FOculusXRUInt64& Space, const FOculusXRUInt64& RoomSpaceID, const TArray& SemanticClassifications, UClass* sceneAnchorComponentInstanceClass); + + // Spawns a scene anchor + AActor* SpawnOrUpdateSceneAnchor(AActor* Anchor, const FOculusXRUInt64& Space, const FOculusXRUInt64& RoomSpaceID, const FVector& BoundedPos, const FVector& BoundedSize, const TArray& SemanticClassifications, const EOculusXRSpaceComponentType AnchorComponentType); + + + // Components for room layout and spatial anchors functionalities + UOculusXRRoomLayoutManagerComponent* RoomLayoutManagerComponent = nullptr; + + class UOculusXRSceneGlobalMeshComponent* SceneGlobalMeshComponent = nullptr; + + // Whether Capture Flow was already launched once + bool bCaptureFlowWasLaunched; + + // Whether last room layout was valid + bool bRoomLayoutIsValid; + + // Whether we found a captured scene + bool bFoundCapturedScene; + + UPROPERTY(Transient) + TMap RoomLayouts; +}; diff --git a/Plugins/MetaXR/Source/OculusXRScene/Public/OculusXRSceneAnchorComponent.h b/Plugins/MetaXR/Source/OculusXRScene/Public/OculusXRSceneAnchorComponent.h new file mode 100644 index 0000000..69f8514 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRScene/Public/OculusXRSceneAnchorComponent.h @@ -0,0 +1,24 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#pragma once + +#include "CoreMinimal.h" +#include "OculusXRAnchorComponent.h" +#include "OculusXRSceneAnchorComponent.generated.h" + +UCLASS(meta = (DisplayName = "OculusXR Scene Anchor Component", BlueprintSpawnableComponent)) +class OCULUSXRSCENE_API UOculusXRSceneAnchorComponent : public UOculusXRAnchorComponent +{ + GENERATED_BODY() + + virtual void TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override; + +public: + UOculusXRSceneAnchorComponent(const FObjectInitializer& ObjectInitializer); + + UPROPERTY(Transient, BlueprintReadOnly, Category = "OculusXR|Scene Anchor Component") + TArray SemanticClassifications; + + UPROPERTY(Transient, BlueprintReadOnly, Category = "OculusXR|Scene Anchor Component") + FOculusXRUInt64 RoomSpaceID = 0; +}; diff --git a/Plugins/MetaXR/Source/OculusXRScene/Public/OculusXRSceneDelegates.h b/Plugins/MetaXR/Source/OculusXRScene/Public/OculusXRSceneDelegates.h new file mode 100644 index 0000000..a655a18 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRScene/Public/OculusXRSceneDelegates.h @@ -0,0 +1,13 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#pragma once + +#include "CoreTypes.h" +#include "OculusXRSceneTypes.h" +#include "Delegates/Delegate.h" + +class FOculusXRSceneEventDelegates +{ +public: + +}; diff --git a/Plugins/MetaXR/Source/OculusXRScene/Public/OculusXRSceneEventDelegates.h b/Plugins/MetaXR/Source/OculusXRScene/Public/OculusXRSceneEventDelegates.h new file mode 100644 index 0000000..bc45ec4 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRScene/Public/OculusXRSceneEventDelegates.h @@ -0,0 +1,17 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#pragma once + +#include +#include "OculusXRSceneTypes.h" +#include "OculusXRSceneEventDelegates.generated.h" + + + +UCLASS() +class UOculusXRSceneEventDelegates : public UEngineSubsystem +{ + GENERATED_BODY() +public: + +}; diff --git a/Plugins/MetaXR/Source/OculusXRScene/Public/OculusXRSceneFunctionLibrary.h b/Plugins/MetaXR/Source/OculusXRScene/Public/OculusXRSceneFunctionLibrary.h new file mode 100644 index 0000000..f63333b --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRScene/Public/OculusXRSceneFunctionLibrary.h @@ -0,0 +1,16 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#pragma once + +#include "OculusXRAnchorTypes.h" +#include "Kismet/BlueprintFunctionLibrary.h" + +#include "OculusXRSceneFunctionLibrary.generated.h" + +UCLASS() +class OCULUSXRSCENE_API UOculusXRSceneFunctionLibrary : public UBlueprintFunctionLibrary +{ + GENERATED_BODY() +public: + +}; diff --git a/Plugins/MetaXR/Source/OculusXRScene/Public/OculusXRSceneGlobalMeshComponent.h b/Plugins/MetaXR/Source/OculusXRScene/Public/OculusXRSceneGlobalMeshComponent.h new file mode 100644 index 0000000..457573d --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRScene/Public/OculusXRSceneGlobalMeshComponent.h @@ -0,0 +1,49 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#pragma once + +#include "CoreMinimal.h" +#include "OculusXRSceneAnchorComponent.h" +#include "Engine/CollisionProfile.h" +#include "OculusXRRoomLayoutManagerComponent.h" +#include "OculusXRSceneGlobalMeshComponent.generated.h" + +class UMaterialInterface; + +UCLASS(meta = (DisplayName = "OculusXR Scene Global Mesh Component", BlueprintSpawnableComponent)) +class OCULUSXRSCENE_API UOculusXRSceneGlobalMeshComponent : public UActorComponent +{ + GENERATED_BODY() + + virtual void TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override; + +public: + UOculusXRSceneGlobalMeshComponent(const FObjectInitializer& ObjectInitializer); + + void CreateMeshComponent(const FOculusXRUInt64& Space, AActor* GlobalMeshAnchor, const UOculusXRRoomLayoutManagerComponent* RoomLayoutManagerComponent) const; + + static const FString GlobalMeshSemanticLabel; + +public: + UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "OculusXR") + bool Collision = false; + + UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "OculusXR") + FCollisionProfileName CollisionProfileName; + + UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "OculusXR") + bool Visible = false; + + UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "OculusXR") + UMaterialInterface* Material = nullptr; + + UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "OculusXR") + TSoftClassPtr SceneAnchorComponent = TSoftClassPtr(FSoftClassPath(UOculusXRSceneAnchorComponent::StaticClass())); + +public: + bool HasCollision() const; + + bool IsVisible() const; + + UClass* GetAnchorComponentClass() const; +}; diff --git a/Plugins/MetaXR/Source/OculusXRScene/Public/OculusXRSceneSubsystem.h b/Plugins/MetaXR/Source/OculusXRScene/Public/OculusXRSceneSubsystem.h new file mode 100644 index 0000000..5e1a945 --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRScene/Public/OculusXRSceneSubsystem.h @@ -0,0 +1,31 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#pragma once + +#include "OculusXRSceneTypes.h" +#include +#include + +#include "OculusXRSceneSubsystem.generated.h" + +UCLASS() +class UOculusXRSceneSubsystem : public UGameInstanceSubsystem, public FTickableGameObject +{ + GENERATED_BODY() +public: + UOculusXRSceneSubsystem(); + + virtual bool ShouldCreateSubsystem(UObject* Outer) const override; + virtual void Initialize(FSubsystemCollectionBase& Collection) override; + virtual void Deinitialize() override; + + // FTickableGameObject implementation Begin + virtual ETickableTickType GetTickableTickType() const override; + virtual bool IsAllowedToTick() const override final; + virtual void Tick(float DeltaTime) override; + virtual TStatId GetStatId() const override { RETURN_QUICK_DECLARE_CYCLE_STAT(UOculusXRSceneSubsystem, STATGROUP_Tickables); } + // FTickableGameObject implementation End + + +private: +}; diff --git a/Plugins/MetaXR/Source/OculusXRScene/Public/OculusXRSceneTypes.h b/Plugins/MetaXR/Source/OculusXRScene/Public/OculusXRSceneTypes.h new file mode 100644 index 0000000..4725eee --- /dev/null +++ b/Plugins/MetaXR/Source/OculusXRScene/Public/OculusXRSceneTypes.h @@ -0,0 +1,14 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. + +#pragma once + +#include "OculusXRSceneTypes.generated.h" + +USTRUCT() +struct FSceneTypesPlaceholder +{ + GENERATED_BODY() +public: +}; + + diff --git a/Plugins/MetaXR/Source/Thirdparty/KhronosOpenXR/KhronosOpenXRHeaders.build.cs b/Plugins/MetaXR/Source/Thirdparty/KhronosOpenXR/KhronosOpenXRHeaders.build.cs new file mode 100644 index 0000000..cd9ffa9 --- /dev/null +++ b/Plugins/MetaXR/Source/Thirdparty/KhronosOpenXR/KhronosOpenXRHeaders.build.cs @@ -0,0 +1,14 @@ +using UnrealBuildTool; + +public class KhronosOpenXRHeaders : ModuleRules +{ + public KhronosOpenXRHeaders(ReadOnlyTargetRules Target) : base(Target) + { + Type = ModuleType.External; + + string SourceDirectory = "$(PluginDir)/Source/ThirdParty/KhronosOpenXR/"; + + PublicIncludePaths.Add(SourceDirectory + "include"); + } +} + diff --git a/Plugins/MetaXR/Source/Thirdparty/KhronosOpenXR/LICENSE b/Plugins/MetaXR/Source/Thirdparty/KhronosOpenXR/LICENSE new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/Plugins/MetaXR/Source/Thirdparty/KhronosOpenXR/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/Plugins/MetaXR/Source/Thirdparty/KhronosOpenXR/LICENSES/Apache-2.0.txt b/Plugins/MetaXR/Source/Thirdparty/KhronosOpenXR/LICENSES/Apache-2.0.txt new file mode 100644 index 0000000..527a83a --- /dev/null +++ b/Plugins/MetaXR/Source/Thirdparty/KhronosOpenXR/LICENSES/Apache-2.0.txt @@ -0,0 +1,208 @@ +Apache License + +Version 2.0, January 2004 + +http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, +AND DISTRIBUTION + + 1. Definitions. + + + +"License" shall mean the terms and conditions for use, reproduction, and distribution +as defined by Sections 1 through 9 of this document. + + + +"Licensor" shall mean the copyright owner or entity authorized by the copyright +owner that is granting the License. + + + +"Legal Entity" shall mean the union of the acting entity and all other entities +that control, are controlled by, or are under common control with that entity. +For the purposes of this definition, "control" means (i) the power, direct +or indirect, to cause the direction or management of such entity, whether +by contract or otherwise, or (ii) ownership of fifty percent (50%) or more +of the outstanding shares, or (iii) beneficial ownership of such entity. + + + +"You" (or "Your") shall mean an individual or Legal Entity exercising permissions +granted by this License. + + + +"Source" form shall mean the preferred form for making modifications, including +but not limited to software source code, documentation source, and configuration +files. + + + +"Object" form shall mean any form resulting from mechanical transformation +or translation of a Source form, including but not limited to compiled object +code, generated documentation, and conversions to other media types. + + + +"Work" shall mean the work of authorship, whether in Source or Object form, +made available under the License, as indicated by a copyright notice that +is included in or attached to the work (an example is provided in the Appendix +below). + + + +"Derivative Works" shall mean any work, whether in Source or Object form, +that is based on (or derived from) the Work and for which the editorial revisions, +annotations, elaborations, or other modifications represent, as a whole, an +original work of authorship. For the purposes of this License, Derivative +Works shall not include works that remain separable from, or merely link (or +bind by name) to the interfaces of, the Work and Derivative Works thereof. + + + +"Contribution" shall mean any work of authorship, including the original version +of the Work and any modifications or additions to that Work or Derivative +Works thereof, that is intentionally submitted to Licensor for inclusion in +the Work by the copyright owner or by an individual or Legal Entity authorized +to submit on behalf of the copyright owner. For the purposes of this definition, +"submitted" means any form of electronic, verbal, or written communication +sent to the Licensor or its representatives, including but not limited to +communication on electronic mailing lists, source code control systems, and +issue tracking systems that are managed by, or on behalf of, the Licensor +for the purpose of discussing and improving the Work, but excluding communication +that is conspicuously marked or otherwise designated in writing by the copyright +owner as "Not a Contribution." + + + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf +of whom a Contribution has been received by Licensor and subsequently incorporated +within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of this +License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, +no-charge, royalty-free, irrevocable copyright license to reproduce, prepare +Derivative Works of, publicly display, publicly perform, sublicense, and distribute +the Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of this License, +each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, +no-charge, royalty-free, irrevocable (except as stated in this section) patent +license to make, have made, use, offer to sell, sell, import, and otherwise +transfer the Work, where such license applies only to those patent claims +licensable by such Contributor that are necessarily infringed by their Contribution(s) +alone or by combination of their Contribution(s) with the Work to which such +Contribution(s) was submitted. If You institute patent litigation against +any entity (including a cross-claim or counterclaim in a lawsuit) alleging +that the Work or a Contribution incorporated within the Work constitutes direct +or contributory patent infringement, then any patent licenses granted to You +under this License for that Work shall terminate as of the date such litigation +is filed. + +4. Redistribution. You may reproduce and distribute copies of the Work or +Derivative Works thereof in any medium, with or without modifications, and +in Source or Object form, provided that You meet the following conditions: + +(a) You must give any other recipients of the Work or Derivative Works a copy +of this License; and + +(b) You must cause any modified files to carry prominent notices stating that +You changed the files; and + +(c) You must retain, in the Source form of any Derivative Works that You distribute, +all copyright, patent, trademark, and attribution notices from the Source +form of the Work, excluding those notices that do not pertain to any part +of the Derivative Works; and + +(d) If the Work includes a "NOTICE" text file as part of its distribution, +then any Derivative Works that You distribute must include a readable copy +of the attribution notices contained within such NOTICE file, excluding those +notices that do not pertain to any part of the Derivative Works, in at least +one of the following places: within a NOTICE text file distributed as part +of the Derivative Works; within the Source form or documentation, if provided +along with the Derivative Works; or, within a display generated by the Derivative +Works, if and wherever such third-party notices normally appear. The contents +of the NOTICE file are for informational purposes only and do not modify the +License. You may add Your own attribution notices within Derivative Works +that You distribute, alongside or as an addendum to the NOTICE text from the +Work, provided that such additional attribution notices cannot be construed +as modifying the License. + +You may add Your own copyright statement to Your modifications and may provide +additional or different license terms and conditions for use, reproduction, +or distribution of Your modifications, or for any such Derivative Works as +a whole, provided Your use, reproduction, and distribution of the Work otherwise +complies with the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, any +Contribution intentionally submitted for inclusion in the Work by You to the +Licensor shall be under the terms and conditions of this License, without +any additional terms or conditions. Notwithstanding the above, nothing herein +shall supersede or modify the terms of any separate license agreement you +may have executed with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade names, +trademarks, service marks, or product names of the Licensor, except as required +for reasonable and customary use in describing the origin of the Work and +reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or agreed to +in writing, Licensor provides the Work (and each Contributor provides its +Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied, including, without limitation, any warranties +or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR +A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness +of using or redistributing the Work and assume any risks associated with Your +exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, whether +in tort (including negligence), contract, or otherwise, unless required by +applicable law (such as deliberate and grossly negligent acts) or agreed to +in writing, shall any Contributor be liable to You for damages, including +any direct, indirect, special, incidental, or consequential damages of any +character arising as a result of this License or out of the use or inability +to use the Work (including but not limited to damages for loss of goodwill, +work stoppage, computer failure or malfunction, or any and all other commercial +damages or losses), even if such Contributor has been advised of the possibility +of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing the Work +or Derivative Works thereof, You may choose to offer, and charge a fee for, +acceptance of support, warranty, indemnity, or other liability obligations +and/or rights consistent with this License. However, in accepting such obligations, +You may act only on Your own behalf and on Your sole responsibility, not on +behalf of any other Contributor, and only if You agree to indemnify, defend, +and hold each Contributor harmless for any liability incurred by, or claims +asserted against, such Contributor by reason of your accepting any such warranty +or additional liability. END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + +To apply the Apache License to your work, attach the following boilerplate +notice, with the fields enclosed by brackets "[]" replaced with your own identifying +information. (Don't include the brackets!) The text should be enclosed in +the appropriate comment syntax for the file format. We also recommend that +a file or class name and description of purpose be included on the same "printed +page" as the copyright notice for easier identification within third-party +archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); + +you may not use this file except in compliance with the License. + +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software + +distributed under the License is distributed on an "AS IS" BASIS, + +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + +See the License for the specific language governing permissions and + +limitations under the License. diff --git a/Plugins/MetaXR/Source/Thirdparty/KhronosOpenXR/LICENSES/MIT.txt b/Plugins/MetaXR/Source/Thirdparty/KhronosOpenXR/LICENSES/MIT.txt new file mode 100644 index 0000000..204b93d --- /dev/null +++ b/Plugins/MetaXR/Source/Thirdparty/KhronosOpenXR/LICENSES/MIT.txt @@ -0,0 +1,19 @@ +MIT License Copyright (c) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice (including the next +paragraph) shall be included in all copies or substantial portions of the +Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS +OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/Plugins/MetaXR/Source/Thirdparty/KhronosOpenXR/include/khronos/openxr/openxr.h b/Plugins/MetaXR/Source/Thirdparty/KhronosOpenXR/include/khronos/openxr/openxr.h new file mode 100644 index 0000000..889d9ac --- /dev/null +++ b/Plugins/MetaXR/Source/Thirdparty/KhronosOpenXR/include/khronos/openxr/openxr.h @@ -0,0 +1,6161 @@ +#ifndef OPENXR_H_ +#define OPENXR_H_ 1 + +/* +** Copyright 2017-2023 The Khronos Group Inc. +** +** SPDX-License-Identifier: Apache-2.0 OR MIT +*/ + +/* +** This header is generated from the Khronos OpenXR XML API Registry. +** +*/ + + +#ifdef __cplusplus +extern "C" { +#endif + + + +#define XR_VERSION_1_0 1 +#include "openxr_platform_defines.h" +#define XR_MAKE_VERSION(major, minor, patch) \ + ((((major) & 0xffffULL) << 48) | (((minor) & 0xffffULL) << 32) | ((patch) & 0xffffffffULL)) + +// OpenXR current version number. +#define XR_CURRENT_API_VERSION XR_MAKE_VERSION(1, 0, 29) + +#define XR_VERSION_MAJOR(version) (uint16_t)(((uint64_t)(version) >> 48)& 0xffffULL) +#define XR_VERSION_MINOR(version) (uint16_t)(((uint64_t)(version) >> 32) & 0xffffULL) +#define XR_VERSION_PATCH(version) (uint32_t)((uint64_t)(version) & 0xffffffffULL) + +#define XR_MIN_COMPOSITION_LAYERS_SUPPORTED 16 + + +#if !defined(XR_NULL_HANDLE) +#if (XR_PTR_SIZE == 8) && XR_CPP_NULLPTR_SUPPORTED + #define XR_NULL_HANDLE nullptr +#else + #define XR_NULL_HANDLE 0 +#endif +#endif + + + +#define XR_NULL_SYSTEM_ID 0 + + +#define XR_NULL_PATH 0 + + +#define XR_SUCCEEDED(result) ((result) >= 0) + + +#define XR_FAILED(result) ((result) < 0) + + +#define XR_UNQUALIFIED_SUCCESS(result) ((result) == 0) + + +#define XR_NO_DURATION 0 + + +#define XR_INFINITE_DURATION 0x7fffffffffffffffLL + + +#define XR_MIN_HAPTIC_DURATION -1 + + +#define XR_FREQUENCY_UNSPECIFIED 0 + + +#define XR_MAX_EVENT_DATA_SIZE sizeof(XrEventDataBuffer) + + +#define XR_EXTENSION_ENUM_BASE 1000000000 + + +#define XR_EXTENSION_ENUM_STRIDE 1000 + + +#if !defined(XR_MAY_ALIAS) +#if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4)) +#define XR_MAY_ALIAS __attribute__((__may_alias__)) +#else +#define XR_MAY_ALIAS +#endif +#endif + + +#if !defined(XR_DEFINE_HANDLE) +#if (XR_PTR_SIZE == 8) + #define XR_DEFINE_HANDLE(object) typedef struct object##_T* object; +#else + #define XR_DEFINE_HANDLE(object) typedef uint64_t object; +#endif +#endif + + + +#if !defined(XR_DEFINE_ATOM) + #define XR_DEFINE_ATOM(object) typedef uint64_t object; +#endif + + +typedef uint64_t XrVersion; +typedef uint64_t XrFlags64; +XR_DEFINE_ATOM(XrSystemId) +typedef uint32_t XrBool32; +XR_DEFINE_ATOM(XrPath) +typedef int64_t XrTime; +typedef int64_t XrDuration; +XR_DEFINE_HANDLE(XrInstance) +XR_DEFINE_HANDLE(XrSession) +XR_DEFINE_HANDLE(XrSpace) +XR_DEFINE_HANDLE(XrAction) +XR_DEFINE_HANDLE(XrSwapchain) +XR_DEFINE_HANDLE(XrActionSet) +#define XR_TRUE 1 +#define XR_FALSE 0 +#define XR_MAX_EXTENSION_NAME_SIZE 128 +#define XR_MAX_API_LAYER_NAME_SIZE 256 +#define XR_MAX_API_LAYER_DESCRIPTION_SIZE 256 +#define XR_MAX_SYSTEM_NAME_SIZE 256 +#define XR_MAX_APPLICATION_NAME_SIZE 128 +#define XR_MAX_ENGINE_NAME_SIZE 128 +#define XR_MAX_RUNTIME_NAME_SIZE 128 +#define XR_MAX_PATH_LENGTH 256 +#define XR_MAX_STRUCTURE_NAME_SIZE 64 +#define XR_MAX_RESULT_STRING_SIZE 64 +#define XR_MAX_ACTION_SET_NAME_SIZE 64 +#define XR_MAX_LOCALIZED_ACTION_SET_NAME_SIZE 128 +#define XR_MAX_ACTION_NAME_SIZE 64 +#define XR_MAX_LOCALIZED_ACTION_NAME_SIZE 128 + +typedef enum XrResult { + XR_SUCCESS = 0, + XR_TIMEOUT_EXPIRED = 1, + XR_SESSION_LOSS_PENDING = 3, + XR_EVENT_UNAVAILABLE = 4, + XR_SPACE_BOUNDS_UNAVAILABLE = 7, + XR_SESSION_NOT_FOCUSED = 8, + XR_FRAME_DISCARDED = 9, + XR_ERROR_VALIDATION_FAILURE = -1, + XR_ERROR_RUNTIME_FAILURE = -2, + XR_ERROR_OUT_OF_MEMORY = -3, + XR_ERROR_API_VERSION_UNSUPPORTED = -4, + XR_ERROR_INITIALIZATION_FAILED = -6, + XR_ERROR_FUNCTION_UNSUPPORTED = -7, + XR_ERROR_FEATURE_UNSUPPORTED = -8, + XR_ERROR_EXTENSION_NOT_PRESENT = -9, + XR_ERROR_LIMIT_REACHED = -10, + XR_ERROR_SIZE_INSUFFICIENT = -11, + XR_ERROR_HANDLE_INVALID = -12, + XR_ERROR_INSTANCE_LOST = -13, + XR_ERROR_SESSION_RUNNING = -14, + XR_ERROR_SESSION_NOT_RUNNING = -16, + XR_ERROR_SESSION_LOST = -17, + XR_ERROR_SYSTEM_INVALID = -18, + XR_ERROR_PATH_INVALID = -19, + XR_ERROR_PATH_COUNT_EXCEEDED = -20, + XR_ERROR_PATH_FORMAT_INVALID = -21, + XR_ERROR_PATH_UNSUPPORTED = -22, + XR_ERROR_LAYER_INVALID = -23, + XR_ERROR_LAYER_LIMIT_EXCEEDED = -24, + XR_ERROR_SWAPCHAIN_RECT_INVALID = -25, + XR_ERROR_SWAPCHAIN_FORMAT_UNSUPPORTED = -26, + XR_ERROR_ACTION_TYPE_MISMATCH = -27, + XR_ERROR_SESSION_NOT_READY = -28, + XR_ERROR_SESSION_NOT_STOPPING = -29, + XR_ERROR_TIME_INVALID = -30, + XR_ERROR_REFERENCE_SPACE_UNSUPPORTED = -31, + XR_ERROR_FILE_ACCESS_ERROR = -32, + XR_ERROR_FILE_CONTENTS_INVALID = -33, + XR_ERROR_FORM_FACTOR_UNSUPPORTED = -34, + XR_ERROR_FORM_FACTOR_UNAVAILABLE = -35, + XR_ERROR_API_LAYER_NOT_PRESENT = -36, + XR_ERROR_CALL_ORDER_INVALID = -37, + XR_ERROR_GRAPHICS_DEVICE_INVALID = -38, + XR_ERROR_POSE_INVALID = -39, + XR_ERROR_INDEX_OUT_OF_RANGE = -40, + XR_ERROR_VIEW_CONFIGURATION_TYPE_UNSUPPORTED = -41, + XR_ERROR_ENVIRONMENT_BLEND_MODE_UNSUPPORTED = -42, + XR_ERROR_NAME_DUPLICATED = -44, + XR_ERROR_NAME_INVALID = -45, + XR_ERROR_ACTIONSET_NOT_ATTACHED = -46, + XR_ERROR_ACTIONSETS_ALREADY_ATTACHED = -47, + XR_ERROR_LOCALIZED_NAME_DUPLICATED = -48, + XR_ERROR_LOCALIZED_NAME_INVALID = -49, + XR_ERROR_GRAPHICS_REQUIREMENTS_CALL_MISSING = -50, + XR_ERROR_RUNTIME_UNAVAILABLE = -51, + XR_ERROR_ANDROID_THREAD_SETTINGS_ID_INVALID_KHR = -1000003000, + XR_ERROR_ANDROID_THREAD_SETTINGS_FAILURE_KHR = -1000003001, + XR_ERROR_CREATE_SPATIAL_ANCHOR_FAILED_MSFT = -1000039001, + XR_ERROR_SECONDARY_VIEW_CONFIGURATION_TYPE_NOT_ENABLED_MSFT = -1000053000, + XR_ERROR_CONTROLLER_MODEL_KEY_INVALID_MSFT = -1000055000, + XR_ERROR_REPROJECTION_MODE_UNSUPPORTED_MSFT = -1000066000, + XR_ERROR_COMPUTE_NEW_SCENE_NOT_COMPLETED_MSFT = -1000097000, + XR_ERROR_SCENE_COMPONENT_ID_INVALID_MSFT = -1000097001, + XR_ERROR_SCENE_COMPONENT_TYPE_MISMATCH_MSFT = -1000097002, + XR_ERROR_SCENE_MESH_BUFFER_ID_INVALID_MSFT = -1000097003, + XR_ERROR_SCENE_COMPUTE_FEATURE_INCOMPATIBLE_MSFT = -1000097004, + XR_ERROR_SCENE_COMPUTE_CONSISTENCY_MISMATCH_MSFT = -1000097005, + XR_ERROR_DISPLAY_REFRESH_RATE_UNSUPPORTED_FB = -1000101000, + XR_ERROR_COLOR_SPACE_UNSUPPORTED_FB = -1000108000, + XR_ERROR_SPACE_COMPONENT_NOT_SUPPORTED_FB = -1000113000, + XR_ERROR_SPACE_COMPONENT_NOT_ENABLED_FB = -1000113001, + XR_ERROR_SPACE_COMPONENT_STATUS_PENDING_FB = -1000113002, + XR_ERROR_SPACE_COMPONENT_STATUS_ALREADY_SET_FB = -1000113003, + XR_ERROR_UNEXPECTED_STATE_PASSTHROUGH_FB = -1000118000, + XR_ERROR_FEATURE_ALREADY_CREATED_PASSTHROUGH_FB = -1000118001, + XR_ERROR_FEATURE_REQUIRED_PASSTHROUGH_FB = -1000118002, + XR_ERROR_NOT_PERMITTED_PASSTHROUGH_FB = -1000118003, + XR_ERROR_INSUFFICIENT_RESOURCES_PASSTHROUGH_FB = -1000118004, + XR_ERROR_UNKNOWN_PASSTHROUGH_FB = -1000118050, + XR_ERROR_RENDER_MODEL_KEY_INVALID_FB = -1000119000, + XR_RENDER_MODEL_UNAVAILABLE_FB = 1000119020, + XR_ERROR_MARKER_NOT_TRACKED_VARJO = -1000124000, + XR_ERROR_MARKER_ID_INVALID_VARJO = -1000124001, + XR_ERROR_SPATIAL_ANCHOR_NAME_NOT_FOUND_MSFT = -1000142001, + XR_ERROR_SPATIAL_ANCHOR_NAME_INVALID_MSFT = -1000142002, + XR_ERROR_SPACE_MAPPING_INSUFFICIENT_FB = -1000169000, + XR_ERROR_SPACE_LOCALIZATION_FAILED_FB = -1000169001, + XR_ERROR_SPACE_NETWORK_TIMEOUT_FB = -1000169002, + XR_ERROR_SPACE_NETWORK_REQUEST_FAILED_FB = -1000169003, + XR_ERROR_SPACE_CLOUD_STORAGE_DISABLED_FB = -1000169004, + XR_ERROR_PASSTHROUGH_COLOR_LUT_BUFFER_SIZE_MISMATCH_META = -1000266000, + XR_ERROR_HINT_ALREADY_SET_QCOM = -1000306000, + XR_ERROR_SPACE_NOT_LOCATABLE_EXT = -1000429000, + XR_ERROR_PLANE_DETECTION_PERMISSION_DENIED_EXT = -1000429001, + XR_RESULT_MAX_ENUM = 0x7FFFFFFF +} XrResult; + +typedef enum XrStructureType { + XR_TYPE_UNKNOWN = 0, + XR_TYPE_API_LAYER_PROPERTIES = 1, + XR_TYPE_EXTENSION_PROPERTIES = 2, + XR_TYPE_INSTANCE_CREATE_INFO = 3, + XR_TYPE_SYSTEM_GET_INFO = 4, + XR_TYPE_SYSTEM_PROPERTIES = 5, + XR_TYPE_VIEW_LOCATE_INFO = 6, + XR_TYPE_VIEW = 7, + XR_TYPE_SESSION_CREATE_INFO = 8, + XR_TYPE_SWAPCHAIN_CREATE_INFO = 9, + XR_TYPE_SESSION_BEGIN_INFO = 10, + XR_TYPE_VIEW_STATE = 11, + XR_TYPE_FRAME_END_INFO = 12, + XR_TYPE_HAPTIC_VIBRATION = 13, + XR_TYPE_EVENT_DATA_BUFFER = 16, + XR_TYPE_EVENT_DATA_INSTANCE_LOSS_PENDING = 17, + XR_TYPE_EVENT_DATA_SESSION_STATE_CHANGED = 18, + XR_TYPE_ACTION_STATE_BOOLEAN = 23, + XR_TYPE_ACTION_STATE_FLOAT = 24, + XR_TYPE_ACTION_STATE_VECTOR2F = 25, + XR_TYPE_ACTION_STATE_POSE = 27, + XR_TYPE_ACTION_SET_CREATE_INFO = 28, + XR_TYPE_ACTION_CREATE_INFO = 29, + XR_TYPE_INSTANCE_PROPERTIES = 32, + XR_TYPE_FRAME_WAIT_INFO = 33, + XR_TYPE_COMPOSITION_LAYER_PROJECTION = 35, + XR_TYPE_COMPOSITION_LAYER_QUAD = 36, + XR_TYPE_REFERENCE_SPACE_CREATE_INFO = 37, + XR_TYPE_ACTION_SPACE_CREATE_INFO = 38, + XR_TYPE_EVENT_DATA_REFERENCE_SPACE_CHANGE_PENDING = 40, + XR_TYPE_VIEW_CONFIGURATION_VIEW = 41, + XR_TYPE_SPACE_LOCATION = 42, + XR_TYPE_SPACE_VELOCITY = 43, + XR_TYPE_FRAME_STATE = 44, + XR_TYPE_VIEW_CONFIGURATION_PROPERTIES = 45, + XR_TYPE_FRAME_BEGIN_INFO = 46, + XR_TYPE_COMPOSITION_LAYER_PROJECTION_VIEW = 48, + XR_TYPE_EVENT_DATA_EVENTS_LOST = 49, + XR_TYPE_INTERACTION_PROFILE_SUGGESTED_BINDING = 51, + XR_TYPE_EVENT_DATA_INTERACTION_PROFILE_CHANGED = 52, + XR_TYPE_INTERACTION_PROFILE_STATE = 53, + XR_TYPE_SWAPCHAIN_IMAGE_ACQUIRE_INFO = 55, + XR_TYPE_SWAPCHAIN_IMAGE_WAIT_INFO = 56, + XR_TYPE_SWAPCHAIN_IMAGE_RELEASE_INFO = 57, + XR_TYPE_ACTION_STATE_GET_INFO = 58, + XR_TYPE_HAPTIC_ACTION_INFO = 59, + XR_TYPE_SESSION_ACTION_SETS_ATTACH_INFO = 60, + XR_TYPE_ACTIONS_SYNC_INFO = 61, + XR_TYPE_BOUND_SOURCES_FOR_ACTION_ENUMERATE_INFO = 62, + XR_TYPE_INPUT_SOURCE_LOCALIZED_NAME_GET_INFO = 63, + XR_TYPE_COMPOSITION_LAYER_CUBE_KHR = 1000006000, + XR_TYPE_INSTANCE_CREATE_INFO_ANDROID_KHR = 1000008000, + XR_TYPE_COMPOSITION_LAYER_DEPTH_INFO_KHR = 1000010000, + XR_TYPE_VULKAN_SWAPCHAIN_FORMAT_LIST_CREATE_INFO_KHR = 1000014000, + XR_TYPE_EVENT_DATA_PERF_SETTINGS_EXT = 1000015000, + XR_TYPE_COMPOSITION_LAYER_CYLINDER_KHR = 1000017000, + XR_TYPE_COMPOSITION_LAYER_EQUIRECT_KHR = 1000018000, + XR_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT = 1000019000, + XR_TYPE_DEBUG_UTILS_MESSENGER_CALLBACK_DATA_EXT = 1000019001, + XR_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT = 1000019002, + XR_TYPE_DEBUG_UTILS_LABEL_EXT = 1000019003, + XR_TYPE_GRAPHICS_BINDING_OPENGL_WIN32_KHR = 1000023000, + XR_TYPE_GRAPHICS_BINDING_OPENGL_XLIB_KHR = 1000023001, + XR_TYPE_GRAPHICS_BINDING_OPENGL_XCB_KHR = 1000023002, + XR_TYPE_GRAPHICS_BINDING_OPENGL_WAYLAND_KHR = 1000023003, + XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_KHR = 1000023004, + XR_TYPE_GRAPHICS_REQUIREMENTS_OPENGL_KHR = 1000023005, + XR_TYPE_GRAPHICS_BINDING_OPENGL_ES_ANDROID_KHR = 1000024001, + XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_ES_KHR = 1000024002, + XR_TYPE_GRAPHICS_REQUIREMENTS_OPENGL_ES_KHR = 1000024003, + XR_TYPE_GRAPHICS_BINDING_VULKAN_KHR = 1000025000, + XR_TYPE_SWAPCHAIN_IMAGE_VULKAN_KHR = 1000025001, + XR_TYPE_GRAPHICS_REQUIREMENTS_VULKAN_KHR = 1000025002, + XR_TYPE_GRAPHICS_BINDING_D3D11_KHR = 1000027000, + XR_TYPE_SWAPCHAIN_IMAGE_D3D11_KHR = 1000027001, + XR_TYPE_GRAPHICS_REQUIREMENTS_D3D11_KHR = 1000027002, + XR_TYPE_GRAPHICS_BINDING_D3D12_KHR = 1000028000, + XR_TYPE_SWAPCHAIN_IMAGE_D3D12_KHR = 1000028001, + XR_TYPE_GRAPHICS_REQUIREMENTS_D3D12_KHR = 1000028002, + XR_TYPE_SYSTEM_EYE_GAZE_INTERACTION_PROPERTIES_EXT = 1000030000, + XR_TYPE_EYE_GAZE_SAMPLE_TIME_EXT = 1000030001, + XR_TYPE_VISIBILITY_MASK_KHR = 1000031000, + XR_TYPE_EVENT_DATA_VISIBILITY_MASK_CHANGED_KHR = 1000031001, + XR_TYPE_SESSION_CREATE_INFO_OVERLAY_EXTX = 1000033000, + XR_TYPE_EVENT_DATA_MAIN_SESSION_VISIBILITY_CHANGED_EXTX = 1000033003, + XR_TYPE_COMPOSITION_LAYER_COLOR_SCALE_BIAS_KHR = 1000034000, + XR_TYPE_SPATIAL_ANCHOR_CREATE_INFO_MSFT = 1000039000, + XR_TYPE_SPATIAL_ANCHOR_SPACE_CREATE_INFO_MSFT = 1000039001, + XR_TYPE_COMPOSITION_LAYER_IMAGE_LAYOUT_FB = 1000040000, + XR_TYPE_COMPOSITION_LAYER_ALPHA_BLEND_FB = 1000041001, + XR_TYPE_VIEW_CONFIGURATION_DEPTH_RANGE_EXT = 1000046000, + XR_TYPE_GRAPHICS_BINDING_EGL_MNDX = 1000048004, + XR_TYPE_SPATIAL_GRAPH_NODE_SPACE_CREATE_INFO_MSFT = 1000049000, + XR_TYPE_SPATIAL_GRAPH_STATIC_NODE_BINDING_CREATE_INFO_MSFT = 1000049001, + XR_TYPE_SPATIAL_GRAPH_NODE_BINDING_PROPERTIES_GET_INFO_MSFT = 1000049002, + XR_TYPE_SPATIAL_GRAPH_NODE_BINDING_PROPERTIES_MSFT = 1000049003, + XR_TYPE_SYSTEM_HAND_TRACKING_PROPERTIES_EXT = 1000051000, + XR_TYPE_HAND_TRACKER_CREATE_INFO_EXT = 1000051001, + XR_TYPE_HAND_JOINTS_LOCATE_INFO_EXT = 1000051002, + XR_TYPE_HAND_JOINT_LOCATIONS_EXT = 1000051003, + XR_TYPE_HAND_JOINT_VELOCITIES_EXT = 1000051004, + XR_TYPE_SYSTEM_HAND_TRACKING_MESH_PROPERTIES_MSFT = 1000052000, + XR_TYPE_HAND_MESH_SPACE_CREATE_INFO_MSFT = 1000052001, + XR_TYPE_HAND_MESH_UPDATE_INFO_MSFT = 1000052002, + XR_TYPE_HAND_MESH_MSFT = 1000052003, + XR_TYPE_HAND_POSE_TYPE_INFO_MSFT = 1000052004, + XR_TYPE_SECONDARY_VIEW_CONFIGURATION_SESSION_BEGIN_INFO_MSFT = 1000053000, + XR_TYPE_SECONDARY_VIEW_CONFIGURATION_STATE_MSFT = 1000053001, + XR_TYPE_SECONDARY_VIEW_CONFIGURATION_FRAME_STATE_MSFT = 1000053002, + XR_TYPE_SECONDARY_VIEW_CONFIGURATION_FRAME_END_INFO_MSFT = 1000053003, + XR_TYPE_SECONDARY_VIEW_CONFIGURATION_LAYER_INFO_MSFT = 1000053004, + XR_TYPE_SECONDARY_VIEW_CONFIGURATION_SWAPCHAIN_CREATE_INFO_MSFT = 1000053005, + XR_TYPE_CONTROLLER_MODEL_KEY_STATE_MSFT = 1000055000, + XR_TYPE_CONTROLLER_MODEL_NODE_PROPERTIES_MSFT = 1000055001, + XR_TYPE_CONTROLLER_MODEL_PROPERTIES_MSFT = 1000055002, + XR_TYPE_CONTROLLER_MODEL_NODE_STATE_MSFT = 1000055003, + XR_TYPE_CONTROLLER_MODEL_STATE_MSFT = 1000055004, + XR_TYPE_VIEW_CONFIGURATION_VIEW_FOV_EPIC = 1000059000, + XR_TYPE_HOLOGRAPHIC_WINDOW_ATTACHMENT_MSFT = 1000063000, + XR_TYPE_COMPOSITION_LAYER_REPROJECTION_INFO_MSFT = 1000066000, + XR_TYPE_COMPOSITION_LAYER_REPROJECTION_PLANE_OVERRIDE_MSFT = 1000066001, + XR_TYPE_ANDROID_SURFACE_SWAPCHAIN_CREATE_INFO_FB = 1000070000, + XR_TYPE_COMPOSITION_LAYER_SECURE_CONTENT_FB = 1000072000, + XR_TYPE_BODY_TRACKER_CREATE_INFO_FB = 1000076001, + XR_TYPE_BODY_JOINTS_LOCATE_INFO_FB = 1000076002, + XR_TYPE_SYSTEM_BODY_TRACKING_PROPERTIES_FB = 1000076004, + XR_TYPE_BODY_JOINT_LOCATIONS_FB = 1000076005, + XR_TYPE_BODY_SKELETON_FB = 1000076006, + XR_TYPE_INTERACTION_PROFILE_DPAD_BINDING_EXT = 1000078000, + XR_TYPE_INTERACTION_PROFILE_ANALOG_THRESHOLD_VALVE = 1000079000, + XR_TYPE_HAND_JOINTS_MOTION_RANGE_INFO_EXT = 1000080000, + XR_TYPE_LOADER_INIT_INFO_ANDROID_KHR = 1000089000, + XR_TYPE_VULKAN_INSTANCE_CREATE_INFO_KHR = 1000090000, + XR_TYPE_VULKAN_DEVICE_CREATE_INFO_KHR = 1000090001, + XR_TYPE_VULKAN_GRAPHICS_DEVICE_GET_INFO_KHR = 1000090003, + XR_TYPE_COMPOSITION_LAYER_EQUIRECT2_KHR = 1000091000, + XR_TYPE_SCENE_OBSERVER_CREATE_INFO_MSFT = 1000097000, + XR_TYPE_SCENE_CREATE_INFO_MSFT = 1000097001, + XR_TYPE_NEW_SCENE_COMPUTE_INFO_MSFT = 1000097002, + XR_TYPE_VISUAL_MESH_COMPUTE_LOD_INFO_MSFT = 1000097003, + XR_TYPE_SCENE_COMPONENTS_MSFT = 1000097004, + XR_TYPE_SCENE_COMPONENTS_GET_INFO_MSFT = 1000097005, + XR_TYPE_SCENE_COMPONENT_LOCATIONS_MSFT = 1000097006, + XR_TYPE_SCENE_COMPONENTS_LOCATE_INFO_MSFT = 1000097007, + XR_TYPE_SCENE_OBJECTS_MSFT = 1000097008, + XR_TYPE_SCENE_COMPONENT_PARENT_FILTER_INFO_MSFT = 1000097009, + XR_TYPE_SCENE_OBJECT_TYPES_FILTER_INFO_MSFT = 1000097010, + XR_TYPE_SCENE_PLANES_MSFT = 1000097011, + XR_TYPE_SCENE_PLANE_ALIGNMENT_FILTER_INFO_MSFT = 1000097012, + XR_TYPE_SCENE_MESHES_MSFT = 1000097013, + XR_TYPE_SCENE_MESH_BUFFERS_GET_INFO_MSFT = 1000097014, + XR_TYPE_SCENE_MESH_BUFFERS_MSFT = 1000097015, + XR_TYPE_SCENE_MESH_VERTEX_BUFFER_MSFT = 1000097016, + XR_TYPE_SCENE_MESH_INDICES_UINT32_MSFT = 1000097017, + XR_TYPE_SCENE_MESH_INDICES_UINT16_MSFT = 1000097018, + XR_TYPE_SERIALIZED_SCENE_FRAGMENT_DATA_GET_INFO_MSFT = 1000098000, + XR_TYPE_SCENE_DESERIALIZE_INFO_MSFT = 1000098001, + XR_TYPE_EVENT_DATA_DISPLAY_REFRESH_RATE_CHANGED_FB = 1000101000, + XR_TYPE_VIVE_TRACKER_PATHS_HTCX = 1000103000, + XR_TYPE_EVENT_DATA_VIVE_TRACKER_CONNECTED_HTCX = 1000103001, + XR_TYPE_SYSTEM_FACIAL_TRACKING_PROPERTIES_HTC = 1000104000, + XR_TYPE_FACIAL_TRACKER_CREATE_INFO_HTC = 1000104001, + XR_TYPE_FACIAL_EXPRESSIONS_HTC = 1000104002, + XR_TYPE_SYSTEM_COLOR_SPACE_PROPERTIES_FB = 1000108000, + XR_TYPE_HAND_TRACKING_MESH_FB = 1000110001, + XR_TYPE_HAND_TRACKING_SCALE_FB = 1000110003, + XR_TYPE_HAND_TRACKING_AIM_STATE_FB = 1000111001, + XR_TYPE_HAND_TRACKING_CAPSULES_STATE_FB = 1000112000, + XR_TYPE_SYSTEM_SPATIAL_ENTITY_PROPERTIES_FB = 1000113004, + XR_TYPE_SPATIAL_ANCHOR_CREATE_INFO_FB = 1000113003, + XR_TYPE_SPACE_COMPONENT_STATUS_SET_INFO_FB = 1000113007, + XR_TYPE_SPACE_COMPONENT_STATUS_FB = 1000113001, + XR_TYPE_EVENT_DATA_SPATIAL_ANCHOR_CREATE_COMPLETE_FB = 1000113005, + XR_TYPE_EVENT_DATA_SPACE_SET_STATUS_COMPLETE_FB = 1000113006, + XR_TYPE_FOVEATION_PROFILE_CREATE_INFO_FB = 1000114000, + XR_TYPE_SWAPCHAIN_CREATE_INFO_FOVEATION_FB = 1000114001, + XR_TYPE_SWAPCHAIN_STATE_FOVEATION_FB = 1000114002, + XR_TYPE_FOVEATION_LEVEL_PROFILE_CREATE_INFO_FB = 1000115000, + XR_TYPE_KEYBOARD_SPACE_CREATE_INFO_FB = 1000116009, + XR_TYPE_KEYBOARD_TRACKING_QUERY_FB = 1000116004, + XR_TYPE_SYSTEM_KEYBOARD_TRACKING_PROPERTIES_FB = 1000116002, + XR_TYPE_TRIANGLE_MESH_CREATE_INFO_FB = 1000117001, + XR_TYPE_SYSTEM_PASSTHROUGH_PROPERTIES_FB = 1000118000, + XR_TYPE_PASSTHROUGH_CREATE_INFO_FB = 1000118001, + XR_TYPE_PASSTHROUGH_LAYER_CREATE_INFO_FB = 1000118002, + XR_TYPE_COMPOSITION_LAYER_PASSTHROUGH_FB = 1000118003, + XR_TYPE_GEOMETRY_INSTANCE_CREATE_INFO_FB = 1000118004, + XR_TYPE_GEOMETRY_INSTANCE_TRANSFORM_FB = 1000118005, + XR_TYPE_SYSTEM_PASSTHROUGH_PROPERTIES2_FB = 1000118006, + XR_TYPE_PASSTHROUGH_STYLE_FB = 1000118020, + XR_TYPE_PASSTHROUGH_COLOR_MAP_MONO_TO_RGBA_FB = 1000118021, + XR_TYPE_PASSTHROUGH_COLOR_MAP_MONO_TO_MONO_FB = 1000118022, + XR_TYPE_PASSTHROUGH_BRIGHTNESS_CONTRAST_SATURATION_FB = 1000118023, + XR_TYPE_EVENT_DATA_PASSTHROUGH_STATE_CHANGED_FB = 1000118030, + XR_TYPE_RENDER_MODEL_PATH_INFO_FB = 1000119000, + XR_TYPE_RENDER_MODEL_PROPERTIES_FB = 1000119001, + XR_TYPE_RENDER_MODEL_BUFFER_FB = 1000119002, + XR_TYPE_RENDER_MODEL_LOAD_INFO_FB = 1000119003, + XR_TYPE_SYSTEM_RENDER_MODEL_PROPERTIES_FB = 1000119004, + XR_TYPE_RENDER_MODEL_CAPABILITIES_REQUEST_FB = 1000119005, + XR_TYPE_BINDING_MODIFICATIONS_KHR = 1000120000, + XR_TYPE_VIEW_LOCATE_FOVEATED_RENDERING_VARJO = 1000121000, + XR_TYPE_FOVEATED_VIEW_CONFIGURATION_VIEW_VARJO = 1000121001, + XR_TYPE_SYSTEM_FOVEATED_RENDERING_PROPERTIES_VARJO = 1000121002, + XR_TYPE_COMPOSITION_LAYER_DEPTH_TEST_VARJO = 1000122000, + XR_TYPE_SYSTEM_MARKER_TRACKING_PROPERTIES_VARJO = 1000124000, + XR_TYPE_EVENT_DATA_MARKER_TRACKING_UPDATE_VARJO = 1000124001, + XR_TYPE_MARKER_SPACE_CREATE_INFO_VARJO = 1000124002, + XR_TYPE_FRAME_END_INFO_ML = 1000135000, + XR_TYPE_GLOBAL_DIMMER_FRAME_END_INFO_ML = 1000136000, + XR_TYPE_COORDINATE_SPACE_CREATE_INFO_ML = 1000137000, + XR_TYPE_SPATIAL_ANCHOR_PERSISTENCE_INFO_MSFT = 1000142000, + XR_TYPE_SPATIAL_ANCHOR_FROM_PERSISTED_ANCHOR_CREATE_INFO_MSFT = 1000142001, + XR_TYPE_SPACE_QUERY_INFO_FB = 1000156001, + XR_TYPE_SPACE_QUERY_RESULTS_FB = 1000156002, + XR_TYPE_SPACE_STORAGE_LOCATION_FILTER_INFO_FB = 1000156003, + XR_TYPE_SPACE_UUID_FILTER_INFO_FB = 1000156054, + XR_TYPE_SPACE_COMPONENT_FILTER_INFO_FB = 1000156052, + XR_TYPE_EVENT_DATA_SPACE_QUERY_RESULTS_AVAILABLE_FB = 1000156103, + XR_TYPE_EVENT_DATA_SPACE_QUERY_COMPLETE_FB = 1000156104, + XR_TYPE_SPACE_SAVE_INFO_FB = 1000158000, + XR_TYPE_SPACE_ERASE_INFO_FB = 1000158001, + XR_TYPE_EVENT_DATA_SPACE_SAVE_COMPLETE_FB = 1000158106, + XR_TYPE_EVENT_DATA_SPACE_ERASE_COMPLETE_FB = 1000158107, + XR_TYPE_SWAPCHAIN_IMAGE_FOVEATION_VULKAN_FB = 1000160000, + XR_TYPE_SWAPCHAIN_STATE_ANDROID_SURFACE_DIMENSIONS_FB = 1000161000, + XR_TYPE_SWAPCHAIN_STATE_SAMPLER_OPENGL_ES_FB = 1000162000, + XR_TYPE_SWAPCHAIN_STATE_SAMPLER_VULKAN_FB = 1000163000, + XR_TYPE_SPACE_SHARE_INFO_FB = 1000169001, + XR_TYPE_EVENT_DATA_SPACE_SHARE_COMPLETE_FB = 1000169002, + XR_TYPE_COMPOSITION_LAYER_SPACE_WARP_INFO_FB = 1000171000, + XR_TYPE_SYSTEM_SPACE_WARP_PROPERTIES_FB = 1000171001, + XR_TYPE_HAPTIC_AMPLITUDE_ENVELOPE_VIBRATION_FB = 1000173001, + XR_TYPE_SEMANTIC_LABELS_FB = 1000175000, + XR_TYPE_ROOM_LAYOUT_FB = 1000175001, + XR_TYPE_BOUNDARY_2D_FB = 1000175002, + XR_TYPE_SEMANTIC_LABELS_SUPPORT_INFO_FB = 1000175010, + XR_TYPE_DIGITAL_LENS_CONTROL_ALMALENCE = 1000196000, + XR_TYPE_EVENT_DATA_SCENE_CAPTURE_COMPLETE_FB = 1000198001, + XR_TYPE_SCENE_CAPTURE_REQUEST_INFO_FB = 1000198050, + XR_TYPE_SPACE_CONTAINER_FB = 1000199000, + XR_TYPE_FOVEATION_EYE_TRACKED_PROFILE_CREATE_INFO_META = 1000200000, + XR_TYPE_FOVEATION_EYE_TRACKED_STATE_META = 1000200001, + XR_TYPE_SYSTEM_FOVEATION_EYE_TRACKED_PROPERTIES_META = 1000200002, + XR_TYPE_SYSTEM_FACE_TRACKING_PROPERTIES_FB = 1000201004, + XR_TYPE_FACE_TRACKER_CREATE_INFO_FB = 1000201005, + XR_TYPE_FACE_EXPRESSION_INFO_FB = 1000201002, + XR_TYPE_FACE_EXPRESSION_WEIGHTS_FB = 1000201006, + XR_TYPE_EYE_TRACKER_CREATE_INFO_FB = 1000202001, + XR_TYPE_EYE_GAZES_INFO_FB = 1000202002, + XR_TYPE_EYE_GAZES_FB = 1000202003, + XR_TYPE_SYSTEM_EYE_TRACKING_PROPERTIES_FB = 1000202004, + XR_TYPE_PASSTHROUGH_KEYBOARD_HANDS_INTENSITY_FB = 1000203002, + XR_TYPE_COMPOSITION_LAYER_SETTINGS_FB = 1000204000, + XR_TYPE_HAPTIC_PCM_VIBRATION_FB = 1000209001, + XR_TYPE_DEVICE_PCM_SAMPLE_RATE_STATE_FB = 1000209002, + XR_TYPE_COMPOSITION_LAYER_DEPTH_TEST_FB = 1000212000, + XR_TYPE_LOCAL_DIMMING_FRAME_END_INFO_META = 1000216000, + XR_TYPE_PASSTHROUGH_PREFERENCES_META = 1000217000, + XR_TYPE_SYSTEM_VIRTUAL_KEYBOARD_PROPERTIES_META = 1000219001, + XR_TYPE_VIRTUAL_KEYBOARD_CREATE_INFO_META = 1000219002, + XR_TYPE_VIRTUAL_KEYBOARD_SPACE_CREATE_INFO_META = 1000219003, + XR_TYPE_VIRTUAL_KEYBOARD_LOCATION_INFO_META = 1000219004, + XR_TYPE_VIRTUAL_KEYBOARD_MODEL_VISIBILITY_SET_INFO_META = 1000219005, + XR_TYPE_VIRTUAL_KEYBOARD_ANIMATION_STATE_META = 1000219006, + XR_TYPE_VIRTUAL_KEYBOARD_MODEL_ANIMATION_STATES_META = 1000219007, + XR_TYPE_VIRTUAL_KEYBOARD_TEXTURE_DATA_META = 1000219009, + XR_TYPE_VIRTUAL_KEYBOARD_INPUT_INFO_META = 1000219010, + XR_TYPE_VIRTUAL_KEYBOARD_TEXT_CONTEXT_CHANGE_INFO_META = 1000219011, + XR_TYPE_EVENT_DATA_VIRTUAL_KEYBOARD_COMMIT_TEXT_META = 1000219014, + XR_TYPE_EVENT_DATA_VIRTUAL_KEYBOARD_BACKSPACE_META = 1000219015, + XR_TYPE_EVENT_DATA_VIRTUAL_KEYBOARD_ENTER_META = 1000219016, + XR_TYPE_EVENT_DATA_VIRTUAL_KEYBOARD_SHOWN_META = 1000219017, + XR_TYPE_EVENT_DATA_VIRTUAL_KEYBOARD_HIDDEN_META = 1000219018, + XR_TYPE_EXTERNAL_CAMERA_OCULUS = 1000226000, + XR_TYPE_VULKAN_SWAPCHAIN_CREATE_INFO_META = 1000227000, + XR_TYPE_PERFORMANCE_METRICS_STATE_META = 1000232001, + XR_TYPE_PERFORMANCE_METRICS_COUNTER_META = 1000232002, + XR_TYPE_SPACE_LIST_SAVE_INFO_FB = 1000238000, + XR_TYPE_EVENT_DATA_SPACE_LIST_SAVE_COMPLETE_FB = 1000238001, + XR_TYPE_SPACE_USER_CREATE_INFO_FB = 1000241001, + XR_TYPE_SYSTEM_HEADSET_ID_PROPERTIES_META = 1000245000, + XR_TYPE_SYSTEM_PASSTHROUGH_COLOR_LUT_PROPERTIES_META = 1000266000, + XR_TYPE_PASSTHROUGH_COLOR_LUT_CREATE_INFO_META = 1000266001, + XR_TYPE_PASSTHROUGH_COLOR_LUT_UPDATE_INFO_META = 1000266002, + XR_TYPE_PASSTHROUGH_COLOR_MAP_LUT_META = 1000266100, + XR_TYPE_PASSTHROUGH_COLOR_MAP_INTERPOLATED_LUT_META = 1000266101, + XR_TYPE_PASSTHROUGH_CREATE_INFO_HTC = 1000317001, + XR_TYPE_PASSTHROUGH_COLOR_HTC = 1000317002, + XR_TYPE_PASSTHROUGH_MESH_TRANSFORM_INFO_HTC = 1000317003, + XR_TYPE_COMPOSITION_LAYER_PASSTHROUGH_HTC = 1000317004, + XR_TYPE_FOVEATION_APPLY_INFO_HTC = 1000318000, + XR_TYPE_FOVEATION_DYNAMIC_MODE_INFO_HTC = 1000318001, + XR_TYPE_FOVEATION_CUSTOM_MODE_INFO_HTC = 1000318002, + XR_TYPE_ACTIVE_ACTION_SET_PRIORITIES_EXT = 1000373000, + XR_TYPE_SYSTEM_FORCE_FEEDBACK_CURL_PROPERTIES_MNDX = 1000375000, + XR_TYPE_FORCE_FEEDBACK_CURL_APPLY_LOCATIONS_MNDX = 1000375001, + XR_TYPE_HAND_TRACKING_DATA_SOURCE_INFO_EXT = 1000428000, + XR_TYPE_HAND_TRACKING_DATA_SOURCE_STATE_EXT = 1000428001, + XR_TYPE_PLANE_DETECTOR_CREATE_INFO_EXT = 1000429001, + XR_TYPE_PLANE_DETECTOR_BEGIN_INFO_EXT = 1000429002, + XR_TYPE_PLANE_DETECTOR_GET_INFO_EXT = 1000429003, + XR_TYPE_PLANE_DETECTOR_LOCATIONS_EXT = 1000429004, + XR_TYPE_PLANE_DETECTOR_LOCATION_EXT = 1000429005, + XR_TYPE_PLANE_DETECTOR_POLYGON_BUFFER_EXT = 1000429006, + XR_TYPE_SYSTEM_PLANE_DETECTION_PROPERTIES_EXT = 1000429007, + XR_TYPE_GRAPHICS_BINDING_VULKAN2_KHR = XR_TYPE_GRAPHICS_BINDING_VULKAN_KHR, + XR_TYPE_SWAPCHAIN_IMAGE_VULKAN2_KHR = XR_TYPE_SWAPCHAIN_IMAGE_VULKAN_KHR, + XR_TYPE_GRAPHICS_REQUIREMENTS_VULKAN2_KHR = XR_TYPE_GRAPHICS_REQUIREMENTS_VULKAN_KHR, + XR_TYPE_DEVICE_PCM_SAMPLE_RATE_GET_INFO_FB = XR_TYPE_DEVICE_PCM_SAMPLE_RATE_STATE_FB, + XR_STRUCTURE_TYPE_MAX_ENUM = 0x7FFFFFFF +} XrStructureType; + +typedef enum XrFormFactor { + XR_FORM_FACTOR_HEAD_MOUNTED_DISPLAY = 1, + XR_FORM_FACTOR_HANDHELD_DISPLAY = 2, + XR_FORM_FACTOR_MAX_ENUM = 0x7FFFFFFF +} XrFormFactor; + +typedef enum XrViewConfigurationType { + XR_VIEW_CONFIGURATION_TYPE_PRIMARY_MONO = 1, + XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO = 2, + XR_VIEW_CONFIGURATION_TYPE_PRIMARY_QUAD_VARJO = 1000037000, + XR_VIEW_CONFIGURATION_TYPE_SECONDARY_MONO_FIRST_PERSON_OBSERVER_MSFT = 1000054000, + XR_VIEW_CONFIGURATION_TYPE_MAX_ENUM = 0x7FFFFFFF +} XrViewConfigurationType; + +typedef enum XrEnvironmentBlendMode { + XR_ENVIRONMENT_BLEND_MODE_OPAQUE = 1, + XR_ENVIRONMENT_BLEND_MODE_ADDITIVE = 2, + XR_ENVIRONMENT_BLEND_MODE_ALPHA_BLEND = 3, + XR_ENVIRONMENT_BLEND_MODE_MAX_ENUM = 0x7FFFFFFF +} XrEnvironmentBlendMode; + +typedef enum XrReferenceSpaceType { + XR_REFERENCE_SPACE_TYPE_VIEW = 1, + XR_REFERENCE_SPACE_TYPE_LOCAL = 2, + XR_REFERENCE_SPACE_TYPE_STAGE = 3, + XR_REFERENCE_SPACE_TYPE_UNBOUNDED_MSFT = 1000038000, + XR_REFERENCE_SPACE_TYPE_COMBINED_EYE_VARJO = 1000121000, + XR_REFERENCE_SPACE_TYPE_LOCAL_FLOOR_EXT = 1000426000, + XR_REFERENCE_SPACE_TYPE_MAX_ENUM = 0x7FFFFFFF +} XrReferenceSpaceType; + +typedef enum XrActionType { + XR_ACTION_TYPE_BOOLEAN_INPUT = 1, + XR_ACTION_TYPE_FLOAT_INPUT = 2, + XR_ACTION_TYPE_VECTOR2F_INPUT = 3, + XR_ACTION_TYPE_POSE_INPUT = 4, + XR_ACTION_TYPE_VIBRATION_OUTPUT = 100, + XR_ACTION_TYPE_MAX_ENUM = 0x7FFFFFFF +} XrActionType; + +typedef enum XrEyeVisibility { + XR_EYE_VISIBILITY_BOTH = 0, + XR_EYE_VISIBILITY_LEFT = 1, + XR_EYE_VISIBILITY_RIGHT = 2, + XR_EYE_VISIBILITY_MAX_ENUM = 0x7FFFFFFF +} XrEyeVisibility; + +typedef enum XrSessionState { + XR_SESSION_STATE_UNKNOWN = 0, + XR_SESSION_STATE_IDLE = 1, + XR_SESSION_STATE_READY = 2, + XR_SESSION_STATE_SYNCHRONIZED = 3, + XR_SESSION_STATE_VISIBLE = 4, + XR_SESSION_STATE_FOCUSED = 5, + XR_SESSION_STATE_STOPPING = 6, + XR_SESSION_STATE_LOSS_PENDING = 7, + XR_SESSION_STATE_EXITING = 8, + XR_SESSION_STATE_MAX_ENUM = 0x7FFFFFFF +} XrSessionState; + +typedef enum XrObjectType { + XR_OBJECT_TYPE_UNKNOWN = 0, + XR_OBJECT_TYPE_INSTANCE = 1, + XR_OBJECT_TYPE_SESSION = 2, + XR_OBJECT_TYPE_SWAPCHAIN = 3, + XR_OBJECT_TYPE_SPACE = 4, + XR_OBJECT_TYPE_ACTION_SET = 5, + XR_OBJECT_TYPE_ACTION = 6, + XR_OBJECT_TYPE_DEBUG_UTILS_MESSENGER_EXT = 1000019000, + XR_OBJECT_TYPE_SPATIAL_ANCHOR_MSFT = 1000039000, + XR_OBJECT_TYPE_SPATIAL_GRAPH_NODE_BINDING_MSFT = 1000049000, + XR_OBJECT_TYPE_HAND_TRACKER_EXT = 1000051000, + XR_OBJECT_TYPE_BODY_TRACKER_FB = 1000076000, + XR_OBJECT_TYPE_SCENE_OBSERVER_MSFT = 1000097000, + XR_OBJECT_TYPE_SCENE_MSFT = 1000097001, + XR_OBJECT_TYPE_FACIAL_TRACKER_HTC = 1000104000, + XR_OBJECT_TYPE_FOVEATION_PROFILE_FB = 1000114000, + XR_OBJECT_TYPE_TRIANGLE_MESH_FB = 1000117000, + XR_OBJECT_TYPE_PASSTHROUGH_FB = 1000118000, + XR_OBJECT_TYPE_PASSTHROUGH_LAYER_FB = 1000118002, + XR_OBJECT_TYPE_GEOMETRY_INSTANCE_FB = 1000118004, + XR_OBJECT_TYPE_SPATIAL_ANCHOR_STORE_CONNECTION_MSFT = 1000142000, + XR_OBJECT_TYPE_FACE_TRACKER_FB = 1000201000, + XR_OBJECT_TYPE_EYE_TRACKER_FB = 1000202000, + XR_OBJECT_TYPE_VIRTUAL_KEYBOARD_META = 1000219000, + XR_OBJECT_TYPE_SPACE_USER_FB = 1000241000, + XR_OBJECT_TYPE_PASSTHROUGH_COLOR_LUT_META = 1000266000, + XR_OBJECT_TYPE_PASSTHROUGH_HTC = 1000317000, + XR_OBJECT_TYPE_PLANE_DETECTOR_EXT = 1000429000, + XR_OBJECT_TYPE_MAX_ENUM = 0x7FFFFFFF +} XrObjectType; +typedef XrFlags64 XrInstanceCreateFlags; + +// Flag bits for XrInstanceCreateFlags + +typedef XrFlags64 XrSessionCreateFlags; + +// Flag bits for XrSessionCreateFlags + +typedef XrFlags64 XrSpaceVelocityFlags; + +// Flag bits for XrSpaceVelocityFlags +static const XrSpaceVelocityFlags XR_SPACE_VELOCITY_LINEAR_VALID_BIT = 0x00000001; +static const XrSpaceVelocityFlags XR_SPACE_VELOCITY_ANGULAR_VALID_BIT = 0x00000002; + +typedef XrFlags64 XrSpaceLocationFlags; + +// Flag bits for XrSpaceLocationFlags +static const XrSpaceLocationFlags XR_SPACE_LOCATION_ORIENTATION_VALID_BIT = 0x00000001; +static const XrSpaceLocationFlags XR_SPACE_LOCATION_POSITION_VALID_BIT = 0x00000002; +static const XrSpaceLocationFlags XR_SPACE_LOCATION_ORIENTATION_TRACKED_BIT = 0x00000004; +static const XrSpaceLocationFlags XR_SPACE_LOCATION_POSITION_TRACKED_BIT = 0x00000008; + +typedef XrFlags64 XrSwapchainCreateFlags; + +// Flag bits for XrSwapchainCreateFlags +static const XrSwapchainCreateFlags XR_SWAPCHAIN_CREATE_PROTECTED_CONTENT_BIT = 0x00000001; +static const XrSwapchainCreateFlags XR_SWAPCHAIN_CREATE_STATIC_IMAGE_BIT = 0x00000002; + +typedef XrFlags64 XrSwapchainUsageFlags; + +// Flag bits for XrSwapchainUsageFlags +static const XrSwapchainUsageFlags XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT = 0x00000001; +static const XrSwapchainUsageFlags XR_SWAPCHAIN_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT = 0x00000002; +static const XrSwapchainUsageFlags XR_SWAPCHAIN_USAGE_UNORDERED_ACCESS_BIT = 0x00000004; +static const XrSwapchainUsageFlags XR_SWAPCHAIN_USAGE_TRANSFER_SRC_BIT = 0x00000008; +static const XrSwapchainUsageFlags XR_SWAPCHAIN_USAGE_TRANSFER_DST_BIT = 0x00000010; +static const XrSwapchainUsageFlags XR_SWAPCHAIN_USAGE_SAMPLED_BIT = 0x00000020; +static const XrSwapchainUsageFlags XR_SWAPCHAIN_USAGE_MUTABLE_FORMAT_BIT = 0x00000040; +static const XrSwapchainUsageFlags XR_SWAPCHAIN_USAGE_INPUT_ATTACHMENT_BIT_MND = 0x00000080; +static const XrSwapchainUsageFlags XR_SWAPCHAIN_USAGE_INPUT_ATTACHMENT_BIT_KHR = 0x00000080; // alias of XR_SWAPCHAIN_USAGE_INPUT_ATTACHMENT_BIT_MND + +typedef XrFlags64 XrCompositionLayerFlags; + +// Flag bits for XrCompositionLayerFlags +static const XrCompositionLayerFlags XR_COMPOSITION_LAYER_CORRECT_CHROMATIC_ABERRATION_BIT = 0x00000001; +static const XrCompositionLayerFlags XR_COMPOSITION_LAYER_BLEND_TEXTURE_SOURCE_ALPHA_BIT = 0x00000002; +static const XrCompositionLayerFlags XR_COMPOSITION_LAYER_UNPREMULTIPLIED_ALPHA_BIT = 0x00000004; + +typedef XrFlags64 XrViewStateFlags; + +// Flag bits for XrViewStateFlags +static const XrViewStateFlags XR_VIEW_STATE_ORIENTATION_VALID_BIT = 0x00000001; +static const XrViewStateFlags XR_VIEW_STATE_POSITION_VALID_BIT = 0x00000002; +static const XrViewStateFlags XR_VIEW_STATE_ORIENTATION_TRACKED_BIT = 0x00000004; +static const XrViewStateFlags XR_VIEW_STATE_POSITION_TRACKED_BIT = 0x00000008; + +typedef XrFlags64 XrInputSourceLocalizedNameFlags; + +// Flag bits for XrInputSourceLocalizedNameFlags +static const XrInputSourceLocalizedNameFlags XR_INPUT_SOURCE_LOCALIZED_NAME_USER_PATH_BIT = 0x00000001; +static const XrInputSourceLocalizedNameFlags XR_INPUT_SOURCE_LOCALIZED_NAME_INTERACTION_PROFILE_BIT = 0x00000002; +static const XrInputSourceLocalizedNameFlags XR_INPUT_SOURCE_LOCALIZED_NAME_COMPONENT_BIT = 0x00000004; + +typedef void (XRAPI_PTR *PFN_xrVoidFunction)(void); +typedef struct XrApiLayerProperties { + XrStructureType type; + void* XR_MAY_ALIAS next; + char layerName[XR_MAX_API_LAYER_NAME_SIZE]; + XrVersion specVersion; + uint32_t layerVersion; + char description[XR_MAX_API_LAYER_DESCRIPTION_SIZE]; +} XrApiLayerProperties; + +typedef struct XrExtensionProperties { + XrStructureType type; + void* XR_MAY_ALIAS next; + char extensionName[XR_MAX_EXTENSION_NAME_SIZE]; + uint32_t extensionVersion; +} XrExtensionProperties; + +typedef struct XrApplicationInfo { + char applicationName[XR_MAX_APPLICATION_NAME_SIZE]; + uint32_t applicationVersion; + char engineName[XR_MAX_ENGINE_NAME_SIZE]; + uint32_t engineVersion; + XrVersion apiVersion; +} XrApplicationInfo; + +typedef struct XrInstanceCreateInfo { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrInstanceCreateFlags createFlags; + XrApplicationInfo applicationInfo; + uint32_t enabledApiLayerCount; + const char* const* enabledApiLayerNames; + uint32_t enabledExtensionCount; + const char* const* enabledExtensionNames; +} XrInstanceCreateInfo; + +typedef struct XrInstanceProperties { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrVersion runtimeVersion; + char runtimeName[XR_MAX_RUNTIME_NAME_SIZE]; +} XrInstanceProperties; + +typedef struct XrEventDataBuffer { + XrStructureType type; + const void* XR_MAY_ALIAS next; + uint8_t varying[4000]; +} XrEventDataBuffer; + +typedef struct XrSystemGetInfo { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrFormFactor formFactor; +} XrSystemGetInfo; + +typedef struct XrSystemGraphicsProperties { + uint32_t maxSwapchainImageHeight; + uint32_t maxSwapchainImageWidth; + uint32_t maxLayerCount; +} XrSystemGraphicsProperties; + +typedef struct XrSystemTrackingProperties { + XrBool32 orientationTracking; + XrBool32 positionTracking; +} XrSystemTrackingProperties; + +typedef struct XrSystemProperties { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrSystemId systemId; + uint32_t vendorId; + char systemName[XR_MAX_SYSTEM_NAME_SIZE]; + XrSystemGraphicsProperties graphicsProperties; + XrSystemTrackingProperties trackingProperties; +} XrSystemProperties; + +typedef struct XrSessionCreateInfo { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSessionCreateFlags createFlags; + XrSystemId systemId; +} XrSessionCreateInfo; + +typedef struct XrVector3f { + float x; + float y; + float z; +} XrVector3f; + +// XrSpaceVelocity extends XrSpaceLocation +typedef struct XrSpaceVelocity { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrSpaceVelocityFlags velocityFlags; + XrVector3f linearVelocity; + XrVector3f angularVelocity; +} XrSpaceVelocity; + +typedef struct XrQuaternionf { + float x; + float y; + float z; + float w; +} XrQuaternionf; + +typedef struct XrPosef { + XrQuaternionf orientation; + XrVector3f position; +} XrPosef; + +typedef struct XrReferenceSpaceCreateInfo { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrReferenceSpaceType referenceSpaceType; + XrPosef poseInReferenceSpace; +} XrReferenceSpaceCreateInfo; + +typedef struct XrExtent2Df { + float width; + float height; +} XrExtent2Df; + +typedef struct XrActionSpaceCreateInfo { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrAction action; + XrPath subactionPath; + XrPosef poseInActionSpace; +} XrActionSpaceCreateInfo; + +typedef struct XrSpaceLocation { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrSpaceLocationFlags locationFlags; + XrPosef pose; +} XrSpaceLocation; + +typedef struct XrViewConfigurationProperties { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrViewConfigurationType viewConfigurationType; + XrBool32 fovMutable; +} XrViewConfigurationProperties; + +typedef struct XrViewConfigurationView { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint32_t recommendedImageRectWidth; + uint32_t maxImageRectWidth; + uint32_t recommendedImageRectHeight; + uint32_t maxImageRectHeight; + uint32_t recommendedSwapchainSampleCount; + uint32_t maxSwapchainSampleCount; +} XrViewConfigurationView; + +typedef struct XrSwapchainCreateInfo { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSwapchainCreateFlags createFlags; + XrSwapchainUsageFlags usageFlags; + int64_t format; + uint32_t sampleCount; + uint32_t width; + uint32_t height; + uint32_t faceCount; + uint32_t arraySize; + uint32_t mipCount; +} XrSwapchainCreateInfo; + +typedef struct XR_MAY_ALIAS XrSwapchainImageBaseHeader { + XrStructureType type; + void* XR_MAY_ALIAS next; +} XrSwapchainImageBaseHeader; + +typedef struct XrSwapchainImageAcquireInfo { + XrStructureType type; + const void* XR_MAY_ALIAS next; +} XrSwapchainImageAcquireInfo; + +typedef struct XrSwapchainImageWaitInfo { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrDuration timeout; +} XrSwapchainImageWaitInfo; + +typedef struct XrSwapchainImageReleaseInfo { + XrStructureType type; + const void* XR_MAY_ALIAS next; +} XrSwapchainImageReleaseInfo; + +typedef struct XrSessionBeginInfo { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrViewConfigurationType primaryViewConfigurationType; +} XrSessionBeginInfo; + +typedef struct XrFrameWaitInfo { + XrStructureType type; + const void* XR_MAY_ALIAS next; +} XrFrameWaitInfo; + +typedef struct XrFrameState { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrTime predictedDisplayTime; + XrDuration predictedDisplayPeriod; + XrBool32 shouldRender; +} XrFrameState; + +typedef struct XrFrameBeginInfo { + XrStructureType type; + const void* XR_MAY_ALIAS next; +} XrFrameBeginInfo; + +typedef struct XR_MAY_ALIAS XrCompositionLayerBaseHeader { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrCompositionLayerFlags layerFlags; + XrSpace space; +} XrCompositionLayerBaseHeader; + +typedef struct XrFrameEndInfo { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrTime displayTime; + XrEnvironmentBlendMode environmentBlendMode; + uint32_t layerCount; + const XrCompositionLayerBaseHeader* const* layers; +} XrFrameEndInfo; + +typedef struct XrViewLocateInfo { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrViewConfigurationType viewConfigurationType; + XrTime displayTime; + XrSpace space; +} XrViewLocateInfo; + +typedef struct XrViewState { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrViewStateFlags viewStateFlags; +} XrViewState; + +typedef struct XrFovf { + float angleLeft; + float angleRight; + float angleUp; + float angleDown; +} XrFovf; + +typedef struct XrView { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrPosef pose; + XrFovf fov; +} XrView; + +typedef struct XrActionSetCreateInfo { + XrStructureType type; + const void* XR_MAY_ALIAS next; + char actionSetName[XR_MAX_ACTION_SET_NAME_SIZE]; + char localizedActionSetName[XR_MAX_LOCALIZED_ACTION_SET_NAME_SIZE]; + uint32_t priority; +} XrActionSetCreateInfo; + +typedef struct XrActionCreateInfo { + XrStructureType type; + const void* XR_MAY_ALIAS next; + char actionName[XR_MAX_ACTION_NAME_SIZE]; + XrActionType actionType; + uint32_t countSubactionPaths; + const XrPath* subactionPaths; + char localizedActionName[XR_MAX_LOCALIZED_ACTION_NAME_SIZE]; +} XrActionCreateInfo; + +typedef struct XrActionSuggestedBinding { + XrAction action; + XrPath binding; +} XrActionSuggestedBinding; + +typedef struct XrInteractionProfileSuggestedBinding { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrPath interactionProfile; + uint32_t countSuggestedBindings; + const XrActionSuggestedBinding* suggestedBindings; +} XrInteractionProfileSuggestedBinding; + +typedef struct XrSessionActionSetsAttachInfo { + XrStructureType type; + const void* XR_MAY_ALIAS next; + uint32_t countActionSets; + const XrActionSet* actionSets; +} XrSessionActionSetsAttachInfo; + +typedef struct XrInteractionProfileState { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrPath interactionProfile; +} XrInteractionProfileState; + +typedef struct XrActionStateGetInfo { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrAction action; + XrPath subactionPath; +} XrActionStateGetInfo; + +typedef struct XrActionStateBoolean { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrBool32 currentState; + XrBool32 changedSinceLastSync; + XrTime lastChangeTime; + XrBool32 isActive; +} XrActionStateBoolean; + +typedef struct XrActionStateFloat { + XrStructureType type; + void* XR_MAY_ALIAS next; + float currentState; + XrBool32 changedSinceLastSync; + XrTime lastChangeTime; + XrBool32 isActive; +} XrActionStateFloat; + +typedef struct XrVector2f { + float x; + float y; +} XrVector2f; + +typedef struct XrActionStateVector2f { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrVector2f currentState; + XrBool32 changedSinceLastSync; + XrTime lastChangeTime; + XrBool32 isActive; +} XrActionStateVector2f; + +typedef struct XrActionStatePose { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrBool32 isActive; +} XrActionStatePose; + +typedef struct XrActiveActionSet { + XrActionSet actionSet; + XrPath subactionPath; +} XrActiveActionSet; + +typedef struct XrActionsSyncInfo { + XrStructureType type; + const void* XR_MAY_ALIAS next; + uint32_t countActiveActionSets; + const XrActiveActionSet* activeActionSets; +} XrActionsSyncInfo; + +typedef struct XrBoundSourcesForActionEnumerateInfo { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrAction action; +} XrBoundSourcesForActionEnumerateInfo; + +typedef struct XrInputSourceLocalizedNameGetInfo { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrPath sourcePath; + XrInputSourceLocalizedNameFlags whichComponents; +} XrInputSourceLocalizedNameGetInfo; + +typedef struct XrHapticActionInfo { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrAction action; + XrPath subactionPath; +} XrHapticActionInfo; + +typedef struct XR_MAY_ALIAS XrHapticBaseHeader { + XrStructureType type; + const void* XR_MAY_ALIAS next; +} XrHapticBaseHeader; + +typedef struct XR_MAY_ALIAS XrBaseInStructure { + XrStructureType type; + const struct XrBaseInStructure* next; +} XrBaseInStructure; + +typedef struct XR_MAY_ALIAS XrBaseOutStructure { + XrStructureType type; + struct XrBaseOutStructure* next; +} XrBaseOutStructure; + +typedef struct XrOffset2Di { + int32_t x; + int32_t y; +} XrOffset2Di; + +typedef struct XrExtent2Di { + int32_t width; + int32_t height; +} XrExtent2Di; + +typedef struct XrRect2Di { + XrOffset2Di offset; + XrExtent2Di extent; +} XrRect2Di; + +typedef struct XrSwapchainSubImage { + XrSwapchain swapchain; + XrRect2Di imageRect; + uint32_t imageArrayIndex; +} XrSwapchainSubImage; + +typedef struct XrCompositionLayerProjectionView { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrPosef pose; + XrFovf fov; + XrSwapchainSubImage subImage; +} XrCompositionLayerProjectionView; + +typedef struct XrCompositionLayerProjection { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrCompositionLayerFlags layerFlags; + XrSpace space; + uint32_t viewCount; + const XrCompositionLayerProjectionView* views; +} XrCompositionLayerProjection; + +typedef struct XrCompositionLayerQuad { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrCompositionLayerFlags layerFlags; + XrSpace space; + XrEyeVisibility eyeVisibility; + XrSwapchainSubImage subImage; + XrPosef pose; + XrExtent2Df size; +} XrCompositionLayerQuad; + +typedef struct XR_MAY_ALIAS XrEventDataBaseHeader { + XrStructureType type; + const void* XR_MAY_ALIAS next; +} XrEventDataBaseHeader; + +typedef struct XrEventDataEventsLost { + XrStructureType type; + const void* XR_MAY_ALIAS next; + uint32_t lostEventCount; +} XrEventDataEventsLost; + +typedef struct XrEventDataInstanceLossPending { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrTime lossTime; +} XrEventDataInstanceLossPending; + +typedef struct XrEventDataSessionStateChanged { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSession session; + XrSessionState state; + XrTime time; +} XrEventDataSessionStateChanged; + +typedef struct XrEventDataReferenceSpaceChangePending { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSession session; + XrReferenceSpaceType referenceSpaceType; + XrTime changeTime; + XrBool32 poseValid; + XrPosef poseInPreviousSpace; +} XrEventDataReferenceSpaceChangePending; + +typedef struct XrEventDataInteractionProfileChanged { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSession session; +} XrEventDataInteractionProfileChanged; + +typedef struct XrHapticVibration { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrDuration duration; + float frequency; + float amplitude; +} XrHapticVibration; + +typedef struct XrOffset2Df { + float x; + float y; +} XrOffset2Df; + +typedef struct XrRect2Df { + XrOffset2Df offset; + XrExtent2Df extent; +} XrRect2Df; + +typedef struct XrVector4f { + float x; + float y; + float z; + float w; +} XrVector4f; + +typedef struct XrColor4f { + float r; + float g; + float b; + float a; +} XrColor4f; + +typedef XrResult (XRAPI_PTR *PFN_xrGetInstanceProcAddr)(XrInstance instance, const char* name, PFN_xrVoidFunction* function); +typedef XrResult (XRAPI_PTR *PFN_xrEnumerateApiLayerProperties)(uint32_t propertyCapacityInput, uint32_t* propertyCountOutput, XrApiLayerProperties* properties); +typedef XrResult (XRAPI_PTR *PFN_xrEnumerateInstanceExtensionProperties)(const char* layerName, uint32_t propertyCapacityInput, uint32_t* propertyCountOutput, XrExtensionProperties* properties); +typedef XrResult (XRAPI_PTR *PFN_xrCreateInstance)(const XrInstanceCreateInfo* createInfo, XrInstance* instance); +typedef XrResult (XRAPI_PTR *PFN_xrDestroyInstance)(XrInstance instance); +typedef XrResult (XRAPI_PTR *PFN_xrGetInstanceProperties)(XrInstance instance, XrInstanceProperties* instanceProperties); +typedef XrResult (XRAPI_PTR *PFN_xrPollEvent)(XrInstance instance, XrEventDataBuffer* eventData); +typedef XrResult (XRAPI_PTR *PFN_xrResultToString)(XrInstance instance, XrResult value, char buffer[XR_MAX_RESULT_STRING_SIZE]); +typedef XrResult (XRAPI_PTR *PFN_xrStructureTypeToString)(XrInstance instance, XrStructureType value, char buffer[XR_MAX_STRUCTURE_NAME_SIZE]); +typedef XrResult (XRAPI_PTR *PFN_xrGetSystem)(XrInstance instance, const XrSystemGetInfo* getInfo, XrSystemId* systemId); +typedef XrResult (XRAPI_PTR *PFN_xrGetSystemProperties)(XrInstance instance, XrSystemId systemId, XrSystemProperties* properties); +typedef XrResult (XRAPI_PTR *PFN_xrEnumerateEnvironmentBlendModes)(XrInstance instance, XrSystemId systemId, XrViewConfigurationType viewConfigurationType, uint32_t environmentBlendModeCapacityInput, uint32_t* environmentBlendModeCountOutput, XrEnvironmentBlendMode* environmentBlendModes); +typedef XrResult (XRAPI_PTR *PFN_xrCreateSession)(XrInstance instance, const XrSessionCreateInfo* createInfo, XrSession* session); +typedef XrResult (XRAPI_PTR *PFN_xrDestroySession)(XrSession session); +typedef XrResult (XRAPI_PTR *PFN_xrEnumerateReferenceSpaces)(XrSession session, uint32_t spaceCapacityInput, uint32_t* spaceCountOutput, XrReferenceSpaceType* spaces); +typedef XrResult (XRAPI_PTR *PFN_xrCreateReferenceSpace)(XrSession session, const XrReferenceSpaceCreateInfo* createInfo, XrSpace* space); +typedef XrResult (XRAPI_PTR *PFN_xrGetReferenceSpaceBoundsRect)(XrSession session, XrReferenceSpaceType referenceSpaceType, XrExtent2Df* bounds); +typedef XrResult (XRAPI_PTR *PFN_xrCreateActionSpace)(XrSession session, const XrActionSpaceCreateInfo* createInfo, XrSpace* space); +typedef XrResult (XRAPI_PTR *PFN_xrLocateSpace)(XrSpace space, XrSpace baseSpace, XrTime time, XrSpaceLocation* location); +typedef XrResult (XRAPI_PTR *PFN_xrDestroySpace)(XrSpace space); +typedef XrResult (XRAPI_PTR *PFN_xrEnumerateViewConfigurations)(XrInstance instance, XrSystemId systemId, uint32_t viewConfigurationTypeCapacityInput, uint32_t* viewConfigurationTypeCountOutput, XrViewConfigurationType* viewConfigurationTypes); +typedef XrResult (XRAPI_PTR *PFN_xrGetViewConfigurationProperties)(XrInstance instance, XrSystemId systemId, XrViewConfigurationType viewConfigurationType, XrViewConfigurationProperties* configurationProperties); +typedef XrResult (XRAPI_PTR *PFN_xrEnumerateViewConfigurationViews)(XrInstance instance, XrSystemId systemId, XrViewConfigurationType viewConfigurationType, uint32_t viewCapacityInput, uint32_t* viewCountOutput, XrViewConfigurationView* views); +typedef XrResult (XRAPI_PTR *PFN_xrEnumerateSwapchainFormats)(XrSession session, uint32_t formatCapacityInput, uint32_t* formatCountOutput, int64_t* formats); +typedef XrResult (XRAPI_PTR *PFN_xrCreateSwapchain)(XrSession session, const XrSwapchainCreateInfo* createInfo, XrSwapchain* swapchain); +typedef XrResult (XRAPI_PTR *PFN_xrDestroySwapchain)(XrSwapchain swapchain); +typedef XrResult (XRAPI_PTR *PFN_xrEnumerateSwapchainImages)(XrSwapchain swapchain, uint32_t imageCapacityInput, uint32_t* imageCountOutput, XrSwapchainImageBaseHeader* images); +typedef XrResult (XRAPI_PTR *PFN_xrAcquireSwapchainImage)(XrSwapchain swapchain, const XrSwapchainImageAcquireInfo* acquireInfo, uint32_t* index); +typedef XrResult (XRAPI_PTR *PFN_xrWaitSwapchainImage)(XrSwapchain swapchain, const XrSwapchainImageWaitInfo* waitInfo); +typedef XrResult (XRAPI_PTR *PFN_xrReleaseSwapchainImage)(XrSwapchain swapchain, const XrSwapchainImageReleaseInfo* releaseInfo); +typedef XrResult (XRAPI_PTR *PFN_xrBeginSession)(XrSession session, const XrSessionBeginInfo* beginInfo); +typedef XrResult (XRAPI_PTR *PFN_xrEndSession)(XrSession session); +typedef XrResult (XRAPI_PTR *PFN_xrRequestExitSession)(XrSession session); +typedef XrResult (XRAPI_PTR *PFN_xrWaitFrame)(XrSession session, const XrFrameWaitInfo* frameWaitInfo, XrFrameState* frameState); +typedef XrResult (XRAPI_PTR *PFN_xrBeginFrame)(XrSession session, const XrFrameBeginInfo* frameBeginInfo); +typedef XrResult (XRAPI_PTR *PFN_xrEndFrame)(XrSession session, const XrFrameEndInfo* frameEndInfo); +typedef XrResult (XRAPI_PTR *PFN_xrLocateViews)(XrSession session, const XrViewLocateInfo* viewLocateInfo, XrViewState* viewState, uint32_t viewCapacityInput, uint32_t* viewCountOutput, XrView* views); +typedef XrResult (XRAPI_PTR *PFN_xrStringToPath)(XrInstance instance, const char* pathString, XrPath* path); +typedef XrResult (XRAPI_PTR *PFN_xrPathToString)(XrInstance instance, XrPath path, uint32_t bufferCapacityInput, uint32_t* bufferCountOutput, char* buffer); +typedef XrResult (XRAPI_PTR *PFN_xrCreateActionSet)(XrInstance instance, const XrActionSetCreateInfo* createInfo, XrActionSet* actionSet); +typedef XrResult (XRAPI_PTR *PFN_xrDestroyActionSet)(XrActionSet actionSet); +typedef XrResult (XRAPI_PTR *PFN_xrCreateAction)(XrActionSet actionSet, const XrActionCreateInfo* createInfo, XrAction* action); +typedef XrResult (XRAPI_PTR *PFN_xrDestroyAction)(XrAction action); +typedef XrResult (XRAPI_PTR *PFN_xrSuggestInteractionProfileBindings)(XrInstance instance, const XrInteractionProfileSuggestedBinding* suggestedBindings); +typedef XrResult (XRAPI_PTR *PFN_xrAttachSessionActionSets)(XrSession session, const XrSessionActionSetsAttachInfo* attachInfo); +typedef XrResult (XRAPI_PTR *PFN_xrGetCurrentInteractionProfile)(XrSession session, XrPath topLevelUserPath, XrInteractionProfileState* interactionProfile); +typedef XrResult (XRAPI_PTR *PFN_xrGetActionStateBoolean)(XrSession session, const XrActionStateGetInfo* getInfo, XrActionStateBoolean* state); +typedef XrResult (XRAPI_PTR *PFN_xrGetActionStateFloat)(XrSession session, const XrActionStateGetInfo* getInfo, XrActionStateFloat* state); +typedef XrResult (XRAPI_PTR *PFN_xrGetActionStateVector2f)(XrSession session, const XrActionStateGetInfo* getInfo, XrActionStateVector2f* state); +typedef XrResult (XRAPI_PTR *PFN_xrGetActionStatePose)(XrSession session, const XrActionStateGetInfo* getInfo, XrActionStatePose* state); +typedef XrResult (XRAPI_PTR *PFN_xrSyncActions)(XrSession session, const XrActionsSyncInfo* syncInfo); +typedef XrResult (XRAPI_PTR *PFN_xrEnumerateBoundSourcesForAction)(XrSession session, const XrBoundSourcesForActionEnumerateInfo* enumerateInfo, uint32_t sourceCapacityInput, uint32_t* sourceCountOutput, XrPath* sources); +typedef XrResult (XRAPI_PTR *PFN_xrGetInputSourceLocalizedName)(XrSession session, const XrInputSourceLocalizedNameGetInfo* getInfo, uint32_t bufferCapacityInput, uint32_t* bufferCountOutput, char* buffer); +typedef XrResult (XRAPI_PTR *PFN_xrApplyHapticFeedback)(XrSession session, const XrHapticActionInfo* hapticActionInfo, const XrHapticBaseHeader* hapticFeedback); +typedef XrResult (XRAPI_PTR *PFN_xrStopHapticFeedback)(XrSession session, const XrHapticActionInfo* hapticActionInfo); + +#ifndef XR_NO_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrGetInstanceProcAddr( + XrInstance instance, + const char* name, + PFN_xrVoidFunction* function); + +XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateApiLayerProperties( + uint32_t propertyCapacityInput, + uint32_t* propertyCountOutput, + XrApiLayerProperties* properties); + +XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateInstanceExtensionProperties( + const char* layerName, + uint32_t propertyCapacityInput, + uint32_t* propertyCountOutput, + XrExtensionProperties* properties); + +XRAPI_ATTR XrResult XRAPI_CALL xrCreateInstance( + const XrInstanceCreateInfo* createInfo, + XrInstance* instance); + +XRAPI_ATTR XrResult XRAPI_CALL xrDestroyInstance( + XrInstance instance); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetInstanceProperties( + XrInstance instance, + XrInstanceProperties* instanceProperties); + +XRAPI_ATTR XrResult XRAPI_CALL xrPollEvent( + XrInstance instance, + XrEventDataBuffer* eventData); + +XRAPI_ATTR XrResult XRAPI_CALL xrResultToString( + XrInstance instance, + XrResult value, + char buffer[XR_MAX_RESULT_STRING_SIZE]); + +XRAPI_ATTR XrResult XRAPI_CALL xrStructureTypeToString( + XrInstance instance, + XrStructureType value, + char buffer[XR_MAX_STRUCTURE_NAME_SIZE]); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetSystem( + XrInstance instance, + const XrSystemGetInfo* getInfo, + XrSystemId* systemId); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetSystemProperties( + XrInstance instance, + XrSystemId systemId, + XrSystemProperties* properties); + +XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateEnvironmentBlendModes( + XrInstance instance, + XrSystemId systemId, + XrViewConfigurationType viewConfigurationType, + uint32_t environmentBlendModeCapacityInput, + uint32_t* environmentBlendModeCountOutput, + XrEnvironmentBlendMode* environmentBlendModes); + +XRAPI_ATTR XrResult XRAPI_CALL xrCreateSession( + XrInstance instance, + const XrSessionCreateInfo* createInfo, + XrSession* session); + +XRAPI_ATTR XrResult XRAPI_CALL xrDestroySession( + XrSession session); + +XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateReferenceSpaces( + XrSession session, + uint32_t spaceCapacityInput, + uint32_t* spaceCountOutput, + XrReferenceSpaceType* spaces); + +XRAPI_ATTR XrResult XRAPI_CALL xrCreateReferenceSpace( + XrSession session, + const XrReferenceSpaceCreateInfo* createInfo, + XrSpace* space); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetReferenceSpaceBoundsRect( + XrSession session, + XrReferenceSpaceType referenceSpaceType, + XrExtent2Df* bounds); + +XRAPI_ATTR XrResult XRAPI_CALL xrCreateActionSpace( + XrSession session, + const XrActionSpaceCreateInfo* createInfo, + XrSpace* space); + +XRAPI_ATTR XrResult XRAPI_CALL xrLocateSpace( + XrSpace space, + XrSpace baseSpace, + XrTime time, + XrSpaceLocation* location); + +XRAPI_ATTR XrResult XRAPI_CALL xrDestroySpace( + XrSpace space); + +XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateViewConfigurations( + XrInstance instance, + XrSystemId systemId, + uint32_t viewConfigurationTypeCapacityInput, + uint32_t* viewConfigurationTypeCountOutput, + XrViewConfigurationType* viewConfigurationTypes); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetViewConfigurationProperties( + XrInstance instance, + XrSystemId systemId, + XrViewConfigurationType viewConfigurationType, + XrViewConfigurationProperties* configurationProperties); + +XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateViewConfigurationViews( + XrInstance instance, + XrSystemId systemId, + XrViewConfigurationType viewConfigurationType, + uint32_t viewCapacityInput, + uint32_t* viewCountOutput, + XrViewConfigurationView* views); + +XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateSwapchainFormats( + XrSession session, + uint32_t formatCapacityInput, + uint32_t* formatCountOutput, + int64_t* formats); + +XRAPI_ATTR XrResult XRAPI_CALL xrCreateSwapchain( + XrSession session, + const XrSwapchainCreateInfo* createInfo, + XrSwapchain* swapchain); + +XRAPI_ATTR XrResult XRAPI_CALL xrDestroySwapchain( + XrSwapchain swapchain); + +XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateSwapchainImages( + XrSwapchain swapchain, + uint32_t imageCapacityInput, + uint32_t* imageCountOutput, + XrSwapchainImageBaseHeader* images); + +XRAPI_ATTR XrResult XRAPI_CALL xrAcquireSwapchainImage( + XrSwapchain swapchain, + const XrSwapchainImageAcquireInfo* acquireInfo, + uint32_t* index); + +XRAPI_ATTR XrResult XRAPI_CALL xrWaitSwapchainImage( + XrSwapchain swapchain, + const XrSwapchainImageWaitInfo* waitInfo); + +XRAPI_ATTR XrResult XRAPI_CALL xrReleaseSwapchainImage( + XrSwapchain swapchain, + const XrSwapchainImageReleaseInfo* releaseInfo); + +XRAPI_ATTR XrResult XRAPI_CALL xrBeginSession( + XrSession session, + const XrSessionBeginInfo* beginInfo); + +XRAPI_ATTR XrResult XRAPI_CALL xrEndSession( + XrSession session); + +XRAPI_ATTR XrResult XRAPI_CALL xrRequestExitSession( + XrSession session); + +XRAPI_ATTR XrResult XRAPI_CALL xrWaitFrame( + XrSession session, + const XrFrameWaitInfo* frameWaitInfo, + XrFrameState* frameState); + +XRAPI_ATTR XrResult XRAPI_CALL xrBeginFrame( + XrSession session, + const XrFrameBeginInfo* frameBeginInfo); + +XRAPI_ATTR XrResult XRAPI_CALL xrEndFrame( + XrSession session, + const XrFrameEndInfo* frameEndInfo); + +XRAPI_ATTR XrResult XRAPI_CALL xrLocateViews( + XrSession session, + const XrViewLocateInfo* viewLocateInfo, + XrViewState* viewState, + uint32_t viewCapacityInput, + uint32_t* viewCountOutput, + XrView* views); + +XRAPI_ATTR XrResult XRAPI_CALL xrStringToPath( + XrInstance instance, + const char* pathString, + XrPath* path); + +XRAPI_ATTR XrResult XRAPI_CALL xrPathToString( + XrInstance instance, + XrPath path, + uint32_t bufferCapacityInput, + uint32_t* bufferCountOutput, + char* buffer); + +XRAPI_ATTR XrResult XRAPI_CALL xrCreateActionSet( + XrInstance instance, + const XrActionSetCreateInfo* createInfo, + XrActionSet* actionSet); + +XRAPI_ATTR XrResult XRAPI_CALL xrDestroyActionSet( + XrActionSet actionSet); + +XRAPI_ATTR XrResult XRAPI_CALL xrCreateAction( + XrActionSet actionSet, + const XrActionCreateInfo* createInfo, + XrAction* action); + +XRAPI_ATTR XrResult XRAPI_CALL xrDestroyAction( + XrAction action); + +XRAPI_ATTR XrResult XRAPI_CALL xrSuggestInteractionProfileBindings( + XrInstance instance, + const XrInteractionProfileSuggestedBinding* suggestedBindings); + +XRAPI_ATTR XrResult XRAPI_CALL xrAttachSessionActionSets( + XrSession session, + const XrSessionActionSetsAttachInfo* attachInfo); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetCurrentInteractionProfile( + XrSession session, + XrPath topLevelUserPath, + XrInteractionProfileState* interactionProfile); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetActionStateBoolean( + XrSession session, + const XrActionStateGetInfo* getInfo, + XrActionStateBoolean* state); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetActionStateFloat( + XrSession session, + const XrActionStateGetInfo* getInfo, + XrActionStateFloat* state); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetActionStateVector2f( + XrSession session, + const XrActionStateGetInfo* getInfo, + XrActionStateVector2f* state); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetActionStatePose( + XrSession session, + const XrActionStateGetInfo* getInfo, + XrActionStatePose* state); + +XRAPI_ATTR XrResult XRAPI_CALL xrSyncActions( + XrSession session, + const XrActionsSyncInfo* syncInfo); + +XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateBoundSourcesForAction( + XrSession session, + const XrBoundSourcesForActionEnumerateInfo* enumerateInfo, + uint32_t sourceCapacityInput, + uint32_t* sourceCountOutput, + XrPath* sources); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetInputSourceLocalizedName( + XrSession session, + const XrInputSourceLocalizedNameGetInfo* getInfo, + uint32_t bufferCapacityInput, + uint32_t* bufferCountOutput, + char* buffer); + +XRAPI_ATTR XrResult XRAPI_CALL xrApplyHapticFeedback( + XrSession session, + const XrHapticActionInfo* hapticActionInfo, + const XrHapticBaseHeader* hapticFeedback); + +XRAPI_ATTR XrResult XRAPI_CALL xrStopHapticFeedback( + XrSession session, + const XrHapticActionInfo* hapticActionInfo); +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_KHR_composition_layer_cube 1 +#define XR_KHR_composition_layer_cube_SPEC_VERSION 8 +#define XR_KHR_COMPOSITION_LAYER_CUBE_EXTENSION_NAME "XR_KHR_composition_layer_cube" +typedef struct XrCompositionLayerCubeKHR { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrCompositionLayerFlags layerFlags; + XrSpace space; + XrEyeVisibility eyeVisibility; + XrSwapchain swapchain; + uint32_t imageArrayIndex; + XrQuaternionf orientation; +} XrCompositionLayerCubeKHR; + + + +#define XR_KHR_composition_layer_depth 1 +#define XR_KHR_composition_layer_depth_SPEC_VERSION 6 +#define XR_KHR_COMPOSITION_LAYER_DEPTH_EXTENSION_NAME "XR_KHR_composition_layer_depth" +// XrCompositionLayerDepthInfoKHR extends XrCompositionLayerProjectionView +typedef struct XrCompositionLayerDepthInfoKHR { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSwapchainSubImage subImage; + float minDepth; + float maxDepth; + float nearZ; + float farZ; +} XrCompositionLayerDepthInfoKHR; + + + +#define XR_KHR_composition_layer_cylinder 1 +#define XR_KHR_composition_layer_cylinder_SPEC_VERSION 4 +#define XR_KHR_COMPOSITION_LAYER_CYLINDER_EXTENSION_NAME "XR_KHR_composition_layer_cylinder" +typedef struct XrCompositionLayerCylinderKHR { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrCompositionLayerFlags layerFlags; + XrSpace space; + XrEyeVisibility eyeVisibility; + XrSwapchainSubImage subImage; + XrPosef pose; + float radius; + float centralAngle; + float aspectRatio; +} XrCompositionLayerCylinderKHR; + + + +#define XR_KHR_composition_layer_equirect 1 +#define XR_KHR_composition_layer_equirect_SPEC_VERSION 3 +#define XR_KHR_COMPOSITION_LAYER_EQUIRECT_EXTENSION_NAME "XR_KHR_composition_layer_equirect" +typedef struct XrCompositionLayerEquirectKHR { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrCompositionLayerFlags layerFlags; + XrSpace space; + XrEyeVisibility eyeVisibility; + XrSwapchainSubImage subImage; + XrPosef pose; + float radius; + XrVector2f scale; + XrVector2f bias; +} XrCompositionLayerEquirectKHR; + + + +#define XR_KHR_visibility_mask 1 +#define XR_KHR_visibility_mask_SPEC_VERSION 2 +#define XR_KHR_VISIBILITY_MASK_EXTENSION_NAME "XR_KHR_visibility_mask" + +typedef enum XrVisibilityMaskTypeKHR { + XR_VISIBILITY_MASK_TYPE_HIDDEN_TRIANGLE_MESH_KHR = 1, + XR_VISIBILITY_MASK_TYPE_VISIBLE_TRIANGLE_MESH_KHR = 2, + XR_VISIBILITY_MASK_TYPE_LINE_LOOP_KHR = 3, + XR_VISIBILITY_MASK_TYPE_MAX_ENUM_KHR = 0x7FFFFFFF +} XrVisibilityMaskTypeKHR; +typedef struct XrVisibilityMaskKHR { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint32_t vertexCapacityInput; + uint32_t vertexCountOutput; + XrVector2f* vertices; + uint32_t indexCapacityInput; + uint32_t indexCountOutput; + uint32_t* indices; +} XrVisibilityMaskKHR; + +typedef struct XrEventDataVisibilityMaskChangedKHR { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSession session; + XrViewConfigurationType viewConfigurationType; + uint32_t viewIndex; +} XrEventDataVisibilityMaskChangedKHR; + +typedef XrResult (XRAPI_PTR *PFN_xrGetVisibilityMaskKHR)(XrSession session, XrViewConfigurationType viewConfigurationType, uint32_t viewIndex, XrVisibilityMaskTypeKHR visibilityMaskType, XrVisibilityMaskKHR* visibilityMask); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrGetVisibilityMaskKHR( + XrSession session, + XrViewConfigurationType viewConfigurationType, + uint32_t viewIndex, + XrVisibilityMaskTypeKHR visibilityMaskType, + XrVisibilityMaskKHR* visibilityMask); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_KHR_composition_layer_color_scale_bias 1 +#define XR_KHR_composition_layer_color_scale_bias_SPEC_VERSION 5 +#define XR_KHR_COMPOSITION_LAYER_COLOR_SCALE_BIAS_EXTENSION_NAME "XR_KHR_composition_layer_color_scale_bias" +// XrCompositionLayerColorScaleBiasKHR extends XrCompositionLayerBaseHeader +typedef struct XrCompositionLayerColorScaleBiasKHR { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrColor4f colorScale; + XrColor4f colorBias; +} XrCompositionLayerColorScaleBiasKHR; + + + +#define XR_KHR_loader_init 1 +#define XR_KHR_loader_init_SPEC_VERSION 1 +#define XR_KHR_LOADER_INIT_EXTENSION_NAME "XR_KHR_loader_init" +typedef struct XR_MAY_ALIAS XrLoaderInitInfoBaseHeaderKHR { + XrStructureType type; + const void* XR_MAY_ALIAS next; +} XrLoaderInitInfoBaseHeaderKHR; + +typedef XrResult (XRAPI_PTR *PFN_xrInitializeLoaderKHR)(const XrLoaderInitInfoBaseHeaderKHR* loaderInitInfo); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrInitializeLoaderKHR( + const XrLoaderInitInfoBaseHeaderKHR* loaderInitInfo); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_KHR_composition_layer_equirect2 1 +#define XR_KHR_composition_layer_equirect2_SPEC_VERSION 1 +#define XR_KHR_COMPOSITION_LAYER_EQUIRECT2_EXTENSION_NAME "XR_KHR_composition_layer_equirect2" +typedef struct XrCompositionLayerEquirect2KHR { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrCompositionLayerFlags layerFlags; + XrSpace space; + XrEyeVisibility eyeVisibility; + XrSwapchainSubImage subImage; + XrPosef pose; + float radius; + float centralHorizontalAngle; + float upperVerticalAngle; + float lowerVerticalAngle; +} XrCompositionLayerEquirect2KHR; + + + +#define XR_KHR_binding_modification 1 +#define XR_KHR_binding_modification_SPEC_VERSION 1 +#define XR_KHR_BINDING_MODIFICATION_EXTENSION_NAME "XR_KHR_binding_modification" +typedef struct XR_MAY_ALIAS XrBindingModificationBaseHeaderKHR { + XrStructureType type; + const void* XR_MAY_ALIAS next; +} XrBindingModificationBaseHeaderKHR; + +// XrBindingModificationsKHR extends XrInteractionProfileSuggestedBinding +typedef struct XrBindingModificationsKHR { + XrStructureType type; + const void* XR_MAY_ALIAS next; + uint32_t bindingModificationCount; + const XrBindingModificationBaseHeaderKHR* const* bindingModifications; +} XrBindingModificationsKHR; + + + +#define XR_KHR_swapchain_usage_input_attachment_bit 1 +#define XR_KHR_swapchain_usage_input_attachment_bit_SPEC_VERSION 3 +#define XR_KHR_SWAPCHAIN_USAGE_INPUT_ATTACHMENT_BIT_EXTENSION_NAME "XR_KHR_swapchain_usage_input_attachment_bit" + + +#define XR_EXT_performance_settings 1 +#define XR_EXT_performance_settings_SPEC_VERSION 4 +#define XR_EXT_PERFORMANCE_SETTINGS_EXTENSION_NAME "XR_EXT_performance_settings" + +typedef enum XrPerfSettingsDomainEXT { + XR_PERF_SETTINGS_DOMAIN_CPU_EXT = 1, + XR_PERF_SETTINGS_DOMAIN_GPU_EXT = 2, + XR_PERF_SETTINGS_DOMAIN_MAX_ENUM_EXT = 0x7FFFFFFF +} XrPerfSettingsDomainEXT; + +typedef enum XrPerfSettingsSubDomainEXT { + XR_PERF_SETTINGS_SUB_DOMAIN_COMPOSITING_EXT = 1, + XR_PERF_SETTINGS_SUB_DOMAIN_RENDERING_EXT = 2, + XR_PERF_SETTINGS_SUB_DOMAIN_THERMAL_EXT = 3, + XR_PERF_SETTINGS_SUB_DOMAIN_MAX_ENUM_EXT = 0x7FFFFFFF +} XrPerfSettingsSubDomainEXT; + +typedef enum XrPerfSettingsLevelEXT { + XR_PERF_SETTINGS_LEVEL_POWER_SAVINGS_EXT = 0, + XR_PERF_SETTINGS_LEVEL_SUSTAINED_LOW_EXT = 25, + XR_PERF_SETTINGS_LEVEL_SUSTAINED_HIGH_EXT = 50, + XR_PERF_SETTINGS_LEVEL_BOOST_EXT = 75, + XR_PERF_SETTINGS_LEVEL_MAX_ENUM_EXT = 0x7FFFFFFF +} XrPerfSettingsLevelEXT; + +typedef enum XrPerfSettingsNotificationLevelEXT { + XR_PERF_SETTINGS_NOTIF_LEVEL_NORMAL_EXT = 0, + XR_PERF_SETTINGS_NOTIF_LEVEL_WARNING_EXT = 25, + XR_PERF_SETTINGS_NOTIF_LEVEL_IMPAIRED_EXT = 75, + XR_PERF_SETTINGS_NOTIFICATION_LEVEL_MAX_ENUM_EXT = 0x7FFFFFFF +} XrPerfSettingsNotificationLevelEXT; +typedef struct XrEventDataPerfSettingsEXT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrPerfSettingsDomainEXT domain; + XrPerfSettingsSubDomainEXT subDomain; + XrPerfSettingsNotificationLevelEXT fromLevel; + XrPerfSettingsNotificationLevelEXT toLevel; +} XrEventDataPerfSettingsEXT; + +typedef XrResult (XRAPI_PTR *PFN_xrPerfSettingsSetPerformanceLevelEXT)(XrSession session, XrPerfSettingsDomainEXT domain, XrPerfSettingsLevelEXT level); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrPerfSettingsSetPerformanceLevelEXT( + XrSession session, + XrPerfSettingsDomainEXT domain, + XrPerfSettingsLevelEXT level); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_EXT_thermal_query 1 +#define XR_EXT_thermal_query_SPEC_VERSION 2 +#define XR_EXT_THERMAL_QUERY_EXTENSION_NAME "XR_EXT_thermal_query" +typedef XrResult (XRAPI_PTR *PFN_xrThermalGetTemperatureTrendEXT)(XrSession session, XrPerfSettingsDomainEXT domain, XrPerfSettingsNotificationLevelEXT* notificationLevel, float* tempHeadroom, float* tempSlope); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrThermalGetTemperatureTrendEXT( + XrSession session, + XrPerfSettingsDomainEXT domain, + XrPerfSettingsNotificationLevelEXT* notificationLevel, + float* tempHeadroom, + float* tempSlope); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_EXT_debug_utils 1 +XR_DEFINE_HANDLE(XrDebugUtilsMessengerEXT) +#define XR_EXT_debug_utils_SPEC_VERSION 4 +#define XR_EXT_DEBUG_UTILS_EXTENSION_NAME "XR_EXT_debug_utils" +typedef XrFlags64 XrDebugUtilsMessageSeverityFlagsEXT; + +// Flag bits for XrDebugUtilsMessageSeverityFlagsEXT +static const XrDebugUtilsMessageSeverityFlagsEXT XR_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT = 0x00000001; +static const XrDebugUtilsMessageSeverityFlagsEXT XR_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT = 0x00000010; +static const XrDebugUtilsMessageSeverityFlagsEXT XR_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT = 0x00000100; +static const XrDebugUtilsMessageSeverityFlagsEXT XR_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT = 0x00001000; + +typedef XrFlags64 XrDebugUtilsMessageTypeFlagsEXT; + +// Flag bits for XrDebugUtilsMessageTypeFlagsEXT +static const XrDebugUtilsMessageTypeFlagsEXT XR_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT = 0x00000001; +static const XrDebugUtilsMessageTypeFlagsEXT XR_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT = 0x00000002; +static const XrDebugUtilsMessageTypeFlagsEXT XR_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT = 0x00000004; +static const XrDebugUtilsMessageTypeFlagsEXT XR_DEBUG_UTILS_MESSAGE_TYPE_CONFORMANCE_BIT_EXT = 0x00000008; + +typedef struct XrDebugUtilsObjectNameInfoEXT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrObjectType objectType; + uint64_t objectHandle; + const char* objectName; +} XrDebugUtilsObjectNameInfoEXT; + +typedef struct XrDebugUtilsLabelEXT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + const char* labelName; +} XrDebugUtilsLabelEXT; + +typedef struct XrDebugUtilsMessengerCallbackDataEXT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + const char* messageId; + const char* functionName; + const char* message; + uint32_t objectCount; + XrDebugUtilsObjectNameInfoEXT* objects; + uint32_t sessionLabelCount; + XrDebugUtilsLabelEXT* sessionLabels; +} XrDebugUtilsMessengerCallbackDataEXT; + +typedef XrBool32 (XRAPI_PTR *PFN_xrDebugUtilsMessengerCallbackEXT)( + XrDebugUtilsMessageSeverityFlagsEXT messageSeverity, + XrDebugUtilsMessageTypeFlagsEXT messageTypes, + const XrDebugUtilsMessengerCallbackDataEXT* callbackData, + void* userData); + + +// XrDebugUtilsMessengerCreateInfoEXT extends XrInstanceCreateInfo +typedef struct XrDebugUtilsMessengerCreateInfoEXT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrDebugUtilsMessageSeverityFlagsEXT messageSeverities; + XrDebugUtilsMessageTypeFlagsEXT messageTypes; + PFN_xrDebugUtilsMessengerCallbackEXT userCallback; + void* XR_MAY_ALIAS userData; +} XrDebugUtilsMessengerCreateInfoEXT; + +typedef XrResult (XRAPI_PTR *PFN_xrSetDebugUtilsObjectNameEXT)(XrInstance instance, const XrDebugUtilsObjectNameInfoEXT* nameInfo); +typedef XrResult (XRAPI_PTR *PFN_xrCreateDebugUtilsMessengerEXT)(XrInstance instance, const XrDebugUtilsMessengerCreateInfoEXT* createInfo, XrDebugUtilsMessengerEXT* messenger); +typedef XrResult (XRAPI_PTR *PFN_xrDestroyDebugUtilsMessengerEXT)(XrDebugUtilsMessengerEXT messenger); +typedef XrResult (XRAPI_PTR *PFN_xrSubmitDebugUtilsMessageEXT)(XrInstance instance, XrDebugUtilsMessageSeverityFlagsEXT messageSeverity, XrDebugUtilsMessageTypeFlagsEXT messageTypes, const XrDebugUtilsMessengerCallbackDataEXT* callbackData); +typedef XrResult (XRAPI_PTR *PFN_xrSessionBeginDebugUtilsLabelRegionEXT)(XrSession session, const XrDebugUtilsLabelEXT* labelInfo); +typedef XrResult (XRAPI_PTR *PFN_xrSessionEndDebugUtilsLabelRegionEXT)(XrSession session); +typedef XrResult (XRAPI_PTR *PFN_xrSessionInsertDebugUtilsLabelEXT)(XrSession session, const XrDebugUtilsLabelEXT* labelInfo); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrSetDebugUtilsObjectNameEXT( + XrInstance instance, + const XrDebugUtilsObjectNameInfoEXT* nameInfo); + +XRAPI_ATTR XrResult XRAPI_CALL xrCreateDebugUtilsMessengerEXT( + XrInstance instance, + const XrDebugUtilsMessengerCreateInfoEXT* createInfo, + XrDebugUtilsMessengerEXT* messenger); + +XRAPI_ATTR XrResult XRAPI_CALL xrDestroyDebugUtilsMessengerEXT( + XrDebugUtilsMessengerEXT messenger); + +XRAPI_ATTR XrResult XRAPI_CALL xrSubmitDebugUtilsMessageEXT( + XrInstance instance, + XrDebugUtilsMessageSeverityFlagsEXT messageSeverity, + XrDebugUtilsMessageTypeFlagsEXT messageTypes, + const XrDebugUtilsMessengerCallbackDataEXT* callbackData); + +XRAPI_ATTR XrResult XRAPI_CALL xrSessionBeginDebugUtilsLabelRegionEXT( + XrSession session, + const XrDebugUtilsLabelEXT* labelInfo); + +XRAPI_ATTR XrResult XRAPI_CALL xrSessionEndDebugUtilsLabelRegionEXT( + XrSession session); + +XRAPI_ATTR XrResult XRAPI_CALL xrSessionInsertDebugUtilsLabelEXT( + XrSession session, + const XrDebugUtilsLabelEXT* labelInfo); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_EXT_eye_gaze_interaction 1 +#define XR_EXT_eye_gaze_interaction_SPEC_VERSION 2 +#define XR_EXT_EYE_GAZE_INTERACTION_EXTENSION_NAME "XR_EXT_eye_gaze_interaction" +// XrSystemEyeGazeInteractionPropertiesEXT extends XrSystemProperties +typedef struct XrSystemEyeGazeInteractionPropertiesEXT { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrBool32 supportsEyeGazeInteraction; +} XrSystemEyeGazeInteractionPropertiesEXT; + +// XrEyeGazeSampleTimeEXT extends XrSpaceLocation +typedef struct XrEyeGazeSampleTimeEXT { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrTime time; +} XrEyeGazeSampleTimeEXT; + + + +#define XR_EXTX_overlay 1 +#define XR_EXTX_overlay_SPEC_VERSION 5 +#define XR_EXTX_OVERLAY_EXTENSION_NAME "XR_EXTX_overlay" +typedef XrFlags64 XrOverlaySessionCreateFlagsEXTX; + +// Flag bits for XrOverlaySessionCreateFlagsEXTX + +typedef XrFlags64 XrOverlayMainSessionFlagsEXTX; + +// Flag bits for XrOverlayMainSessionFlagsEXTX +static const XrOverlayMainSessionFlagsEXTX XR_OVERLAY_MAIN_SESSION_ENABLED_COMPOSITION_LAYER_INFO_DEPTH_BIT_EXTX = 0x00000001; + +// XrSessionCreateInfoOverlayEXTX extends XrSessionCreateInfo +typedef struct XrSessionCreateInfoOverlayEXTX { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrOverlaySessionCreateFlagsEXTX createFlags; + uint32_t sessionLayersPlacement; +} XrSessionCreateInfoOverlayEXTX; + +typedef struct XrEventDataMainSessionVisibilityChangedEXTX { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrBool32 visible; + XrOverlayMainSessionFlagsEXTX flags; +} XrEventDataMainSessionVisibilityChangedEXTX; + + + +#define XR_VARJO_quad_views 1 +#define XR_VARJO_quad_views_SPEC_VERSION 1 +#define XR_VARJO_QUAD_VIEWS_EXTENSION_NAME "XR_VARJO_quad_views" + + +#define XR_MSFT_unbounded_reference_space 1 +#define XR_MSFT_unbounded_reference_space_SPEC_VERSION 1 +#define XR_MSFT_UNBOUNDED_REFERENCE_SPACE_EXTENSION_NAME "XR_MSFT_unbounded_reference_space" + + +#define XR_MSFT_spatial_anchor 1 +XR_DEFINE_HANDLE(XrSpatialAnchorMSFT) +#define XR_MSFT_spatial_anchor_SPEC_VERSION 2 +#define XR_MSFT_SPATIAL_ANCHOR_EXTENSION_NAME "XR_MSFT_spatial_anchor" +typedef struct XrSpatialAnchorCreateInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSpace space; + XrPosef pose; + XrTime time; +} XrSpatialAnchorCreateInfoMSFT; + +typedef struct XrSpatialAnchorSpaceCreateInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSpatialAnchorMSFT anchor; + XrPosef poseInAnchorSpace; +} XrSpatialAnchorSpaceCreateInfoMSFT; + +typedef XrResult (XRAPI_PTR *PFN_xrCreateSpatialAnchorMSFT)(XrSession session, const XrSpatialAnchorCreateInfoMSFT* createInfo, XrSpatialAnchorMSFT* anchor); +typedef XrResult (XRAPI_PTR *PFN_xrCreateSpatialAnchorSpaceMSFT)(XrSession session, const XrSpatialAnchorSpaceCreateInfoMSFT* createInfo, XrSpace* space); +typedef XrResult (XRAPI_PTR *PFN_xrDestroySpatialAnchorMSFT)(XrSpatialAnchorMSFT anchor); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrCreateSpatialAnchorMSFT( + XrSession session, + const XrSpatialAnchorCreateInfoMSFT* createInfo, + XrSpatialAnchorMSFT* anchor); + +XRAPI_ATTR XrResult XRAPI_CALL xrCreateSpatialAnchorSpaceMSFT( + XrSession session, + const XrSpatialAnchorSpaceCreateInfoMSFT* createInfo, + XrSpace* space); + +XRAPI_ATTR XrResult XRAPI_CALL xrDestroySpatialAnchorMSFT( + XrSpatialAnchorMSFT anchor); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_FB_composition_layer_image_layout 1 +#define XR_FB_composition_layer_image_layout_SPEC_VERSION 1 +#define XR_FB_COMPOSITION_LAYER_IMAGE_LAYOUT_EXTENSION_NAME "XR_FB_composition_layer_image_layout" +typedef XrFlags64 XrCompositionLayerImageLayoutFlagsFB; + +// Flag bits for XrCompositionLayerImageLayoutFlagsFB +static const XrCompositionLayerImageLayoutFlagsFB XR_COMPOSITION_LAYER_IMAGE_LAYOUT_VERTICAL_FLIP_BIT_FB = 0x00000001; + +// XrCompositionLayerImageLayoutFB extends XrCompositionLayerBaseHeader +typedef struct XrCompositionLayerImageLayoutFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrCompositionLayerImageLayoutFlagsFB flags; +} XrCompositionLayerImageLayoutFB; + + + +#define XR_FB_composition_layer_alpha_blend 1 +#define XR_FB_composition_layer_alpha_blend_SPEC_VERSION 2 +#define XR_FB_COMPOSITION_LAYER_ALPHA_BLEND_EXTENSION_NAME "XR_FB_composition_layer_alpha_blend" + +typedef enum XrBlendFactorFB { + XR_BLEND_FACTOR_ZERO_FB = 0, + XR_BLEND_FACTOR_ONE_FB = 1, + XR_BLEND_FACTOR_SRC_ALPHA_FB = 2, + XR_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA_FB = 3, + XR_BLEND_FACTOR_DST_ALPHA_FB = 4, + XR_BLEND_FACTOR_ONE_MINUS_DST_ALPHA_FB = 5, + XR_BLEND_FACTOR_MAX_ENUM_FB = 0x7FFFFFFF +} XrBlendFactorFB; +// XrCompositionLayerAlphaBlendFB extends XrCompositionLayerBaseHeader +typedef struct XrCompositionLayerAlphaBlendFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrBlendFactorFB srcFactorColor; + XrBlendFactorFB dstFactorColor; + XrBlendFactorFB srcFactorAlpha; + XrBlendFactorFB dstFactorAlpha; +} XrCompositionLayerAlphaBlendFB; + + + +#define XR_MND_headless 1 +#define XR_MND_headless_SPEC_VERSION 2 +#define XR_MND_HEADLESS_EXTENSION_NAME "XR_MND_headless" + + +#define XR_OCULUS_android_session_state_enable 1 +#define XR_OCULUS_android_session_state_enable_SPEC_VERSION 1 +#define XR_OCULUS_ANDROID_SESSION_STATE_ENABLE_EXTENSION_NAME "XR_OCULUS_android_session_state_enable" + + +#define XR_EXT_view_configuration_depth_range 1 +#define XR_EXT_view_configuration_depth_range_SPEC_VERSION 1 +#define XR_EXT_VIEW_CONFIGURATION_DEPTH_RANGE_EXTENSION_NAME "XR_EXT_view_configuration_depth_range" +// XrViewConfigurationDepthRangeEXT extends XrViewConfigurationView +typedef struct XrViewConfigurationDepthRangeEXT { + XrStructureType type; + void* XR_MAY_ALIAS next; + float recommendedNearZ; + float minNearZ; + float recommendedFarZ; + float maxFarZ; +} XrViewConfigurationDepthRangeEXT; + + + +#define XR_EXT_conformance_automation 1 +#define XR_EXT_conformance_automation_SPEC_VERSION 3 +#define XR_EXT_CONFORMANCE_AUTOMATION_EXTENSION_NAME "XR_EXT_conformance_automation" +typedef XrResult (XRAPI_PTR *PFN_xrSetInputDeviceActiveEXT)(XrSession session, XrPath interactionProfile, XrPath topLevelPath, XrBool32 isActive); +typedef XrResult (XRAPI_PTR *PFN_xrSetInputDeviceStateBoolEXT)(XrSession session, XrPath topLevelPath, XrPath inputSourcePath, XrBool32 state); +typedef XrResult (XRAPI_PTR *PFN_xrSetInputDeviceStateFloatEXT)(XrSession session, XrPath topLevelPath, XrPath inputSourcePath, float state); +typedef XrResult (XRAPI_PTR *PFN_xrSetInputDeviceStateVector2fEXT)(XrSession session, XrPath topLevelPath, XrPath inputSourcePath, XrVector2f state); +typedef XrResult (XRAPI_PTR *PFN_xrSetInputDeviceLocationEXT)(XrSession session, XrPath topLevelPath, XrPath inputSourcePath, XrSpace space, XrPosef pose); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrSetInputDeviceActiveEXT( + XrSession session, + XrPath interactionProfile, + XrPath topLevelPath, + XrBool32 isActive); + +XRAPI_ATTR XrResult XRAPI_CALL xrSetInputDeviceStateBoolEXT( + XrSession session, + XrPath topLevelPath, + XrPath inputSourcePath, + XrBool32 state); + +XRAPI_ATTR XrResult XRAPI_CALL xrSetInputDeviceStateFloatEXT( + XrSession session, + XrPath topLevelPath, + XrPath inputSourcePath, + float state); + +XRAPI_ATTR XrResult XRAPI_CALL xrSetInputDeviceStateVector2fEXT( + XrSession session, + XrPath topLevelPath, + XrPath inputSourcePath, + XrVector2f state); + +XRAPI_ATTR XrResult XRAPI_CALL xrSetInputDeviceLocationEXT( + XrSession session, + XrPath topLevelPath, + XrPath inputSourcePath, + XrSpace space, + XrPosef pose); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_MSFT_spatial_graph_bridge 1 +XR_DEFINE_HANDLE(XrSpatialGraphNodeBindingMSFT) +#define XR_MSFT_spatial_graph_bridge_SPEC_VERSION 2 +#define XR_MSFT_SPATIAL_GRAPH_BRIDGE_EXTENSION_NAME "XR_MSFT_spatial_graph_bridge" +#define XR_GUID_SIZE_MSFT 16 + +typedef enum XrSpatialGraphNodeTypeMSFT { + XR_SPATIAL_GRAPH_NODE_TYPE_STATIC_MSFT = 1, + XR_SPATIAL_GRAPH_NODE_TYPE_DYNAMIC_MSFT = 2, + XR_SPATIAL_GRAPH_NODE_TYPE_MAX_ENUM_MSFT = 0x7FFFFFFF +} XrSpatialGraphNodeTypeMSFT; +typedef struct XrSpatialGraphNodeSpaceCreateInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSpatialGraphNodeTypeMSFT nodeType; + uint8_t nodeId[XR_GUID_SIZE_MSFT]; + XrPosef pose; +} XrSpatialGraphNodeSpaceCreateInfoMSFT; + +typedef struct XrSpatialGraphStaticNodeBindingCreateInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSpace space; + XrPosef poseInSpace; + XrTime time; +} XrSpatialGraphStaticNodeBindingCreateInfoMSFT; + +typedef struct XrSpatialGraphNodeBindingPropertiesGetInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; +} XrSpatialGraphNodeBindingPropertiesGetInfoMSFT; + +typedef struct XrSpatialGraphNodeBindingPropertiesMSFT { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint8_t nodeId[XR_GUID_SIZE_MSFT]; + XrPosef poseInNodeSpace; +} XrSpatialGraphNodeBindingPropertiesMSFT; + +typedef XrResult (XRAPI_PTR *PFN_xrCreateSpatialGraphNodeSpaceMSFT)(XrSession session, const XrSpatialGraphNodeSpaceCreateInfoMSFT* createInfo, XrSpace* space); +typedef XrResult (XRAPI_PTR *PFN_xrTryCreateSpatialGraphStaticNodeBindingMSFT)(XrSession session, const XrSpatialGraphStaticNodeBindingCreateInfoMSFT* createInfo, XrSpatialGraphNodeBindingMSFT* nodeBinding); +typedef XrResult (XRAPI_PTR *PFN_xrDestroySpatialGraphNodeBindingMSFT)(XrSpatialGraphNodeBindingMSFT nodeBinding); +typedef XrResult (XRAPI_PTR *PFN_xrGetSpatialGraphNodeBindingPropertiesMSFT)(XrSpatialGraphNodeBindingMSFT nodeBinding, const XrSpatialGraphNodeBindingPropertiesGetInfoMSFT* getInfo, XrSpatialGraphNodeBindingPropertiesMSFT* properties); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrCreateSpatialGraphNodeSpaceMSFT( + XrSession session, + const XrSpatialGraphNodeSpaceCreateInfoMSFT* createInfo, + XrSpace* space); + +XRAPI_ATTR XrResult XRAPI_CALL xrTryCreateSpatialGraphStaticNodeBindingMSFT( + XrSession session, + const XrSpatialGraphStaticNodeBindingCreateInfoMSFT* createInfo, + XrSpatialGraphNodeBindingMSFT* nodeBinding); + +XRAPI_ATTR XrResult XRAPI_CALL xrDestroySpatialGraphNodeBindingMSFT( + XrSpatialGraphNodeBindingMSFT nodeBinding); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetSpatialGraphNodeBindingPropertiesMSFT( + XrSpatialGraphNodeBindingMSFT nodeBinding, + const XrSpatialGraphNodeBindingPropertiesGetInfoMSFT* getInfo, + XrSpatialGraphNodeBindingPropertiesMSFT* properties); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_MSFT_hand_interaction 1 +#define XR_MSFT_hand_interaction_SPEC_VERSION 1 +#define XR_MSFT_HAND_INTERACTION_EXTENSION_NAME "XR_MSFT_hand_interaction" + + +#define XR_EXT_hand_tracking 1 + +#define XR_HAND_JOINT_COUNT_EXT 26 + +XR_DEFINE_HANDLE(XrHandTrackerEXT) +#define XR_EXT_hand_tracking_SPEC_VERSION 4 +#define XR_EXT_HAND_TRACKING_EXTENSION_NAME "XR_EXT_hand_tracking" + +typedef enum XrHandEXT { + XR_HAND_LEFT_EXT = 1, + XR_HAND_RIGHT_EXT = 2, + XR_HAND_MAX_ENUM_EXT = 0x7FFFFFFF +} XrHandEXT; + +typedef enum XrHandJointEXT { + XR_HAND_JOINT_PALM_EXT = 0, + XR_HAND_JOINT_WRIST_EXT = 1, + XR_HAND_JOINT_THUMB_METACARPAL_EXT = 2, + XR_HAND_JOINT_THUMB_PROXIMAL_EXT = 3, + XR_HAND_JOINT_THUMB_DISTAL_EXT = 4, + XR_HAND_JOINT_THUMB_TIP_EXT = 5, + XR_HAND_JOINT_INDEX_METACARPAL_EXT = 6, + XR_HAND_JOINT_INDEX_PROXIMAL_EXT = 7, + XR_HAND_JOINT_INDEX_INTERMEDIATE_EXT = 8, + XR_HAND_JOINT_INDEX_DISTAL_EXT = 9, + XR_HAND_JOINT_INDEX_TIP_EXT = 10, + XR_HAND_JOINT_MIDDLE_METACARPAL_EXT = 11, + XR_HAND_JOINT_MIDDLE_PROXIMAL_EXT = 12, + XR_HAND_JOINT_MIDDLE_INTERMEDIATE_EXT = 13, + XR_HAND_JOINT_MIDDLE_DISTAL_EXT = 14, + XR_HAND_JOINT_MIDDLE_TIP_EXT = 15, + XR_HAND_JOINT_RING_METACARPAL_EXT = 16, + XR_HAND_JOINT_RING_PROXIMAL_EXT = 17, + XR_HAND_JOINT_RING_INTERMEDIATE_EXT = 18, + XR_HAND_JOINT_RING_DISTAL_EXT = 19, + XR_HAND_JOINT_RING_TIP_EXT = 20, + XR_HAND_JOINT_LITTLE_METACARPAL_EXT = 21, + XR_HAND_JOINT_LITTLE_PROXIMAL_EXT = 22, + XR_HAND_JOINT_LITTLE_INTERMEDIATE_EXT = 23, + XR_HAND_JOINT_LITTLE_DISTAL_EXT = 24, + XR_HAND_JOINT_LITTLE_TIP_EXT = 25, + XR_HAND_JOINT_MAX_ENUM_EXT = 0x7FFFFFFF +} XrHandJointEXT; + +typedef enum XrHandJointSetEXT { + XR_HAND_JOINT_SET_DEFAULT_EXT = 0, + XR_HAND_JOINT_SET_HAND_WITH_FOREARM_ULTRALEAP = 1000149000, + XR_HAND_JOINT_SET_MAX_ENUM_EXT = 0x7FFFFFFF +} XrHandJointSetEXT; +// XrSystemHandTrackingPropertiesEXT extends XrSystemProperties +typedef struct XrSystemHandTrackingPropertiesEXT { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrBool32 supportsHandTracking; +} XrSystemHandTrackingPropertiesEXT; + +typedef struct XrHandTrackerCreateInfoEXT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrHandEXT hand; + XrHandJointSetEXT handJointSet; +} XrHandTrackerCreateInfoEXT; + +typedef struct XrHandJointsLocateInfoEXT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSpace baseSpace; + XrTime time; +} XrHandJointsLocateInfoEXT; + +typedef struct XrHandJointLocationEXT { + XrSpaceLocationFlags locationFlags; + XrPosef pose; + float radius; +} XrHandJointLocationEXT; + +typedef struct XrHandJointVelocityEXT { + XrSpaceVelocityFlags velocityFlags; + XrVector3f linearVelocity; + XrVector3f angularVelocity; +} XrHandJointVelocityEXT; + +typedef struct XrHandJointLocationsEXT { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrBool32 isActive; + uint32_t jointCount; + XrHandJointLocationEXT* jointLocations; +} XrHandJointLocationsEXT; + +// XrHandJointVelocitiesEXT extends XrHandJointLocationsEXT +typedef struct XrHandJointVelocitiesEXT { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint32_t jointCount; + XrHandJointVelocityEXT* jointVelocities; +} XrHandJointVelocitiesEXT; + +typedef XrResult (XRAPI_PTR *PFN_xrCreateHandTrackerEXT)(XrSession session, const XrHandTrackerCreateInfoEXT* createInfo, XrHandTrackerEXT* handTracker); +typedef XrResult (XRAPI_PTR *PFN_xrDestroyHandTrackerEXT)(XrHandTrackerEXT handTracker); +typedef XrResult (XRAPI_PTR *PFN_xrLocateHandJointsEXT)(XrHandTrackerEXT handTracker, const XrHandJointsLocateInfoEXT* locateInfo, XrHandJointLocationsEXT* locations); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrCreateHandTrackerEXT( + XrSession session, + const XrHandTrackerCreateInfoEXT* createInfo, + XrHandTrackerEXT* handTracker); + +XRAPI_ATTR XrResult XRAPI_CALL xrDestroyHandTrackerEXT( + XrHandTrackerEXT handTracker); + +XRAPI_ATTR XrResult XRAPI_CALL xrLocateHandJointsEXT( + XrHandTrackerEXT handTracker, + const XrHandJointsLocateInfoEXT* locateInfo, + XrHandJointLocationsEXT* locations); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_MSFT_hand_tracking_mesh 1 +#define XR_MSFT_hand_tracking_mesh_SPEC_VERSION 4 +#define XR_MSFT_HAND_TRACKING_MESH_EXTENSION_NAME "XR_MSFT_hand_tracking_mesh" + +typedef enum XrHandPoseTypeMSFT { + XR_HAND_POSE_TYPE_TRACKED_MSFT = 0, + XR_HAND_POSE_TYPE_REFERENCE_OPEN_PALM_MSFT = 1, + XR_HAND_POSE_TYPE_MAX_ENUM_MSFT = 0x7FFFFFFF +} XrHandPoseTypeMSFT; +// XrSystemHandTrackingMeshPropertiesMSFT extends XrSystemProperties +typedef struct XrSystemHandTrackingMeshPropertiesMSFT { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrBool32 supportsHandTrackingMesh; + uint32_t maxHandMeshIndexCount; + uint32_t maxHandMeshVertexCount; +} XrSystemHandTrackingMeshPropertiesMSFT; + +typedef struct XrHandMeshSpaceCreateInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrHandPoseTypeMSFT handPoseType; + XrPosef poseInHandMeshSpace; +} XrHandMeshSpaceCreateInfoMSFT; + +typedef struct XrHandMeshUpdateInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrTime time; + XrHandPoseTypeMSFT handPoseType; +} XrHandMeshUpdateInfoMSFT; + +typedef struct XrHandMeshIndexBufferMSFT { + uint32_t indexBufferKey; + uint32_t indexCapacityInput; + uint32_t indexCountOutput; + uint32_t* indices; +} XrHandMeshIndexBufferMSFT; + +typedef struct XrHandMeshVertexMSFT { + XrVector3f position; + XrVector3f normal; +} XrHandMeshVertexMSFT; + +typedef struct XrHandMeshVertexBufferMSFT { + XrTime vertexUpdateTime; + uint32_t vertexCapacityInput; + uint32_t vertexCountOutput; + XrHandMeshVertexMSFT* vertices; +} XrHandMeshVertexBufferMSFT; + +typedef struct XrHandMeshMSFT { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrBool32 isActive; + XrBool32 indexBufferChanged; + XrBool32 vertexBufferChanged; + XrHandMeshIndexBufferMSFT indexBuffer; + XrHandMeshVertexBufferMSFT vertexBuffer; +} XrHandMeshMSFT; + +// XrHandPoseTypeInfoMSFT extends XrHandTrackerCreateInfoEXT +typedef struct XrHandPoseTypeInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrHandPoseTypeMSFT handPoseType; +} XrHandPoseTypeInfoMSFT; + +typedef XrResult (XRAPI_PTR *PFN_xrCreateHandMeshSpaceMSFT)(XrHandTrackerEXT handTracker, const XrHandMeshSpaceCreateInfoMSFT* createInfo, XrSpace* space); +typedef XrResult (XRAPI_PTR *PFN_xrUpdateHandMeshMSFT)(XrHandTrackerEXT handTracker, const XrHandMeshUpdateInfoMSFT* updateInfo, XrHandMeshMSFT* handMesh); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrCreateHandMeshSpaceMSFT( + XrHandTrackerEXT handTracker, + const XrHandMeshSpaceCreateInfoMSFT* createInfo, + XrSpace* space); + +XRAPI_ATTR XrResult XRAPI_CALL xrUpdateHandMeshMSFT( + XrHandTrackerEXT handTracker, + const XrHandMeshUpdateInfoMSFT* updateInfo, + XrHandMeshMSFT* handMesh); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_MSFT_secondary_view_configuration 1 +#define XR_MSFT_secondary_view_configuration_SPEC_VERSION 1 +#define XR_MSFT_SECONDARY_VIEW_CONFIGURATION_EXTENSION_NAME "XR_MSFT_secondary_view_configuration" +// XrSecondaryViewConfigurationSessionBeginInfoMSFT extends XrSessionBeginInfo +typedef struct XrSecondaryViewConfigurationSessionBeginInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + uint32_t viewConfigurationCount; + const XrViewConfigurationType* enabledViewConfigurationTypes; +} XrSecondaryViewConfigurationSessionBeginInfoMSFT; + +typedef struct XrSecondaryViewConfigurationStateMSFT { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrViewConfigurationType viewConfigurationType; + XrBool32 active; +} XrSecondaryViewConfigurationStateMSFT; + +// XrSecondaryViewConfigurationFrameStateMSFT extends XrFrameState +typedef struct XrSecondaryViewConfigurationFrameStateMSFT { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint32_t viewConfigurationCount; + XrSecondaryViewConfigurationStateMSFT* viewConfigurationStates; +} XrSecondaryViewConfigurationFrameStateMSFT; + +typedef struct XrSecondaryViewConfigurationLayerInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrViewConfigurationType viewConfigurationType; + XrEnvironmentBlendMode environmentBlendMode; + uint32_t layerCount; + const XrCompositionLayerBaseHeader* const* layers; +} XrSecondaryViewConfigurationLayerInfoMSFT; + +// XrSecondaryViewConfigurationFrameEndInfoMSFT extends XrFrameEndInfo +typedef struct XrSecondaryViewConfigurationFrameEndInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + uint32_t viewConfigurationCount; + const XrSecondaryViewConfigurationLayerInfoMSFT* viewConfigurationLayersInfo; +} XrSecondaryViewConfigurationFrameEndInfoMSFT; + +// XrSecondaryViewConfigurationSwapchainCreateInfoMSFT extends XrSwapchainCreateInfo +typedef struct XrSecondaryViewConfigurationSwapchainCreateInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrViewConfigurationType viewConfigurationType; +} XrSecondaryViewConfigurationSwapchainCreateInfoMSFT; + + + +#define XR_MSFT_first_person_observer 1 +#define XR_MSFT_first_person_observer_SPEC_VERSION 1 +#define XR_MSFT_FIRST_PERSON_OBSERVER_EXTENSION_NAME "XR_MSFT_first_person_observer" + + +#define XR_MSFT_controller_model 1 + +#define XR_NULL_CONTROLLER_MODEL_KEY_MSFT 0 + +XR_DEFINE_ATOM(XrControllerModelKeyMSFT) +#define XR_MSFT_controller_model_SPEC_VERSION 2 +#define XR_MSFT_CONTROLLER_MODEL_EXTENSION_NAME "XR_MSFT_controller_model" +#define XR_MAX_CONTROLLER_MODEL_NODE_NAME_SIZE_MSFT 64 +typedef struct XrControllerModelKeyStateMSFT { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrControllerModelKeyMSFT modelKey; +} XrControllerModelKeyStateMSFT; + +typedef struct XrControllerModelNodePropertiesMSFT { + XrStructureType type; + void* XR_MAY_ALIAS next; + char parentNodeName[XR_MAX_CONTROLLER_MODEL_NODE_NAME_SIZE_MSFT]; + char nodeName[XR_MAX_CONTROLLER_MODEL_NODE_NAME_SIZE_MSFT]; +} XrControllerModelNodePropertiesMSFT; + +typedef struct XrControllerModelPropertiesMSFT { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint32_t nodeCapacityInput; + uint32_t nodeCountOutput; + XrControllerModelNodePropertiesMSFT* nodeProperties; +} XrControllerModelPropertiesMSFT; + +typedef struct XrControllerModelNodeStateMSFT { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrPosef nodePose; +} XrControllerModelNodeStateMSFT; + +typedef struct XrControllerModelStateMSFT { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint32_t nodeCapacityInput; + uint32_t nodeCountOutput; + XrControllerModelNodeStateMSFT* nodeStates; +} XrControllerModelStateMSFT; + +typedef XrResult (XRAPI_PTR *PFN_xrGetControllerModelKeyMSFT)(XrSession session, XrPath topLevelUserPath, XrControllerModelKeyStateMSFT* controllerModelKeyState); +typedef XrResult (XRAPI_PTR *PFN_xrLoadControllerModelMSFT)(XrSession session, XrControllerModelKeyMSFT modelKey, uint32_t bufferCapacityInput, uint32_t* bufferCountOutput, uint8_t* buffer); +typedef XrResult (XRAPI_PTR *PFN_xrGetControllerModelPropertiesMSFT)(XrSession session, XrControllerModelKeyMSFT modelKey, XrControllerModelPropertiesMSFT* properties); +typedef XrResult (XRAPI_PTR *PFN_xrGetControllerModelStateMSFT)(XrSession session, XrControllerModelKeyMSFT modelKey, XrControllerModelStateMSFT* state); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrGetControllerModelKeyMSFT( + XrSession session, + XrPath topLevelUserPath, + XrControllerModelKeyStateMSFT* controllerModelKeyState); + +XRAPI_ATTR XrResult XRAPI_CALL xrLoadControllerModelMSFT( + XrSession session, + XrControllerModelKeyMSFT modelKey, + uint32_t bufferCapacityInput, + uint32_t* bufferCountOutput, + uint8_t* buffer); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetControllerModelPropertiesMSFT( + XrSession session, + XrControllerModelKeyMSFT modelKey, + XrControllerModelPropertiesMSFT* properties); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetControllerModelStateMSFT( + XrSession session, + XrControllerModelKeyMSFT modelKey, + XrControllerModelStateMSFT* state); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_EXT_win32_appcontainer_compatible 1 +#define XR_EXT_win32_appcontainer_compatible_SPEC_VERSION 1 +#define XR_EXT_WIN32_APPCONTAINER_COMPATIBLE_EXTENSION_NAME "XR_EXT_win32_appcontainer_compatible" + + +#define XR_EPIC_view_configuration_fov 1 +#define XR_EPIC_view_configuration_fov_SPEC_VERSION 2 +#define XR_EPIC_VIEW_CONFIGURATION_FOV_EXTENSION_NAME "XR_EPIC_view_configuration_fov" +// XrViewConfigurationViewFovEPIC extends XrViewConfigurationView +typedef struct XrViewConfigurationViewFovEPIC { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrFovf recommendedFov; + XrFovf maxMutableFov; +} XrViewConfigurationViewFovEPIC; + + + +#define XR_MSFT_composition_layer_reprojection 1 +#define XR_MSFT_composition_layer_reprojection_SPEC_VERSION 1 +#define XR_MSFT_COMPOSITION_LAYER_REPROJECTION_EXTENSION_NAME "XR_MSFT_composition_layer_reprojection" + +typedef enum XrReprojectionModeMSFT { + XR_REPROJECTION_MODE_DEPTH_MSFT = 1, + XR_REPROJECTION_MODE_PLANAR_FROM_DEPTH_MSFT = 2, + XR_REPROJECTION_MODE_PLANAR_MANUAL_MSFT = 3, + XR_REPROJECTION_MODE_ORIENTATION_ONLY_MSFT = 4, + XR_REPROJECTION_MODE_MAX_ENUM_MSFT = 0x7FFFFFFF +} XrReprojectionModeMSFT; +// XrCompositionLayerReprojectionInfoMSFT extends XrCompositionLayerProjection +typedef struct XrCompositionLayerReprojectionInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrReprojectionModeMSFT reprojectionMode; +} XrCompositionLayerReprojectionInfoMSFT; + +// XrCompositionLayerReprojectionPlaneOverrideMSFT extends XrCompositionLayerProjection +typedef struct XrCompositionLayerReprojectionPlaneOverrideMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrVector3f position; + XrVector3f normal; + XrVector3f velocity; +} XrCompositionLayerReprojectionPlaneOverrideMSFT; + +typedef XrResult (XRAPI_PTR *PFN_xrEnumerateReprojectionModesMSFT)(XrInstance instance, XrSystemId systemId, XrViewConfigurationType viewConfigurationType, uint32_t modeCapacityInput, uint32_t* modeCountOutput, XrReprojectionModeMSFT* modes); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateReprojectionModesMSFT( + XrInstance instance, + XrSystemId systemId, + XrViewConfigurationType viewConfigurationType, + uint32_t modeCapacityInput, + uint32_t* modeCountOutput, + XrReprojectionModeMSFT* modes); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_HUAWEI_controller_interaction 1 +#define XR_HUAWEI_controller_interaction_SPEC_VERSION 1 +#define XR_HUAWEI_CONTROLLER_INTERACTION_EXTENSION_NAME "XR_HUAWEI_controller_interaction" + + +#define XR_FB_swapchain_update_state 1 +#define XR_FB_swapchain_update_state_SPEC_VERSION 3 +#define XR_FB_SWAPCHAIN_UPDATE_STATE_EXTENSION_NAME "XR_FB_swapchain_update_state" +typedef struct XR_MAY_ALIAS XrSwapchainStateBaseHeaderFB { + XrStructureType type; + void* XR_MAY_ALIAS next; +} XrSwapchainStateBaseHeaderFB; + +typedef XrResult (XRAPI_PTR *PFN_xrUpdateSwapchainFB)(XrSwapchain swapchain, const XrSwapchainStateBaseHeaderFB* state); +typedef XrResult (XRAPI_PTR *PFN_xrGetSwapchainStateFB)(XrSwapchain swapchain, XrSwapchainStateBaseHeaderFB* state); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrUpdateSwapchainFB( + XrSwapchain swapchain, + const XrSwapchainStateBaseHeaderFB* state); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetSwapchainStateFB( + XrSwapchain swapchain, + XrSwapchainStateBaseHeaderFB* state); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_FB_composition_layer_secure_content 1 +#define XR_FB_composition_layer_secure_content_SPEC_VERSION 1 +#define XR_FB_COMPOSITION_LAYER_SECURE_CONTENT_EXTENSION_NAME "XR_FB_composition_layer_secure_content" +typedef XrFlags64 XrCompositionLayerSecureContentFlagsFB; + +// Flag bits for XrCompositionLayerSecureContentFlagsFB +static const XrCompositionLayerSecureContentFlagsFB XR_COMPOSITION_LAYER_SECURE_CONTENT_EXCLUDE_LAYER_BIT_FB = 0x00000001; +static const XrCompositionLayerSecureContentFlagsFB XR_COMPOSITION_LAYER_SECURE_CONTENT_REPLACE_LAYER_BIT_FB = 0x00000002; + +// XrCompositionLayerSecureContentFB extends XrCompositionLayerBaseHeader +typedef struct XrCompositionLayerSecureContentFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrCompositionLayerSecureContentFlagsFB flags; +} XrCompositionLayerSecureContentFB; + + + +#define XR_FB_body_tracking 1 +XR_DEFINE_HANDLE(XrBodyTrackerFB) +#define XR_FB_body_tracking_SPEC_VERSION 1 +#define XR_FB_BODY_TRACKING_EXTENSION_NAME "XR_FB_body_tracking" + +typedef enum XrBodyJointFB { + XR_BODY_JOINT_ROOT_FB = 0, + XR_BODY_JOINT_HIPS_FB = 1, + XR_BODY_JOINT_SPINE_LOWER_FB = 2, + XR_BODY_JOINT_SPINE_MIDDLE_FB = 3, + XR_BODY_JOINT_SPINE_UPPER_FB = 4, + XR_BODY_JOINT_CHEST_FB = 5, + XR_BODY_JOINT_NECK_FB = 6, + XR_BODY_JOINT_HEAD_FB = 7, + XR_BODY_JOINT_LEFT_SHOULDER_FB = 8, + XR_BODY_JOINT_LEFT_SCAPULA_FB = 9, + XR_BODY_JOINT_LEFT_ARM_UPPER_FB = 10, + XR_BODY_JOINT_LEFT_ARM_LOWER_FB = 11, + XR_BODY_JOINT_LEFT_HAND_WRIST_TWIST_FB = 12, + XR_BODY_JOINT_RIGHT_SHOULDER_FB = 13, + XR_BODY_JOINT_RIGHT_SCAPULA_FB = 14, + XR_BODY_JOINT_RIGHT_ARM_UPPER_FB = 15, + XR_BODY_JOINT_RIGHT_ARM_LOWER_FB = 16, + XR_BODY_JOINT_RIGHT_HAND_WRIST_TWIST_FB = 17, + XR_BODY_JOINT_LEFT_HAND_PALM_FB = 18, + XR_BODY_JOINT_LEFT_HAND_WRIST_FB = 19, + XR_BODY_JOINT_LEFT_HAND_THUMB_METACARPAL_FB = 20, + XR_BODY_JOINT_LEFT_HAND_THUMB_PROXIMAL_FB = 21, + XR_BODY_JOINT_LEFT_HAND_THUMB_DISTAL_FB = 22, + XR_BODY_JOINT_LEFT_HAND_THUMB_TIP_FB = 23, + XR_BODY_JOINT_LEFT_HAND_INDEX_METACARPAL_FB = 24, + XR_BODY_JOINT_LEFT_HAND_INDEX_PROXIMAL_FB = 25, + XR_BODY_JOINT_LEFT_HAND_INDEX_INTERMEDIATE_FB = 26, + XR_BODY_JOINT_LEFT_HAND_INDEX_DISTAL_FB = 27, + XR_BODY_JOINT_LEFT_HAND_INDEX_TIP_FB = 28, + XR_BODY_JOINT_LEFT_HAND_MIDDLE_METACARPAL_FB = 29, + XR_BODY_JOINT_LEFT_HAND_MIDDLE_PROXIMAL_FB = 30, + XR_BODY_JOINT_LEFT_HAND_MIDDLE_INTERMEDIATE_FB = 31, + XR_BODY_JOINT_LEFT_HAND_MIDDLE_DISTAL_FB = 32, + XR_BODY_JOINT_LEFT_HAND_MIDDLE_TIP_FB = 33, + XR_BODY_JOINT_LEFT_HAND_RING_METACARPAL_FB = 34, + XR_BODY_JOINT_LEFT_HAND_RING_PROXIMAL_FB = 35, + XR_BODY_JOINT_LEFT_HAND_RING_INTERMEDIATE_FB = 36, + XR_BODY_JOINT_LEFT_HAND_RING_DISTAL_FB = 37, + XR_BODY_JOINT_LEFT_HAND_RING_TIP_FB = 38, + XR_BODY_JOINT_LEFT_HAND_LITTLE_METACARPAL_FB = 39, + XR_BODY_JOINT_LEFT_HAND_LITTLE_PROXIMAL_FB = 40, + XR_BODY_JOINT_LEFT_HAND_LITTLE_INTERMEDIATE_FB = 41, + XR_BODY_JOINT_LEFT_HAND_LITTLE_DISTAL_FB = 42, + XR_BODY_JOINT_LEFT_HAND_LITTLE_TIP_FB = 43, + XR_BODY_JOINT_RIGHT_HAND_PALM_FB = 44, + XR_BODY_JOINT_RIGHT_HAND_WRIST_FB = 45, + XR_BODY_JOINT_RIGHT_HAND_THUMB_METACARPAL_FB = 46, + XR_BODY_JOINT_RIGHT_HAND_THUMB_PROXIMAL_FB = 47, + XR_BODY_JOINT_RIGHT_HAND_THUMB_DISTAL_FB = 48, + XR_BODY_JOINT_RIGHT_HAND_THUMB_TIP_FB = 49, + XR_BODY_JOINT_RIGHT_HAND_INDEX_METACARPAL_FB = 50, + XR_BODY_JOINT_RIGHT_HAND_INDEX_PROXIMAL_FB = 51, + XR_BODY_JOINT_RIGHT_HAND_INDEX_INTERMEDIATE_FB = 52, + XR_BODY_JOINT_RIGHT_HAND_INDEX_DISTAL_FB = 53, + XR_BODY_JOINT_RIGHT_HAND_INDEX_TIP_FB = 54, + XR_BODY_JOINT_RIGHT_HAND_MIDDLE_METACARPAL_FB = 55, + XR_BODY_JOINT_RIGHT_HAND_MIDDLE_PROXIMAL_FB = 56, + XR_BODY_JOINT_RIGHT_HAND_MIDDLE_INTERMEDIATE_FB = 57, + XR_BODY_JOINT_RIGHT_HAND_MIDDLE_DISTAL_FB = 58, + XR_BODY_JOINT_RIGHT_HAND_MIDDLE_TIP_FB = 59, + XR_BODY_JOINT_RIGHT_HAND_RING_METACARPAL_FB = 60, + XR_BODY_JOINT_RIGHT_HAND_RING_PROXIMAL_FB = 61, + XR_BODY_JOINT_RIGHT_HAND_RING_INTERMEDIATE_FB = 62, + XR_BODY_JOINT_RIGHT_HAND_RING_DISTAL_FB = 63, + XR_BODY_JOINT_RIGHT_HAND_RING_TIP_FB = 64, + XR_BODY_JOINT_RIGHT_HAND_LITTLE_METACARPAL_FB = 65, + XR_BODY_JOINT_RIGHT_HAND_LITTLE_PROXIMAL_FB = 66, + XR_BODY_JOINT_RIGHT_HAND_LITTLE_INTERMEDIATE_FB = 67, + XR_BODY_JOINT_RIGHT_HAND_LITTLE_DISTAL_FB = 68, + XR_BODY_JOINT_RIGHT_HAND_LITTLE_TIP_FB = 69, + XR_BODY_JOINT_COUNT_FB = 70, + XR_BODY_JOINT_NONE_FB = -1, + XR_BODY_JOINT_MAX_ENUM_FB = 0x7FFFFFFF +} XrBodyJointFB; + +typedef enum XrBodyJointSetFB { + XR_BODY_JOINT_SET_DEFAULT_FB = 0, + XR_BODY_JOINT_SET_MAX_ENUM_FB = 0x7FFFFFFF +} XrBodyJointSetFB; +typedef struct XrBodyJointLocationFB { + XrSpaceLocationFlags locationFlags; + XrPosef pose; +} XrBodyJointLocationFB; + +// XrSystemBodyTrackingPropertiesFB extends XrSystemProperties +typedef struct XrSystemBodyTrackingPropertiesFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrBool32 supportsBodyTracking; +} XrSystemBodyTrackingPropertiesFB; + +typedef struct XrBodyTrackerCreateInfoFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrBodyJointSetFB bodyJointSet; +} XrBodyTrackerCreateInfoFB; + +typedef struct XrBodySkeletonJointFB { + int32_t joint; + int32_t parentJoint; + XrPosef pose; +} XrBodySkeletonJointFB; + +typedef struct XrBodySkeletonFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint32_t jointCount; + XrBodySkeletonJointFB* joints; +} XrBodySkeletonFB; + +typedef struct XrBodyJointsLocateInfoFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSpace baseSpace; + XrTime time; +} XrBodyJointsLocateInfoFB; + +typedef struct XrBodyJointLocationsFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrBool32 isActive; + float confidence; + uint32_t jointCount; + XrBodyJointLocationFB* jointLocations; + uint32_t skeletonChangedCount; + XrTime time; +} XrBodyJointLocationsFB; + +typedef XrResult (XRAPI_PTR *PFN_xrCreateBodyTrackerFB)(XrSession session, const XrBodyTrackerCreateInfoFB* createInfo, XrBodyTrackerFB* bodyTracker); +typedef XrResult (XRAPI_PTR *PFN_xrDestroyBodyTrackerFB)(XrBodyTrackerFB bodyTracker); +typedef XrResult (XRAPI_PTR *PFN_xrLocateBodyJointsFB)(XrBodyTrackerFB bodyTracker, const XrBodyJointsLocateInfoFB* locateInfo, XrBodyJointLocationsFB* locations); +typedef XrResult (XRAPI_PTR *PFN_xrGetBodySkeletonFB)(XrBodyTrackerFB bodyTracker, XrBodySkeletonFB* skeleton); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrCreateBodyTrackerFB( + XrSession session, + const XrBodyTrackerCreateInfoFB* createInfo, + XrBodyTrackerFB* bodyTracker); + +XRAPI_ATTR XrResult XRAPI_CALL xrDestroyBodyTrackerFB( + XrBodyTrackerFB bodyTracker); + +XRAPI_ATTR XrResult XRAPI_CALL xrLocateBodyJointsFB( + XrBodyTrackerFB bodyTracker, + const XrBodyJointsLocateInfoFB* locateInfo, + XrBodyJointLocationsFB* locations); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetBodySkeletonFB( + XrBodyTrackerFB bodyTracker, + XrBodySkeletonFB* skeleton); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_EXT_dpad_binding 1 +#define XR_EXT_dpad_binding_SPEC_VERSION 1 +#define XR_EXT_DPAD_BINDING_EXTENSION_NAME "XR_EXT_dpad_binding" +typedef struct XrInteractionProfileDpadBindingEXT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrPath binding; + XrActionSet actionSet; + float forceThreshold; + float forceThresholdReleased; + float centerRegion; + float wedgeAngle; + XrBool32 isSticky; + const XrHapticBaseHeader* onHaptic; + const XrHapticBaseHeader* offHaptic; +} XrInteractionProfileDpadBindingEXT; + + + +#define XR_VALVE_analog_threshold 1 +#define XR_VALVE_analog_threshold_SPEC_VERSION 2 +#define XR_VALVE_ANALOG_THRESHOLD_EXTENSION_NAME "XR_VALVE_analog_threshold" +typedef struct XrInteractionProfileAnalogThresholdVALVE { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrAction action; + XrPath binding; + float onThreshold; + float offThreshold; + const XrHapticBaseHeader* onHaptic; + const XrHapticBaseHeader* offHaptic; +} XrInteractionProfileAnalogThresholdVALVE; + + + +#define XR_EXT_hand_joints_motion_range 1 +#define XR_EXT_hand_joints_motion_range_SPEC_VERSION 1 +#define XR_EXT_HAND_JOINTS_MOTION_RANGE_EXTENSION_NAME "XR_EXT_hand_joints_motion_range" + +typedef enum XrHandJointsMotionRangeEXT { + XR_HAND_JOINTS_MOTION_RANGE_UNOBSTRUCTED_EXT = 1, + XR_HAND_JOINTS_MOTION_RANGE_CONFORMING_TO_CONTROLLER_EXT = 2, + XR_HAND_JOINTS_MOTION_RANGE_MAX_ENUM_EXT = 0x7FFFFFFF +} XrHandJointsMotionRangeEXT; +// XrHandJointsMotionRangeInfoEXT extends XrHandJointsLocateInfoEXT +typedef struct XrHandJointsMotionRangeInfoEXT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrHandJointsMotionRangeEXT handJointsMotionRange; +} XrHandJointsMotionRangeInfoEXT; + + + +#define XR_EXT_samsung_odyssey_controller 1 +#define XR_EXT_samsung_odyssey_controller_SPEC_VERSION 1 +#define XR_EXT_SAMSUNG_ODYSSEY_CONTROLLER_EXTENSION_NAME "XR_EXT_samsung_odyssey_controller" + + +#define XR_EXT_hp_mixed_reality_controller 1 +#define XR_EXT_hp_mixed_reality_controller_SPEC_VERSION 1 +#define XR_EXT_HP_MIXED_REALITY_CONTROLLER_EXTENSION_NAME "XR_EXT_hp_mixed_reality_controller" + + +#define XR_MND_swapchain_usage_input_attachment_bit 1 +#define XR_MND_swapchain_usage_input_attachment_bit_SPEC_VERSION 2 +#define XR_MND_SWAPCHAIN_USAGE_INPUT_ATTACHMENT_BIT_EXTENSION_NAME "XR_MND_swapchain_usage_input_attachment_bit" + + +#define XR_MSFT_scene_understanding 1 + + XR_DEFINE_HANDLE(XrSceneObserverMSFT) + + + XR_DEFINE_HANDLE(XrSceneMSFT) + +#define XR_MSFT_scene_understanding_SPEC_VERSION 2 +#define XR_MSFT_SCENE_UNDERSTANDING_EXTENSION_NAME "XR_MSFT_scene_understanding" + +typedef enum XrSceneComputeFeatureMSFT { + XR_SCENE_COMPUTE_FEATURE_PLANE_MSFT = 1, + XR_SCENE_COMPUTE_FEATURE_PLANE_MESH_MSFT = 2, + XR_SCENE_COMPUTE_FEATURE_VISUAL_MESH_MSFT = 3, + XR_SCENE_COMPUTE_FEATURE_COLLIDER_MESH_MSFT = 4, + XR_SCENE_COMPUTE_FEATURE_SERIALIZE_SCENE_MSFT = 1000098000, + XR_SCENE_COMPUTE_FEATURE_MAX_ENUM_MSFT = 0x7FFFFFFF +} XrSceneComputeFeatureMSFT; + +typedef enum XrSceneComputeConsistencyMSFT { + XR_SCENE_COMPUTE_CONSISTENCY_SNAPSHOT_COMPLETE_MSFT = 1, + XR_SCENE_COMPUTE_CONSISTENCY_SNAPSHOT_INCOMPLETE_FAST_MSFT = 2, + XR_SCENE_COMPUTE_CONSISTENCY_OCCLUSION_OPTIMIZED_MSFT = 3, + XR_SCENE_COMPUTE_CONSISTENCY_MAX_ENUM_MSFT = 0x7FFFFFFF +} XrSceneComputeConsistencyMSFT; + +typedef enum XrMeshComputeLodMSFT { + XR_MESH_COMPUTE_LOD_COARSE_MSFT = 1, + XR_MESH_COMPUTE_LOD_MEDIUM_MSFT = 2, + XR_MESH_COMPUTE_LOD_FINE_MSFT = 3, + XR_MESH_COMPUTE_LOD_UNLIMITED_MSFT = 4, + XR_MESH_COMPUTE_LOD_MAX_ENUM_MSFT = 0x7FFFFFFF +} XrMeshComputeLodMSFT; + +typedef enum XrSceneComponentTypeMSFT { + XR_SCENE_COMPONENT_TYPE_INVALID_MSFT = -1, + XR_SCENE_COMPONENT_TYPE_OBJECT_MSFT = 1, + XR_SCENE_COMPONENT_TYPE_PLANE_MSFT = 2, + XR_SCENE_COMPONENT_TYPE_VISUAL_MESH_MSFT = 3, + XR_SCENE_COMPONENT_TYPE_COLLIDER_MESH_MSFT = 4, + XR_SCENE_COMPONENT_TYPE_SERIALIZED_SCENE_FRAGMENT_MSFT = 1000098000, + XR_SCENE_COMPONENT_TYPE_MAX_ENUM_MSFT = 0x7FFFFFFF +} XrSceneComponentTypeMSFT; + +typedef enum XrSceneObjectTypeMSFT { + XR_SCENE_OBJECT_TYPE_UNCATEGORIZED_MSFT = -1, + XR_SCENE_OBJECT_TYPE_BACKGROUND_MSFT = 1, + XR_SCENE_OBJECT_TYPE_WALL_MSFT = 2, + XR_SCENE_OBJECT_TYPE_FLOOR_MSFT = 3, + XR_SCENE_OBJECT_TYPE_CEILING_MSFT = 4, + XR_SCENE_OBJECT_TYPE_PLATFORM_MSFT = 5, + XR_SCENE_OBJECT_TYPE_INFERRED_MSFT = 6, + XR_SCENE_OBJECT_TYPE_MAX_ENUM_MSFT = 0x7FFFFFFF +} XrSceneObjectTypeMSFT; + +typedef enum XrScenePlaneAlignmentTypeMSFT { + XR_SCENE_PLANE_ALIGNMENT_TYPE_NON_ORTHOGONAL_MSFT = 0, + XR_SCENE_PLANE_ALIGNMENT_TYPE_HORIZONTAL_MSFT = 1, + XR_SCENE_PLANE_ALIGNMENT_TYPE_VERTICAL_MSFT = 2, + XR_SCENE_PLANE_ALIGNMENT_TYPE_MAX_ENUM_MSFT = 0x7FFFFFFF +} XrScenePlaneAlignmentTypeMSFT; + +typedef enum XrSceneComputeStateMSFT { + XR_SCENE_COMPUTE_STATE_NONE_MSFT = 0, + XR_SCENE_COMPUTE_STATE_UPDATING_MSFT = 1, + XR_SCENE_COMPUTE_STATE_COMPLETED_MSFT = 2, + XR_SCENE_COMPUTE_STATE_COMPLETED_WITH_ERROR_MSFT = 3, + XR_SCENE_COMPUTE_STATE_MAX_ENUM_MSFT = 0x7FFFFFFF +} XrSceneComputeStateMSFT; +typedef struct XrUuidMSFT { + uint8_t bytes[16]; +} XrUuidMSFT; + +typedef struct XrSceneObserverCreateInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; +} XrSceneObserverCreateInfoMSFT; + +typedef struct XrSceneCreateInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; +} XrSceneCreateInfoMSFT; + +typedef struct XrSceneSphereBoundMSFT { + XrVector3f center; + float radius; +} XrSceneSphereBoundMSFT; + +typedef struct XrSceneOrientedBoxBoundMSFT { + XrPosef pose; + XrVector3f extents; +} XrSceneOrientedBoxBoundMSFT; + +typedef struct XrSceneFrustumBoundMSFT { + XrPosef pose; + XrFovf fov; + float farDistance; +} XrSceneFrustumBoundMSFT; + +typedef struct XrSceneBoundsMSFT { + XrSpace space; + XrTime time; + uint32_t sphereCount; + const XrSceneSphereBoundMSFT* spheres; + uint32_t boxCount; + const XrSceneOrientedBoxBoundMSFT* boxes; + uint32_t frustumCount; + const XrSceneFrustumBoundMSFT* frustums; +} XrSceneBoundsMSFT; + +typedef struct XrNewSceneComputeInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + uint32_t requestedFeatureCount; + const XrSceneComputeFeatureMSFT* requestedFeatures; + XrSceneComputeConsistencyMSFT consistency; + XrSceneBoundsMSFT bounds; +} XrNewSceneComputeInfoMSFT; + +// XrVisualMeshComputeLodInfoMSFT extends XrNewSceneComputeInfoMSFT +typedef struct XrVisualMeshComputeLodInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrMeshComputeLodMSFT lod; +} XrVisualMeshComputeLodInfoMSFT; + +typedef struct XrSceneComponentMSFT { + XrSceneComponentTypeMSFT componentType; + XrUuidMSFT id; + XrUuidMSFT parentId; + XrTime updateTime; +} XrSceneComponentMSFT; + +typedef struct XrSceneComponentsMSFT { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint32_t componentCapacityInput; + uint32_t componentCountOutput; + XrSceneComponentMSFT* components; +} XrSceneComponentsMSFT; + +typedef struct XrSceneComponentsGetInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSceneComponentTypeMSFT componentType; +} XrSceneComponentsGetInfoMSFT; + +typedef struct XrSceneComponentLocationMSFT { + XrSpaceLocationFlags flags; + XrPosef pose; +} XrSceneComponentLocationMSFT; + +typedef struct XrSceneComponentLocationsMSFT { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint32_t locationCount; + XrSceneComponentLocationMSFT* locations; +} XrSceneComponentLocationsMSFT; + +typedef struct XrSceneComponentsLocateInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSpace baseSpace; + XrTime time; + uint32_t componentIdCount; + const XrUuidMSFT* componentIds; +} XrSceneComponentsLocateInfoMSFT; + +typedef struct XrSceneObjectMSFT { + XrSceneObjectTypeMSFT objectType; +} XrSceneObjectMSFT; + +// XrSceneObjectsMSFT extends XrSceneComponentsMSFT +typedef struct XrSceneObjectsMSFT { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint32_t sceneObjectCount; + XrSceneObjectMSFT* sceneObjects; +} XrSceneObjectsMSFT; + +// XrSceneComponentParentFilterInfoMSFT extends XrSceneComponentsGetInfoMSFT +typedef struct XrSceneComponentParentFilterInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrUuidMSFT parentId; +} XrSceneComponentParentFilterInfoMSFT; + +// XrSceneObjectTypesFilterInfoMSFT extends XrSceneComponentsGetInfoMSFT +typedef struct XrSceneObjectTypesFilterInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + uint32_t objectTypeCount; + const XrSceneObjectTypeMSFT* objectTypes; +} XrSceneObjectTypesFilterInfoMSFT; + +typedef struct XrScenePlaneMSFT { + XrScenePlaneAlignmentTypeMSFT alignment; + XrExtent2Df size; + uint64_t meshBufferId; + XrBool32 supportsIndicesUint16; +} XrScenePlaneMSFT; + +// XrScenePlanesMSFT extends XrSceneComponentsMSFT +typedef struct XrScenePlanesMSFT { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint32_t scenePlaneCount; + XrScenePlaneMSFT* scenePlanes; +} XrScenePlanesMSFT; + +// XrScenePlaneAlignmentFilterInfoMSFT extends XrSceneComponentsGetInfoMSFT +typedef struct XrScenePlaneAlignmentFilterInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + uint32_t alignmentCount; + const XrScenePlaneAlignmentTypeMSFT* alignments; +} XrScenePlaneAlignmentFilterInfoMSFT; + +typedef struct XrSceneMeshMSFT { + uint64_t meshBufferId; + XrBool32 supportsIndicesUint16; +} XrSceneMeshMSFT; + +// XrSceneMeshesMSFT extends XrSceneComponentsMSFT +typedef struct XrSceneMeshesMSFT { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint32_t sceneMeshCount; + XrSceneMeshMSFT* sceneMeshes; +} XrSceneMeshesMSFT; + +typedef struct XrSceneMeshBuffersGetInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + uint64_t meshBufferId; +} XrSceneMeshBuffersGetInfoMSFT; + +typedef struct XrSceneMeshBuffersMSFT { + XrStructureType type; + void* XR_MAY_ALIAS next; +} XrSceneMeshBuffersMSFT; + +typedef struct XrSceneMeshVertexBufferMSFT { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint32_t vertexCapacityInput; + uint32_t vertexCountOutput; + XrVector3f* vertices; +} XrSceneMeshVertexBufferMSFT; + +typedef struct XrSceneMeshIndicesUint32MSFT { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint32_t indexCapacityInput; + uint32_t indexCountOutput; + uint32_t* indices; +} XrSceneMeshIndicesUint32MSFT; + +typedef struct XrSceneMeshIndicesUint16MSFT { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint32_t indexCapacityInput; + uint32_t indexCountOutput; + uint16_t* indices; +} XrSceneMeshIndicesUint16MSFT; + +typedef XrResult (XRAPI_PTR *PFN_xrEnumerateSceneComputeFeaturesMSFT)(XrInstance instance, XrSystemId systemId, uint32_t featureCapacityInput, uint32_t* featureCountOutput, XrSceneComputeFeatureMSFT* features); +typedef XrResult (XRAPI_PTR *PFN_xrCreateSceneObserverMSFT)(XrSession session, const XrSceneObserverCreateInfoMSFT* createInfo, XrSceneObserverMSFT* sceneObserver); +typedef XrResult (XRAPI_PTR *PFN_xrDestroySceneObserverMSFT)(XrSceneObserverMSFT sceneObserver); +typedef XrResult (XRAPI_PTR *PFN_xrCreateSceneMSFT)(XrSceneObserverMSFT sceneObserver, const XrSceneCreateInfoMSFT* createInfo, XrSceneMSFT* scene); +typedef XrResult (XRAPI_PTR *PFN_xrDestroySceneMSFT)(XrSceneMSFT scene); +typedef XrResult (XRAPI_PTR *PFN_xrComputeNewSceneMSFT)(XrSceneObserverMSFT sceneObserver, const XrNewSceneComputeInfoMSFT* computeInfo); +typedef XrResult (XRAPI_PTR *PFN_xrGetSceneComputeStateMSFT)(XrSceneObserverMSFT sceneObserver, XrSceneComputeStateMSFT* state); +typedef XrResult (XRAPI_PTR *PFN_xrGetSceneComponentsMSFT)(XrSceneMSFT scene, const XrSceneComponentsGetInfoMSFT* getInfo, XrSceneComponentsMSFT* components); +typedef XrResult (XRAPI_PTR *PFN_xrLocateSceneComponentsMSFT)(XrSceneMSFT scene, const XrSceneComponentsLocateInfoMSFT* locateInfo, XrSceneComponentLocationsMSFT* locations); +typedef XrResult (XRAPI_PTR *PFN_xrGetSceneMeshBuffersMSFT)(XrSceneMSFT scene, const XrSceneMeshBuffersGetInfoMSFT* getInfo, XrSceneMeshBuffersMSFT* buffers); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateSceneComputeFeaturesMSFT( + XrInstance instance, + XrSystemId systemId, + uint32_t featureCapacityInput, + uint32_t* featureCountOutput, + XrSceneComputeFeatureMSFT* features); + +XRAPI_ATTR XrResult XRAPI_CALL xrCreateSceneObserverMSFT( + XrSession session, + const XrSceneObserverCreateInfoMSFT* createInfo, + XrSceneObserverMSFT* sceneObserver); + +XRAPI_ATTR XrResult XRAPI_CALL xrDestroySceneObserverMSFT( + XrSceneObserverMSFT sceneObserver); + +XRAPI_ATTR XrResult XRAPI_CALL xrCreateSceneMSFT( + XrSceneObserverMSFT sceneObserver, + const XrSceneCreateInfoMSFT* createInfo, + XrSceneMSFT* scene); + +XRAPI_ATTR XrResult XRAPI_CALL xrDestroySceneMSFT( + XrSceneMSFT scene); + +XRAPI_ATTR XrResult XRAPI_CALL xrComputeNewSceneMSFT( + XrSceneObserverMSFT sceneObserver, + const XrNewSceneComputeInfoMSFT* computeInfo); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetSceneComputeStateMSFT( + XrSceneObserverMSFT sceneObserver, + XrSceneComputeStateMSFT* state); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetSceneComponentsMSFT( + XrSceneMSFT scene, + const XrSceneComponentsGetInfoMSFT* getInfo, + XrSceneComponentsMSFT* components); + +XRAPI_ATTR XrResult XRAPI_CALL xrLocateSceneComponentsMSFT( + XrSceneMSFT scene, + const XrSceneComponentsLocateInfoMSFT* locateInfo, + XrSceneComponentLocationsMSFT* locations); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetSceneMeshBuffersMSFT( + XrSceneMSFT scene, + const XrSceneMeshBuffersGetInfoMSFT* getInfo, + XrSceneMeshBuffersMSFT* buffers); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_MSFT_scene_understanding_serialization 1 +#define XR_MSFT_scene_understanding_serialization_SPEC_VERSION 2 +#define XR_MSFT_SCENE_UNDERSTANDING_SERIALIZATION_EXTENSION_NAME "XR_MSFT_scene_understanding_serialization" +typedef struct XrSerializedSceneFragmentDataGetInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrUuidMSFT sceneFragmentId; +} XrSerializedSceneFragmentDataGetInfoMSFT; + +typedef struct XrDeserializeSceneFragmentMSFT { + uint32_t bufferSize; + const uint8_t* buffer; +} XrDeserializeSceneFragmentMSFT; + +typedef struct XrSceneDeserializeInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + uint32_t fragmentCount; + const XrDeserializeSceneFragmentMSFT* fragments; +} XrSceneDeserializeInfoMSFT; + +typedef XrResult (XRAPI_PTR *PFN_xrDeserializeSceneMSFT)(XrSceneObserverMSFT sceneObserver, const XrSceneDeserializeInfoMSFT* deserializeInfo); +typedef XrResult (XRAPI_PTR *PFN_xrGetSerializedSceneFragmentDataMSFT)(XrSceneMSFT scene, const XrSerializedSceneFragmentDataGetInfoMSFT* getInfo, uint32_t countInput, uint32_t* readOutput, uint8_t* buffer); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrDeserializeSceneMSFT( + XrSceneObserverMSFT sceneObserver, + const XrSceneDeserializeInfoMSFT* deserializeInfo); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetSerializedSceneFragmentDataMSFT( + XrSceneMSFT scene, + const XrSerializedSceneFragmentDataGetInfoMSFT* getInfo, + uint32_t countInput, + uint32_t* readOutput, + uint8_t* buffer); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_FB_display_refresh_rate 1 +#define XR_FB_display_refresh_rate_SPEC_VERSION 1 +#define XR_FB_DISPLAY_REFRESH_RATE_EXTENSION_NAME "XR_FB_display_refresh_rate" +typedef struct XrEventDataDisplayRefreshRateChangedFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + float fromDisplayRefreshRate; + float toDisplayRefreshRate; +} XrEventDataDisplayRefreshRateChangedFB; + +typedef XrResult (XRAPI_PTR *PFN_xrEnumerateDisplayRefreshRatesFB)(XrSession session, uint32_t displayRefreshRateCapacityInput, uint32_t* displayRefreshRateCountOutput, float* displayRefreshRates); +typedef XrResult (XRAPI_PTR *PFN_xrGetDisplayRefreshRateFB)(XrSession session, float* displayRefreshRate); +typedef XrResult (XRAPI_PTR *PFN_xrRequestDisplayRefreshRateFB)(XrSession session, float displayRefreshRate); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateDisplayRefreshRatesFB( + XrSession session, + uint32_t displayRefreshRateCapacityInput, + uint32_t* displayRefreshRateCountOutput, + float* displayRefreshRates); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetDisplayRefreshRateFB( + XrSession session, + float* displayRefreshRate); + +XRAPI_ATTR XrResult XRAPI_CALL xrRequestDisplayRefreshRateFB( + XrSession session, + float displayRefreshRate); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_HTC_vive_cosmos_controller_interaction 1 +#define XR_HTC_vive_cosmos_controller_interaction_SPEC_VERSION 1 +#define XR_HTC_VIVE_COSMOS_CONTROLLER_INTERACTION_EXTENSION_NAME "XR_HTC_vive_cosmos_controller_interaction" + + +#define XR_HTCX_vive_tracker_interaction 1 +#define XR_HTCX_vive_tracker_interaction_SPEC_VERSION 3 +#define XR_HTCX_VIVE_TRACKER_INTERACTION_EXTENSION_NAME "XR_HTCX_vive_tracker_interaction" +typedef struct XrViveTrackerPathsHTCX { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrPath persistentPath; + XrPath rolePath; +} XrViveTrackerPathsHTCX; + +typedef struct XrEventDataViveTrackerConnectedHTCX { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrViveTrackerPathsHTCX* paths; +} XrEventDataViveTrackerConnectedHTCX; + +typedef XrResult (XRAPI_PTR *PFN_xrEnumerateViveTrackerPathsHTCX)(XrInstance instance, uint32_t pathCapacityInput, uint32_t* pathCountOutput, XrViveTrackerPathsHTCX* paths); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateViveTrackerPathsHTCX( + XrInstance instance, + uint32_t pathCapacityInput, + uint32_t* pathCountOutput, + XrViveTrackerPathsHTCX* paths); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_HTC_facial_tracking 1 + +#define XR_FACIAL_EXPRESSION_EYE_COUNT_HTC 14 + + +#define XR_FACIAL_EXPRESSION_LIP_COUNT_HTC 37 + +XR_DEFINE_HANDLE(XrFacialTrackerHTC) +#define XR_HTC_facial_tracking_SPEC_VERSION 2 +#define XR_HTC_FACIAL_TRACKING_EXTENSION_NAME "XR_HTC_facial_tracking" + +typedef enum XrEyeExpressionHTC { + XR_EYE_EXPRESSION_LEFT_BLINK_HTC = 0, + XR_EYE_EXPRESSION_LEFT_WIDE_HTC = 1, + XR_EYE_EXPRESSION_RIGHT_BLINK_HTC = 2, + XR_EYE_EXPRESSION_RIGHT_WIDE_HTC = 3, + XR_EYE_EXPRESSION_LEFT_SQUEEZE_HTC = 4, + XR_EYE_EXPRESSION_RIGHT_SQUEEZE_HTC = 5, + XR_EYE_EXPRESSION_LEFT_DOWN_HTC = 6, + XR_EYE_EXPRESSION_RIGHT_DOWN_HTC = 7, + XR_EYE_EXPRESSION_LEFT_OUT_HTC = 8, + XR_EYE_EXPRESSION_RIGHT_IN_HTC = 9, + XR_EYE_EXPRESSION_LEFT_IN_HTC = 10, + XR_EYE_EXPRESSION_RIGHT_OUT_HTC = 11, + XR_EYE_EXPRESSION_LEFT_UP_HTC = 12, + XR_EYE_EXPRESSION_RIGHT_UP_HTC = 13, + XR_EYE_EXPRESSION_MAX_ENUM_HTC = 0x7FFFFFFF +} XrEyeExpressionHTC; + +typedef enum XrLipExpressionHTC { + XR_LIP_EXPRESSION_JAW_RIGHT_HTC = 0, + XR_LIP_EXPRESSION_JAW_LEFT_HTC = 1, + XR_LIP_EXPRESSION_JAW_FORWARD_HTC = 2, + XR_LIP_EXPRESSION_JAW_OPEN_HTC = 3, + XR_LIP_EXPRESSION_MOUTH_APE_SHAPE_HTC = 4, + XR_LIP_EXPRESSION_MOUTH_UPPER_RIGHT_HTC = 5, + XR_LIP_EXPRESSION_MOUTH_UPPER_LEFT_HTC = 6, + XR_LIP_EXPRESSION_MOUTH_LOWER_RIGHT_HTC = 7, + XR_LIP_EXPRESSION_MOUTH_LOWER_LEFT_HTC = 8, + XR_LIP_EXPRESSION_MOUTH_UPPER_OVERTURN_HTC = 9, + XR_LIP_EXPRESSION_MOUTH_LOWER_OVERTURN_HTC = 10, + XR_LIP_EXPRESSION_MOUTH_POUT_HTC = 11, + XR_LIP_EXPRESSION_MOUTH_SMILE_RIGHT_HTC = 12, + XR_LIP_EXPRESSION_MOUTH_SMILE_LEFT_HTC = 13, + XR_LIP_EXPRESSION_MOUTH_SAD_RIGHT_HTC = 14, + XR_LIP_EXPRESSION_MOUTH_SAD_LEFT_HTC = 15, + XR_LIP_EXPRESSION_CHEEK_PUFF_RIGHT_HTC = 16, + XR_LIP_EXPRESSION_CHEEK_PUFF_LEFT_HTC = 17, + XR_LIP_EXPRESSION_CHEEK_SUCK_HTC = 18, + XR_LIP_EXPRESSION_MOUTH_UPPER_UPRIGHT_HTC = 19, + XR_LIP_EXPRESSION_MOUTH_UPPER_UPLEFT_HTC = 20, + XR_LIP_EXPRESSION_MOUTH_LOWER_DOWNRIGHT_HTC = 21, + XR_LIP_EXPRESSION_MOUTH_LOWER_DOWNLEFT_HTC = 22, + XR_LIP_EXPRESSION_MOUTH_UPPER_INSIDE_HTC = 23, + XR_LIP_EXPRESSION_MOUTH_LOWER_INSIDE_HTC = 24, + XR_LIP_EXPRESSION_MOUTH_LOWER_OVERLAY_HTC = 25, + XR_LIP_EXPRESSION_TONGUE_LONGSTEP1_HTC = 26, + XR_LIP_EXPRESSION_TONGUE_LEFT_HTC = 27, + XR_LIP_EXPRESSION_TONGUE_RIGHT_HTC = 28, + XR_LIP_EXPRESSION_TONGUE_UP_HTC = 29, + XR_LIP_EXPRESSION_TONGUE_DOWN_HTC = 30, + XR_LIP_EXPRESSION_TONGUE_ROLL_HTC = 31, + XR_LIP_EXPRESSION_TONGUE_LONGSTEP2_HTC = 32, + XR_LIP_EXPRESSION_TONGUE_UPRIGHT_MORPH_HTC = 33, + XR_LIP_EXPRESSION_TONGUE_UPLEFT_MORPH_HTC = 34, + XR_LIP_EXPRESSION_TONGUE_DOWNRIGHT_MORPH_HTC = 35, + XR_LIP_EXPRESSION_TONGUE_DOWNLEFT_MORPH_HTC = 36, + XR_LIP_EXPRESSION_MAX_ENUM_HTC = 0x7FFFFFFF +} XrLipExpressionHTC; + +typedef enum XrFacialTrackingTypeHTC { + XR_FACIAL_TRACKING_TYPE_EYE_DEFAULT_HTC = 1, + XR_FACIAL_TRACKING_TYPE_LIP_DEFAULT_HTC = 2, + XR_FACIAL_TRACKING_TYPE_MAX_ENUM_HTC = 0x7FFFFFFF +} XrFacialTrackingTypeHTC; +// XrSystemFacialTrackingPropertiesHTC extends XrSystemProperties +typedef struct XrSystemFacialTrackingPropertiesHTC { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrBool32 supportEyeFacialTracking; + XrBool32 supportLipFacialTracking; +} XrSystemFacialTrackingPropertiesHTC; + +typedef struct XrFacialExpressionsHTC { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrBool32 isActive; + XrTime sampleTime; + uint32_t expressionCount; + float* expressionWeightings; +} XrFacialExpressionsHTC; + +typedef struct XrFacialTrackerCreateInfoHTC { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrFacialTrackingTypeHTC facialTrackingType; +} XrFacialTrackerCreateInfoHTC; + +typedef XrResult (XRAPI_PTR *PFN_xrCreateFacialTrackerHTC)(XrSession session, const XrFacialTrackerCreateInfoHTC* createInfo, XrFacialTrackerHTC* facialTracker); +typedef XrResult (XRAPI_PTR *PFN_xrDestroyFacialTrackerHTC)(XrFacialTrackerHTC facialTracker); +typedef XrResult (XRAPI_PTR *PFN_xrGetFacialExpressionsHTC)(XrFacialTrackerHTC facialTracker, XrFacialExpressionsHTC* facialExpressions); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrCreateFacialTrackerHTC( + XrSession session, + const XrFacialTrackerCreateInfoHTC* createInfo, + XrFacialTrackerHTC* facialTracker); + +XRAPI_ATTR XrResult XRAPI_CALL xrDestroyFacialTrackerHTC( + XrFacialTrackerHTC facialTracker); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetFacialExpressionsHTC( + XrFacialTrackerHTC facialTracker, + XrFacialExpressionsHTC* facialExpressions); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_HTC_vive_focus3_controller_interaction 1 +#define XR_HTC_vive_focus3_controller_interaction_SPEC_VERSION 2 +#define XR_HTC_VIVE_FOCUS3_CONTROLLER_INTERACTION_EXTENSION_NAME "XR_HTC_vive_focus3_controller_interaction" + + +#define XR_HTC_hand_interaction 1 +#define XR_HTC_hand_interaction_SPEC_VERSION 1 +#define XR_HTC_HAND_INTERACTION_EXTENSION_NAME "XR_HTC_hand_interaction" + + +#define XR_HTC_vive_wrist_tracker_interaction 1 +#define XR_HTC_vive_wrist_tracker_interaction_SPEC_VERSION 1 +#define XR_HTC_VIVE_WRIST_TRACKER_INTERACTION_EXTENSION_NAME "XR_HTC_vive_wrist_tracker_interaction" + + +#define XR_FB_color_space 1 +#define XR_FB_color_space_SPEC_VERSION 3 +#define XR_FB_COLOR_SPACE_EXTENSION_NAME "XR_FB_color_space" + +typedef enum XrColorSpaceFB { + XR_COLOR_SPACE_UNMANAGED_FB = 0, + XR_COLOR_SPACE_REC2020_FB = 1, + XR_COLOR_SPACE_REC709_FB = 2, + XR_COLOR_SPACE_RIFT_CV1_FB = 3, + XR_COLOR_SPACE_RIFT_S_FB = 4, + XR_COLOR_SPACE_QUEST_FB = 5, + XR_COLOR_SPACE_P3_FB = 6, + XR_COLOR_SPACE_ADOBE_RGB_FB = 7, + XR_COLOR_SPACE_MAX_ENUM_FB = 0x7FFFFFFF +} XrColorSpaceFB; +// XrSystemColorSpacePropertiesFB extends XrSystemProperties +typedef struct XrSystemColorSpacePropertiesFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrColorSpaceFB colorSpace; +} XrSystemColorSpacePropertiesFB; + +typedef XrResult (XRAPI_PTR *PFN_xrEnumerateColorSpacesFB)(XrSession session, uint32_t colorSpaceCapacityInput, uint32_t* colorSpaceCountOutput, XrColorSpaceFB* colorSpaces); +typedef XrResult (XRAPI_PTR *PFN_xrSetColorSpaceFB)(XrSession session, const XrColorSpaceFB colorspace); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateColorSpacesFB( + XrSession session, + uint32_t colorSpaceCapacityInput, + uint32_t* colorSpaceCountOutput, + XrColorSpaceFB* colorSpaces); + +XRAPI_ATTR XrResult XRAPI_CALL xrSetColorSpaceFB( + XrSession session, + const XrColorSpaceFB colorspace); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_FB_hand_tracking_mesh 1 +#define XR_FB_hand_tracking_mesh_SPEC_VERSION 3 +#define XR_FB_HAND_TRACKING_MESH_EXTENSION_NAME "XR_FB_hand_tracking_mesh" +typedef struct XrVector4sFB { + int16_t x; + int16_t y; + int16_t z; + int16_t w; +} XrVector4sFB; + +typedef struct XrHandTrackingMeshFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint32_t jointCapacityInput; + uint32_t jointCountOutput; + XrPosef* jointBindPoses; + float* jointRadii; + XrHandJointEXT* jointParents; + uint32_t vertexCapacityInput; + uint32_t vertexCountOutput; + XrVector3f* vertexPositions; + XrVector3f* vertexNormals; + XrVector2f* vertexUVs; + XrVector4sFB* vertexBlendIndices; + XrVector4f* vertexBlendWeights; + uint32_t indexCapacityInput; + uint32_t indexCountOutput; + int16_t* indices; +} XrHandTrackingMeshFB; + +// XrHandTrackingScaleFB extends XrHandJointLocationsEXT +typedef struct XrHandTrackingScaleFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + float sensorOutput; + float currentOutput; + XrBool32 overrideHandScale; + float overrideValueInput; +} XrHandTrackingScaleFB; + +typedef XrResult (XRAPI_PTR *PFN_xrGetHandMeshFB)(XrHandTrackerEXT handTracker, XrHandTrackingMeshFB* mesh); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrGetHandMeshFB( + XrHandTrackerEXT handTracker, + XrHandTrackingMeshFB* mesh); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_FB_hand_tracking_aim 1 +#define XR_FB_hand_tracking_aim_SPEC_VERSION 2 +#define XR_FB_HAND_TRACKING_AIM_EXTENSION_NAME "XR_FB_hand_tracking_aim" +typedef XrFlags64 XrHandTrackingAimFlagsFB; + +// Flag bits for XrHandTrackingAimFlagsFB +static const XrHandTrackingAimFlagsFB XR_HAND_TRACKING_AIM_COMPUTED_BIT_FB = 0x00000001; +static const XrHandTrackingAimFlagsFB XR_HAND_TRACKING_AIM_VALID_BIT_FB = 0x00000002; +static const XrHandTrackingAimFlagsFB XR_HAND_TRACKING_AIM_INDEX_PINCHING_BIT_FB = 0x00000004; +static const XrHandTrackingAimFlagsFB XR_HAND_TRACKING_AIM_MIDDLE_PINCHING_BIT_FB = 0x00000008; +static const XrHandTrackingAimFlagsFB XR_HAND_TRACKING_AIM_RING_PINCHING_BIT_FB = 0x00000010; +static const XrHandTrackingAimFlagsFB XR_HAND_TRACKING_AIM_LITTLE_PINCHING_BIT_FB = 0x00000020; +static const XrHandTrackingAimFlagsFB XR_HAND_TRACKING_AIM_SYSTEM_GESTURE_BIT_FB = 0x00000040; +static const XrHandTrackingAimFlagsFB XR_HAND_TRACKING_AIM_DOMINANT_HAND_BIT_FB = 0x00000080; +static const XrHandTrackingAimFlagsFB XR_HAND_TRACKING_AIM_MENU_PRESSED_BIT_FB = 0x00000100; + +// XrHandTrackingAimStateFB extends XrHandJointLocationsEXT +typedef struct XrHandTrackingAimStateFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrHandTrackingAimFlagsFB status; + XrPosef aimPose; + float pinchStrengthIndex; + float pinchStrengthMiddle; + float pinchStrengthRing; + float pinchStrengthLittle; +} XrHandTrackingAimStateFB; + + + +#define XR_FB_hand_tracking_capsules 1 +#define XR_HAND_TRACKING_CAPSULE_POINT_COUNT_FB 2 +#define XR_HAND_TRACKING_CAPSULE_COUNT_FB 19 +#define XR_FB_hand_tracking_capsules_SPEC_VERSION 3 +#define XR_FB_HAND_TRACKING_CAPSULES_EXTENSION_NAME "XR_FB_hand_tracking_capsules" +#define XR_FB_HAND_TRACKING_CAPSULE_POINT_COUNT XR_HAND_TRACKING_CAPSULE_POINT_COUNT_FB +#define XR_FB_HAND_TRACKING_CAPSULE_COUNT XR_HAND_TRACKING_CAPSULE_COUNT_FB +typedef struct XrHandCapsuleFB { + XrVector3f points[XR_HAND_TRACKING_CAPSULE_POINT_COUNT_FB]; + float radius; + XrHandJointEXT joint; +} XrHandCapsuleFB; + +// XrHandTrackingCapsulesStateFB extends XrHandJointLocationsEXT +typedef struct XrHandTrackingCapsulesStateFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrHandCapsuleFB capsules[XR_HAND_TRACKING_CAPSULE_COUNT_FB]; +} XrHandTrackingCapsulesStateFB; + + + +#define XR_FB_spatial_entity 1 +XR_DEFINE_ATOM(XrAsyncRequestIdFB) +#define XR_UUID_SIZE_EXT 16 +#define XR_FB_spatial_entity_SPEC_VERSION 2 +#define XR_FB_SPATIAL_ENTITY_EXTENSION_NAME "XR_FB_spatial_entity" + +typedef enum XrSpaceComponentTypeFB { + XR_SPACE_COMPONENT_TYPE_LOCATABLE_FB = 0, + XR_SPACE_COMPONENT_TYPE_STORABLE_FB = 1, + XR_SPACE_COMPONENT_TYPE_SHARABLE_FB = 2, + XR_SPACE_COMPONENT_TYPE_BOUNDED_2D_FB = 3, + XR_SPACE_COMPONENT_TYPE_BOUNDED_3D_FB = 4, + XR_SPACE_COMPONENT_TYPE_SEMANTIC_LABELS_FB = 5, + XR_SPACE_COMPONENT_TYPE_ROOM_LAYOUT_FB = 6, + XR_SPACE_COMPONENT_TYPE_SPACE_CONTAINER_FB = 7, + XR_SPACE_COMPONENT_TYPE_MAX_ENUM_FB = 0x7FFFFFFF +} XrSpaceComponentTypeFB; +// XrSystemSpatialEntityPropertiesFB extends XrSystemProperties +typedef struct XrSystemSpatialEntityPropertiesFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrBool32 supportsSpatialEntity; +} XrSystemSpatialEntityPropertiesFB; + +typedef struct XrSpatialAnchorCreateInfoFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSpace space; + XrPosef poseInSpace; + XrTime time; +} XrSpatialAnchorCreateInfoFB; + +typedef struct XrSpaceComponentStatusSetInfoFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSpaceComponentTypeFB componentType; + XrBool32 enabled; + XrDuration timeout; +} XrSpaceComponentStatusSetInfoFB; + +typedef struct XrSpaceComponentStatusFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrBool32 enabled; + XrBool32 changePending; +} XrSpaceComponentStatusFB; + +typedef struct XrUuidEXT { + uint8_t data[XR_UUID_SIZE_EXT]; +} XrUuidEXT; + +typedef struct XrEventDataSpatialAnchorCreateCompleteFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrAsyncRequestIdFB requestId; + XrResult result; + XrSpace space; + XrUuidEXT uuid; +} XrEventDataSpatialAnchorCreateCompleteFB; + +typedef struct XrEventDataSpaceSetStatusCompleteFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrAsyncRequestIdFB requestId; + XrResult result; + XrSpace space; + XrUuidEXT uuid; + XrSpaceComponentTypeFB componentType; + XrBool32 enabled; +} XrEventDataSpaceSetStatusCompleteFB; + +typedef XrResult (XRAPI_PTR *PFN_xrCreateSpatialAnchorFB)(XrSession session, const XrSpatialAnchorCreateInfoFB* info, XrAsyncRequestIdFB* requestId); +typedef XrResult (XRAPI_PTR *PFN_xrGetSpaceUuidFB)(XrSpace space, XrUuidEXT* uuid); +typedef XrResult (XRAPI_PTR *PFN_xrEnumerateSpaceSupportedComponentsFB)(XrSpace space, uint32_t componentTypeCapacityInput, uint32_t* componentTypeCountOutput, XrSpaceComponentTypeFB* componentTypes); +typedef XrResult (XRAPI_PTR *PFN_xrSetSpaceComponentStatusFB)(XrSpace space, const XrSpaceComponentStatusSetInfoFB* info, XrAsyncRequestIdFB* requestId); +typedef XrResult (XRAPI_PTR *PFN_xrGetSpaceComponentStatusFB)(XrSpace space, XrSpaceComponentTypeFB componentType, XrSpaceComponentStatusFB* status); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrCreateSpatialAnchorFB( + XrSession session, + const XrSpatialAnchorCreateInfoFB* info, + XrAsyncRequestIdFB* requestId); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetSpaceUuidFB( + XrSpace space, + XrUuidEXT* uuid); + +XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateSpaceSupportedComponentsFB( + XrSpace space, + uint32_t componentTypeCapacityInput, + uint32_t* componentTypeCountOutput, + XrSpaceComponentTypeFB* componentTypes); + +XRAPI_ATTR XrResult XRAPI_CALL xrSetSpaceComponentStatusFB( + XrSpace space, + const XrSpaceComponentStatusSetInfoFB* info, + XrAsyncRequestIdFB* requestId); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetSpaceComponentStatusFB( + XrSpace space, + XrSpaceComponentTypeFB componentType, + XrSpaceComponentStatusFB* status); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_FB_foveation 1 +XR_DEFINE_HANDLE(XrFoveationProfileFB) +#define XR_FB_foveation_SPEC_VERSION 1 +#define XR_FB_FOVEATION_EXTENSION_NAME "XR_FB_foveation" +typedef XrFlags64 XrSwapchainCreateFoveationFlagsFB; + +// Flag bits for XrSwapchainCreateFoveationFlagsFB +static const XrSwapchainCreateFoveationFlagsFB XR_SWAPCHAIN_CREATE_FOVEATION_SCALED_BIN_BIT_FB = 0x00000001; +static const XrSwapchainCreateFoveationFlagsFB XR_SWAPCHAIN_CREATE_FOVEATION_FRAGMENT_DENSITY_MAP_BIT_FB = 0x00000002; + +typedef XrFlags64 XrSwapchainStateFoveationFlagsFB; + +// Flag bits for XrSwapchainStateFoveationFlagsFB + +typedef struct XrFoveationProfileCreateInfoFB { + XrStructureType type; + void* XR_MAY_ALIAS next; +} XrFoveationProfileCreateInfoFB; + +// XrSwapchainCreateInfoFoveationFB extends XrSwapchainCreateInfo +typedef struct XrSwapchainCreateInfoFoveationFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrSwapchainCreateFoveationFlagsFB flags; +} XrSwapchainCreateInfoFoveationFB; + +typedef struct XrSwapchainStateFoveationFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrSwapchainStateFoveationFlagsFB flags; + XrFoveationProfileFB profile; +} XrSwapchainStateFoveationFB; + +typedef XrResult (XRAPI_PTR *PFN_xrCreateFoveationProfileFB)(XrSession session, const XrFoveationProfileCreateInfoFB* createInfo, XrFoveationProfileFB* profile); +typedef XrResult (XRAPI_PTR *PFN_xrDestroyFoveationProfileFB)(XrFoveationProfileFB profile); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrCreateFoveationProfileFB( + XrSession session, + const XrFoveationProfileCreateInfoFB* createInfo, + XrFoveationProfileFB* profile); + +XRAPI_ATTR XrResult XRAPI_CALL xrDestroyFoveationProfileFB( + XrFoveationProfileFB profile); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_FB_foveation_configuration 1 +#define XR_FB_foveation_configuration_SPEC_VERSION 1 +#define XR_FB_FOVEATION_CONFIGURATION_EXTENSION_NAME "XR_FB_foveation_configuration" + +typedef enum XrFoveationLevelFB { + XR_FOVEATION_LEVEL_NONE_FB = 0, + XR_FOVEATION_LEVEL_LOW_FB = 1, + XR_FOVEATION_LEVEL_MEDIUM_FB = 2, + XR_FOVEATION_LEVEL_HIGH_FB = 3, + XR_FOVEATION_LEVEL_MAX_ENUM_FB = 0x7FFFFFFF +} XrFoveationLevelFB; + +typedef enum XrFoveationDynamicFB { + XR_FOVEATION_DYNAMIC_DISABLED_FB = 0, + XR_FOVEATION_DYNAMIC_LEVEL_ENABLED_FB = 1, + XR_FOVEATION_DYNAMIC_MAX_ENUM_FB = 0x7FFFFFFF +} XrFoveationDynamicFB; +// XrFoveationLevelProfileCreateInfoFB extends XrFoveationProfileCreateInfoFB +typedef struct XrFoveationLevelProfileCreateInfoFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrFoveationLevelFB level; + float verticalOffset; + XrFoveationDynamicFB dynamic; +} XrFoveationLevelProfileCreateInfoFB; + + + +#define XR_FB_keyboard_tracking 1 +#define XR_FB_keyboard_tracking_SPEC_VERSION 1 +#define XR_FB_KEYBOARD_TRACKING_EXTENSION_NAME "XR_FB_keyboard_tracking" +#define XR_MAX_KEYBOARD_TRACKING_NAME_SIZE_FB 128 +typedef XrFlags64 XrKeyboardTrackingFlagsFB; + +// Flag bits for XrKeyboardTrackingFlagsFB +static const XrKeyboardTrackingFlagsFB XR_KEYBOARD_TRACKING_EXISTS_BIT_FB = 0x00000001; +static const XrKeyboardTrackingFlagsFB XR_KEYBOARD_TRACKING_LOCAL_BIT_FB = 0x00000002; +static const XrKeyboardTrackingFlagsFB XR_KEYBOARD_TRACKING_REMOTE_BIT_FB = 0x00000004; +static const XrKeyboardTrackingFlagsFB XR_KEYBOARD_TRACKING_CONNECTED_BIT_FB = 0x00000008; + +typedef XrFlags64 XrKeyboardTrackingQueryFlagsFB; + +// Flag bits for XrKeyboardTrackingQueryFlagsFB +static const XrKeyboardTrackingQueryFlagsFB XR_KEYBOARD_TRACKING_QUERY_LOCAL_BIT_FB = 0x00000002; +static const XrKeyboardTrackingQueryFlagsFB XR_KEYBOARD_TRACKING_QUERY_REMOTE_BIT_FB = 0x00000004; + +// XrSystemKeyboardTrackingPropertiesFB extends XrSystemProperties +typedef struct XrSystemKeyboardTrackingPropertiesFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrBool32 supportsKeyboardTracking; +} XrSystemKeyboardTrackingPropertiesFB; + +typedef struct XrKeyboardTrackingDescriptionFB { + uint64_t trackedKeyboardId; + XrVector3f size; + XrKeyboardTrackingFlagsFB flags; + char name[XR_MAX_KEYBOARD_TRACKING_NAME_SIZE_FB]; +} XrKeyboardTrackingDescriptionFB; + +typedef struct XrKeyboardSpaceCreateInfoFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint64_t trackedKeyboardId; +} XrKeyboardSpaceCreateInfoFB; + +typedef struct XrKeyboardTrackingQueryFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrKeyboardTrackingQueryFlagsFB flags; +} XrKeyboardTrackingQueryFB; + +typedef XrResult (XRAPI_PTR *PFN_xrQuerySystemTrackedKeyboardFB)(XrSession session, const XrKeyboardTrackingQueryFB* queryInfo, XrKeyboardTrackingDescriptionFB* keyboard); +typedef XrResult (XRAPI_PTR *PFN_xrCreateKeyboardSpaceFB)(XrSession session, const XrKeyboardSpaceCreateInfoFB* createInfo, XrSpace* keyboardSpace); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrQuerySystemTrackedKeyboardFB( + XrSession session, + const XrKeyboardTrackingQueryFB* queryInfo, + XrKeyboardTrackingDescriptionFB* keyboard); + +XRAPI_ATTR XrResult XRAPI_CALL xrCreateKeyboardSpaceFB( + XrSession session, + const XrKeyboardSpaceCreateInfoFB* createInfo, + XrSpace* keyboardSpace); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_FB_triangle_mesh 1 +XR_DEFINE_HANDLE(XrTriangleMeshFB) +#define XR_FB_triangle_mesh_SPEC_VERSION 2 +#define XR_FB_TRIANGLE_MESH_EXTENSION_NAME "XR_FB_triangle_mesh" + +typedef enum XrWindingOrderFB { + XR_WINDING_ORDER_UNKNOWN_FB = 0, + XR_WINDING_ORDER_CW_FB = 1, + XR_WINDING_ORDER_CCW_FB = 2, + XR_WINDING_ORDER_MAX_ENUM_FB = 0x7FFFFFFF +} XrWindingOrderFB; +typedef XrFlags64 XrTriangleMeshFlagsFB; + +// Flag bits for XrTriangleMeshFlagsFB +static const XrTriangleMeshFlagsFB XR_TRIANGLE_MESH_MUTABLE_BIT_FB = 0x00000001; + +typedef struct XrTriangleMeshCreateInfoFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrTriangleMeshFlagsFB flags; + XrWindingOrderFB windingOrder; + uint32_t vertexCount; + const XrVector3f* vertexBuffer; + uint32_t triangleCount; + const uint32_t* indexBuffer; +} XrTriangleMeshCreateInfoFB; + +typedef XrResult (XRAPI_PTR *PFN_xrCreateTriangleMeshFB)(XrSession session, const XrTriangleMeshCreateInfoFB* createInfo, XrTriangleMeshFB* outTriangleMesh); +typedef XrResult (XRAPI_PTR *PFN_xrDestroyTriangleMeshFB)(XrTriangleMeshFB mesh); +typedef XrResult (XRAPI_PTR *PFN_xrTriangleMeshGetVertexBufferFB)(XrTriangleMeshFB mesh, XrVector3f** outVertexBuffer); +typedef XrResult (XRAPI_PTR *PFN_xrTriangleMeshGetIndexBufferFB)(XrTriangleMeshFB mesh, uint32_t** outIndexBuffer); +typedef XrResult (XRAPI_PTR *PFN_xrTriangleMeshBeginUpdateFB)(XrTriangleMeshFB mesh); +typedef XrResult (XRAPI_PTR *PFN_xrTriangleMeshEndUpdateFB)(XrTriangleMeshFB mesh, uint32_t vertexCount, uint32_t triangleCount); +typedef XrResult (XRAPI_PTR *PFN_xrTriangleMeshBeginVertexBufferUpdateFB)(XrTriangleMeshFB mesh, uint32_t* outVertexCount); +typedef XrResult (XRAPI_PTR *PFN_xrTriangleMeshEndVertexBufferUpdateFB)(XrTriangleMeshFB mesh); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrCreateTriangleMeshFB( + XrSession session, + const XrTriangleMeshCreateInfoFB* createInfo, + XrTriangleMeshFB* outTriangleMesh); + +XRAPI_ATTR XrResult XRAPI_CALL xrDestroyTriangleMeshFB( + XrTriangleMeshFB mesh); + +XRAPI_ATTR XrResult XRAPI_CALL xrTriangleMeshGetVertexBufferFB( + XrTriangleMeshFB mesh, + XrVector3f** outVertexBuffer); + +XRAPI_ATTR XrResult XRAPI_CALL xrTriangleMeshGetIndexBufferFB( + XrTriangleMeshFB mesh, + uint32_t** outIndexBuffer); + +XRAPI_ATTR XrResult XRAPI_CALL xrTriangleMeshBeginUpdateFB( + XrTriangleMeshFB mesh); + +XRAPI_ATTR XrResult XRAPI_CALL xrTriangleMeshEndUpdateFB( + XrTriangleMeshFB mesh, + uint32_t vertexCount, + uint32_t triangleCount); + +XRAPI_ATTR XrResult XRAPI_CALL xrTriangleMeshBeginVertexBufferUpdateFB( + XrTriangleMeshFB mesh, + uint32_t* outVertexCount); + +XRAPI_ATTR XrResult XRAPI_CALL xrTriangleMeshEndVertexBufferUpdateFB( + XrTriangleMeshFB mesh); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_FB_passthrough 1 +XR_DEFINE_HANDLE(XrPassthroughFB) +XR_DEFINE_HANDLE(XrPassthroughLayerFB) +XR_DEFINE_HANDLE(XrGeometryInstanceFB) +#define XR_FB_passthrough_SPEC_VERSION 3 +#define XR_FB_PASSTHROUGH_EXTENSION_NAME "XR_FB_passthrough" +#define XR_PASSTHROUGH_COLOR_MAP_MONO_SIZE_FB 256 + +typedef enum XrPassthroughLayerPurposeFB { + XR_PASSTHROUGH_LAYER_PURPOSE_RECONSTRUCTION_FB = 0, + XR_PASSTHROUGH_LAYER_PURPOSE_PROJECTED_FB = 1, + XR_PASSTHROUGH_LAYER_PURPOSE_TRACKED_KEYBOARD_HANDS_FB = 1000203001, + XR_PASSTHROUGH_LAYER_PURPOSE_TRACKED_KEYBOARD_MASKED_HANDS_FB = 1000203002, + XR_PASSTHROUGH_LAYER_PURPOSE_MAX_ENUM_FB = 0x7FFFFFFF +} XrPassthroughLayerPurposeFB; +typedef XrFlags64 XrPassthroughCapabilityFlagsFB; + +// Flag bits for XrPassthroughCapabilityFlagsFB +static const XrPassthroughCapabilityFlagsFB XR_PASSTHROUGH_CAPABILITY_BIT_FB = 0x00000001; +static const XrPassthroughCapabilityFlagsFB XR_PASSTHROUGH_CAPABILITY_COLOR_BIT_FB = 0x00000002; +static const XrPassthroughCapabilityFlagsFB XR_PASSTHROUGH_CAPABILITY_LAYER_DEPTH_BIT_FB = 0x00000004; + +typedef XrFlags64 XrPassthroughFlagsFB; + +// Flag bits for XrPassthroughFlagsFB +static const XrPassthroughFlagsFB XR_PASSTHROUGH_IS_RUNNING_AT_CREATION_BIT_FB = 0x00000001; +static const XrPassthroughFlagsFB XR_PASSTHROUGH_LAYER_DEPTH_BIT_FB = 0x00000002; + +typedef XrFlags64 XrPassthroughStateChangedFlagsFB; + +// Flag bits for XrPassthroughStateChangedFlagsFB +static const XrPassthroughStateChangedFlagsFB XR_PASSTHROUGH_STATE_CHANGED_REINIT_REQUIRED_BIT_FB = 0x00000001; +static const XrPassthroughStateChangedFlagsFB XR_PASSTHROUGH_STATE_CHANGED_NON_RECOVERABLE_ERROR_BIT_FB = 0x00000002; +static const XrPassthroughStateChangedFlagsFB XR_PASSTHROUGH_STATE_CHANGED_RECOVERABLE_ERROR_BIT_FB = 0x00000004; +static const XrPassthroughStateChangedFlagsFB XR_PASSTHROUGH_STATE_CHANGED_RESTORED_ERROR_BIT_FB = 0x00000008; + +// XrSystemPassthroughPropertiesFB extends XrSystemProperties +typedef struct XrSystemPassthroughPropertiesFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrBool32 supportsPassthrough; +} XrSystemPassthroughPropertiesFB; + +// XrSystemPassthroughProperties2FB extends XrSystemProperties +typedef struct XrSystemPassthroughProperties2FB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrPassthroughCapabilityFlagsFB capabilities; +} XrSystemPassthroughProperties2FB; + +typedef struct XrPassthroughCreateInfoFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrPassthroughFlagsFB flags; +} XrPassthroughCreateInfoFB; + +typedef struct XrPassthroughLayerCreateInfoFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrPassthroughFB passthrough; + XrPassthroughFlagsFB flags; + XrPassthroughLayerPurposeFB purpose; +} XrPassthroughLayerCreateInfoFB; + +// XrCompositionLayerPassthroughFB extends XrCompositionLayerBaseHeader +typedef struct XrCompositionLayerPassthroughFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrCompositionLayerFlags flags; + XrSpace space; + XrPassthroughLayerFB layerHandle; +} XrCompositionLayerPassthroughFB; + +typedef struct XrGeometryInstanceCreateInfoFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrPassthroughLayerFB layer; + XrTriangleMeshFB mesh; + XrSpace baseSpace; + XrPosef pose; + XrVector3f scale; +} XrGeometryInstanceCreateInfoFB; + +typedef struct XrGeometryInstanceTransformFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSpace baseSpace; + XrTime time; + XrPosef pose; + XrVector3f scale; +} XrGeometryInstanceTransformFB; + +typedef struct XrPassthroughStyleFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + float textureOpacityFactor; + XrColor4f edgeColor; +} XrPassthroughStyleFB; + +// XrPassthroughColorMapMonoToRgbaFB extends XrPassthroughStyleFB +typedef struct XrPassthroughColorMapMonoToRgbaFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrColor4f textureColorMap[XR_PASSTHROUGH_COLOR_MAP_MONO_SIZE_FB]; +} XrPassthroughColorMapMonoToRgbaFB; + +// XrPassthroughColorMapMonoToMonoFB extends XrPassthroughStyleFB +typedef struct XrPassthroughColorMapMonoToMonoFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + uint8_t textureColorMap[XR_PASSTHROUGH_COLOR_MAP_MONO_SIZE_FB]; +} XrPassthroughColorMapMonoToMonoFB; + +// XrPassthroughBrightnessContrastSaturationFB extends XrPassthroughStyleFB +typedef struct XrPassthroughBrightnessContrastSaturationFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + float brightness; + float contrast; + float saturation; +} XrPassthroughBrightnessContrastSaturationFB; + +typedef struct XrEventDataPassthroughStateChangedFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrPassthroughStateChangedFlagsFB flags; +} XrEventDataPassthroughStateChangedFB; + +typedef XrResult (XRAPI_PTR *PFN_xrCreatePassthroughFB)(XrSession session, const XrPassthroughCreateInfoFB* createInfo, XrPassthroughFB* outPassthrough); +typedef XrResult (XRAPI_PTR *PFN_xrDestroyPassthroughFB)(XrPassthroughFB passthrough); +typedef XrResult (XRAPI_PTR *PFN_xrPassthroughStartFB)(XrPassthroughFB passthrough); +typedef XrResult (XRAPI_PTR *PFN_xrPassthroughPauseFB)(XrPassthroughFB passthrough); +typedef XrResult (XRAPI_PTR *PFN_xrCreatePassthroughLayerFB)(XrSession session, const XrPassthroughLayerCreateInfoFB* createInfo, XrPassthroughLayerFB* outLayer); +typedef XrResult (XRAPI_PTR *PFN_xrDestroyPassthroughLayerFB)(XrPassthroughLayerFB layer); +typedef XrResult (XRAPI_PTR *PFN_xrPassthroughLayerPauseFB)(XrPassthroughLayerFB layer); +typedef XrResult (XRAPI_PTR *PFN_xrPassthroughLayerResumeFB)(XrPassthroughLayerFB layer); +typedef XrResult (XRAPI_PTR *PFN_xrPassthroughLayerSetStyleFB)(XrPassthroughLayerFB layer, const XrPassthroughStyleFB* style); +typedef XrResult (XRAPI_PTR *PFN_xrCreateGeometryInstanceFB)(XrSession session, const XrGeometryInstanceCreateInfoFB* createInfo, XrGeometryInstanceFB* outGeometryInstance); +typedef XrResult (XRAPI_PTR *PFN_xrDestroyGeometryInstanceFB)(XrGeometryInstanceFB instance); +typedef XrResult (XRAPI_PTR *PFN_xrGeometryInstanceSetTransformFB)(XrGeometryInstanceFB instance, const XrGeometryInstanceTransformFB* transformation); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrCreatePassthroughFB( + XrSession session, + const XrPassthroughCreateInfoFB* createInfo, + XrPassthroughFB* outPassthrough); + +XRAPI_ATTR XrResult XRAPI_CALL xrDestroyPassthroughFB( + XrPassthroughFB passthrough); + +XRAPI_ATTR XrResult XRAPI_CALL xrPassthroughStartFB( + XrPassthroughFB passthrough); + +XRAPI_ATTR XrResult XRAPI_CALL xrPassthroughPauseFB( + XrPassthroughFB passthrough); + +XRAPI_ATTR XrResult XRAPI_CALL xrCreatePassthroughLayerFB( + XrSession session, + const XrPassthroughLayerCreateInfoFB* createInfo, + XrPassthroughLayerFB* outLayer); + +XRAPI_ATTR XrResult XRAPI_CALL xrDestroyPassthroughLayerFB( + XrPassthroughLayerFB layer); + +XRAPI_ATTR XrResult XRAPI_CALL xrPassthroughLayerPauseFB( + XrPassthroughLayerFB layer); + +XRAPI_ATTR XrResult XRAPI_CALL xrPassthroughLayerResumeFB( + XrPassthroughLayerFB layer); + +XRAPI_ATTR XrResult XRAPI_CALL xrPassthroughLayerSetStyleFB( + XrPassthroughLayerFB layer, + const XrPassthroughStyleFB* style); + +XRAPI_ATTR XrResult XRAPI_CALL xrCreateGeometryInstanceFB( + XrSession session, + const XrGeometryInstanceCreateInfoFB* createInfo, + XrGeometryInstanceFB* outGeometryInstance); + +XRAPI_ATTR XrResult XRAPI_CALL xrDestroyGeometryInstanceFB( + XrGeometryInstanceFB instance); + +XRAPI_ATTR XrResult XRAPI_CALL xrGeometryInstanceSetTransformFB( + XrGeometryInstanceFB instance, + const XrGeometryInstanceTransformFB* transformation); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_FB_render_model 1 + +#define XR_NULL_RENDER_MODEL_KEY_FB 0 + +XR_DEFINE_ATOM(XrRenderModelKeyFB) +#define XR_FB_render_model_SPEC_VERSION 4 +#define XR_FB_RENDER_MODEL_EXTENSION_NAME "XR_FB_render_model" +#define XR_MAX_RENDER_MODEL_NAME_SIZE_FB 64 +typedef XrFlags64 XrRenderModelFlagsFB; + +// Flag bits for XrRenderModelFlagsFB +static const XrRenderModelFlagsFB XR_RENDER_MODEL_SUPPORTS_GLTF_2_0_SUBSET_1_BIT_FB = 0x00000001; +static const XrRenderModelFlagsFB XR_RENDER_MODEL_SUPPORTS_GLTF_2_0_SUBSET_2_BIT_FB = 0x00000002; + +typedef struct XrRenderModelPathInfoFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrPath path; +} XrRenderModelPathInfoFB; + +typedef struct XrRenderModelPropertiesFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint32_t vendorId; + char modelName[XR_MAX_RENDER_MODEL_NAME_SIZE_FB]; + XrRenderModelKeyFB modelKey; + uint32_t modelVersion; + XrRenderModelFlagsFB flags; +} XrRenderModelPropertiesFB; + +typedef struct XrRenderModelBufferFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint32_t bufferCapacityInput; + uint32_t bufferCountOutput; + uint8_t* buffer; +} XrRenderModelBufferFB; + +typedef struct XrRenderModelLoadInfoFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrRenderModelKeyFB modelKey; +} XrRenderModelLoadInfoFB; + +// XrSystemRenderModelPropertiesFB extends XrSystemProperties +typedef struct XrSystemRenderModelPropertiesFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrBool32 supportsRenderModelLoading; +} XrSystemRenderModelPropertiesFB; + +// XrRenderModelCapabilitiesRequestFB extends XrSystemProperties +typedef struct XrRenderModelCapabilitiesRequestFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrRenderModelFlagsFB flags; +} XrRenderModelCapabilitiesRequestFB; + +typedef XrResult (XRAPI_PTR *PFN_xrEnumerateRenderModelPathsFB)(XrSession session, uint32_t pathCapacityInput, uint32_t* pathCountOutput, XrRenderModelPathInfoFB* paths); +typedef XrResult (XRAPI_PTR *PFN_xrGetRenderModelPropertiesFB)(XrSession session, XrPath path, XrRenderModelPropertiesFB* properties); +typedef XrResult (XRAPI_PTR *PFN_xrLoadRenderModelFB)(XrSession session, const XrRenderModelLoadInfoFB* info, XrRenderModelBufferFB* buffer); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateRenderModelPathsFB( + XrSession session, + uint32_t pathCapacityInput, + uint32_t* pathCountOutput, + XrRenderModelPathInfoFB* paths); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetRenderModelPropertiesFB( + XrSession session, + XrPath path, + XrRenderModelPropertiesFB* properties); + +XRAPI_ATTR XrResult XRAPI_CALL xrLoadRenderModelFB( + XrSession session, + const XrRenderModelLoadInfoFB* info, + XrRenderModelBufferFB* buffer); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_VARJO_foveated_rendering 1 +#define XR_VARJO_foveated_rendering_SPEC_VERSION 3 +#define XR_VARJO_FOVEATED_RENDERING_EXTENSION_NAME "XR_VARJO_foveated_rendering" +// XrViewLocateFoveatedRenderingVARJO extends XrViewLocateInfo +typedef struct XrViewLocateFoveatedRenderingVARJO { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrBool32 foveatedRenderingActive; +} XrViewLocateFoveatedRenderingVARJO; + +// XrFoveatedViewConfigurationViewVARJO extends XrViewConfigurationView +typedef struct XrFoveatedViewConfigurationViewVARJO { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrBool32 foveatedRenderingActive; +} XrFoveatedViewConfigurationViewVARJO; + +// XrSystemFoveatedRenderingPropertiesVARJO extends XrSystemProperties +typedef struct XrSystemFoveatedRenderingPropertiesVARJO { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrBool32 supportsFoveatedRendering; +} XrSystemFoveatedRenderingPropertiesVARJO; + + + +#define XR_VARJO_composition_layer_depth_test 1 +#define XR_VARJO_composition_layer_depth_test_SPEC_VERSION 2 +#define XR_VARJO_COMPOSITION_LAYER_DEPTH_TEST_EXTENSION_NAME "XR_VARJO_composition_layer_depth_test" +// XrCompositionLayerDepthTestVARJO extends XrCompositionLayerProjection +typedef struct XrCompositionLayerDepthTestVARJO { + XrStructureType type; + const void* XR_MAY_ALIAS next; + float depthTestRangeNearZ; + float depthTestRangeFarZ; +} XrCompositionLayerDepthTestVARJO; + + + +#define XR_VARJO_environment_depth_estimation 1 +#define XR_VARJO_environment_depth_estimation_SPEC_VERSION 1 +#define XR_VARJO_ENVIRONMENT_DEPTH_ESTIMATION_EXTENSION_NAME "XR_VARJO_environment_depth_estimation" +typedef XrResult (XRAPI_PTR *PFN_xrSetEnvironmentDepthEstimationVARJO)(XrSession session, XrBool32 enabled); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrSetEnvironmentDepthEstimationVARJO( + XrSession session, + XrBool32 enabled); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_VARJO_marker_tracking 1 +#define XR_VARJO_marker_tracking_SPEC_VERSION 1 +#define XR_VARJO_MARKER_TRACKING_EXTENSION_NAME "XR_VARJO_marker_tracking" +// XrSystemMarkerTrackingPropertiesVARJO extends XrSystemProperties +typedef struct XrSystemMarkerTrackingPropertiesVARJO { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrBool32 supportsMarkerTracking; +} XrSystemMarkerTrackingPropertiesVARJO; + +typedef struct XrEventDataMarkerTrackingUpdateVARJO { + XrStructureType type; + const void* XR_MAY_ALIAS next; + uint64_t markerId; + XrBool32 isActive; + XrBool32 isPredicted; + XrTime time; +} XrEventDataMarkerTrackingUpdateVARJO; + +typedef struct XrMarkerSpaceCreateInfoVARJO { + XrStructureType type; + const void* XR_MAY_ALIAS next; + uint64_t markerId; + XrPosef poseInMarkerSpace; +} XrMarkerSpaceCreateInfoVARJO; + +typedef XrResult (XRAPI_PTR *PFN_xrSetMarkerTrackingVARJO)(XrSession session, XrBool32 enabled); +typedef XrResult (XRAPI_PTR *PFN_xrSetMarkerTrackingTimeoutVARJO)(XrSession session, uint64_t markerId, XrDuration timeout); +typedef XrResult (XRAPI_PTR *PFN_xrSetMarkerTrackingPredictionVARJO)(XrSession session, uint64_t markerId, XrBool32 enabled); +typedef XrResult (XRAPI_PTR *PFN_xrGetMarkerSizeVARJO)(XrSession session, uint64_t markerId, XrExtent2Df* size); +typedef XrResult (XRAPI_PTR *PFN_xrCreateMarkerSpaceVARJO)(XrSession session, const XrMarkerSpaceCreateInfoVARJO* createInfo, XrSpace* space); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrSetMarkerTrackingVARJO( + XrSession session, + XrBool32 enabled); + +XRAPI_ATTR XrResult XRAPI_CALL xrSetMarkerTrackingTimeoutVARJO( + XrSession session, + uint64_t markerId, + XrDuration timeout); + +XRAPI_ATTR XrResult XRAPI_CALL xrSetMarkerTrackingPredictionVARJO( + XrSession session, + uint64_t markerId, + XrBool32 enabled); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetMarkerSizeVARJO( + XrSession session, + uint64_t markerId, + XrExtent2Df* size); + +XRAPI_ATTR XrResult XRAPI_CALL xrCreateMarkerSpaceVARJO( + XrSession session, + const XrMarkerSpaceCreateInfoVARJO* createInfo, + XrSpace* space); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_VARJO_view_offset 1 +#define XR_VARJO_view_offset_SPEC_VERSION 1 +#define XR_VARJO_VIEW_OFFSET_EXTENSION_NAME "XR_VARJO_view_offset" +typedef XrResult (XRAPI_PTR *PFN_xrSetViewOffsetVARJO)(XrSession session, float offset); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrSetViewOffsetVARJO( + XrSession session, + float offset); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_ML_ml2_controller_interaction 1 +#define XR_ML_ml2_controller_interaction_SPEC_VERSION 1 +#define XR_ML_ML2_CONTROLLER_INTERACTION_EXTENSION_NAME "XR_ML_ml2_controller_interaction" + + +#define XR_ML_frame_end_info 1 +#define XR_ML_frame_end_info_SPEC_VERSION 1 +#define XR_ML_FRAME_END_INFO_EXTENSION_NAME "XR_ML_frame_end_info" +typedef XrFlags64 XrFrameEndInfoFlagsML; + +// Flag bits for XrFrameEndInfoFlagsML +static const XrFrameEndInfoFlagsML XR_FRAME_END_INFO_PROTECTED_BIT_ML = 0x00000001; +static const XrFrameEndInfoFlagsML XR_FRAME_END_INFO_VIGNETTE_BIT_ML = 0x00000002; + +// XrFrameEndInfoML extends XrFrameEndInfo +typedef struct XrFrameEndInfoML { + XrStructureType type; + const void* XR_MAY_ALIAS next; + float focusDistance; + XrFrameEndInfoFlagsML flags; +} XrFrameEndInfoML; + + + +#define XR_ML_global_dimmer 1 +#define XR_ML_global_dimmer_SPEC_VERSION 1 +#define XR_ML_GLOBAL_DIMMER_EXTENSION_NAME "XR_ML_global_dimmer" +typedef XrFlags64 XrGlobalDimmerFrameEndInfoFlagsML; + +// Flag bits for XrGlobalDimmerFrameEndInfoFlagsML +static const XrGlobalDimmerFrameEndInfoFlagsML XR_GLOBAL_DIMMER_FRAME_END_INFO_ENABLED_BIT_ML = 0x00000001; + +// XrGlobalDimmerFrameEndInfoML extends XrFrameEndInfo +typedef struct XrGlobalDimmerFrameEndInfoML { + XrStructureType type; + const void* XR_MAY_ALIAS next; + float dimmerValue; + XrGlobalDimmerFrameEndInfoFlagsML flags; +} XrGlobalDimmerFrameEndInfoML; + + + +#define XR_MSFT_spatial_anchor_persistence 1 +XR_DEFINE_HANDLE(XrSpatialAnchorStoreConnectionMSFT) +#define XR_MAX_SPATIAL_ANCHOR_NAME_SIZE_MSFT 256 +#define XR_MSFT_spatial_anchor_persistence_SPEC_VERSION 2 +#define XR_MSFT_SPATIAL_ANCHOR_PERSISTENCE_EXTENSION_NAME "XR_MSFT_spatial_anchor_persistence" +typedef struct XrSpatialAnchorPersistenceNameMSFT { + char name[XR_MAX_SPATIAL_ANCHOR_NAME_SIZE_MSFT]; +} XrSpatialAnchorPersistenceNameMSFT; + +typedef struct XrSpatialAnchorPersistenceInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSpatialAnchorPersistenceNameMSFT spatialAnchorPersistenceName; + XrSpatialAnchorMSFT spatialAnchor; +} XrSpatialAnchorPersistenceInfoMSFT; + +typedef struct XrSpatialAnchorFromPersistedAnchorCreateInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSpatialAnchorStoreConnectionMSFT spatialAnchorStore; + XrSpatialAnchorPersistenceNameMSFT spatialAnchorPersistenceName; +} XrSpatialAnchorFromPersistedAnchorCreateInfoMSFT; + +typedef XrResult (XRAPI_PTR *PFN_xrCreateSpatialAnchorStoreConnectionMSFT)(XrSession session, XrSpatialAnchorStoreConnectionMSFT* spatialAnchorStore); +typedef XrResult (XRAPI_PTR *PFN_xrDestroySpatialAnchorStoreConnectionMSFT)(XrSpatialAnchorStoreConnectionMSFT spatialAnchorStore); +typedef XrResult (XRAPI_PTR *PFN_xrPersistSpatialAnchorMSFT)(XrSpatialAnchorStoreConnectionMSFT spatialAnchorStore, const XrSpatialAnchorPersistenceInfoMSFT* spatialAnchorPersistenceInfo); +typedef XrResult (XRAPI_PTR *PFN_xrEnumeratePersistedSpatialAnchorNamesMSFT)(XrSpatialAnchorStoreConnectionMSFT spatialAnchorStore, uint32_t spatialAnchorNamesCapacityInput, uint32_t* spatialAnchorNamesCountOutput, XrSpatialAnchorPersistenceNameMSFT* persistedAnchorNames); +typedef XrResult (XRAPI_PTR *PFN_xrCreateSpatialAnchorFromPersistedNameMSFT)(XrSession session, const XrSpatialAnchorFromPersistedAnchorCreateInfoMSFT* spatialAnchorCreateInfo, XrSpatialAnchorMSFT* spatialAnchor); +typedef XrResult (XRAPI_PTR *PFN_xrUnpersistSpatialAnchorMSFT)(XrSpatialAnchorStoreConnectionMSFT spatialAnchorStore, const XrSpatialAnchorPersistenceNameMSFT* spatialAnchorPersistenceName); +typedef XrResult (XRAPI_PTR *PFN_xrClearSpatialAnchorStoreMSFT)(XrSpatialAnchorStoreConnectionMSFT spatialAnchorStore); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrCreateSpatialAnchorStoreConnectionMSFT( + XrSession session, + XrSpatialAnchorStoreConnectionMSFT* spatialAnchorStore); + +XRAPI_ATTR XrResult XRAPI_CALL xrDestroySpatialAnchorStoreConnectionMSFT( + XrSpatialAnchorStoreConnectionMSFT spatialAnchorStore); + +XRAPI_ATTR XrResult XRAPI_CALL xrPersistSpatialAnchorMSFT( + XrSpatialAnchorStoreConnectionMSFT spatialAnchorStore, + const XrSpatialAnchorPersistenceInfoMSFT* spatialAnchorPersistenceInfo); + +XRAPI_ATTR XrResult XRAPI_CALL xrEnumeratePersistedSpatialAnchorNamesMSFT( + XrSpatialAnchorStoreConnectionMSFT spatialAnchorStore, + uint32_t spatialAnchorNamesCapacityInput, + uint32_t* spatialAnchorNamesCountOutput, + XrSpatialAnchorPersistenceNameMSFT* persistedAnchorNames); + +XRAPI_ATTR XrResult XRAPI_CALL xrCreateSpatialAnchorFromPersistedNameMSFT( + XrSession session, + const XrSpatialAnchorFromPersistedAnchorCreateInfoMSFT* spatialAnchorCreateInfo, + XrSpatialAnchorMSFT* spatialAnchor); + +XRAPI_ATTR XrResult XRAPI_CALL xrUnpersistSpatialAnchorMSFT( + XrSpatialAnchorStoreConnectionMSFT spatialAnchorStore, + const XrSpatialAnchorPersistenceNameMSFT* spatialAnchorPersistenceName); + +XRAPI_ATTR XrResult XRAPI_CALL xrClearSpatialAnchorStoreMSFT( + XrSpatialAnchorStoreConnectionMSFT spatialAnchorStore); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_ULTRALEAP_hand_tracking_forearm 1 + +#define XR_HAND_FOREARM_JOINT_COUNT_ULTRALEAP 27 + +#define XR_ULTRALEAP_hand_tracking_forearm_SPEC_VERSION 1 +#define XR_ULTRALEAP_HAND_TRACKING_FOREARM_EXTENSION_NAME "XR_ULTRALEAP_hand_tracking_forearm" + +typedef enum XrHandForearmJointULTRALEAP { + XR_HAND_FOREARM_JOINT_PALM_ULTRALEAP = 0, + XR_HAND_FOREARM_JOINT_WRIST_ULTRALEAP = 1, + XR_HAND_FOREARM_JOINT_THUMB_METACARPAL_ULTRALEAP = 2, + XR_HAND_FOREARM_JOINT_THUMB_PROXIMAL_ULTRALEAP = 3, + XR_HAND_FOREARM_JOINT_THUMB_DISTAL_ULTRALEAP = 4, + XR_HAND_FOREARM_JOINT_THUMB_TIP_ULTRALEAP = 5, + XR_HAND_FOREARM_JOINT_INDEX_METACARPAL_ULTRALEAP = 6, + XR_HAND_FOREARM_JOINT_INDEX_PROXIMAL_ULTRALEAP = 7, + XR_HAND_FOREARM_JOINT_INDEX_INTERMEDIATE_ULTRALEAP = 8, + XR_HAND_FOREARM_JOINT_INDEX_DISTAL_ULTRALEAP = 9, + XR_HAND_FOREARM_JOINT_INDEX_TIP_ULTRALEAP = 10, + XR_HAND_FOREARM_JOINT_MIDDLE_METACARPAL_ULTRALEAP = 11, + XR_HAND_FOREARM_JOINT_MIDDLE_PROXIMAL_ULTRALEAP = 12, + XR_HAND_FOREARM_JOINT_MIDDLE_INTERMEDIATE_ULTRALEAP = 13, + XR_HAND_FOREARM_JOINT_MIDDLE_DISTAL_ULTRALEAP = 14, + XR_HAND_FOREARM_JOINT_MIDDLE_TIP_ULTRALEAP = 15, + XR_HAND_FOREARM_JOINT_RING_METACARPAL_ULTRALEAP = 16, + XR_HAND_FOREARM_JOINT_RING_PROXIMAL_ULTRALEAP = 17, + XR_HAND_FOREARM_JOINT_RING_INTERMEDIATE_ULTRALEAP = 18, + XR_HAND_FOREARM_JOINT_RING_DISTAL_ULTRALEAP = 19, + XR_HAND_FOREARM_JOINT_RING_TIP_ULTRALEAP = 20, + XR_HAND_FOREARM_JOINT_LITTLE_METACARPAL_ULTRALEAP = 21, + XR_HAND_FOREARM_JOINT_LITTLE_PROXIMAL_ULTRALEAP = 22, + XR_HAND_FOREARM_JOINT_LITTLE_INTERMEDIATE_ULTRALEAP = 23, + XR_HAND_FOREARM_JOINT_LITTLE_DISTAL_ULTRALEAP = 24, + XR_HAND_FOREARM_JOINT_LITTLE_TIP_ULTRALEAP = 25, + XR_HAND_FOREARM_JOINT_ELBOW_ULTRALEAP = 26, + XR_HAND_FOREARM_JOINT_MAX_ENUM_ULTRALEAP = 0x7FFFFFFF +} XrHandForearmJointULTRALEAP; + + +#define XR_FB_spatial_entity_query 1 +#define XR_FB_spatial_entity_query_SPEC_VERSION 1 +#define XR_FB_SPATIAL_ENTITY_QUERY_EXTENSION_NAME "XR_FB_spatial_entity_query" + +typedef enum XrSpaceQueryActionFB { + XR_SPACE_QUERY_ACTION_LOAD_FB = 0, + XR_SPACE_QUERY_ACTION_MAX_ENUM_FB = 0x7FFFFFFF +} XrSpaceQueryActionFB; + +typedef enum XrSpaceStorageLocationFB { + XR_SPACE_STORAGE_LOCATION_INVALID_FB = 0, + XR_SPACE_STORAGE_LOCATION_LOCAL_FB = 1, + XR_SPACE_STORAGE_LOCATION_CLOUD_FB = 2, + XR_SPACE_STORAGE_LOCATION_MAX_ENUM_FB = 0x7FFFFFFF +} XrSpaceStorageLocationFB; +typedef struct XR_MAY_ALIAS XrSpaceQueryInfoBaseHeaderFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; +} XrSpaceQueryInfoBaseHeaderFB; + +typedef struct XR_MAY_ALIAS XrSpaceFilterInfoBaseHeaderFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; +} XrSpaceFilterInfoBaseHeaderFB; + +typedef struct XrSpaceQueryInfoFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSpaceQueryActionFB queryAction; + uint32_t maxResultCount; + XrDuration timeout; + const XrSpaceFilterInfoBaseHeaderFB* filter; + const XrSpaceFilterInfoBaseHeaderFB* excludeFilter; +} XrSpaceQueryInfoFB; + +// XrSpaceStorageLocationFilterInfoFB extends XrSpaceFilterInfoBaseHeaderFB +typedef struct XrSpaceStorageLocationFilterInfoFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSpaceStorageLocationFB location; +} XrSpaceStorageLocationFilterInfoFB; + +typedef struct XrSpaceUuidFilterInfoFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + uint32_t uuidCount; + XrUuidEXT* uuids; +} XrSpaceUuidFilterInfoFB; + +typedef struct XrSpaceComponentFilterInfoFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSpaceComponentTypeFB componentType; +} XrSpaceComponentFilterInfoFB; + +typedef struct XrSpaceQueryResultFB { + XrSpace space; + XrUuidEXT uuid; +} XrSpaceQueryResultFB; + +typedef struct XrSpaceQueryResultsFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint32_t resultCapacityInput; + uint32_t resultCountOutput; + XrSpaceQueryResultFB* results; +} XrSpaceQueryResultsFB; + +typedef struct XrEventDataSpaceQueryResultsAvailableFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrAsyncRequestIdFB requestId; +} XrEventDataSpaceQueryResultsAvailableFB; + +typedef struct XrEventDataSpaceQueryCompleteFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrAsyncRequestIdFB requestId; + XrResult result; +} XrEventDataSpaceQueryCompleteFB; + +typedef XrResult (XRAPI_PTR *PFN_xrQuerySpacesFB)(XrSession session, const XrSpaceQueryInfoBaseHeaderFB* info, XrAsyncRequestIdFB* requestId); +typedef XrResult (XRAPI_PTR *PFN_xrRetrieveSpaceQueryResultsFB)(XrSession session, XrAsyncRequestIdFB requestId, XrSpaceQueryResultsFB* results); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrQuerySpacesFB( + XrSession session, + const XrSpaceQueryInfoBaseHeaderFB* info, + XrAsyncRequestIdFB* requestId); + +XRAPI_ATTR XrResult XRAPI_CALL xrRetrieveSpaceQueryResultsFB( + XrSession session, + XrAsyncRequestIdFB requestId, + XrSpaceQueryResultsFB* results); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_FB_spatial_entity_storage 1 +#define XR_FB_spatial_entity_storage_SPEC_VERSION 1 +#define XR_FB_SPATIAL_ENTITY_STORAGE_EXTENSION_NAME "XR_FB_spatial_entity_storage" + +typedef enum XrSpacePersistenceModeFB { + XR_SPACE_PERSISTENCE_MODE_INVALID_FB = 0, + XR_SPACE_PERSISTENCE_MODE_INDEFINITE_FB = 1, + XR_SPACE_PERSISTENCE_MODE_MAX_ENUM_FB = 0x7FFFFFFF +} XrSpacePersistenceModeFB; +typedef struct XrSpaceSaveInfoFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSpace space; + XrSpaceStorageLocationFB location; + XrSpacePersistenceModeFB persistenceMode; +} XrSpaceSaveInfoFB; + +typedef struct XrSpaceEraseInfoFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSpace space; + XrSpaceStorageLocationFB location; +} XrSpaceEraseInfoFB; + +typedef struct XrEventDataSpaceSaveCompleteFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrAsyncRequestIdFB requestId; + XrResult result; + XrSpace space; + XrUuidEXT uuid; + XrSpaceStorageLocationFB location; +} XrEventDataSpaceSaveCompleteFB; + +typedef struct XrEventDataSpaceEraseCompleteFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrAsyncRequestIdFB requestId; + XrResult result; + XrSpace space; + XrUuidEXT uuid; + XrSpaceStorageLocationFB location; +} XrEventDataSpaceEraseCompleteFB; + +typedef XrResult (XRAPI_PTR *PFN_xrSaveSpaceFB)(XrSession session, const XrSpaceSaveInfoFB* info, XrAsyncRequestIdFB* requestId); +typedef XrResult (XRAPI_PTR *PFN_xrEraseSpaceFB)(XrSession session, const XrSpaceEraseInfoFB* info, XrAsyncRequestIdFB* requestId); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrSaveSpaceFB( + XrSession session, + const XrSpaceSaveInfoFB* info, + XrAsyncRequestIdFB* requestId); + +XRAPI_ATTR XrResult XRAPI_CALL xrEraseSpaceFB( + XrSession session, + const XrSpaceEraseInfoFB* info, + XrAsyncRequestIdFB* requestId); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_FB_touch_controller_pro 1 +#define XR_FB_touch_controller_pro_SPEC_VERSION 1 +#define XR_FB_TOUCH_CONTROLLER_PRO_EXTENSION_NAME "XR_FB_touch_controller_pro" + + +#define XR_FB_spatial_entity_sharing 1 +XR_DEFINE_HANDLE(XrSpaceUserFB) +#define XR_FB_spatial_entity_sharing_SPEC_VERSION 1 +#define XR_FB_SPATIAL_ENTITY_SHARING_EXTENSION_NAME "XR_FB_spatial_entity_sharing" +typedef struct XrSpaceShareInfoFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + uint32_t spaceCount; + XrSpace* spaces; + uint32_t userCount; + XrSpaceUserFB* users; +} XrSpaceShareInfoFB; + +typedef struct XrEventDataSpaceShareCompleteFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrAsyncRequestIdFB requestId; + XrResult result; +} XrEventDataSpaceShareCompleteFB; + +typedef XrResult (XRAPI_PTR *PFN_xrShareSpacesFB)(XrSession session, const XrSpaceShareInfoFB* info, XrAsyncRequestIdFB* requestId); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrShareSpacesFB( + XrSession session, + const XrSpaceShareInfoFB* info, + XrAsyncRequestIdFB* requestId); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_FB_space_warp 1 +#define XR_FB_space_warp_SPEC_VERSION 2 +#define XR_FB_SPACE_WARP_EXTENSION_NAME "XR_FB_space_warp" +typedef XrFlags64 XrCompositionLayerSpaceWarpInfoFlagsFB; + +// Flag bits for XrCompositionLayerSpaceWarpInfoFlagsFB +static const XrCompositionLayerSpaceWarpInfoFlagsFB XR_COMPOSITION_LAYER_SPACE_WARP_INFO_FRAME_SKIP_BIT_FB = 0x00000001; + +// XrCompositionLayerSpaceWarpInfoFB extends XrCompositionLayerProjectionView +typedef struct XrCompositionLayerSpaceWarpInfoFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrCompositionLayerSpaceWarpInfoFlagsFB layerFlags; + XrSwapchainSubImage motionVectorSubImage; + XrPosef appSpaceDeltaPose; + XrSwapchainSubImage depthSubImage; + float minDepth; + float maxDepth; + float nearZ; + float farZ; +} XrCompositionLayerSpaceWarpInfoFB; + +// XrSystemSpaceWarpPropertiesFB extends XrSystemProperties +typedef struct XrSystemSpaceWarpPropertiesFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint32_t recommendedMotionVectorImageRectWidth; + uint32_t recommendedMotionVectorImageRectHeight; +} XrSystemSpaceWarpPropertiesFB; + + + +#define XR_FB_haptic_amplitude_envelope 1 + +#define XR_MAX_HAPTIC_AMPLITUDE_ENVELOPE_SAMPLES_FB 4000u + +#define XR_FB_haptic_amplitude_envelope_SPEC_VERSION 1 +#define XR_FB_HAPTIC_AMPLITUDE_ENVELOPE_EXTENSION_NAME "XR_FB_haptic_amplitude_envelope" +typedef struct XrHapticAmplitudeEnvelopeVibrationFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrDuration duration; + uint32_t amplitudeCount; + const float* amplitudes; +} XrHapticAmplitudeEnvelopeVibrationFB; + + + +#define XR_FB_scene 1 +#define XR_FB_scene_SPEC_VERSION 3 +#define XR_FB_SCENE_EXTENSION_NAME "XR_FB_scene" +typedef XrFlags64 XrSemanticLabelsSupportFlagsFB; + +// Flag bits for XrSemanticLabelsSupportFlagsFB +static const XrSemanticLabelsSupportFlagsFB XR_SEMANTIC_LABELS_SUPPORT_MULTIPLE_SEMANTIC_LABELS_BIT_FB = 0x00000001; +static const XrSemanticLabelsSupportFlagsFB XR_SEMANTIC_LABELS_SUPPORT_ACCEPT_DESK_TO_TABLE_MIGRATION_BIT_FB = 0x00000002; + +typedef struct XrExtent3DfFB { + float width; + float height; + float depth; +} XrExtent3DfFB; + +typedef struct XrOffset3DfFB { + float x; + float y; + float z; +} XrOffset3DfFB; + +typedef struct XrRect3DfFB { + XrOffset3DfFB offset; + XrExtent3DfFB extent; +} XrRect3DfFB; + +typedef struct XrSemanticLabelsFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + uint32_t bufferCapacityInput; + uint32_t bufferCountOutput; + char* buffer; +} XrSemanticLabelsFB; + +typedef struct XrRoomLayoutFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrUuidEXT floorUuid; + XrUuidEXT ceilingUuid; + uint32_t wallUuidCapacityInput; + uint32_t wallUuidCountOutput; + XrUuidEXT* wallUuids; +} XrRoomLayoutFB; + +typedef struct XrBoundary2DFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + uint32_t vertexCapacityInput; + uint32_t vertexCountOutput; + XrVector2f* vertices; +} XrBoundary2DFB; + +typedef struct XrSemanticLabelsSupportInfoFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSemanticLabelsSupportFlagsFB flags; + const char* recognizedLabels; +} XrSemanticLabelsSupportInfoFB; + +typedef XrResult (XRAPI_PTR *PFN_xrGetSpaceBoundingBox2DFB)(XrSession session, XrSpace space, XrRect2Df* boundingBox2DOutput); +typedef XrResult (XRAPI_PTR *PFN_xrGetSpaceBoundingBox3DFB)(XrSession session, XrSpace space, XrRect3DfFB* boundingBox3DOutput); +typedef XrResult (XRAPI_PTR *PFN_xrGetSpaceSemanticLabelsFB)(XrSession session, XrSpace space, XrSemanticLabelsFB* semanticLabelsOutput); +typedef XrResult (XRAPI_PTR *PFN_xrGetSpaceBoundary2DFB)(XrSession session, XrSpace space, XrBoundary2DFB* boundary2DOutput); +typedef XrResult (XRAPI_PTR *PFN_xrGetSpaceRoomLayoutFB)(XrSession session, XrSpace space, XrRoomLayoutFB* roomLayoutOutput); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrGetSpaceBoundingBox2DFB( + XrSession session, + XrSpace space, + XrRect2Df* boundingBox2DOutput); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetSpaceBoundingBox3DFB( + XrSession session, + XrSpace space, + XrRect3DfFB* boundingBox3DOutput); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetSpaceSemanticLabelsFB( + XrSession session, + XrSpace space, + XrSemanticLabelsFB* semanticLabelsOutput); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetSpaceBoundary2DFB( + XrSession session, + XrSpace space, + XrBoundary2DFB* boundary2DOutput); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetSpaceRoomLayoutFB( + XrSession session, + XrSpace space, + XrRoomLayoutFB* roomLayoutOutput); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_EXT_palm_pose 1 +#define XR_EXT_palm_pose_SPEC_VERSION 2 +#define XR_EXT_PALM_POSE_EXTENSION_NAME "XR_EXT_palm_pose" + + +#define XR_ALMALENCE_digital_lens_control 1 +#define XR_ALMALENCE_digital_lens_control_SPEC_VERSION 1 +#define XR_ALMALENCE_DIGITAL_LENS_CONTROL_EXTENSION_NAME "XR_ALMALENCE_digital_lens_control" +typedef XrFlags64 XrDigitalLensControlFlagsALMALENCE; + +// Flag bits for XrDigitalLensControlFlagsALMALENCE +static const XrDigitalLensControlFlagsALMALENCE XR_DIGITAL_LENS_CONTROL_PROCESSING_DISABLE_BIT_ALMALENCE = 0x00000001; + +typedef struct XrDigitalLensControlALMALENCE { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrDigitalLensControlFlagsALMALENCE flags; +} XrDigitalLensControlALMALENCE; + +typedef XrResult (XRAPI_PTR *PFN_xrSetDigitalLensControlALMALENCE)(XrSession session, const XrDigitalLensControlALMALENCE* digitalLensControl); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrSetDigitalLensControlALMALENCE( + XrSession session, + const XrDigitalLensControlALMALENCE* digitalLensControl); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_FB_scene_capture 1 +#define XR_FB_scene_capture_SPEC_VERSION 1 +#define XR_FB_SCENE_CAPTURE_EXTENSION_NAME "XR_FB_scene_capture" +typedef struct XrEventDataSceneCaptureCompleteFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrAsyncRequestIdFB requestId; + XrResult result; +} XrEventDataSceneCaptureCompleteFB; + +typedef struct XrSceneCaptureRequestInfoFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + uint32_t requestByteCount; + const char* request; +} XrSceneCaptureRequestInfoFB; + +typedef XrResult (XRAPI_PTR *PFN_xrRequestSceneCaptureFB)(XrSession session, const XrSceneCaptureRequestInfoFB* info, XrAsyncRequestIdFB* requestId); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrRequestSceneCaptureFB( + XrSession session, + const XrSceneCaptureRequestInfoFB* info, + XrAsyncRequestIdFB* requestId); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_FB_spatial_entity_container 1 +#define XR_FB_spatial_entity_container_SPEC_VERSION 2 +#define XR_FB_SPATIAL_ENTITY_CONTAINER_EXTENSION_NAME "XR_FB_spatial_entity_container" +typedef struct XrSpaceContainerFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + uint32_t uuidCapacityInput; + uint32_t uuidCountOutput; + XrUuidEXT* uuids; +} XrSpaceContainerFB; + +typedef XrResult (XRAPI_PTR *PFN_xrGetSpaceContainerFB)(XrSession session, XrSpace space, XrSpaceContainerFB* spaceContainerOutput); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrGetSpaceContainerFB( + XrSession session, + XrSpace space, + XrSpaceContainerFB* spaceContainerOutput); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_META_foveation_eye_tracked 1 +#define XR_FOVEATION_CENTER_SIZE_META 2 +#define XR_META_foveation_eye_tracked_SPEC_VERSION 1 +#define XR_META_FOVEATION_EYE_TRACKED_EXTENSION_NAME "XR_META_foveation_eye_tracked" +typedef XrFlags64 XrFoveationEyeTrackedProfileCreateFlagsMETA; + +// Flag bits for XrFoveationEyeTrackedProfileCreateFlagsMETA + +typedef XrFlags64 XrFoveationEyeTrackedStateFlagsMETA; + +// Flag bits for XrFoveationEyeTrackedStateFlagsMETA +static const XrFoveationEyeTrackedStateFlagsMETA XR_FOVEATION_EYE_TRACKED_STATE_VALID_BIT_META = 0x00000001; + +// XrFoveationEyeTrackedProfileCreateInfoMETA extends XrFoveationLevelProfileCreateInfoFB +typedef struct XrFoveationEyeTrackedProfileCreateInfoMETA { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrFoveationEyeTrackedProfileCreateFlagsMETA flags; +} XrFoveationEyeTrackedProfileCreateInfoMETA; + +typedef struct XrFoveationEyeTrackedStateMETA { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrVector2f foveationCenter[XR_FOVEATION_CENTER_SIZE_META]; + XrFoveationEyeTrackedStateFlagsMETA flags; +} XrFoveationEyeTrackedStateMETA; + +// XrSystemFoveationEyeTrackedPropertiesMETA extends XrSystemProperties +typedef struct XrSystemFoveationEyeTrackedPropertiesMETA { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrBool32 supportsFoveationEyeTracked; +} XrSystemFoveationEyeTrackedPropertiesMETA; + +typedef XrResult (XRAPI_PTR *PFN_xrGetFoveationEyeTrackedStateMETA)(XrSession session, XrFoveationEyeTrackedStateMETA* foveationState); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrGetFoveationEyeTrackedStateMETA( + XrSession session, + XrFoveationEyeTrackedStateMETA* foveationState); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_FB_face_tracking 1 + +#define XR_FACE_EXPRESSSION_SET_DEFAULT_FB XR_FACE_EXPRESSION_SET_DEFAULT_FB + +XR_DEFINE_HANDLE(XrFaceTrackerFB) +#define XR_FB_face_tracking_SPEC_VERSION 1 +#define XR_FB_FACE_TRACKING_EXTENSION_NAME "XR_FB_face_tracking" + +typedef enum XrFaceExpressionFB { + XR_FACE_EXPRESSION_BROW_LOWERER_L_FB = 0, + XR_FACE_EXPRESSION_BROW_LOWERER_R_FB = 1, + XR_FACE_EXPRESSION_CHEEK_PUFF_L_FB = 2, + XR_FACE_EXPRESSION_CHEEK_PUFF_R_FB = 3, + XR_FACE_EXPRESSION_CHEEK_RAISER_L_FB = 4, + XR_FACE_EXPRESSION_CHEEK_RAISER_R_FB = 5, + XR_FACE_EXPRESSION_CHEEK_SUCK_L_FB = 6, + XR_FACE_EXPRESSION_CHEEK_SUCK_R_FB = 7, + XR_FACE_EXPRESSION_CHIN_RAISER_B_FB = 8, + XR_FACE_EXPRESSION_CHIN_RAISER_T_FB = 9, + XR_FACE_EXPRESSION_DIMPLER_L_FB = 10, + XR_FACE_EXPRESSION_DIMPLER_R_FB = 11, + XR_FACE_EXPRESSION_EYES_CLOSED_L_FB = 12, + XR_FACE_EXPRESSION_EYES_CLOSED_R_FB = 13, + XR_FACE_EXPRESSION_EYES_LOOK_DOWN_L_FB = 14, + XR_FACE_EXPRESSION_EYES_LOOK_DOWN_R_FB = 15, + XR_FACE_EXPRESSION_EYES_LOOK_LEFT_L_FB = 16, + XR_FACE_EXPRESSION_EYES_LOOK_LEFT_R_FB = 17, + XR_FACE_EXPRESSION_EYES_LOOK_RIGHT_L_FB = 18, + XR_FACE_EXPRESSION_EYES_LOOK_RIGHT_R_FB = 19, + XR_FACE_EXPRESSION_EYES_LOOK_UP_L_FB = 20, + XR_FACE_EXPRESSION_EYES_LOOK_UP_R_FB = 21, + XR_FACE_EXPRESSION_INNER_BROW_RAISER_L_FB = 22, + XR_FACE_EXPRESSION_INNER_BROW_RAISER_R_FB = 23, + XR_FACE_EXPRESSION_JAW_DROP_FB = 24, + XR_FACE_EXPRESSION_JAW_SIDEWAYS_LEFT_FB = 25, + XR_FACE_EXPRESSION_JAW_SIDEWAYS_RIGHT_FB = 26, + XR_FACE_EXPRESSION_JAW_THRUST_FB = 27, + XR_FACE_EXPRESSION_LID_TIGHTENER_L_FB = 28, + XR_FACE_EXPRESSION_LID_TIGHTENER_R_FB = 29, + XR_FACE_EXPRESSION_LIP_CORNER_DEPRESSOR_L_FB = 30, + XR_FACE_EXPRESSION_LIP_CORNER_DEPRESSOR_R_FB = 31, + XR_FACE_EXPRESSION_LIP_CORNER_PULLER_L_FB = 32, + XR_FACE_EXPRESSION_LIP_CORNER_PULLER_R_FB = 33, + XR_FACE_EXPRESSION_LIP_FUNNELER_LB_FB = 34, + XR_FACE_EXPRESSION_LIP_FUNNELER_LT_FB = 35, + XR_FACE_EXPRESSION_LIP_FUNNELER_RB_FB = 36, + XR_FACE_EXPRESSION_LIP_FUNNELER_RT_FB = 37, + XR_FACE_EXPRESSION_LIP_PRESSOR_L_FB = 38, + XR_FACE_EXPRESSION_LIP_PRESSOR_R_FB = 39, + XR_FACE_EXPRESSION_LIP_PUCKER_L_FB = 40, + XR_FACE_EXPRESSION_LIP_PUCKER_R_FB = 41, + XR_FACE_EXPRESSION_LIP_STRETCHER_L_FB = 42, + XR_FACE_EXPRESSION_LIP_STRETCHER_R_FB = 43, + XR_FACE_EXPRESSION_LIP_SUCK_LB_FB = 44, + XR_FACE_EXPRESSION_LIP_SUCK_LT_FB = 45, + XR_FACE_EXPRESSION_LIP_SUCK_RB_FB = 46, + XR_FACE_EXPRESSION_LIP_SUCK_RT_FB = 47, + XR_FACE_EXPRESSION_LIP_TIGHTENER_L_FB = 48, + XR_FACE_EXPRESSION_LIP_TIGHTENER_R_FB = 49, + XR_FACE_EXPRESSION_LIPS_TOWARD_FB = 50, + XR_FACE_EXPRESSION_LOWER_LIP_DEPRESSOR_L_FB = 51, + XR_FACE_EXPRESSION_LOWER_LIP_DEPRESSOR_R_FB = 52, + XR_FACE_EXPRESSION_MOUTH_LEFT_FB = 53, + XR_FACE_EXPRESSION_MOUTH_RIGHT_FB = 54, + XR_FACE_EXPRESSION_NOSE_WRINKLER_L_FB = 55, + XR_FACE_EXPRESSION_NOSE_WRINKLER_R_FB = 56, + XR_FACE_EXPRESSION_OUTER_BROW_RAISER_L_FB = 57, + XR_FACE_EXPRESSION_OUTER_BROW_RAISER_R_FB = 58, + XR_FACE_EXPRESSION_UPPER_LID_RAISER_L_FB = 59, + XR_FACE_EXPRESSION_UPPER_LID_RAISER_R_FB = 60, + XR_FACE_EXPRESSION_UPPER_LIP_RAISER_L_FB = 61, + XR_FACE_EXPRESSION_UPPER_LIP_RAISER_R_FB = 62, + XR_FACE_EXPRESSION_COUNT_FB = 63, + XR_FACE_EXPRESSION_MAX_ENUM_FB = 0x7FFFFFFF +} XrFaceExpressionFB; + +typedef enum XrFaceExpressionSetFB { + XR_FACE_EXPRESSION_SET_DEFAULT_FB = 0, + XR_FACE_EXPRESSION_SET_MAX_ENUM_FB = 0x7FFFFFFF +} XrFaceExpressionSetFB; + +typedef enum XrFaceConfidenceFB { + XR_FACE_CONFIDENCE_LOWER_FACE_FB = 0, + XR_FACE_CONFIDENCE_UPPER_FACE_FB = 1, + XR_FACE_CONFIDENCE_COUNT_FB = 2, + XR_FACE_CONFIDENCE_MAX_ENUM_FB = 0x7FFFFFFF +} XrFaceConfidenceFB; +// XrSystemFaceTrackingPropertiesFB extends XrSystemProperties +typedef struct XrSystemFaceTrackingPropertiesFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrBool32 supportsFaceTracking; +} XrSystemFaceTrackingPropertiesFB; + +typedef struct XrFaceTrackerCreateInfoFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrFaceExpressionSetFB faceExpressionSet; +} XrFaceTrackerCreateInfoFB; + +typedef struct XrFaceExpressionInfoFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrTime time; +} XrFaceExpressionInfoFB; + +typedef struct XrFaceExpressionStatusFB { + XrBool32 isValid; + XrBool32 isEyeFollowingBlendshapesValid; +} XrFaceExpressionStatusFB; + +typedef struct XrFaceExpressionWeightsFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint32_t weightCount; + float* weights; + uint32_t confidenceCount; + float* confidences; + XrFaceExpressionStatusFB status; + XrTime time; +} XrFaceExpressionWeightsFB; + +typedef XrResult (XRAPI_PTR *PFN_xrCreateFaceTrackerFB)(XrSession session, const XrFaceTrackerCreateInfoFB* createInfo, XrFaceTrackerFB* faceTracker); +typedef XrResult (XRAPI_PTR *PFN_xrDestroyFaceTrackerFB)(XrFaceTrackerFB faceTracker); +typedef XrResult (XRAPI_PTR *PFN_xrGetFaceExpressionWeightsFB)(XrFaceTrackerFB faceTracker, const XrFaceExpressionInfoFB* expressionInfo, XrFaceExpressionWeightsFB* expressionWeights); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrCreateFaceTrackerFB( + XrSession session, + const XrFaceTrackerCreateInfoFB* createInfo, + XrFaceTrackerFB* faceTracker); + +XRAPI_ATTR XrResult XRAPI_CALL xrDestroyFaceTrackerFB( + XrFaceTrackerFB faceTracker); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetFaceExpressionWeightsFB( + XrFaceTrackerFB faceTracker, + const XrFaceExpressionInfoFB* expressionInfo, + XrFaceExpressionWeightsFB* expressionWeights); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_FB_eye_tracking_social 1 +XR_DEFINE_HANDLE(XrEyeTrackerFB) +#define XR_FB_eye_tracking_social_SPEC_VERSION 1 +#define XR_FB_EYE_TRACKING_SOCIAL_EXTENSION_NAME "XR_FB_eye_tracking_social" + +typedef enum XrEyePositionFB { + XR_EYE_POSITION_LEFT_FB = 0, + XR_EYE_POSITION_RIGHT_FB = 1, + XR_EYE_POSITION_COUNT_FB = 2, + XR_EYE_POSITION_MAX_ENUM_FB = 0x7FFFFFFF +} XrEyePositionFB; +typedef struct XrEyeGazeFB { + XrBool32 isValid; + XrPosef gazePose; + float gazeConfidence; +} XrEyeGazeFB; + +typedef struct XrEyeTrackerCreateInfoFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; +} XrEyeTrackerCreateInfoFB; + +typedef struct XrEyeGazesInfoFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSpace baseSpace; + XrTime time; +} XrEyeGazesInfoFB; + +// XrSystemEyeTrackingPropertiesFB extends XrSystemProperties +typedef struct XrSystemEyeTrackingPropertiesFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrBool32 supportsEyeTracking; +} XrSystemEyeTrackingPropertiesFB; + +typedef struct XrEyeGazesFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrEyeGazeFB gaze[XR_EYE_POSITION_COUNT_FB]; + XrTime time; +} XrEyeGazesFB; + +typedef XrResult (XRAPI_PTR *PFN_xrCreateEyeTrackerFB)(XrSession session, const XrEyeTrackerCreateInfoFB* createInfo, XrEyeTrackerFB* eyeTracker); +typedef XrResult (XRAPI_PTR *PFN_xrDestroyEyeTrackerFB)(XrEyeTrackerFB eyeTracker); +typedef XrResult (XRAPI_PTR *PFN_xrGetEyeGazesFB)(XrEyeTrackerFB eyeTracker, const XrEyeGazesInfoFB* gazeInfo, XrEyeGazesFB* eyeGazes); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrCreateEyeTrackerFB( + XrSession session, + const XrEyeTrackerCreateInfoFB* createInfo, + XrEyeTrackerFB* eyeTracker); + +XRAPI_ATTR XrResult XRAPI_CALL xrDestroyEyeTrackerFB( + XrEyeTrackerFB eyeTracker); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetEyeGazesFB( + XrEyeTrackerFB eyeTracker, + const XrEyeGazesInfoFB* gazeInfo, + XrEyeGazesFB* eyeGazes); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_FB_passthrough_keyboard_hands 1 +#define XR_FB_passthrough_keyboard_hands_SPEC_VERSION 2 +#define XR_FB_PASSTHROUGH_KEYBOARD_HANDS_EXTENSION_NAME "XR_FB_passthrough_keyboard_hands" +typedef struct XrPassthroughKeyboardHandsIntensityFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + float leftHandIntensity; + float rightHandIntensity; +} XrPassthroughKeyboardHandsIntensityFB; + +typedef XrResult (XRAPI_PTR *PFN_xrPassthroughLayerSetKeyboardHandsIntensityFB)(XrPassthroughLayerFB layer, const XrPassthroughKeyboardHandsIntensityFB* intensity); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrPassthroughLayerSetKeyboardHandsIntensityFB( + XrPassthroughLayerFB layer, + const XrPassthroughKeyboardHandsIntensityFB* intensity); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_FB_composition_layer_settings 1 +#define XR_FB_composition_layer_settings_SPEC_VERSION 1 +#define XR_FB_COMPOSITION_LAYER_SETTINGS_EXTENSION_NAME "XR_FB_composition_layer_settings" +typedef XrFlags64 XrCompositionLayerSettingsFlagsFB; + +// Flag bits for XrCompositionLayerSettingsFlagsFB +static const XrCompositionLayerSettingsFlagsFB XR_COMPOSITION_LAYER_SETTINGS_NORMAL_SUPER_SAMPLING_BIT_FB = 0x00000001; +static const XrCompositionLayerSettingsFlagsFB XR_COMPOSITION_LAYER_SETTINGS_QUALITY_SUPER_SAMPLING_BIT_FB = 0x00000002; +static const XrCompositionLayerSettingsFlagsFB XR_COMPOSITION_LAYER_SETTINGS_NORMAL_SHARPENING_BIT_FB = 0x00000004; +static const XrCompositionLayerSettingsFlagsFB XR_COMPOSITION_LAYER_SETTINGS_QUALITY_SHARPENING_BIT_FB = 0x00000008; + +// XrCompositionLayerSettingsFB extends XrCompositionLayerBaseHeader +typedef struct XrCompositionLayerSettingsFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrCompositionLayerSettingsFlagsFB layerFlags; +} XrCompositionLayerSettingsFB; + + + +#define XR_FB_touch_controller_proximity 1 +#define XR_FB_touch_controller_proximity_SPEC_VERSION 1 +#define XR_FB_TOUCH_CONTROLLER_PROXIMITY_EXTENSION_NAME "XR_FB_touch_controller_proximity" + + +#define XR_FB_haptic_pcm 1 + +#define XR_MAX_HAPTIC_PCM_BUFFER_SIZE_FB 4000 + +#define XR_FB_haptic_pcm_SPEC_VERSION 1 +#define XR_FB_HAPTIC_PCM_EXTENSION_NAME "XR_FB_haptic_pcm" +typedef struct XrHapticPcmVibrationFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + uint32_t bufferSize; + const float* buffer; + float sampleRate; + XrBool32 append; + uint32_t* samplesConsumed; +} XrHapticPcmVibrationFB; + +typedef struct XrDevicePcmSampleRateStateFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + float sampleRate; +} XrDevicePcmSampleRateStateFB; + +typedef XrDevicePcmSampleRateStateFB XrDevicePcmSampleRateGetInfoFB; + +typedef XrResult (XRAPI_PTR *PFN_xrGetDeviceSampleRateFB)(XrSession session, const XrHapticActionInfo* hapticActionInfo, XrDevicePcmSampleRateGetInfoFB* deviceSampleRate); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrGetDeviceSampleRateFB( + XrSession session, + const XrHapticActionInfo* hapticActionInfo, + XrDevicePcmSampleRateGetInfoFB* deviceSampleRate); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_FB_composition_layer_depth_test 1 +#define XR_FB_composition_layer_depth_test_SPEC_VERSION 1 +#define XR_FB_COMPOSITION_LAYER_DEPTH_TEST_EXTENSION_NAME "XR_FB_composition_layer_depth_test" + +typedef enum XrCompareOpFB { + XR_COMPARE_OP_NEVER_FB = 0, + XR_COMPARE_OP_LESS_FB = 1, + XR_COMPARE_OP_EQUAL_FB = 2, + XR_COMPARE_OP_LESS_OR_EQUAL_FB = 3, + XR_COMPARE_OP_GREATER_FB = 4, + XR_COMPARE_OP_NOT_EQUAL_FB = 5, + XR_COMPARE_OP_GREATER_OR_EQUAL_FB = 6, + XR_COMPARE_OP_ALWAYS_FB = 7, + XR_COMPARE_OP_MAX_ENUM_FB = 0x7FFFFFFF +} XrCompareOpFB; +// XrCompositionLayerDepthTestFB extends XrCompositionLayerBaseHeader +typedef struct XrCompositionLayerDepthTestFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrBool32 depthMask; + XrCompareOpFB compareOp; +} XrCompositionLayerDepthTestFB; + + + +#define XR_META_local_dimming 1 +#define XR_META_local_dimming_SPEC_VERSION 1 +#define XR_META_LOCAL_DIMMING_EXTENSION_NAME "XR_META_local_dimming" + +typedef enum XrLocalDimmingModeMETA { + XR_LOCAL_DIMMING_MODE_OFF_META = 0, + XR_LOCAL_DIMMING_MODE_ON_META = 1, + XR_LOCAL_DIMMING_MODE_MAX_ENUM_META = 0x7FFFFFFF +} XrLocalDimmingModeMETA; +// XrLocalDimmingFrameEndInfoMETA extends XrFrameEndInfo +typedef struct XrLocalDimmingFrameEndInfoMETA { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrLocalDimmingModeMETA localDimmingMode; +} XrLocalDimmingFrameEndInfoMETA; + + + +#define XR_META_passthrough_preferences 1 +#define XR_META_passthrough_preferences_SPEC_VERSION 1 +#define XR_META_PASSTHROUGH_PREFERENCES_EXTENSION_NAME "XR_META_passthrough_preferences" +typedef XrFlags64 XrPassthroughPreferenceFlagsMETA; + +// Flag bits for XrPassthroughPreferenceFlagsMETA +static const XrPassthroughPreferenceFlagsMETA XR_PASSTHROUGH_PREFERENCE_DEFAULT_TO_ACTIVE_BIT_META = 0x00000001; + +typedef struct XrPassthroughPreferencesMETA { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrPassthroughPreferenceFlagsMETA flags; +} XrPassthroughPreferencesMETA; + +typedef XrResult (XRAPI_PTR *PFN_xrGetPassthroughPreferencesMETA)(XrSession session, XrPassthroughPreferencesMETA* preferences); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrGetPassthroughPreferencesMETA( + XrSession session, + XrPassthroughPreferencesMETA* preferences); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_META_virtual_keyboard 1 +XR_DEFINE_HANDLE(XrVirtualKeyboardMETA) +#define XR_MAX_VIRTUAL_KEYBOARD_COMMIT_TEXT_SIZE_META 3992 +#define XR_META_virtual_keyboard_SPEC_VERSION 1 +#define XR_META_VIRTUAL_KEYBOARD_EXTENSION_NAME "XR_META_virtual_keyboard" + +typedef enum XrVirtualKeyboardLocationTypeMETA { + XR_VIRTUAL_KEYBOARD_LOCATION_TYPE_CUSTOM_META = 0, + XR_VIRTUAL_KEYBOARD_LOCATION_TYPE_FAR_META = 1, + XR_VIRTUAL_KEYBOARD_LOCATION_TYPE_DIRECT_META = 2, + XR_VIRTUAL_KEYBOARD_LOCATION_TYPE_MAX_ENUM_META = 0x7FFFFFFF +} XrVirtualKeyboardLocationTypeMETA; + +typedef enum XrVirtualKeyboardInputSourceMETA { + XR_VIRTUAL_KEYBOARD_INPUT_SOURCE_CONTROLLER_RAY_LEFT_META = 1, + XR_VIRTUAL_KEYBOARD_INPUT_SOURCE_CONTROLLER_RAY_RIGHT_META = 2, + XR_VIRTUAL_KEYBOARD_INPUT_SOURCE_HAND_RAY_LEFT_META = 3, + XR_VIRTUAL_KEYBOARD_INPUT_SOURCE_HAND_RAY_RIGHT_META = 4, + XR_VIRTUAL_KEYBOARD_INPUT_SOURCE_CONTROLLER_DIRECT_LEFT_META = 5, + XR_VIRTUAL_KEYBOARD_INPUT_SOURCE_CONTROLLER_DIRECT_RIGHT_META = 6, + XR_VIRTUAL_KEYBOARD_INPUT_SOURCE_HAND_DIRECT_INDEX_TIP_LEFT_META = 7, + XR_VIRTUAL_KEYBOARD_INPUT_SOURCE_HAND_DIRECT_INDEX_TIP_RIGHT_META = 8, + XR_VIRTUAL_KEYBOARD_INPUT_SOURCE_MAX_ENUM_META = 0x7FFFFFFF +} XrVirtualKeyboardInputSourceMETA; +typedef XrFlags64 XrVirtualKeyboardInputStateFlagsMETA; + +// Flag bits for XrVirtualKeyboardInputStateFlagsMETA +static const XrVirtualKeyboardInputStateFlagsMETA XR_VIRTUAL_KEYBOARD_INPUT_STATE_PRESSED_BIT_META = 0x00000001; + +// XrSystemVirtualKeyboardPropertiesMETA extends XrSystemProperties +typedef struct XrSystemVirtualKeyboardPropertiesMETA { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrBool32 supportsVirtualKeyboard; +} XrSystemVirtualKeyboardPropertiesMETA; + +typedef struct XrVirtualKeyboardCreateInfoMETA { + XrStructureType type; + const void* XR_MAY_ALIAS next; +} XrVirtualKeyboardCreateInfoMETA; + +typedef struct XrVirtualKeyboardSpaceCreateInfoMETA { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrVirtualKeyboardLocationTypeMETA locationType; + XrSpace space; + XrPosef poseInSpace; +} XrVirtualKeyboardSpaceCreateInfoMETA; + +typedef struct XrVirtualKeyboardLocationInfoMETA { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrVirtualKeyboardLocationTypeMETA locationType; + XrSpace space; + XrPosef poseInSpace; + float scale; +} XrVirtualKeyboardLocationInfoMETA; + +typedef struct XrVirtualKeyboardModelVisibilitySetInfoMETA { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrBool32 visible; +} XrVirtualKeyboardModelVisibilitySetInfoMETA; + +typedef struct XrVirtualKeyboardAnimationStateMETA { + XrStructureType type; + void* XR_MAY_ALIAS next; + int32_t animationIndex; + float fraction; +} XrVirtualKeyboardAnimationStateMETA; + +typedef struct XrVirtualKeyboardModelAnimationStatesMETA { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint32_t stateCapacityInput; + uint32_t stateCountOutput; + XrVirtualKeyboardAnimationStateMETA* states; +} XrVirtualKeyboardModelAnimationStatesMETA; + +typedef struct XrVirtualKeyboardTextureDataMETA { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint32_t textureWidth; + uint32_t textureHeight; + uint32_t bufferCapacityInput; + uint32_t bufferCountOutput; + uint8_t* buffer; +} XrVirtualKeyboardTextureDataMETA; + +typedef struct XrVirtualKeyboardInputInfoMETA { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrVirtualKeyboardInputSourceMETA inputSource; + XrSpace inputSpace; + XrPosef inputPoseInSpace; + XrVirtualKeyboardInputStateFlagsMETA inputState; +} XrVirtualKeyboardInputInfoMETA; + +typedef struct XrVirtualKeyboardTextContextChangeInfoMETA { + XrStructureType type; + const void* XR_MAY_ALIAS next; + const char* textContext; +} XrVirtualKeyboardTextContextChangeInfoMETA; + +typedef struct XrEventDataVirtualKeyboardCommitTextMETA { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrVirtualKeyboardMETA keyboard; + char text[XR_MAX_VIRTUAL_KEYBOARD_COMMIT_TEXT_SIZE_META]; +} XrEventDataVirtualKeyboardCommitTextMETA; + +typedef struct XrEventDataVirtualKeyboardBackspaceMETA { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrVirtualKeyboardMETA keyboard; +} XrEventDataVirtualKeyboardBackspaceMETA; + +typedef struct XrEventDataVirtualKeyboardEnterMETA { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrVirtualKeyboardMETA keyboard; +} XrEventDataVirtualKeyboardEnterMETA; + +typedef struct XrEventDataVirtualKeyboardShownMETA { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrVirtualKeyboardMETA keyboard; +} XrEventDataVirtualKeyboardShownMETA; + +typedef struct XrEventDataVirtualKeyboardHiddenMETA { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrVirtualKeyboardMETA keyboard; +} XrEventDataVirtualKeyboardHiddenMETA; + +typedef XrResult (XRAPI_PTR *PFN_xrCreateVirtualKeyboardMETA)(XrSession session, const XrVirtualKeyboardCreateInfoMETA* createInfo, XrVirtualKeyboardMETA* keyboard); +typedef XrResult (XRAPI_PTR *PFN_xrDestroyVirtualKeyboardMETA)(XrVirtualKeyboardMETA keyboard); +typedef XrResult (XRAPI_PTR *PFN_xrCreateVirtualKeyboardSpaceMETA)(XrSession session, XrVirtualKeyboardMETA keyboard, const XrVirtualKeyboardSpaceCreateInfoMETA* createInfo, XrSpace* keyboardSpace); +typedef XrResult (XRAPI_PTR *PFN_xrSuggestVirtualKeyboardLocationMETA)(XrVirtualKeyboardMETA keyboard, const XrVirtualKeyboardLocationInfoMETA* locationInfo); +typedef XrResult (XRAPI_PTR *PFN_xrGetVirtualKeyboardScaleMETA)(XrVirtualKeyboardMETA keyboard, float* scale); +typedef XrResult (XRAPI_PTR *PFN_xrSetVirtualKeyboardModelVisibilityMETA)(XrVirtualKeyboardMETA keyboard, const XrVirtualKeyboardModelVisibilitySetInfoMETA* modelVisibility); +typedef XrResult (XRAPI_PTR *PFN_xrGetVirtualKeyboardModelAnimationStatesMETA)(XrVirtualKeyboardMETA keyboard, XrVirtualKeyboardModelAnimationStatesMETA* animationStates); +typedef XrResult (XRAPI_PTR *PFN_xrGetVirtualKeyboardDirtyTexturesMETA)(XrVirtualKeyboardMETA keyboard, uint32_t textureIdCapacityInput, uint32_t* textureIdCountOutput, uint64_t* textureIds); +typedef XrResult (XRAPI_PTR *PFN_xrGetVirtualKeyboardTextureDataMETA)(XrVirtualKeyboardMETA keyboard, uint64_t textureId, XrVirtualKeyboardTextureDataMETA* textureData); +typedef XrResult (XRAPI_PTR *PFN_xrSendVirtualKeyboardInputMETA)(XrVirtualKeyboardMETA keyboard, const XrVirtualKeyboardInputInfoMETA* info, XrPosef* interactorRootPose); +typedef XrResult (XRAPI_PTR *PFN_xrChangeVirtualKeyboardTextContextMETA)(XrVirtualKeyboardMETA keyboard, const XrVirtualKeyboardTextContextChangeInfoMETA* changeInfo); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrCreateVirtualKeyboardMETA( + XrSession session, + const XrVirtualKeyboardCreateInfoMETA* createInfo, + XrVirtualKeyboardMETA* keyboard); + +XRAPI_ATTR XrResult XRAPI_CALL xrDestroyVirtualKeyboardMETA( + XrVirtualKeyboardMETA keyboard); + +XRAPI_ATTR XrResult XRAPI_CALL xrCreateVirtualKeyboardSpaceMETA( + XrSession session, + XrVirtualKeyboardMETA keyboard, + const XrVirtualKeyboardSpaceCreateInfoMETA* createInfo, + XrSpace* keyboardSpace); + +XRAPI_ATTR XrResult XRAPI_CALL xrSuggestVirtualKeyboardLocationMETA( + XrVirtualKeyboardMETA keyboard, + const XrVirtualKeyboardLocationInfoMETA* locationInfo); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetVirtualKeyboardScaleMETA( + XrVirtualKeyboardMETA keyboard, + float* scale); + +XRAPI_ATTR XrResult XRAPI_CALL xrSetVirtualKeyboardModelVisibilityMETA( + XrVirtualKeyboardMETA keyboard, + const XrVirtualKeyboardModelVisibilitySetInfoMETA* modelVisibility); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetVirtualKeyboardModelAnimationStatesMETA( + XrVirtualKeyboardMETA keyboard, + XrVirtualKeyboardModelAnimationStatesMETA* animationStates); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetVirtualKeyboardDirtyTexturesMETA( + XrVirtualKeyboardMETA keyboard, + uint32_t textureIdCapacityInput, + uint32_t* textureIdCountOutput, + uint64_t* textureIds); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetVirtualKeyboardTextureDataMETA( + XrVirtualKeyboardMETA keyboard, + uint64_t textureId, + XrVirtualKeyboardTextureDataMETA* textureData); + +XRAPI_ATTR XrResult XRAPI_CALL xrSendVirtualKeyboardInputMETA( + XrVirtualKeyboardMETA keyboard, + const XrVirtualKeyboardInputInfoMETA* info, + XrPosef* interactorRootPose); + +XRAPI_ATTR XrResult XRAPI_CALL xrChangeVirtualKeyboardTextContextMETA( + XrVirtualKeyboardMETA keyboard, + const XrVirtualKeyboardTextContextChangeInfoMETA* changeInfo); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_OCULUS_external_camera 1 +#define XR_MAX_EXTERNAL_CAMERA_NAME_SIZE_OCULUS 32 +#define XR_OCULUS_external_camera_SPEC_VERSION 1 +#define XR_OCULUS_EXTERNAL_CAMERA_EXTENSION_NAME "XR_OCULUS_external_camera" + +typedef enum XrExternalCameraAttachedToDeviceOCULUS { + XR_EXTERNAL_CAMERA_ATTACHED_TO_DEVICE_NONE_OCULUS = 0, + XR_EXTERNAL_CAMERA_ATTACHED_TO_DEVICE_HMD_OCULUS = 1, + XR_EXTERNAL_CAMERA_ATTACHED_TO_DEVICE_LTOUCH_OCULUS = 2, + XR_EXTERNAL_CAMERA_ATTACHED_TO_DEVICE_RTOUCH_OCULUS = 3, + XR_EXTERNAL_CAMERA_ATTACHED_TO_DEVICE_MAX_ENUM_OCULUS = 0x7FFFFFFF +} XrExternalCameraAttachedToDeviceOCULUS; +typedef XrFlags64 XrExternalCameraStatusFlagsOCULUS; + +// Flag bits for XrExternalCameraStatusFlagsOCULUS +static const XrExternalCameraStatusFlagsOCULUS XR_EXTERNAL_CAMERA_STATUS_CONNECTED_BIT_OCULUS = 0x00000001; +static const XrExternalCameraStatusFlagsOCULUS XR_EXTERNAL_CAMERA_STATUS_CALIBRATING_BIT_OCULUS = 0x00000002; +static const XrExternalCameraStatusFlagsOCULUS XR_EXTERNAL_CAMERA_STATUS_CALIBRATION_FAILED_BIT_OCULUS = 0x00000004; +static const XrExternalCameraStatusFlagsOCULUS XR_EXTERNAL_CAMERA_STATUS_CALIBRATED_BIT_OCULUS = 0x00000008; +static const XrExternalCameraStatusFlagsOCULUS XR_EXTERNAL_CAMERA_STATUS_CAPTURING_BIT_OCULUS = 0x00000010; + +typedef struct XrExternalCameraIntrinsicsOCULUS { + XrTime lastChangeTime; + XrFovf fov; + float virtualNearPlaneDistance; + float virtualFarPlaneDistance; + XrExtent2Di imageSensorPixelResolution; +} XrExternalCameraIntrinsicsOCULUS; + +typedef struct XrExternalCameraExtrinsicsOCULUS { + XrTime lastChangeTime; + XrExternalCameraStatusFlagsOCULUS cameraStatusFlags; + XrExternalCameraAttachedToDeviceOCULUS attachedToDevice; + XrPosef relativePose; +} XrExternalCameraExtrinsicsOCULUS; + +typedef struct XrExternalCameraOCULUS { + XrStructureType type; + const void* XR_MAY_ALIAS next; + char name[XR_MAX_EXTERNAL_CAMERA_NAME_SIZE_OCULUS]; + XrExternalCameraIntrinsicsOCULUS intrinsics; + XrExternalCameraExtrinsicsOCULUS extrinsics; +} XrExternalCameraOCULUS; + +typedef XrResult (XRAPI_PTR *PFN_xrEnumerateExternalCamerasOCULUS)(XrSession session, uint32_t cameraCapacityInput, uint32_t* cameraCountOutput, XrExternalCameraOCULUS* cameras); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateExternalCamerasOCULUS( + XrSession session, + uint32_t cameraCapacityInput, + uint32_t* cameraCountOutput, + XrExternalCameraOCULUS* cameras); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_META_performance_metrics 1 +#define XR_META_performance_metrics_SPEC_VERSION 2 +#define XR_META_PERFORMANCE_METRICS_EXTENSION_NAME "XR_META_performance_metrics" + +typedef enum XrPerformanceMetricsCounterUnitMETA { + XR_PERFORMANCE_METRICS_COUNTER_UNIT_GENERIC_META = 0, + XR_PERFORMANCE_METRICS_COUNTER_UNIT_PERCENTAGE_META = 1, + XR_PERFORMANCE_METRICS_COUNTER_UNIT_MILLISECONDS_META = 2, + XR_PERFORMANCE_METRICS_COUNTER_UNIT_BYTES_META = 3, + XR_PERFORMANCE_METRICS_COUNTER_UNIT_HERTZ_META = 4, + XR_PERFORMANCE_METRICS_COUNTER_UNIT_MAX_ENUM_META = 0x7FFFFFFF +} XrPerformanceMetricsCounterUnitMETA; +typedef XrFlags64 XrPerformanceMetricsCounterFlagsMETA; + +// Flag bits for XrPerformanceMetricsCounterFlagsMETA +static const XrPerformanceMetricsCounterFlagsMETA XR_PERFORMANCE_METRICS_COUNTER_ANY_VALUE_VALID_BIT_META = 0x00000001; +static const XrPerformanceMetricsCounterFlagsMETA XR_PERFORMANCE_METRICS_COUNTER_UINT_VALUE_VALID_BIT_META = 0x00000002; +static const XrPerformanceMetricsCounterFlagsMETA XR_PERFORMANCE_METRICS_COUNTER_FLOAT_VALUE_VALID_BIT_META = 0x00000004; + +typedef struct XrPerformanceMetricsStateMETA { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrBool32 enabled; +} XrPerformanceMetricsStateMETA; + +typedef struct XrPerformanceMetricsCounterMETA { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrPerformanceMetricsCounterFlagsMETA counterFlags; + XrPerformanceMetricsCounterUnitMETA counterUnit; + uint32_t uintValue; + float floatValue; +} XrPerformanceMetricsCounterMETA; + +typedef XrResult (XRAPI_PTR *PFN_xrEnumeratePerformanceMetricsCounterPathsMETA)(XrInstance instance, uint32_t counterPathCapacityInput, uint32_t* counterPathCountOutput, XrPath* counterPaths); +typedef XrResult (XRAPI_PTR *PFN_xrSetPerformanceMetricsStateMETA)(XrSession session, const XrPerformanceMetricsStateMETA* state); +typedef XrResult (XRAPI_PTR *PFN_xrGetPerformanceMetricsStateMETA)(XrSession session, XrPerformanceMetricsStateMETA* state); +typedef XrResult (XRAPI_PTR *PFN_xrQueryPerformanceMetricsCounterMETA)(XrSession session, XrPath counterPath, XrPerformanceMetricsCounterMETA* counter); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrEnumeratePerformanceMetricsCounterPathsMETA( + XrInstance instance, + uint32_t counterPathCapacityInput, + uint32_t* counterPathCountOutput, + XrPath* counterPaths); + +XRAPI_ATTR XrResult XRAPI_CALL xrSetPerformanceMetricsStateMETA( + XrSession session, + const XrPerformanceMetricsStateMETA* state); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetPerformanceMetricsStateMETA( + XrSession session, + XrPerformanceMetricsStateMETA* state); + +XRAPI_ATTR XrResult XRAPI_CALL xrQueryPerformanceMetricsCounterMETA( + XrSession session, + XrPath counterPath, + XrPerformanceMetricsCounterMETA* counter); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_FB_spatial_entity_storage_batch 1 +#define XR_FB_spatial_entity_storage_batch_SPEC_VERSION 1 +#define XR_FB_SPATIAL_ENTITY_STORAGE_BATCH_EXTENSION_NAME "XR_FB_spatial_entity_storage_batch" +typedef struct XrSpaceListSaveInfoFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + uint32_t spaceCount; + XrSpace* spaces; + XrSpaceStorageLocationFB location; +} XrSpaceListSaveInfoFB; + +typedef struct XrEventDataSpaceListSaveCompleteFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrAsyncRequestIdFB requestId; + XrResult result; +} XrEventDataSpaceListSaveCompleteFB; + +typedef XrResult (XRAPI_PTR *PFN_xrSaveSpaceListFB)(XrSession session, const XrSpaceListSaveInfoFB* info, XrAsyncRequestIdFB* requestId); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrSaveSpaceListFB( + XrSession session, + const XrSpaceListSaveInfoFB* info, + XrAsyncRequestIdFB* requestId); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_FB_spatial_entity_user 1 +typedef uint64_t XrSpaceUserIdFB; +#define XR_FB_spatial_entity_user_SPEC_VERSION 1 +#define XR_FB_SPATIAL_ENTITY_USER_EXTENSION_NAME "XR_FB_spatial_entity_user" +typedef struct XrSpaceUserCreateInfoFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSpaceUserIdFB userId; +} XrSpaceUserCreateInfoFB; + +typedef XrResult (XRAPI_PTR *PFN_xrCreateSpaceUserFB)(XrSession session, const XrSpaceUserCreateInfoFB* info, XrSpaceUserFB* user); +typedef XrResult (XRAPI_PTR *PFN_xrGetSpaceUserIdFB)(XrSpaceUserFB user, XrSpaceUserIdFB* userId); +typedef XrResult (XRAPI_PTR *PFN_xrDestroySpaceUserFB)(XrSpaceUserFB user); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrCreateSpaceUserFB( + XrSession session, + const XrSpaceUserCreateInfoFB* info, + XrSpaceUserFB* user); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetSpaceUserIdFB( + XrSpaceUserFB user, + XrSpaceUserIdFB* userId); + +XRAPI_ATTR XrResult XRAPI_CALL xrDestroySpaceUserFB( + XrSpaceUserFB user); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_META_headset_id 1 +#define XR_META_headset_id_SPEC_VERSION 1 +#define XR_META_HEADSET_ID_EXTENSION_NAME "XR_META_headset_id" +// XrSystemHeadsetIdPropertiesMETA extends XrSystemProperties +typedef struct XrSystemHeadsetIdPropertiesMETA { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrUuidEXT id; +} XrSystemHeadsetIdPropertiesMETA; + + + +#define XR_META_passthrough_color_lut 1 +XR_DEFINE_HANDLE(XrPassthroughColorLutMETA) +#define XR_META_passthrough_color_lut_SPEC_VERSION 1 +#define XR_META_PASSTHROUGH_COLOR_LUT_EXTENSION_NAME "XR_META_passthrough_color_lut" + +typedef enum XrPassthroughColorLutChannelsMETA { + XR_PASSTHROUGH_COLOR_LUT_CHANNELS_RGB_META = 1, + XR_PASSTHROUGH_COLOR_LUT_CHANNELS_RGBA_META = 2, + XR_PASSTHROUGH_COLOR_LUT_CHANNELS_MAX_ENUM_META = 0x7FFFFFFF +} XrPassthroughColorLutChannelsMETA; +typedef struct XrPassthroughColorLutDataMETA { + uint32_t bufferSize; + const uint8_t* buffer; +} XrPassthroughColorLutDataMETA; + +typedef struct XrPassthroughColorLutCreateInfoMETA { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrPassthroughColorLutChannelsMETA channels; + uint32_t resolution; + XrPassthroughColorLutDataMETA data; +} XrPassthroughColorLutCreateInfoMETA; + +typedef struct XrPassthroughColorLutUpdateInfoMETA { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrPassthroughColorLutDataMETA data; +} XrPassthroughColorLutUpdateInfoMETA; + +// XrPassthroughColorMapLutMETA extends XrPassthroughStyleFB +typedef struct XrPassthroughColorMapLutMETA { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrPassthroughColorLutMETA colorLut; + float weight; +} XrPassthroughColorMapLutMETA; + +// XrPassthroughColorMapInterpolatedLutMETA extends XrPassthroughStyleFB +typedef struct XrPassthroughColorMapInterpolatedLutMETA { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrPassthroughColorLutMETA sourceColorLut; + XrPassthroughColorLutMETA targetColorLut; + float weight; +} XrPassthroughColorMapInterpolatedLutMETA; + +// XrSystemPassthroughColorLutPropertiesMETA extends XrSystemProperties +typedef struct XrSystemPassthroughColorLutPropertiesMETA { + XrStructureType type; + const void* XR_MAY_ALIAS next; + uint32_t maxColorLutResolution; +} XrSystemPassthroughColorLutPropertiesMETA; + +typedef XrResult (XRAPI_PTR *PFN_xrCreatePassthroughColorLutMETA)(XrPassthroughFB passthrough, const XrPassthroughColorLutCreateInfoMETA* createInfo, XrPassthroughColorLutMETA* colorLut); +typedef XrResult (XRAPI_PTR *PFN_xrDestroyPassthroughColorLutMETA)(XrPassthroughColorLutMETA colorLut); +typedef XrResult (XRAPI_PTR *PFN_xrUpdatePassthroughColorLutMETA)(XrPassthroughColorLutMETA colorLut, const XrPassthroughColorLutUpdateInfoMETA* updateInfo); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrCreatePassthroughColorLutMETA( + XrPassthroughFB passthrough, + const XrPassthroughColorLutCreateInfoMETA* createInfo, + XrPassthroughColorLutMETA* colorLut); + +XRAPI_ATTR XrResult XRAPI_CALL xrDestroyPassthroughColorLutMETA( + XrPassthroughColorLutMETA colorLut); + +XRAPI_ATTR XrResult XRAPI_CALL xrUpdatePassthroughColorLutMETA( + XrPassthroughColorLutMETA colorLut, + const XrPassthroughColorLutUpdateInfoMETA* updateInfo); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_EXT_uuid 1 +#define XR_EXT_uuid_SPEC_VERSION 1 +#define XR_EXT_UUID_EXTENSION_NAME "XR_EXT_uuid" + + +#define XR_EXT_hand_interaction 1 +#define XR_EXT_hand_interaction_SPEC_VERSION 1 +#define XR_EXT_HAND_INTERACTION_EXTENSION_NAME "XR_EXT_hand_interaction" + + +#define XR_QCOM_tracking_optimization_settings 1 +#define XR_QCOM_tracking_optimization_settings_SPEC_VERSION 1 +#define XR_QCOM_TRACKING_OPTIMIZATION_SETTINGS_EXTENSION_NAME "XR_QCOM_tracking_optimization_settings" + +typedef enum XrTrackingOptimizationSettingsDomainQCOM { + XR_TRACKING_OPTIMIZATION_SETTINGS_DOMAIN_ALL_QCOM = 1, + XR_TRACKING_OPTIMIZATION_SETTINGS_DOMAIN_MAX_ENUM_QCOM = 0x7FFFFFFF +} XrTrackingOptimizationSettingsDomainQCOM; + +typedef enum XrTrackingOptimizationSettingsHintQCOM { + XR_TRACKING_OPTIMIZATION_SETTINGS_HINT_NONE_QCOM = 0, + XR_TRACKING_OPTIMIZATION_SETTINGS_HINT_LONG_RANGE_PRIORIZATION_QCOM = 1, + XR_TRACKING_OPTIMIZATION_SETTINGS_HINT_CLOSE_RANGE_PRIORIZATION_QCOM = 2, + XR_TRACKING_OPTIMIZATION_SETTINGS_HINT_LOW_POWER_PRIORIZATION_QCOM = 3, + XR_TRACKING_OPTIMIZATION_SETTINGS_HINT_HIGH_POWER_PRIORIZATION_QCOM = 4, + XR_TRACKING_OPTIMIZATION_SETTINGS_HINT_MAX_ENUM_QCOM = 0x7FFFFFFF +} XrTrackingOptimizationSettingsHintQCOM; +typedef XrResult (XRAPI_PTR *PFN_xrSetTrackingOptimizationSettingsHintQCOM)(XrSession session, XrTrackingOptimizationSettingsDomainQCOM domain, XrTrackingOptimizationSettingsHintQCOM hint); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrSetTrackingOptimizationSettingsHintQCOM( + XrSession session, + XrTrackingOptimizationSettingsDomainQCOM domain, + XrTrackingOptimizationSettingsHintQCOM hint); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_HTC_passthrough 1 +XR_DEFINE_HANDLE(XrPassthroughHTC) +#define XR_HTC_passthrough_SPEC_VERSION 1 +#define XR_HTC_PASSTHROUGH_EXTENSION_NAME "XR_HTC_passthrough" + +typedef enum XrPassthroughFormHTC { + XR_PASSTHROUGH_FORM_PLANAR_HTC = 0, + XR_PASSTHROUGH_FORM_PROJECTED_HTC = 1, + XR_PASSTHROUGH_FORM_MAX_ENUM_HTC = 0x7FFFFFFF +} XrPassthroughFormHTC; +typedef struct XrPassthroughCreateInfoHTC { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrPassthroughFormHTC form; +} XrPassthroughCreateInfoHTC; + +typedef struct XrPassthroughColorHTC { + XrStructureType type; + const void* XR_MAY_ALIAS next; + float alpha; +} XrPassthroughColorHTC; + +// XrPassthroughMeshTransformInfoHTC extends XrCompositionLayerPassthroughHTC +typedef struct XrPassthroughMeshTransformInfoHTC { + XrStructureType type; + const void* XR_MAY_ALIAS next; + uint32_t vertexCount; + const XrVector3f* vertices; + uint32_t indexCount; + const uint32_t* indices; + XrSpace baseSpace; + XrTime time; + XrPosef pose; + XrVector3f scale; +} XrPassthroughMeshTransformInfoHTC; + +typedef struct XrCompositionLayerPassthroughHTC { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrCompositionLayerFlags layerFlags; + XrSpace space; + XrPassthroughHTC passthrough; + XrPassthroughColorHTC color; +} XrCompositionLayerPassthroughHTC; + +typedef XrResult (XRAPI_PTR *PFN_xrCreatePassthroughHTC)(XrSession session, const XrPassthroughCreateInfoHTC* createInfo, XrPassthroughHTC* passthrough); +typedef XrResult (XRAPI_PTR *PFN_xrDestroyPassthroughHTC)(XrPassthroughHTC passthrough); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrCreatePassthroughHTC( + XrSession session, + const XrPassthroughCreateInfoHTC* createInfo, + XrPassthroughHTC* passthrough); + +XRAPI_ATTR XrResult XRAPI_CALL xrDestroyPassthroughHTC( + XrPassthroughHTC passthrough); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_HTC_foveation 1 +#define XR_HTC_foveation_SPEC_VERSION 1 +#define XR_HTC_FOVEATION_EXTENSION_NAME "XR_HTC_foveation" + +typedef enum XrFoveationModeHTC { + XR_FOVEATION_MODE_DISABLE_HTC = 0, + XR_FOVEATION_MODE_FIXED_HTC = 1, + XR_FOVEATION_MODE_DYNAMIC_HTC = 2, + XR_FOVEATION_MODE_CUSTOM_HTC = 3, + XR_FOVEATION_MODE_MAX_ENUM_HTC = 0x7FFFFFFF +} XrFoveationModeHTC; + +typedef enum XrFoveationLevelHTC { + XR_FOVEATION_LEVEL_NONE_HTC = 0, + XR_FOVEATION_LEVEL_LOW_HTC = 1, + XR_FOVEATION_LEVEL_MEDIUM_HTC = 2, + XR_FOVEATION_LEVEL_HIGH_HTC = 3, + XR_FOVEATION_LEVEL_MAX_ENUM_HTC = 0x7FFFFFFF +} XrFoveationLevelHTC; +typedef XrFlags64 XrFoveationDynamicFlagsHTC; + +// Flag bits for XrFoveationDynamicFlagsHTC +static const XrFoveationDynamicFlagsHTC XR_FOVEATION_DYNAMIC_LEVEL_ENABLED_BIT_HTC = 0x00000001; +static const XrFoveationDynamicFlagsHTC XR_FOVEATION_DYNAMIC_CLEAR_FOV_ENABLED_BIT_HTC = 0x00000002; +static const XrFoveationDynamicFlagsHTC XR_FOVEATION_DYNAMIC_FOCAL_CENTER_OFFSET_ENABLED_BIT_HTC = 0x00000004; + +typedef struct XrFoveationApplyInfoHTC { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrFoveationModeHTC mode; + uint32_t subImageCount; + XrSwapchainSubImage* subImages; +} XrFoveationApplyInfoHTC; + +typedef struct XrFoveationConfigurationHTC { + XrFoveationLevelHTC level; + float clearFovDegree; + XrVector2f focalCenterOffset; +} XrFoveationConfigurationHTC; + +// XrFoveationDynamicModeInfoHTC extends XrFoveationApplyInfoHTC +typedef struct XrFoveationDynamicModeInfoHTC { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrFoveationDynamicFlagsHTC dynamicFlags; +} XrFoveationDynamicModeInfoHTC; + +// XrFoveationCustomModeInfoHTC extends XrFoveationApplyInfoHTC +typedef struct XrFoveationCustomModeInfoHTC { + XrStructureType type; + const void* XR_MAY_ALIAS next; + uint32_t configCount; + const XrFoveationConfigurationHTC* configs; +} XrFoveationCustomModeInfoHTC; + +typedef XrResult (XRAPI_PTR *PFN_xrApplyFoveationHTC)(XrSession session, const XrFoveationApplyInfoHTC* applyInfo); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrApplyFoveationHTC( + XrSession session, + const XrFoveationApplyInfoHTC* applyInfo); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_EXT_active_action_set_priority 1 +#define XR_EXT_active_action_set_priority_SPEC_VERSION 1 +#define XR_EXT_ACTIVE_ACTION_SET_PRIORITY_EXTENSION_NAME "XR_EXT_active_action_set_priority" +typedef struct XrActiveActionSetPriorityEXT { + XrActionSet actionSet; + uint32_t priorityOverride; +} XrActiveActionSetPriorityEXT; + +// XrActiveActionSetPrioritiesEXT extends XrActionsSyncInfo +typedef struct XrActiveActionSetPrioritiesEXT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + uint32_t actionSetPriorityCount; + const XrActiveActionSetPriorityEXT* actionSetPriorities; +} XrActiveActionSetPrioritiesEXT; + + + +#define XR_MNDX_force_feedback_curl 1 +#define XR_MNDX_force_feedback_curl_SPEC_VERSION 1 +#define XR_MNDX_FORCE_FEEDBACK_CURL_EXTENSION_NAME "XR_MNDX_force_feedback_curl" + +typedef enum XrForceFeedbackCurlLocationMNDX { + XR_FORCE_FEEDBACK_CURL_LOCATION_THUMB_CURL_MNDX = 0, + XR_FORCE_FEEDBACK_CURL_LOCATION_INDEX_CURL_MNDX = 1, + XR_FORCE_FEEDBACK_CURL_LOCATION_MIDDLE_CURL_MNDX = 2, + XR_FORCE_FEEDBACK_CURL_LOCATION_RING_CURL_MNDX = 3, + XR_FORCE_FEEDBACK_CURL_LOCATION_LITTLE_CURL_MNDX = 4, + XR_FORCE_FEEDBACK_CURL_LOCATION_MAX_ENUM_MNDX = 0x7FFFFFFF +} XrForceFeedbackCurlLocationMNDX; +// XrSystemForceFeedbackCurlPropertiesMNDX extends XrSystemProperties +typedef struct XrSystemForceFeedbackCurlPropertiesMNDX { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrBool32 supportsForceFeedbackCurl; +} XrSystemForceFeedbackCurlPropertiesMNDX; + +typedef struct XrForceFeedbackCurlApplyLocationMNDX { + XrForceFeedbackCurlLocationMNDX location; + float value; +} XrForceFeedbackCurlApplyLocationMNDX; + +typedef struct XrForceFeedbackCurlApplyLocationsMNDX { + XrStructureType type; + const void* XR_MAY_ALIAS next; + uint32_t locationCount; + XrForceFeedbackCurlApplyLocationMNDX* locations; +} XrForceFeedbackCurlApplyLocationsMNDX; + +typedef XrResult (XRAPI_PTR *PFN_xrApplyForceFeedbackCurlMNDX)(XrHandTrackerEXT handTracker, const XrForceFeedbackCurlApplyLocationsMNDX* locations); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrApplyForceFeedbackCurlMNDX( + XrHandTrackerEXT handTracker, + const XrForceFeedbackCurlApplyLocationsMNDX* locations); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_BD_controller_interaction 1 +#define XR_BD_controller_interaction_SPEC_VERSION 1 +#define XR_BD_CONTROLLER_INTERACTION_EXTENSION_NAME "XR_BD_controller_interaction" + + +#define XR_EXT_local_floor 1 +#define XR_EXT_local_floor_SPEC_VERSION 1 +#define XR_EXT_LOCAL_FLOOR_EXTENSION_NAME "XR_EXT_local_floor" + + +#define XR_EXT_hand_tracking_data_source 1 +#define XR_EXT_hand_tracking_data_source_SPEC_VERSION 1 +#define XR_EXT_HAND_TRACKING_DATA_SOURCE_EXTENSION_NAME "XR_EXT_hand_tracking_data_source" + +typedef enum XrHandTrackingDataSourceEXT { + XR_HAND_TRACKING_DATA_SOURCE_UNOBSTRUCTED_EXT = 1, + XR_HAND_TRACKING_DATA_SOURCE_CONTROLLER_EXT = 2, + XR_HAND_TRACKING_DATA_SOURCE_MAX_ENUM_EXT = 0x7FFFFFFF +} XrHandTrackingDataSourceEXT; +// XrHandTrackingDataSourceInfoEXT extends XrHandTrackerCreateInfoEXT +typedef struct XrHandTrackingDataSourceInfoEXT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + uint32_t requestedDataSourceCount; + XrHandTrackingDataSourceEXT* requestedDataSources; +} XrHandTrackingDataSourceInfoEXT; + +// XrHandTrackingDataSourceStateEXT extends XrHandJointLocationsEXT +typedef struct XrHandTrackingDataSourceStateEXT { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrBool32 isActive; + XrHandTrackingDataSourceEXT dataSource; +} XrHandTrackingDataSourceStateEXT; + + + +#define XR_EXT_plane_detection 1 +XR_DEFINE_HANDLE(XrPlaneDetectorEXT) +#define XR_EXT_plane_detection_SPEC_VERSION 1 +#define XR_EXT_PLANE_DETECTION_EXTENSION_NAME "XR_EXT_plane_detection" + +typedef enum XrPlaneDetectorOrientationEXT { + XR_PLANE_DETECTOR_ORIENTATION_HORIZONTAL_UPWARD_EXT = 0, + XR_PLANE_DETECTOR_ORIENTATION_HORIZONTAL_DOWNWARD_EXT = 1, + XR_PLANE_DETECTOR_ORIENTATION_VERTICAL_EXT = 2, + XR_PLANE_DETECTOR_ORIENTATION_ARBITRARY_EXT = 3, + XR_PLANE_DETECTOR_ORIENTATION_MAX_ENUM_EXT = 0x7FFFFFFF +} XrPlaneDetectorOrientationEXT; + +typedef enum XrPlaneDetectorSemanticTypeEXT { + XR_PLANE_DETECTOR_SEMANTIC_TYPE_UNDEFINED_EXT = 0, + XR_PLANE_DETECTOR_SEMANTIC_TYPE_CEILING_EXT = 1, + XR_PLANE_DETECTOR_SEMANTIC_TYPE_FLOOR_EXT = 2, + XR_PLANE_DETECTOR_SEMANTIC_TYPE_WALL_EXT = 3, + XR_PLANE_DETECTOR_SEMANTIC_TYPE_PLATFORM_EXT = 4, + XR_PLANE_DETECTOR_SEMANTIC_TYPE_MAX_ENUM_EXT = 0x7FFFFFFF +} XrPlaneDetectorSemanticTypeEXT; + +typedef enum XrPlaneDetectionStateEXT { + XR_PLANE_DETECTION_STATE_NONE_EXT = 0, + XR_PLANE_DETECTION_STATE_PENDING_EXT = 1, + XR_PLANE_DETECTION_STATE_DONE_EXT = 2, + XR_PLANE_DETECTION_STATE_ERROR_EXT = 3, + XR_PLANE_DETECTION_STATE_FATAL_EXT = 4, + XR_PLANE_DETECTION_STATE_MAX_ENUM_EXT = 0x7FFFFFFF +} XrPlaneDetectionStateEXT; +typedef XrFlags64 XrPlaneDetectionCapabilityFlagsEXT; + +// Flag bits for XrPlaneDetectionCapabilityFlagsEXT +static const XrPlaneDetectionCapabilityFlagsEXT XR_PLANE_DETECTION_CAPABILITY_PLANE_DETECTION_BIT_EXT = 0x00000001; +static const XrPlaneDetectionCapabilityFlagsEXT XR_PLANE_DETECTION_CAPABILITY_PLANE_HOLES_BIT_EXT = 0x00000002; +static const XrPlaneDetectionCapabilityFlagsEXT XR_PLANE_DETECTION_CAPABILITY_SEMANTIC_CEILING_BIT_EXT = 0x00000004; +static const XrPlaneDetectionCapabilityFlagsEXT XR_PLANE_DETECTION_CAPABILITY_SEMANTIC_FLOOR_BIT_EXT = 0x00000008; +static const XrPlaneDetectionCapabilityFlagsEXT XR_PLANE_DETECTION_CAPABILITY_SEMANTIC_WALL_BIT_EXT = 0x00000010; +static const XrPlaneDetectionCapabilityFlagsEXT XR_PLANE_DETECTION_CAPABILITY_SEMANTIC_PLATFORM_BIT_EXT = 0x00000020; +static const XrPlaneDetectionCapabilityFlagsEXT XR_PLANE_DETECTION_CAPABILITY_ORIENTATION_BIT_EXT = 0x00000040; + +typedef XrFlags64 XrPlaneDetectorFlagsEXT; + +// Flag bits for XrPlaneDetectorFlagsEXT +static const XrPlaneDetectorFlagsEXT XR_PLANE_DETECTOR_ENABLE_CONTOUR_BIT_EXT = 0x00000001; + +// XrSystemPlaneDetectionPropertiesEXT extends XrSystemProperties +typedef struct XrSystemPlaneDetectionPropertiesEXT { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrPlaneDetectionCapabilityFlagsEXT supportedFeatures; +} XrSystemPlaneDetectionPropertiesEXT; + +typedef struct XrPlaneDetectorCreateInfoEXT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrPlaneDetectorFlagsEXT flags; +} XrPlaneDetectorCreateInfoEXT; + +typedef struct XrExtent3DfEXT { + float width; + float height; + float depth; +} XrExtent3DfEXT; + +typedef struct XrPlaneDetectorBeginInfoEXT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSpace baseSpace; + XrTime time; + uint32_t orientationCount; + const XrPlaneDetectorOrientationEXT* orientations; + uint32_t semanticTypeCount; + const XrPlaneDetectorSemanticTypeEXT* semanticTypes; + uint32_t maxPlanes; + float minArea; + XrPosef boundingBoxPose; + XrExtent3DfEXT boundingBoxExtent; +} XrPlaneDetectorBeginInfoEXT; + +typedef struct XrPlaneDetectorGetInfoEXT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSpace baseSpace; + XrTime time; +} XrPlaneDetectorGetInfoEXT; + +typedef struct XrPlaneDetectorLocationEXT { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint64_t planeId; + XrSpaceLocationFlags locationFlags; + XrPosef pose; + XrExtent2Df extents; + XrPlaneDetectorOrientationEXT orientation; + XrPlaneDetectorSemanticTypeEXT semanticType; + uint32_t polygonBufferCount; +} XrPlaneDetectorLocationEXT; + +typedef struct XrPlaneDetectorLocationsEXT { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint32_t planeLocationCapacityInput; + uint32_t planeLocationCountOutput; + XrPlaneDetectorLocationEXT* planeLocations; +} XrPlaneDetectorLocationsEXT; + +typedef struct XrPlaneDetectorPolygonBufferEXT { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint32_t vertexCapacityInput; + uint32_t vertexCountOutput; + XrVector2f* vertices; +} XrPlaneDetectorPolygonBufferEXT; + +typedef XrResult (XRAPI_PTR *PFN_xrCreatePlaneDetectorEXT)(XrSession session, const XrPlaneDetectorCreateInfoEXT* createInfo, XrPlaneDetectorEXT* planeDetector); +typedef XrResult (XRAPI_PTR *PFN_xrDestroyPlaneDetectorEXT)(XrPlaneDetectorEXT planeDetector); +typedef XrResult (XRAPI_PTR *PFN_xrBeginPlaneDetectionEXT)(XrPlaneDetectorEXT planeDetector, const XrPlaneDetectorBeginInfoEXT* beginInfo); +typedef XrResult (XRAPI_PTR *PFN_xrGetPlaneDetectionStateEXT)(XrPlaneDetectorEXT planeDetector, XrPlaneDetectionStateEXT* state); +typedef XrResult (XRAPI_PTR *PFN_xrGetPlaneDetectionsEXT)(XrPlaneDetectorEXT planeDetector, const XrPlaneDetectorGetInfoEXT* info, XrPlaneDetectorLocationsEXT* locations); +typedef XrResult (XRAPI_PTR *PFN_xrGetPlanePolygonBufferEXT)(XrPlaneDetectorEXT planeDetector, uint64_t planeId, uint32_t polygonBufferIndex, XrPlaneDetectorPolygonBufferEXT* polygonBuffer); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrCreatePlaneDetectorEXT( + XrSession session, + const XrPlaneDetectorCreateInfoEXT* createInfo, + XrPlaneDetectorEXT* planeDetector); + +XRAPI_ATTR XrResult XRAPI_CALL xrDestroyPlaneDetectorEXT( + XrPlaneDetectorEXT planeDetector); + +XRAPI_ATTR XrResult XRAPI_CALL xrBeginPlaneDetectionEXT( + XrPlaneDetectorEXT planeDetector, + const XrPlaneDetectorBeginInfoEXT* beginInfo); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetPlaneDetectionStateEXT( + XrPlaneDetectorEXT planeDetector, + XrPlaneDetectionStateEXT* state); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetPlaneDetectionsEXT( + XrPlaneDetectorEXT planeDetector, + const XrPlaneDetectorGetInfoEXT* info, + XrPlaneDetectorLocationsEXT* locations); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetPlanePolygonBufferEXT( + XrPlaneDetectorEXT planeDetector, + uint64_t planeId, + uint32_t polygonBufferIndex, + XrPlaneDetectorPolygonBufferEXT* polygonBuffer); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_OPPO_controller_interaction 1 +#define XR_OPPO_controller_interaction_SPEC_VERSION 1 +#define XR_OPPO_CONTROLLER_INTERACTION_EXTENSION_NAME "XR_OPPO_controller_interaction" + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Plugins/MetaXR/Source/Thirdparty/KhronosOpenXR/include/khronos/openxr/openxr_platform.h b/Plugins/MetaXR/Source/Thirdparty/KhronosOpenXR/include/khronos/openxr/openxr_platform.h new file mode 100644 index 0000000..fcfe90a --- /dev/null +++ b/Plugins/MetaXR/Source/Thirdparty/KhronosOpenXR/include/khronos/openxr/openxr_platform.h @@ -0,0 +1,715 @@ +#ifndef OPENXR_PLATFORM_H_ +#define OPENXR_PLATFORM_H_ 1 + +/* +** Copyright 2017-2023 The Khronos Group Inc. +** +** SPDX-License-Identifier: Apache-2.0 OR MIT +*/ + +/* +** This header is generated from the Khronos OpenXR XML API Registry. +** +*/ + +#include "openxr.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +#ifdef XR_USE_PLATFORM_ANDROID + +#define XR_KHR_android_thread_settings 1 +#define XR_KHR_android_thread_settings_SPEC_VERSION 5 +#define XR_KHR_ANDROID_THREAD_SETTINGS_EXTENSION_NAME "XR_KHR_android_thread_settings" + +typedef enum XrAndroidThreadTypeKHR { + XR_ANDROID_THREAD_TYPE_APPLICATION_MAIN_KHR = 1, + XR_ANDROID_THREAD_TYPE_APPLICATION_WORKER_KHR = 2, + XR_ANDROID_THREAD_TYPE_RENDERER_MAIN_KHR = 3, + XR_ANDROID_THREAD_TYPE_RENDERER_WORKER_KHR = 4, + XR_ANDROID_THREAD_TYPE_MAX_ENUM_KHR = 0x7FFFFFFF +} XrAndroidThreadTypeKHR; +typedef XrResult (XRAPI_PTR *PFN_xrSetAndroidApplicationThreadKHR)(XrSession session, XrAndroidThreadTypeKHR threadType, uint32_t threadId); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrSetAndroidApplicationThreadKHR( + XrSession session, + XrAndroidThreadTypeKHR threadType, + uint32_t threadId); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ +#endif /* XR_USE_PLATFORM_ANDROID */ + +#ifdef XR_USE_PLATFORM_ANDROID + +#define XR_KHR_android_surface_swapchain 1 +#define XR_KHR_android_surface_swapchain_SPEC_VERSION 4 +#define XR_KHR_ANDROID_SURFACE_SWAPCHAIN_EXTENSION_NAME "XR_KHR_android_surface_swapchain" +typedef XrResult (XRAPI_PTR *PFN_xrCreateSwapchainAndroidSurfaceKHR)(XrSession session, const XrSwapchainCreateInfo* info, XrSwapchain* swapchain, jobject* surface); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrCreateSwapchainAndroidSurfaceKHR( + XrSession session, + const XrSwapchainCreateInfo* info, + XrSwapchain* swapchain, + jobject* surface); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ +#endif /* XR_USE_PLATFORM_ANDROID */ + +#ifdef XR_USE_PLATFORM_ANDROID + +#define XR_KHR_android_create_instance 1 +#define XR_KHR_android_create_instance_SPEC_VERSION 3 +#define XR_KHR_ANDROID_CREATE_INSTANCE_EXTENSION_NAME "XR_KHR_android_create_instance" +// XrInstanceCreateInfoAndroidKHR extends XrInstanceCreateInfo +typedef struct XrInstanceCreateInfoAndroidKHR { + XrStructureType type; + const void* XR_MAY_ALIAS next; + void* XR_MAY_ALIAS applicationVM; + void* XR_MAY_ALIAS applicationActivity; +} XrInstanceCreateInfoAndroidKHR; + +#endif /* XR_USE_PLATFORM_ANDROID */ + +#ifdef XR_USE_GRAPHICS_API_VULKAN + +#define XR_KHR_vulkan_swapchain_format_list 1 +#define XR_KHR_vulkan_swapchain_format_list_SPEC_VERSION 4 +#define XR_KHR_VULKAN_SWAPCHAIN_FORMAT_LIST_EXTENSION_NAME "XR_KHR_vulkan_swapchain_format_list" +typedef struct XrVulkanSwapchainFormatListCreateInfoKHR { + XrStructureType type; + const void* XR_MAY_ALIAS next; + uint32_t viewFormatCount; + const VkFormat* viewFormats; +} XrVulkanSwapchainFormatListCreateInfoKHR; + +#endif /* XR_USE_GRAPHICS_API_VULKAN */ + +#ifdef XR_USE_GRAPHICS_API_OPENGL + +#define XR_KHR_opengl_enable 1 +#define XR_KHR_opengl_enable_SPEC_VERSION 10 +#define XR_KHR_OPENGL_ENABLE_EXTENSION_NAME "XR_KHR_opengl_enable" +#ifdef XR_USE_PLATFORM_WIN32 +// XrGraphicsBindingOpenGLWin32KHR extends XrSessionCreateInfo +typedef struct XrGraphicsBindingOpenGLWin32KHR { + XrStructureType type; + const void* XR_MAY_ALIAS next; + HDC hDC; + HGLRC hGLRC; +} XrGraphicsBindingOpenGLWin32KHR; +#endif // XR_USE_PLATFORM_WIN32 + +#ifdef XR_USE_PLATFORM_XLIB +// XrGraphicsBindingOpenGLXlibKHR extends XrSessionCreateInfo +typedef struct XrGraphicsBindingOpenGLXlibKHR { + XrStructureType type; + const void* XR_MAY_ALIAS next; + Display* xDisplay; + uint32_t visualid; + GLXFBConfig glxFBConfig; + GLXDrawable glxDrawable; + GLXContext glxContext; +} XrGraphicsBindingOpenGLXlibKHR; +#endif // XR_USE_PLATFORM_XLIB + +#ifdef XR_USE_PLATFORM_XCB +// XrGraphicsBindingOpenGLXcbKHR extends XrSessionCreateInfo +typedef struct XrGraphicsBindingOpenGLXcbKHR { + XrStructureType type; + const void* XR_MAY_ALIAS next; + xcb_connection_t* connection; + uint32_t screenNumber; + xcb_glx_fbconfig_t fbconfigid; + xcb_visualid_t visualid; + xcb_glx_drawable_t glxDrawable; + xcb_glx_context_t glxContext; +} XrGraphicsBindingOpenGLXcbKHR; +#endif // XR_USE_PLATFORM_XCB + +#ifdef XR_USE_PLATFORM_WAYLAND +// XrGraphicsBindingOpenGLWaylandKHR extends XrSessionCreateInfo +typedef struct XrGraphicsBindingOpenGLWaylandKHR { + XrStructureType type; + const void* XR_MAY_ALIAS next; + struct wl_display* display; +} XrGraphicsBindingOpenGLWaylandKHR; +#endif // XR_USE_PLATFORM_WAYLAND + +typedef struct XrSwapchainImageOpenGLKHR { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint32_t image; +} XrSwapchainImageOpenGLKHR; + +typedef struct XrGraphicsRequirementsOpenGLKHR { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrVersion minApiVersionSupported; + XrVersion maxApiVersionSupported; +} XrGraphicsRequirementsOpenGLKHR; + +typedef XrResult (XRAPI_PTR *PFN_xrGetOpenGLGraphicsRequirementsKHR)(XrInstance instance, XrSystemId systemId, XrGraphicsRequirementsOpenGLKHR* graphicsRequirements); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrGetOpenGLGraphicsRequirementsKHR( + XrInstance instance, + XrSystemId systemId, + XrGraphicsRequirementsOpenGLKHR* graphicsRequirements); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ +#endif /* XR_USE_GRAPHICS_API_OPENGL */ + +#ifdef XR_USE_GRAPHICS_API_OPENGL_ES + +#define XR_KHR_opengl_es_enable 1 +#define XR_KHR_opengl_es_enable_SPEC_VERSION 8 +#define XR_KHR_OPENGL_ES_ENABLE_EXTENSION_NAME "XR_KHR_opengl_es_enable" +#ifdef XR_USE_PLATFORM_ANDROID +// XrGraphicsBindingOpenGLESAndroidKHR extends XrSessionCreateInfo +typedef struct XrGraphicsBindingOpenGLESAndroidKHR { + XrStructureType type; + const void* XR_MAY_ALIAS next; + EGLDisplay display; + EGLConfig config; + EGLContext context; +} XrGraphicsBindingOpenGLESAndroidKHR; +#endif // XR_USE_PLATFORM_ANDROID + +typedef struct XrSwapchainImageOpenGLESKHR { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint32_t image; +} XrSwapchainImageOpenGLESKHR; + +typedef struct XrGraphicsRequirementsOpenGLESKHR { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrVersion minApiVersionSupported; + XrVersion maxApiVersionSupported; +} XrGraphicsRequirementsOpenGLESKHR; + +typedef XrResult (XRAPI_PTR *PFN_xrGetOpenGLESGraphicsRequirementsKHR)(XrInstance instance, XrSystemId systemId, XrGraphicsRequirementsOpenGLESKHR* graphicsRequirements); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrGetOpenGLESGraphicsRequirementsKHR( + XrInstance instance, + XrSystemId systemId, + XrGraphicsRequirementsOpenGLESKHR* graphicsRequirements); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ +#endif /* XR_USE_GRAPHICS_API_OPENGL_ES */ + +#ifdef XR_USE_GRAPHICS_API_VULKAN + +#define XR_KHR_vulkan_enable 1 +#define XR_KHR_vulkan_enable_SPEC_VERSION 8 +#define XR_KHR_VULKAN_ENABLE_EXTENSION_NAME "XR_KHR_vulkan_enable" +// XrGraphicsBindingVulkanKHR extends XrSessionCreateInfo +typedef struct XrGraphicsBindingVulkanKHR { + XrStructureType type; + const void* XR_MAY_ALIAS next; + VkInstance instance; + VkPhysicalDevice physicalDevice; + VkDevice device; + uint32_t queueFamilyIndex; + uint32_t queueIndex; +} XrGraphicsBindingVulkanKHR; + +typedef struct XrSwapchainImageVulkanKHR { + XrStructureType type; + void* XR_MAY_ALIAS next; + VkImage image; +} XrSwapchainImageVulkanKHR; + +typedef struct XrGraphicsRequirementsVulkanKHR { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrVersion minApiVersionSupported; + XrVersion maxApiVersionSupported; +} XrGraphicsRequirementsVulkanKHR; + +typedef XrResult (XRAPI_PTR *PFN_xrGetVulkanInstanceExtensionsKHR)(XrInstance instance, XrSystemId systemId, uint32_t bufferCapacityInput, uint32_t* bufferCountOutput, char* buffer); +typedef XrResult (XRAPI_PTR *PFN_xrGetVulkanDeviceExtensionsKHR)(XrInstance instance, XrSystemId systemId, uint32_t bufferCapacityInput, uint32_t* bufferCountOutput, char* buffer); +typedef XrResult (XRAPI_PTR *PFN_xrGetVulkanGraphicsDeviceKHR)(XrInstance instance, XrSystemId systemId, VkInstance vkInstance, VkPhysicalDevice* vkPhysicalDevice); +typedef XrResult (XRAPI_PTR *PFN_xrGetVulkanGraphicsRequirementsKHR)(XrInstance instance, XrSystemId systemId, XrGraphicsRequirementsVulkanKHR* graphicsRequirements); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrGetVulkanInstanceExtensionsKHR( + XrInstance instance, + XrSystemId systemId, + uint32_t bufferCapacityInput, + uint32_t* bufferCountOutput, + char* buffer); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetVulkanDeviceExtensionsKHR( + XrInstance instance, + XrSystemId systemId, + uint32_t bufferCapacityInput, + uint32_t* bufferCountOutput, + char* buffer); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetVulkanGraphicsDeviceKHR( + XrInstance instance, + XrSystemId systemId, + VkInstance vkInstance, + VkPhysicalDevice* vkPhysicalDevice); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetVulkanGraphicsRequirementsKHR( + XrInstance instance, + XrSystemId systemId, + XrGraphicsRequirementsVulkanKHR* graphicsRequirements); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ +#endif /* XR_USE_GRAPHICS_API_VULKAN */ + +#ifdef XR_USE_GRAPHICS_API_D3D11 + +#define XR_KHR_D3D11_enable 1 +#define XR_KHR_D3D11_enable_SPEC_VERSION 9 +#define XR_KHR_D3D11_ENABLE_EXTENSION_NAME "XR_KHR_D3D11_enable" +// XrGraphicsBindingD3D11KHR extends XrSessionCreateInfo +typedef struct XrGraphicsBindingD3D11KHR { + XrStructureType type; + const void* XR_MAY_ALIAS next; + ID3D11Device* device; +} XrGraphicsBindingD3D11KHR; + +typedef struct XrSwapchainImageD3D11KHR { + XrStructureType type; + void* XR_MAY_ALIAS next; + ID3D11Texture2D* texture; +} XrSwapchainImageD3D11KHR; + +typedef struct XrGraphicsRequirementsD3D11KHR { + XrStructureType type; + void* XR_MAY_ALIAS next; + LUID adapterLuid; + D3D_FEATURE_LEVEL minFeatureLevel; +} XrGraphicsRequirementsD3D11KHR; + +typedef XrResult (XRAPI_PTR *PFN_xrGetD3D11GraphicsRequirementsKHR)(XrInstance instance, XrSystemId systemId, XrGraphicsRequirementsD3D11KHR* graphicsRequirements); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrGetD3D11GraphicsRequirementsKHR( + XrInstance instance, + XrSystemId systemId, + XrGraphicsRequirementsD3D11KHR* graphicsRequirements); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ +#endif /* XR_USE_GRAPHICS_API_D3D11 */ + +#ifdef XR_USE_GRAPHICS_API_D3D12 + +#define XR_KHR_D3D12_enable 1 +#define XR_KHR_D3D12_enable_SPEC_VERSION 9 +#define XR_KHR_D3D12_ENABLE_EXTENSION_NAME "XR_KHR_D3D12_enable" +// XrGraphicsBindingD3D12KHR extends XrSessionCreateInfo +typedef struct XrGraphicsBindingD3D12KHR { + XrStructureType type; + const void* XR_MAY_ALIAS next; + ID3D12Device* device; + ID3D12CommandQueue* queue; +} XrGraphicsBindingD3D12KHR; + +typedef struct XrSwapchainImageD3D12KHR { + XrStructureType type; + void* XR_MAY_ALIAS next; + ID3D12Resource* texture; +} XrSwapchainImageD3D12KHR; + +typedef struct XrGraphicsRequirementsD3D12KHR { + XrStructureType type; + void* XR_MAY_ALIAS next; + LUID adapterLuid; + D3D_FEATURE_LEVEL minFeatureLevel; +} XrGraphicsRequirementsD3D12KHR; + +typedef XrResult (XRAPI_PTR *PFN_xrGetD3D12GraphicsRequirementsKHR)(XrInstance instance, XrSystemId systemId, XrGraphicsRequirementsD3D12KHR* graphicsRequirements); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrGetD3D12GraphicsRequirementsKHR( + XrInstance instance, + XrSystemId systemId, + XrGraphicsRequirementsD3D12KHR* graphicsRequirements); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ +#endif /* XR_USE_GRAPHICS_API_D3D12 */ + +#ifdef XR_USE_PLATFORM_WIN32 + +#define XR_KHR_win32_convert_performance_counter_time 1 +#define XR_KHR_win32_convert_performance_counter_time_SPEC_VERSION 1 +#define XR_KHR_WIN32_CONVERT_PERFORMANCE_COUNTER_TIME_EXTENSION_NAME "XR_KHR_win32_convert_performance_counter_time" +typedef XrResult (XRAPI_PTR *PFN_xrConvertWin32PerformanceCounterToTimeKHR)(XrInstance instance, const LARGE_INTEGER* performanceCounter, XrTime* time); +typedef XrResult (XRAPI_PTR *PFN_xrConvertTimeToWin32PerformanceCounterKHR)(XrInstance instance, XrTime time, LARGE_INTEGER* performanceCounter); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrConvertWin32PerformanceCounterToTimeKHR( + XrInstance instance, + const LARGE_INTEGER* performanceCounter, + XrTime* time); + +XRAPI_ATTR XrResult XRAPI_CALL xrConvertTimeToWin32PerformanceCounterKHR( + XrInstance instance, + XrTime time, + LARGE_INTEGER* performanceCounter); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ +#endif /* XR_USE_PLATFORM_WIN32 */ + +#ifdef XR_USE_TIMESPEC + +#define XR_KHR_convert_timespec_time 1 +#define XR_KHR_convert_timespec_time_SPEC_VERSION 1 +#define XR_KHR_CONVERT_TIMESPEC_TIME_EXTENSION_NAME "XR_KHR_convert_timespec_time" +typedef XrResult (XRAPI_PTR *PFN_xrConvertTimespecTimeToTimeKHR)(XrInstance instance, const struct timespec* timespecTime, XrTime* time); +typedef XrResult (XRAPI_PTR *PFN_xrConvertTimeToTimespecTimeKHR)(XrInstance instance, XrTime time, struct timespec* timespecTime); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrConvertTimespecTimeToTimeKHR( + XrInstance instance, + const struct timespec* timespecTime, + XrTime* time); + +XRAPI_ATTR XrResult XRAPI_CALL xrConvertTimeToTimespecTimeKHR( + XrInstance instance, + XrTime time, + struct timespec* timespecTime); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ +#endif /* XR_USE_TIMESPEC */ + +#ifdef XR_USE_PLATFORM_ANDROID + +#define XR_KHR_loader_init_android 1 +#define XR_KHR_loader_init_android_SPEC_VERSION 1 +#define XR_KHR_LOADER_INIT_ANDROID_EXTENSION_NAME "XR_KHR_loader_init_android" +typedef struct XrLoaderInitInfoAndroidKHR { + XrStructureType type; + const void* XR_MAY_ALIAS next; + void* XR_MAY_ALIAS applicationVM; + void* XR_MAY_ALIAS applicationContext; +} XrLoaderInitInfoAndroidKHR; + +#endif /* XR_USE_PLATFORM_ANDROID */ + +#ifdef XR_USE_GRAPHICS_API_VULKAN + +#define XR_KHR_vulkan_enable2 1 +#define XR_KHR_vulkan_enable2_SPEC_VERSION 2 +#define XR_KHR_VULKAN_ENABLE2_EXTENSION_NAME "XR_KHR_vulkan_enable2" +typedef XrFlags64 XrVulkanInstanceCreateFlagsKHR; + +// Flag bits for XrVulkanInstanceCreateFlagsKHR + +typedef XrFlags64 XrVulkanDeviceCreateFlagsKHR; + +// Flag bits for XrVulkanDeviceCreateFlagsKHR + +typedef struct XrVulkanInstanceCreateInfoKHR { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSystemId systemId; + XrVulkanInstanceCreateFlagsKHR createFlags; + PFN_vkGetInstanceProcAddr pfnGetInstanceProcAddr; + const VkInstanceCreateInfo* vulkanCreateInfo; + const VkAllocationCallbacks* vulkanAllocator; +} XrVulkanInstanceCreateInfoKHR; + +typedef struct XrVulkanDeviceCreateInfoKHR { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSystemId systemId; + XrVulkanDeviceCreateFlagsKHR createFlags; + PFN_vkGetInstanceProcAddr pfnGetInstanceProcAddr; + VkPhysicalDevice vulkanPhysicalDevice; + const VkDeviceCreateInfo* vulkanCreateInfo; + const VkAllocationCallbacks* vulkanAllocator; +} XrVulkanDeviceCreateInfoKHR; + +typedef XrGraphicsBindingVulkanKHR XrGraphicsBindingVulkan2KHR; + +typedef struct XrVulkanGraphicsDeviceGetInfoKHR { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSystemId systemId; + VkInstance vulkanInstance; +} XrVulkanGraphicsDeviceGetInfoKHR; + +typedef XrSwapchainImageVulkanKHR XrSwapchainImageVulkan2KHR; + +typedef XrGraphicsRequirementsVulkanKHR XrGraphicsRequirementsVulkan2KHR; + +typedef XrResult (XRAPI_PTR *PFN_xrCreateVulkanInstanceKHR)(XrInstance instance, const XrVulkanInstanceCreateInfoKHR* createInfo, VkInstance* vulkanInstance, VkResult* vulkanResult); +typedef XrResult (XRAPI_PTR *PFN_xrCreateVulkanDeviceKHR)(XrInstance instance, const XrVulkanDeviceCreateInfoKHR* createInfo, VkDevice* vulkanDevice, VkResult* vulkanResult); +typedef XrResult (XRAPI_PTR *PFN_xrGetVulkanGraphicsDevice2KHR)(XrInstance instance, const XrVulkanGraphicsDeviceGetInfoKHR* getInfo, VkPhysicalDevice* vulkanPhysicalDevice); +typedef XrResult (XRAPI_PTR *PFN_xrGetVulkanGraphicsRequirements2KHR)(XrInstance instance, XrSystemId systemId, XrGraphicsRequirementsVulkanKHR* graphicsRequirements); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrCreateVulkanInstanceKHR( + XrInstance instance, + const XrVulkanInstanceCreateInfoKHR* createInfo, + VkInstance* vulkanInstance, + VkResult* vulkanResult); + +XRAPI_ATTR XrResult XRAPI_CALL xrCreateVulkanDeviceKHR( + XrInstance instance, + const XrVulkanDeviceCreateInfoKHR* createInfo, + VkDevice* vulkanDevice, + VkResult* vulkanResult); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetVulkanGraphicsDevice2KHR( + XrInstance instance, + const XrVulkanGraphicsDeviceGetInfoKHR* getInfo, + VkPhysicalDevice* vulkanPhysicalDevice); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetVulkanGraphicsRequirements2KHR( + XrInstance instance, + XrSystemId systemId, + XrGraphicsRequirementsVulkanKHR* graphicsRequirements); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ +#endif /* XR_USE_GRAPHICS_API_VULKAN */ + +#ifdef XR_USE_PLATFORM_EGL + +#define XR_MNDX_egl_enable 1 +#define XR_MNDX_egl_enable_SPEC_VERSION 1 +#define XR_MNDX_EGL_ENABLE_EXTENSION_NAME "XR_MNDX_egl_enable" +typedef void *(*PFN_xrEglGetProcAddressMNDX)(const char *name); +// XrGraphicsBindingEGLMNDX extends XrSessionCreateInfo +typedef struct XrGraphicsBindingEGLMNDX { + XrStructureType type; + const void* XR_MAY_ALIAS next; + PFN_xrEglGetProcAddressMNDX getProcAddress; + EGLDisplay display; + EGLConfig config; + EGLContext context; +} XrGraphicsBindingEGLMNDX; + +#endif /* XR_USE_PLATFORM_EGL */ + +#ifdef XR_USE_PLATFORM_WIN32 + +#define XR_MSFT_perception_anchor_interop 1 +#define XR_MSFT_perception_anchor_interop_SPEC_VERSION 1 +#define XR_MSFT_PERCEPTION_ANCHOR_INTEROP_EXTENSION_NAME "XR_MSFT_perception_anchor_interop" +typedef XrResult (XRAPI_PTR *PFN_xrCreateSpatialAnchorFromPerceptionAnchorMSFT)(XrSession session, IUnknown* perceptionAnchor, XrSpatialAnchorMSFT* anchor); +typedef XrResult (XRAPI_PTR *PFN_xrTryGetPerceptionAnchorFromSpatialAnchorMSFT)(XrSession session, XrSpatialAnchorMSFT anchor, IUnknown** perceptionAnchor); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrCreateSpatialAnchorFromPerceptionAnchorMSFT( + XrSession session, + IUnknown* perceptionAnchor, + XrSpatialAnchorMSFT* anchor); + +XRAPI_ATTR XrResult XRAPI_CALL xrTryGetPerceptionAnchorFromSpatialAnchorMSFT( + XrSession session, + XrSpatialAnchorMSFT anchor, + IUnknown** perceptionAnchor); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ +#endif /* XR_USE_PLATFORM_WIN32 */ + +#ifdef XR_USE_PLATFORM_WIN32 + +#define XR_MSFT_holographic_window_attachment 1 +#define XR_MSFT_holographic_window_attachment_SPEC_VERSION 1 +#define XR_MSFT_HOLOGRAPHIC_WINDOW_ATTACHMENT_EXTENSION_NAME "XR_MSFT_holographic_window_attachment" +#ifdef XR_USE_PLATFORM_WIN32 +// XrHolographicWindowAttachmentMSFT extends XrSessionCreateInfo +typedef struct XrHolographicWindowAttachmentMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + IUnknown* holographicSpace; + IUnknown* coreWindow; +} XrHolographicWindowAttachmentMSFT; +#endif // XR_USE_PLATFORM_WIN32 + +#endif /* XR_USE_PLATFORM_WIN32 */ + +#ifdef XR_USE_PLATFORM_ANDROID + +#define XR_FB_android_surface_swapchain_create 1 +#define XR_FB_android_surface_swapchain_create_SPEC_VERSION 1 +#define XR_FB_ANDROID_SURFACE_SWAPCHAIN_CREATE_EXTENSION_NAME "XR_FB_android_surface_swapchain_create" +typedef XrFlags64 XrAndroidSurfaceSwapchainFlagsFB; + +// Flag bits for XrAndroidSurfaceSwapchainFlagsFB +static const XrAndroidSurfaceSwapchainFlagsFB XR_ANDROID_SURFACE_SWAPCHAIN_SYNCHRONOUS_BIT_FB = 0x00000001; +static const XrAndroidSurfaceSwapchainFlagsFB XR_ANDROID_SURFACE_SWAPCHAIN_USE_TIMESTAMPS_BIT_FB = 0x00000002; + +#ifdef XR_USE_PLATFORM_ANDROID +// XrAndroidSurfaceSwapchainCreateInfoFB extends XrSwapchainCreateInfo +typedef struct XrAndroidSurfaceSwapchainCreateInfoFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrAndroidSurfaceSwapchainFlagsFB createFlags; +} XrAndroidSurfaceSwapchainCreateInfoFB; +#endif // XR_USE_PLATFORM_ANDROID + +#endif /* XR_USE_PLATFORM_ANDROID */ + +#ifdef XR_USE_PLATFORM_ML + +#define XR_ML_compat 1 +#define XR_ML_compat_SPEC_VERSION 1 +#define XR_ML_COMPAT_EXTENSION_NAME "XR_ML_compat" +typedef struct XrCoordinateSpaceCreateInfoML { + XrStructureType type; + const void* XR_MAY_ALIAS next; + MLCoordinateFrameUID cfuid; + XrPosef poseInCoordinateSpace; +} XrCoordinateSpaceCreateInfoML; + +typedef XrResult (XRAPI_PTR *PFN_xrCreateSpaceFromCoordinateFrameUIDML)(XrSession session, const XrCoordinateSpaceCreateInfoML *createInfo, XrSpace* space); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrCreateSpaceFromCoordinateFrameUIDML( + XrSession session, + const XrCoordinateSpaceCreateInfoML * createInfo, + XrSpace* space); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ +#endif /* XR_USE_PLATFORM_ML */ + +#ifdef XR_USE_PLATFORM_WIN32 + +#define XR_OCULUS_audio_device_guid 1 +#define XR_OCULUS_audio_device_guid_SPEC_VERSION 1 +#define XR_OCULUS_AUDIO_DEVICE_GUID_EXTENSION_NAME "XR_OCULUS_audio_device_guid" +#define XR_MAX_AUDIO_DEVICE_STR_SIZE_OCULUS 128 +typedef XrResult (XRAPI_PTR *PFN_xrGetAudioOutputDeviceGuidOculus)(XrInstance instance, wchar_t buffer[XR_MAX_AUDIO_DEVICE_STR_SIZE_OCULUS]); +typedef XrResult (XRAPI_PTR *PFN_xrGetAudioInputDeviceGuidOculus)(XrInstance instance, wchar_t buffer[XR_MAX_AUDIO_DEVICE_STR_SIZE_OCULUS]); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrGetAudioOutputDeviceGuidOculus( + XrInstance instance, + wchar_t buffer[XR_MAX_AUDIO_DEVICE_STR_SIZE_OCULUS]); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetAudioInputDeviceGuidOculus( + XrInstance instance, + wchar_t buffer[XR_MAX_AUDIO_DEVICE_STR_SIZE_OCULUS]); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ +#endif /* XR_USE_PLATFORM_WIN32 */ + +#ifdef XR_USE_GRAPHICS_API_VULKAN + +#define XR_FB_foveation_vulkan 1 +#define XR_FB_foveation_vulkan_SPEC_VERSION 1 +#define XR_FB_FOVEATION_VULKAN_EXTENSION_NAME "XR_FB_foveation_vulkan" +// XrSwapchainImageFoveationVulkanFB extends XrSwapchainImageVulkanKHR +typedef struct XrSwapchainImageFoveationVulkanFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + VkImage image; + uint32_t width; + uint32_t height; +} XrSwapchainImageFoveationVulkanFB; + +#endif /* XR_USE_GRAPHICS_API_VULKAN */ + +#ifdef XR_USE_PLATFORM_ANDROID + +#define XR_FB_swapchain_update_state_android_surface 1 +#define XR_FB_swapchain_update_state_android_surface_SPEC_VERSION 1 +#define XR_FB_SWAPCHAIN_UPDATE_STATE_ANDROID_SURFACE_EXTENSION_NAME "XR_FB_swapchain_update_state_android_surface" +#ifdef XR_USE_PLATFORM_ANDROID +typedef struct XrSwapchainStateAndroidSurfaceDimensionsFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint32_t width; + uint32_t height; +} XrSwapchainStateAndroidSurfaceDimensionsFB; +#endif // XR_USE_PLATFORM_ANDROID + +#endif /* XR_USE_PLATFORM_ANDROID */ + +#ifdef XR_USE_GRAPHICS_API_OPENGL_ES + +#define XR_FB_swapchain_update_state_opengl_es 1 +#define XR_FB_swapchain_update_state_opengl_es_SPEC_VERSION 1 +#define XR_FB_SWAPCHAIN_UPDATE_STATE_OPENGL_ES_EXTENSION_NAME "XR_FB_swapchain_update_state_opengl_es" +#ifdef XR_USE_GRAPHICS_API_OPENGL_ES +typedef struct XrSwapchainStateSamplerOpenGLESFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + EGLenum minFilter; + EGLenum magFilter; + EGLenum wrapModeS; + EGLenum wrapModeT; + EGLenum swizzleRed; + EGLenum swizzleGreen; + EGLenum swizzleBlue; + EGLenum swizzleAlpha; + float maxAnisotropy; + XrColor4f borderColor; +} XrSwapchainStateSamplerOpenGLESFB; +#endif // XR_USE_GRAPHICS_API_OPENGL_ES + +#endif /* XR_USE_GRAPHICS_API_OPENGL_ES */ + +#ifdef XR_USE_GRAPHICS_API_VULKAN + +#define XR_FB_swapchain_update_state_vulkan 1 +#define XR_FB_swapchain_update_state_vulkan_SPEC_VERSION 1 +#define XR_FB_SWAPCHAIN_UPDATE_STATE_VULKAN_EXTENSION_NAME "XR_FB_swapchain_update_state_vulkan" +#ifdef XR_USE_GRAPHICS_API_VULKAN +typedef struct XrSwapchainStateSamplerVulkanFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + VkFilter minFilter; + VkFilter magFilter; + VkSamplerMipmapMode mipmapMode; + VkSamplerAddressMode wrapModeS; + VkSamplerAddressMode wrapModeT; + VkComponentSwizzle swizzleRed; + VkComponentSwizzle swizzleGreen; + VkComponentSwizzle swizzleBlue; + VkComponentSwizzle swizzleAlpha; + float maxAnisotropy; + XrColor4f borderColor; +} XrSwapchainStateSamplerVulkanFB; +#endif // XR_USE_GRAPHICS_API_VULKAN + +#endif /* XR_USE_GRAPHICS_API_VULKAN */ + +#ifdef XR_USE_GRAPHICS_API_VULKAN + +#define XR_META_vulkan_swapchain_create_info 1 +#define XR_META_vulkan_swapchain_create_info_SPEC_VERSION 1 +#define XR_META_VULKAN_SWAPCHAIN_CREATE_INFO_EXTENSION_NAME "XR_META_vulkan_swapchain_create_info" +// XrVulkanSwapchainCreateInfoMETA extends XrSwapchainCreateInfo +typedef struct XrVulkanSwapchainCreateInfoMETA { + XrStructureType type; + const void* XR_MAY_ALIAS next; + VkImageCreateFlags additionalCreateFlags; + VkImageUsageFlags additionalUsageFlags; +} XrVulkanSwapchainCreateInfoMETA; + +#endif /* XR_USE_GRAPHICS_API_VULKAN */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Plugins/MetaXR/Source/Thirdparty/KhronosOpenXR/include/khronos/openxr/openxr_platform_defines.h b/Plugins/MetaXR/Source/Thirdparty/KhronosOpenXR/include/khronos/openxr/openxr_platform_defines.h new file mode 100644 index 0000000..820b7b3 --- /dev/null +++ b/Plugins/MetaXR/Source/Thirdparty/KhronosOpenXR/include/khronos/openxr/openxr_platform_defines.h @@ -0,0 +1,114 @@ +/* +** Copyright (c) 2017-2023, The Khronos Group Inc. +** +** SPDX-License-Identifier: Apache-2.0 OR MIT +*/ + +#ifndef OPENXR_PLATFORM_DEFINES_H_ +#define OPENXR_PLATFORM_DEFINES_H_ 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/* Platform-specific calling convention macros. + * + * Platforms should define these so that OpenXR clients call OpenXR functions + * with the same calling conventions that the OpenXR implementation expects. + * + * XRAPI_ATTR - Placed before the return type in function declarations. + * Useful for C++11 and GCC/Clang-style function attribute syntax. + * XRAPI_CALL - Placed after the return type in function declarations. + * Useful for MSVC-style calling convention syntax. + * XRAPI_PTR - Placed between the '(' and '*' in function pointer types. + * + * Function declaration: XRAPI_ATTR void XRAPI_CALL xrFunction(void); + * Function pointer type: typedef void (XRAPI_PTR *PFN_xrFunction)(void); + */ +#if defined(_WIN32) +#define XRAPI_ATTR +// On Windows, functions use the stdcall convention +#define XRAPI_CALL __stdcall +#define XRAPI_PTR XRAPI_CALL +#elif defined(__ANDROID__) && defined(__ARM_ARCH) && __ARM_ARCH < 7 +#error "API not supported for the 'armeabi' NDK ABI" +#elif defined(__ANDROID__) && defined(__ARM_ARCH) && __ARM_ARCH >= 7 && defined(__ARM_32BIT_STATE) +// On Android 32-bit ARM targets, functions use the "hardfloat" +// calling convention, i.e. float parameters are passed in registers. This +// is true even if the rest of the application passes floats on the stack, +// as it does by default when compiling for the armeabi-v7a NDK ABI. +#define XRAPI_ATTR __attribute__((pcs("aapcs-vfp"))) +#define XRAPI_CALL +#define XRAPI_PTR XRAPI_ATTR +#else +// On other platforms, use the default calling convention +#define XRAPI_ATTR +#define XRAPI_CALL +#define XRAPI_PTR +#endif + +#include + +#if !defined(XR_NO_STDINT_H) +#if defined(_MSC_VER) && (_MSC_VER < 1600) +typedef signed __int8 int8_t; +typedef unsigned __int8 uint8_t; +typedef signed __int16 int16_t; +typedef unsigned __int16 uint16_t; +typedef signed __int32 int32_t; +typedef unsigned __int32 uint32_t; +typedef signed __int64 int64_t; +typedef unsigned __int64 uint64_t; +#else +#include +#endif +#endif // !defined( XR_NO_STDINT_H ) + +// XR_PTR_SIZE (in bytes) +#if (defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__) ) || defined(_M_X64) || defined(__ia64) || defined(_M_IA64) || defined(__aarch64__) || defined(__powerpc64__)) +#define XR_PTR_SIZE 8 +#else +#define XR_PTR_SIZE 4 +#endif + +// Needed so we can use clang __has_feature portably. +#if !defined(XR_COMPILER_HAS_FEATURE) +#if defined(__clang__) +#define XR_COMPILER_HAS_FEATURE(x) __has_feature(x) +#else +#define XR_COMPILER_HAS_FEATURE(x) 0 +#endif +#endif + +// Identifies if the current compiler has C++11 support enabled. +// Does not by itself identify if any given C++11 feature is present. +#if !defined(XR_CPP11_ENABLED) && defined(__cplusplus) +#if defined(__GNUC__) && defined(__GXX_EXPERIMENTAL_CXX0X__) +#define XR_CPP11_ENABLED 1 +#elif defined(_MSC_VER) && (_MSC_VER >= 1600) +#define XR_CPP11_ENABLED 1 +#elif (__cplusplus >= 201103L) // 201103 is the first C++11 version. +#define XR_CPP11_ENABLED 1 +#endif +#endif + +// Identifies if the current compiler supports C++11 nullptr. +#if !defined(XR_CPP_NULLPTR_SUPPORTED) +#if defined(XR_CPP11_ENABLED) && \ + ((defined(__clang__) && XR_COMPILER_HAS_FEATURE(cxx_nullptr)) || \ + (defined(__GNUC__) && (((__GNUC__ * 1000) + __GNUC_MINOR__) >= 4006)) || \ + (defined(_MSC_VER) && (_MSC_VER >= 1600)) || \ + (defined(__EDG_VERSION__) && (__EDG_VERSION__ >= 403))) +#define XR_CPP_NULLPTR_SUPPORTED 1 +#endif +#endif + +#if !defined(XR_CPP_NULLPTR_SUPPORTED) +#define XR_CPP_NULLPTR_SUPPORTED 0 +#endif // !defined(XR_CPP_NULLPTR_SUPPORTED) + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Plugins/MetaXR/Source/Thirdparty/KhronosOpenXR/include/khronos/openxr/openxr_reflection.h b/Plugins/MetaXR/Source/Thirdparty/KhronosOpenXR/include/khronos/openxr/openxr_reflection.h new file mode 100644 index 0000000..0901ef4 --- /dev/null +++ b/Plugins/MetaXR/Source/Thirdparty/KhronosOpenXR/include/khronos/openxr/openxr_reflection.h @@ -0,0 +1,4594 @@ +#ifndef OPENXR_REFLECTION_H_ +#define OPENXR_REFLECTION_H_ 1 + +/* +** Copyright (c) 2017-2023, The Khronos Group Inc. +** +** SPDX-License-Identifier: Apache-2.0 OR MIT +*/ + +/* +** This header is generated from the Khronos OpenXR XML API Registry. +** +*/ + +#include "openxr.h" + +/* +This file contains expansion macros (X Macros) for OpenXR enumerations and structures. +Example of how to use expansion macros to make an enum-to-string function: + +#define XR_ENUM_CASE_STR(name, val) case name: return #name; +#define XR_ENUM_STR(enumType) \ + constexpr const char* XrEnumStr(enumType e) { \ + switch (e) { \ + XR_LIST_ENUM_##enumType(XR_ENUM_CASE_STR) \ + default: return "Unknown"; \ + } \ + } \ + +XR_ENUM_STR(XrResult); +*/ + +#define XR_LIST_ENUM_XrResult(_) \ + _(XR_SUCCESS, 0) \ + _(XR_TIMEOUT_EXPIRED, 1) \ + _(XR_SESSION_LOSS_PENDING, 3) \ + _(XR_EVENT_UNAVAILABLE, 4) \ + _(XR_SPACE_BOUNDS_UNAVAILABLE, 7) \ + _(XR_SESSION_NOT_FOCUSED, 8) \ + _(XR_FRAME_DISCARDED, 9) \ + _(XR_ERROR_VALIDATION_FAILURE, -1) \ + _(XR_ERROR_RUNTIME_FAILURE, -2) \ + _(XR_ERROR_OUT_OF_MEMORY, -3) \ + _(XR_ERROR_API_VERSION_UNSUPPORTED, -4) \ + _(XR_ERROR_INITIALIZATION_FAILED, -6) \ + _(XR_ERROR_FUNCTION_UNSUPPORTED, -7) \ + _(XR_ERROR_FEATURE_UNSUPPORTED, -8) \ + _(XR_ERROR_EXTENSION_NOT_PRESENT, -9) \ + _(XR_ERROR_LIMIT_REACHED, -10) \ + _(XR_ERROR_SIZE_INSUFFICIENT, -11) \ + _(XR_ERROR_HANDLE_INVALID, -12) \ + _(XR_ERROR_INSTANCE_LOST, -13) \ + _(XR_ERROR_SESSION_RUNNING, -14) \ + _(XR_ERROR_SESSION_NOT_RUNNING, -16) \ + _(XR_ERROR_SESSION_LOST, -17) \ + _(XR_ERROR_SYSTEM_INVALID, -18) \ + _(XR_ERROR_PATH_INVALID, -19) \ + _(XR_ERROR_PATH_COUNT_EXCEEDED, -20) \ + _(XR_ERROR_PATH_FORMAT_INVALID, -21) \ + _(XR_ERROR_PATH_UNSUPPORTED, -22) \ + _(XR_ERROR_LAYER_INVALID, -23) \ + _(XR_ERROR_LAYER_LIMIT_EXCEEDED, -24) \ + _(XR_ERROR_SWAPCHAIN_RECT_INVALID, -25) \ + _(XR_ERROR_SWAPCHAIN_FORMAT_UNSUPPORTED, -26) \ + _(XR_ERROR_ACTION_TYPE_MISMATCH, -27) \ + _(XR_ERROR_SESSION_NOT_READY, -28) \ + _(XR_ERROR_SESSION_NOT_STOPPING, -29) \ + _(XR_ERROR_TIME_INVALID, -30) \ + _(XR_ERROR_REFERENCE_SPACE_UNSUPPORTED, -31) \ + _(XR_ERROR_FILE_ACCESS_ERROR, -32) \ + _(XR_ERROR_FILE_CONTENTS_INVALID, -33) \ + _(XR_ERROR_FORM_FACTOR_UNSUPPORTED, -34) \ + _(XR_ERROR_FORM_FACTOR_UNAVAILABLE, -35) \ + _(XR_ERROR_API_LAYER_NOT_PRESENT, -36) \ + _(XR_ERROR_CALL_ORDER_INVALID, -37) \ + _(XR_ERROR_GRAPHICS_DEVICE_INVALID, -38) \ + _(XR_ERROR_POSE_INVALID, -39) \ + _(XR_ERROR_INDEX_OUT_OF_RANGE, -40) \ + _(XR_ERROR_VIEW_CONFIGURATION_TYPE_UNSUPPORTED, -41) \ + _(XR_ERROR_ENVIRONMENT_BLEND_MODE_UNSUPPORTED, -42) \ + _(XR_ERROR_NAME_DUPLICATED, -44) \ + _(XR_ERROR_NAME_INVALID, -45) \ + _(XR_ERROR_ACTIONSET_NOT_ATTACHED, -46) \ + _(XR_ERROR_ACTIONSETS_ALREADY_ATTACHED, -47) \ + _(XR_ERROR_LOCALIZED_NAME_DUPLICATED, -48) \ + _(XR_ERROR_LOCALIZED_NAME_INVALID, -49) \ + _(XR_ERROR_GRAPHICS_REQUIREMENTS_CALL_MISSING, -50) \ + _(XR_ERROR_RUNTIME_UNAVAILABLE, -51) \ + _(XR_ERROR_ANDROID_THREAD_SETTINGS_ID_INVALID_KHR, -1000003000) \ + _(XR_ERROR_ANDROID_THREAD_SETTINGS_FAILURE_KHR, -1000003001) \ + _(XR_ERROR_CREATE_SPATIAL_ANCHOR_FAILED_MSFT, -1000039001) \ + _(XR_ERROR_SECONDARY_VIEW_CONFIGURATION_TYPE_NOT_ENABLED_MSFT, -1000053000) \ + _(XR_ERROR_CONTROLLER_MODEL_KEY_INVALID_MSFT, -1000055000) \ + _(XR_ERROR_REPROJECTION_MODE_UNSUPPORTED_MSFT, -1000066000) \ + _(XR_ERROR_COMPUTE_NEW_SCENE_NOT_COMPLETED_MSFT, -1000097000) \ + _(XR_ERROR_SCENE_COMPONENT_ID_INVALID_MSFT, -1000097001) \ + _(XR_ERROR_SCENE_COMPONENT_TYPE_MISMATCH_MSFT, -1000097002) \ + _(XR_ERROR_SCENE_MESH_BUFFER_ID_INVALID_MSFT, -1000097003) \ + _(XR_ERROR_SCENE_COMPUTE_FEATURE_INCOMPATIBLE_MSFT, -1000097004) \ + _(XR_ERROR_SCENE_COMPUTE_CONSISTENCY_MISMATCH_MSFT, -1000097005) \ + _(XR_ERROR_DISPLAY_REFRESH_RATE_UNSUPPORTED_FB, -1000101000) \ + _(XR_ERROR_COLOR_SPACE_UNSUPPORTED_FB, -1000108000) \ + _(XR_ERROR_SPACE_COMPONENT_NOT_SUPPORTED_FB, -1000113000) \ + _(XR_ERROR_SPACE_COMPONENT_NOT_ENABLED_FB, -1000113001) \ + _(XR_ERROR_SPACE_COMPONENT_STATUS_PENDING_FB, -1000113002) \ + _(XR_ERROR_SPACE_COMPONENT_STATUS_ALREADY_SET_FB, -1000113003) \ + _(XR_ERROR_UNEXPECTED_STATE_PASSTHROUGH_FB, -1000118000) \ + _(XR_ERROR_FEATURE_ALREADY_CREATED_PASSTHROUGH_FB, -1000118001) \ + _(XR_ERROR_FEATURE_REQUIRED_PASSTHROUGH_FB, -1000118002) \ + _(XR_ERROR_NOT_PERMITTED_PASSTHROUGH_FB, -1000118003) \ + _(XR_ERROR_INSUFFICIENT_RESOURCES_PASSTHROUGH_FB, -1000118004) \ + _(XR_ERROR_UNKNOWN_PASSTHROUGH_FB, -1000118050) \ + _(XR_ERROR_RENDER_MODEL_KEY_INVALID_FB, -1000119000) \ + _(XR_RENDER_MODEL_UNAVAILABLE_FB, 1000119020) \ + _(XR_ERROR_MARKER_NOT_TRACKED_VARJO, -1000124000) \ + _(XR_ERROR_MARKER_ID_INVALID_VARJO, -1000124001) \ + _(XR_ERROR_SPATIAL_ANCHOR_NAME_NOT_FOUND_MSFT, -1000142001) \ + _(XR_ERROR_SPATIAL_ANCHOR_NAME_INVALID_MSFT, -1000142002) \ + _(XR_ERROR_SPACE_MAPPING_INSUFFICIENT_FB, -1000169000) \ + _(XR_ERROR_SPACE_LOCALIZATION_FAILED_FB, -1000169001) \ + _(XR_ERROR_SPACE_NETWORK_TIMEOUT_FB, -1000169002) \ + _(XR_ERROR_SPACE_NETWORK_REQUEST_FAILED_FB, -1000169003) \ + _(XR_ERROR_SPACE_CLOUD_STORAGE_DISABLED_FB, -1000169004) \ + _(XR_ERROR_PASSTHROUGH_COLOR_LUT_BUFFER_SIZE_MISMATCH_META, -1000266000) \ + _(XR_ERROR_HINT_ALREADY_SET_QCOM, -1000306000) \ + _(XR_ERROR_SPACE_NOT_LOCATABLE_EXT, -1000429000) \ + _(XR_ERROR_PLANE_DETECTION_PERMISSION_DENIED_EXT, -1000429001) \ + _(XR_RESULT_MAX_ENUM, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrStructureType(_) \ + _(XR_TYPE_UNKNOWN, 0) \ + _(XR_TYPE_API_LAYER_PROPERTIES, 1) \ + _(XR_TYPE_EXTENSION_PROPERTIES, 2) \ + _(XR_TYPE_INSTANCE_CREATE_INFO, 3) \ + _(XR_TYPE_SYSTEM_GET_INFO, 4) \ + _(XR_TYPE_SYSTEM_PROPERTIES, 5) \ + _(XR_TYPE_VIEW_LOCATE_INFO, 6) \ + _(XR_TYPE_VIEW, 7) \ + _(XR_TYPE_SESSION_CREATE_INFO, 8) \ + _(XR_TYPE_SWAPCHAIN_CREATE_INFO, 9) \ + _(XR_TYPE_SESSION_BEGIN_INFO, 10) \ + _(XR_TYPE_VIEW_STATE, 11) \ + _(XR_TYPE_FRAME_END_INFO, 12) \ + _(XR_TYPE_HAPTIC_VIBRATION, 13) \ + _(XR_TYPE_EVENT_DATA_BUFFER, 16) \ + _(XR_TYPE_EVENT_DATA_INSTANCE_LOSS_PENDING, 17) \ + _(XR_TYPE_EVENT_DATA_SESSION_STATE_CHANGED, 18) \ + _(XR_TYPE_ACTION_STATE_BOOLEAN, 23) \ + _(XR_TYPE_ACTION_STATE_FLOAT, 24) \ + _(XR_TYPE_ACTION_STATE_VECTOR2F, 25) \ + _(XR_TYPE_ACTION_STATE_POSE, 27) \ + _(XR_TYPE_ACTION_SET_CREATE_INFO, 28) \ + _(XR_TYPE_ACTION_CREATE_INFO, 29) \ + _(XR_TYPE_INSTANCE_PROPERTIES, 32) \ + _(XR_TYPE_FRAME_WAIT_INFO, 33) \ + _(XR_TYPE_COMPOSITION_LAYER_PROJECTION, 35) \ + _(XR_TYPE_COMPOSITION_LAYER_QUAD, 36) \ + _(XR_TYPE_REFERENCE_SPACE_CREATE_INFO, 37) \ + _(XR_TYPE_ACTION_SPACE_CREATE_INFO, 38) \ + _(XR_TYPE_EVENT_DATA_REFERENCE_SPACE_CHANGE_PENDING, 40) \ + _(XR_TYPE_VIEW_CONFIGURATION_VIEW, 41) \ + _(XR_TYPE_SPACE_LOCATION, 42) \ + _(XR_TYPE_SPACE_VELOCITY, 43) \ + _(XR_TYPE_FRAME_STATE, 44) \ + _(XR_TYPE_VIEW_CONFIGURATION_PROPERTIES, 45) \ + _(XR_TYPE_FRAME_BEGIN_INFO, 46) \ + _(XR_TYPE_COMPOSITION_LAYER_PROJECTION_VIEW, 48) \ + _(XR_TYPE_EVENT_DATA_EVENTS_LOST, 49) \ + _(XR_TYPE_INTERACTION_PROFILE_SUGGESTED_BINDING, 51) \ + _(XR_TYPE_EVENT_DATA_INTERACTION_PROFILE_CHANGED, 52) \ + _(XR_TYPE_INTERACTION_PROFILE_STATE, 53) \ + _(XR_TYPE_SWAPCHAIN_IMAGE_ACQUIRE_INFO, 55) \ + _(XR_TYPE_SWAPCHAIN_IMAGE_WAIT_INFO, 56) \ + _(XR_TYPE_SWAPCHAIN_IMAGE_RELEASE_INFO, 57) \ + _(XR_TYPE_ACTION_STATE_GET_INFO, 58) \ + _(XR_TYPE_HAPTIC_ACTION_INFO, 59) \ + _(XR_TYPE_SESSION_ACTION_SETS_ATTACH_INFO, 60) \ + _(XR_TYPE_ACTIONS_SYNC_INFO, 61) \ + _(XR_TYPE_BOUND_SOURCES_FOR_ACTION_ENUMERATE_INFO, 62) \ + _(XR_TYPE_INPUT_SOURCE_LOCALIZED_NAME_GET_INFO, 63) \ + _(XR_TYPE_COMPOSITION_LAYER_CUBE_KHR, 1000006000) \ + _(XR_TYPE_INSTANCE_CREATE_INFO_ANDROID_KHR, 1000008000) \ + _(XR_TYPE_COMPOSITION_LAYER_DEPTH_INFO_KHR, 1000010000) \ + _(XR_TYPE_VULKAN_SWAPCHAIN_FORMAT_LIST_CREATE_INFO_KHR, 1000014000) \ + _(XR_TYPE_EVENT_DATA_PERF_SETTINGS_EXT, 1000015000) \ + _(XR_TYPE_COMPOSITION_LAYER_CYLINDER_KHR, 1000017000) \ + _(XR_TYPE_COMPOSITION_LAYER_EQUIRECT_KHR, 1000018000) \ + _(XR_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT, 1000019000) \ + _(XR_TYPE_DEBUG_UTILS_MESSENGER_CALLBACK_DATA_EXT, 1000019001) \ + _(XR_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT, 1000019002) \ + _(XR_TYPE_DEBUG_UTILS_LABEL_EXT, 1000019003) \ + _(XR_TYPE_GRAPHICS_BINDING_OPENGL_WIN32_KHR, 1000023000) \ + _(XR_TYPE_GRAPHICS_BINDING_OPENGL_XLIB_KHR, 1000023001) \ + _(XR_TYPE_GRAPHICS_BINDING_OPENGL_XCB_KHR, 1000023002) \ + _(XR_TYPE_GRAPHICS_BINDING_OPENGL_WAYLAND_KHR, 1000023003) \ + _(XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_KHR, 1000023004) \ + _(XR_TYPE_GRAPHICS_REQUIREMENTS_OPENGL_KHR, 1000023005) \ + _(XR_TYPE_GRAPHICS_BINDING_OPENGL_ES_ANDROID_KHR, 1000024001) \ + _(XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_ES_KHR, 1000024002) \ + _(XR_TYPE_GRAPHICS_REQUIREMENTS_OPENGL_ES_KHR, 1000024003) \ + _(XR_TYPE_GRAPHICS_BINDING_VULKAN_KHR, 1000025000) \ + _(XR_TYPE_SWAPCHAIN_IMAGE_VULKAN_KHR, 1000025001) \ + _(XR_TYPE_GRAPHICS_REQUIREMENTS_VULKAN_KHR, 1000025002) \ + _(XR_TYPE_GRAPHICS_BINDING_D3D11_KHR, 1000027000) \ + _(XR_TYPE_SWAPCHAIN_IMAGE_D3D11_KHR, 1000027001) \ + _(XR_TYPE_GRAPHICS_REQUIREMENTS_D3D11_KHR, 1000027002) \ + _(XR_TYPE_GRAPHICS_BINDING_D3D12_KHR, 1000028000) \ + _(XR_TYPE_SWAPCHAIN_IMAGE_D3D12_KHR, 1000028001) \ + _(XR_TYPE_GRAPHICS_REQUIREMENTS_D3D12_KHR, 1000028002) \ + _(XR_TYPE_SYSTEM_EYE_GAZE_INTERACTION_PROPERTIES_EXT, 1000030000) \ + _(XR_TYPE_EYE_GAZE_SAMPLE_TIME_EXT, 1000030001) \ + _(XR_TYPE_VISIBILITY_MASK_KHR, 1000031000) \ + _(XR_TYPE_EVENT_DATA_VISIBILITY_MASK_CHANGED_KHR, 1000031001) \ + _(XR_TYPE_SESSION_CREATE_INFO_OVERLAY_EXTX, 1000033000) \ + _(XR_TYPE_EVENT_DATA_MAIN_SESSION_VISIBILITY_CHANGED_EXTX, 1000033003) \ + _(XR_TYPE_COMPOSITION_LAYER_COLOR_SCALE_BIAS_KHR, 1000034000) \ + _(XR_TYPE_SPATIAL_ANCHOR_CREATE_INFO_MSFT, 1000039000) \ + _(XR_TYPE_SPATIAL_ANCHOR_SPACE_CREATE_INFO_MSFT, 1000039001) \ + _(XR_TYPE_COMPOSITION_LAYER_IMAGE_LAYOUT_FB, 1000040000) \ + _(XR_TYPE_COMPOSITION_LAYER_ALPHA_BLEND_FB, 1000041001) \ + _(XR_TYPE_VIEW_CONFIGURATION_DEPTH_RANGE_EXT, 1000046000) \ + _(XR_TYPE_GRAPHICS_BINDING_EGL_MNDX, 1000048004) \ + _(XR_TYPE_SPATIAL_GRAPH_NODE_SPACE_CREATE_INFO_MSFT, 1000049000) \ + _(XR_TYPE_SPATIAL_GRAPH_STATIC_NODE_BINDING_CREATE_INFO_MSFT, 1000049001) \ + _(XR_TYPE_SPATIAL_GRAPH_NODE_BINDING_PROPERTIES_GET_INFO_MSFT, 1000049002) \ + _(XR_TYPE_SPATIAL_GRAPH_NODE_BINDING_PROPERTIES_MSFT, 1000049003) \ + _(XR_TYPE_SYSTEM_HAND_TRACKING_PROPERTIES_EXT, 1000051000) \ + _(XR_TYPE_HAND_TRACKER_CREATE_INFO_EXT, 1000051001) \ + _(XR_TYPE_HAND_JOINTS_LOCATE_INFO_EXT, 1000051002) \ + _(XR_TYPE_HAND_JOINT_LOCATIONS_EXT, 1000051003) \ + _(XR_TYPE_HAND_JOINT_VELOCITIES_EXT, 1000051004) \ + _(XR_TYPE_SYSTEM_HAND_TRACKING_MESH_PROPERTIES_MSFT, 1000052000) \ + _(XR_TYPE_HAND_MESH_SPACE_CREATE_INFO_MSFT, 1000052001) \ + _(XR_TYPE_HAND_MESH_UPDATE_INFO_MSFT, 1000052002) \ + _(XR_TYPE_HAND_MESH_MSFT, 1000052003) \ + _(XR_TYPE_HAND_POSE_TYPE_INFO_MSFT, 1000052004) \ + _(XR_TYPE_SECONDARY_VIEW_CONFIGURATION_SESSION_BEGIN_INFO_MSFT, 1000053000) \ + _(XR_TYPE_SECONDARY_VIEW_CONFIGURATION_STATE_MSFT, 1000053001) \ + _(XR_TYPE_SECONDARY_VIEW_CONFIGURATION_FRAME_STATE_MSFT, 1000053002) \ + _(XR_TYPE_SECONDARY_VIEW_CONFIGURATION_FRAME_END_INFO_MSFT, 1000053003) \ + _(XR_TYPE_SECONDARY_VIEW_CONFIGURATION_LAYER_INFO_MSFT, 1000053004) \ + _(XR_TYPE_SECONDARY_VIEW_CONFIGURATION_SWAPCHAIN_CREATE_INFO_MSFT, 1000053005) \ + _(XR_TYPE_CONTROLLER_MODEL_KEY_STATE_MSFT, 1000055000) \ + _(XR_TYPE_CONTROLLER_MODEL_NODE_PROPERTIES_MSFT, 1000055001) \ + _(XR_TYPE_CONTROLLER_MODEL_PROPERTIES_MSFT, 1000055002) \ + _(XR_TYPE_CONTROLLER_MODEL_NODE_STATE_MSFT, 1000055003) \ + _(XR_TYPE_CONTROLLER_MODEL_STATE_MSFT, 1000055004) \ + _(XR_TYPE_VIEW_CONFIGURATION_VIEW_FOV_EPIC, 1000059000) \ + _(XR_TYPE_HOLOGRAPHIC_WINDOW_ATTACHMENT_MSFT, 1000063000) \ + _(XR_TYPE_COMPOSITION_LAYER_REPROJECTION_INFO_MSFT, 1000066000) \ + _(XR_TYPE_COMPOSITION_LAYER_REPROJECTION_PLANE_OVERRIDE_MSFT, 1000066001) \ + _(XR_TYPE_ANDROID_SURFACE_SWAPCHAIN_CREATE_INFO_FB, 1000070000) \ + _(XR_TYPE_COMPOSITION_LAYER_SECURE_CONTENT_FB, 1000072000) \ + _(XR_TYPE_BODY_TRACKER_CREATE_INFO_FB, 1000076001) \ + _(XR_TYPE_BODY_JOINTS_LOCATE_INFO_FB, 1000076002) \ + _(XR_TYPE_SYSTEM_BODY_TRACKING_PROPERTIES_FB, 1000076004) \ + _(XR_TYPE_BODY_JOINT_LOCATIONS_FB, 1000076005) \ + _(XR_TYPE_BODY_SKELETON_FB, 1000076006) \ + _(XR_TYPE_INTERACTION_PROFILE_DPAD_BINDING_EXT, 1000078000) \ + _(XR_TYPE_INTERACTION_PROFILE_ANALOG_THRESHOLD_VALVE, 1000079000) \ + _(XR_TYPE_HAND_JOINTS_MOTION_RANGE_INFO_EXT, 1000080000) \ + _(XR_TYPE_LOADER_INIT_INFO_ANDROID_KHR, 1000089000) \ + _(XR_TYPE_VULKAN_INSTANCE_CREATE_INFO_KHR, 1000090000) \ + _(XR_TYPE_VULKAN_DEVICE_CREATE_INFO_KHR, 1000090001) \ + _(XR_TYPE_VULKAN_GRAPHICS_DEVICE_GET_INFO_KHR, 1000090003) \ + _(XR_TYPE_COMPOSITION_LAYER_EQUIRECT2_KHR, 1000091000) \ + _(XR_TYPE_SCENE_OBSERVER_CREATE_INFO_MSFT, 1000097000) \ + _(XR_TYPE_SCENE_CREATE_INFO_MSFT, 1000097001) \ + _(XR_TYPE_NEW_SCENE_COMPUTE_INFO_MSFT, 1000097002) \ + _(XR_TYPE_VISUAL_MESH_COMPUTE_LOD_INFO_MSFT, 1000097003) \ + _(XR_TYPE_SCENE_COMPONENTS_MSFT, 1000097004) \ + _(XR_TYPE_SCENE_COMPONENTS_GET_INFO_MSFT, 1000097005) \ + _(XR_TYPE_SCENE_COMPONENT_LOCATIONS_MSFT, 1000097006) \ + _(XR_TYPE_SCENE_COMPONENTS_LOCATE_INFO_MSFT, 1000097007) \ + _(XR_TYPE_SCENE_OBJECTS_MSFT, 1000097008) \ + _(XR_TYPE_SCENE_COMPONENT_PARENT_FILTER_INFO_MSFT, 1000097009) \ + _(XR_TYPE_SCENE_OBJECT_TYPES_FILTER_INFO_MSFT, 1000097010) \ + _(XR_TYPE_SCENE_PLANES_MSFT, 1000097011) \ + _(XR_TYPE_SCENE_PLANE_ALIGNMENT_FILTER_INFO_MSFT, 1000097012) \ + _(XR_TYPE_SCENE_MESHES_MSFT, 1000097013) \ + _(XR_TYPE_SCENE_MESH_BUFFERS_GET_INFO_MSFT, 1000097014) \ + _(XR_TYPE_SCENE_MESH_BUFFERS_MSFT, 1000097015) \ + _(XR_TYPE_SCENE_MESH_VERTEX_BUFFER_MSFT, 1000097016) \ + _(XR_TYPE_SCENE_MESH_INDICES_UINT32_MSFT, 1000097017) \ + _(XR_TYPE_SCENE_MESH_INDICES_UINT16_MSFT, 1000097018) \ + _(XR_TYPE_SERIALIZED_SCENE_FRAGMENT_DATA_GET_INFO_MSFT, 1000098000) \ + _(XR_TYPE_SCENE_DESERIALIZE_INFO_MSFT, 1000098001) \ + _(XR_TYPE_EVENT_DATA_DISPLAY_REFRESH_RATE_CHANGED_FB, 1000101000) \ + _(XR_TYPE_VIVE_TRACKER_PATHS_HTCX, 1000103000) \ + _(XR_TYPE_EVENT_DATA_VIVE_TRACKER_CONNECTED_HTCX, 1000103001) \ + _(XR_TYPE_SYSTEM_FACIAL_TRACKING_PROPERTIES_HTC, 1000104000) \ + _(XR_TYPE_FACIAL_TRACKER_CREATE_INFO_HTC, 1000104001) \ + _(XR_TYPE_FACIAL_EXPRESSIONS_HTC, 1000104002) \ + _(XR_TYPE_SYSTEM_COLOR_SPACE_PROPERTIES_FB, 1000108000) \ + _(XR_TYPE_HAND_TRACKING_MESH_FB, 1000110001) \ + _(XR_TYPE_HAND_TRACKING_SCALE_FB, 1000110003) \ + _(XR_TYPE_HAND_TRACKING_AIM_STATE_FB, 1000111001) \ + _(XR_TYPE_HAND_TRACKING_CAPSULES_STATE_FB, 1000112000) \ + _(XR_TYPE_SYSTEM_SPATIAL_ENTITY_PROPERTIES_FB, 1000113004) \ + _(XR_TYPE_SPATIAL_ANCHOR_CREATE_INFO_FB, 1000113003) \ + _(XR_TYPE_SPACE_COMPONENT_STATUS_SET_INFO_FB, 1000113007) \ + _(XR_TYPE_SPACE_COMPONENT_STATUS_FB, 1000113001) \ + _(XR_TYPE_EVENT_DATA_SPATIAL_ANCHOR_CREATE_COMPLETE_FB, 1000113005) \ + _(XR_TYPE_EVENT_DATA_SPACE_SET_STATUS_COMPLETE_FB, 1000113006) \ + _(XR_TYPE_FOVEATION_PROFILE_CREATE_INFO_FB, 1000114000) \ + _(XR_TYPE_SWAPCHAIN_CREATE_INFO_FOVEATION_FB, 1000114001) \ + _(XR_TYPE_SWAPCHAIN_STATE_FOVEATION_FB, 1000114002) \ + _(XR_TYPE_FOVEATION_LEVEL_PROFILE_CREATE_INFO_FB, 1000115000) \ + _(XR_TYPE_KEYBOARD_SPACE_CREATE_INFO_FB, 1000116009) \ + _(XR_TYPE_KEYBOARD_TRACKING_QUERY_FB, 1000116004) \ + _(XR_TYPE_SYSTEM_KEYBOARD_TRACKING_PROPERTIES_FB, 1000116002) \ + _(XR_TYPE_TRIANGLE_MESH_CREATE_INFO_FB, 1000117001) \ + _(XR_TYPE_SYSTEM_PASSTHROUGH_PROPERTIES_FB, 1000118000) \ + _(XR_TYPE_PASSTHROUGH_CREATE_INFO_FB, 1000118001) \ + _(XR_TYPE_PASSTHROUGH_LAYER_CREATE_INFO_FB, 1000118002) \ + _(XR_TYPE_COMPOSITION_LAYER_PASSTHROUGH_FB, 1000118003) \ + _(XR_TYPE_GEOMETRY_INSTANCE_CREATE_INFO_FB, 1000118004) \ + _(XR_TYPE_GEOMETRY_INSTANCE_TRANSFORM_FB, 1000118005) \ + _(XR_TYPE_SYSTEM_PASSTHROUGH_PROPERTIES2_FB, 1000118006) \ + _(XR_TYPE_PASSTHROUGH_STYLE_FB, 1000118020) \ + _(XR_TYPE_PASSTHROUGH_COLOR_MAP_MONO_TO_RGBA_FB, 1000118021) \ + _(XR_TYPE_PASSTHROUGH_COLOR_MAP_MONO_TO_MONO_FB, 1000118022) \ + _(XR_TYPE_PASSTHROUGH_BRIGHTNESS_CONTRAST_SATURATION_FB, 1000118023) \ + _(XR_TYPE_EVENT_DATA_PASSTHROUGH_STATE_CHANGED_FB, 1000118030) \ + _(XR_TYPE_RENDER_MODEL_PATH_INFO_FB, 1000119000) \ + _(XR_TYPE_RENDER_MODEL_PROPERTIES_FB, 1000119001) \ + _(XR_TYPE_RENDER_MODEL_BUFFER_FB, 1000119002) \ + _(XR_TYPE_RENDER_MODEL_LOAD_INFO_FB, 1000119003) \ + _(XR_TYPE_SYSTEM_RENDER_MODEL_PROPERTIES_FB, 1000119004) \ + _(XR_TYPE_RENDER_MODEL_CAPABILITIES_REQUEST_FB, 1000119005) \ + _(XR_TYPE_BINDING_MODIFICATIONS_KHR, 1000120000) \ + _(XR_TYPE_VIEW_LOCATE_FOVEATED_RENDERING_VARJO, 1000121000) \ + _(XR_TYPE_FOVEATED_VIEW_CONFIGURATION_VIEW_VARJO, 1000121001) \ + _(XR_TYPE_SYSTEM_FOVEATED_RENDERING_PROPERTIES_VARJO, 1000121002) \ + _(XR_TYPE_COMPOSITION_LAYER_DEPTH_TEST_VARJO, 1000122000) \ + _(XR_TYPE_SYSTEM_MARKER_TRACKING_PROPERTIES_VARJO, 1000124000) \ + _(XR_TYPE_EVENT_DATA_MARKER_TRACKING_UPDATE_VARJO, 1000124001) \ + _(XR_TYPE_MARKER_SPACE_CREATE_INFO_VARJO, 1000124002) \ + _(XR_TYPE_FRAME_END_INFO_ML, 1000135000) \ + _(XR_TYPE_GLOBAL_DIMMER_FRAME_END_INFO_ML, 1000136000) \ + _(XR_TYPE_COORDINATE_SPACE_CREATE_INFO_ML, 1000137000) \ + _(XR_TYPE_SPATIAL_ANCHOR_PERSISTENCE_INFO_MSFT, 1000142000) \ + _(XR_TYPE_SPATIAL_ANCHOR_FROM_PERSISTED_ANCHOR_CREATE_INFO_MSFT, 1000142001) \ + _(XR_TYPE_SPACE_QUERY_INFO_FB, 1000156001) \ + _(XR_TYPE_SPACE_QUERY_RESULTS_FB, 1000156002) \ + _(XR_TYPE_SPACE_STORAGE_LOCATION_FILTER_INFO_FB, 1000156003) \ + _(XR_TYPE_SPACE_UUID_FILTER_INFO_FB, 1000156054) \ + _(XR_TYPE_SPACE_COMPONENT_FILTER_INFO_FB, 1000156052) \ + _(XR_TYPE_EVENT_DATA_SPACE_QUERY_RESULTS_AVAILABLE_FB, 1000156103) \ + _(XR_TYPE_EVENT_DATA_SPACE_QUERY_COMPLETE_FB, 1000156104) \ + _(XR_TYPE_SPACE_SAVE_INFO_FB, 1000158000) \ + _(XR_TYPE_SPACE_ERASE_INFO_FB, 1000158001) \ + _(XR_TYPE_EVENT_DATA_SPACE_SAVE_COMPLETE_FB, 1000158106) \ + _(XR_TYPE_EVENT_DATA_SPACE_ERASE_COMPLETE_FB, 1000158107) \ + _(XR_TYPE_SWAPCHAIN_IMAGE_FOVEATION_VULKAN_FB, 1000160000) \ + _(XR_TYPE_SWAPCHAIN_STATE_ANDROID_SURFACE_DIMENSIONS_FB, 1000161000) \ + _(XR_TYPE_SWAPCHAIN_STATE_SAMPLER_OPENGL_ES_FB, 1000162000) \ + _(XR_TYPE_SWAPCHAIN_STATE_SAMPLER_VULKAN_FB, 1000163000) \ + _(XR_TYPE_SPACE_SHARE_INFO_FB, 1000169001) \ + _(XR_TYPE_EVENT_DATA_SPACE_SHARE_COMPLETE_FB, 1000169002) \ + _(XR_TYPE_COMPOSITION_LAYER_SPACE_WARP_INFO_FB, 1000171000) \ + _(XR_TYPE_SYSTEM_SPACE_WARP_PROPERTIES_FB, 1000171001) \ + _(XR_TYPE_HAPTIC_AMPLITUDE_ENVELOPE_VIBRATION_FB, 1000173001) \ + _(XR_TYPE_SEMANTIC_LABELS_FB, 1000175000) \ + _(XR_TYPE_ROOM_LAYOUT_FB, 1000175001) \ + _(XR_TYPE_BOUNDARY_2D_FB, 1000175002) \ + _(XR_TYPE_SEMANTIC_LABELS_SUPPORT_INFO_FB, 1000175010) \ + _(XR_TYPE_DIGITAL_LENS_CONTROL_ALMALENCE, 1000196000) \ + _(XR_TYPE_EVENT_DATA_SCENE_CAPTURE_COMPLETE_FB, 1000198001) \ + _(XR_TYPE_SCENE_CAPTURE_REQUEST_INFO_FB, 1000198050) \ + _(XR_TYPE_SPACE_CONTAINER_FB, 1000199000) \ + _(XR_TYPE_FOVEATION_EYE_TRACKED_PROFILE_CREATE_INFO_META, 1000200000) \ + _(XR_TYPE_FOVEATION_EYE_TRACKED_STATE_META, 1000200001) \ + _(XR_TYPE_SYSTEM_FOVEATION_EYE_TRACKED_PROPERTIES_META, 1000200002) \ + _(XR_TYPE_SYSTEM_FACE_TRACKING_PROPERTIES_FB, 1000201004) \ + _(XR_TYPE_FACE_TRACKER_CREATE_INFO_FB, 1000201005) \ + _(XR_TYPE_FACE_EXPRESSION_INFO_FB, 1000201002) \ + _(XR_TYPE_FACE_EXPRESSION_WEIGHTS_FB, 1000201006) \ + _(XR_TYPE_EYE_TRACKER_CREATE_INFO_FB, 1000202001) \ + _(XR_TYPE_EYE_GAZES_INFO_FB, 1000202002) \ + _(XR_TYPE_EYE_GAZES_FB, 1000202003) \ + _(XR_TYPE_SYSTEM_EYE_TRACKING_PROPERTIES_FB, 1000202004) \ + _(XR_TYPE_PASSTHROUGH_KEYBOARD_HANDS_INTENSITY_FB, 1000203002) \ + _(XR_TYPE_COMPOSITION_LAYER_SETTINGS_FB, 1000204000) \ + _(XR_TYPE_HAPTIC_PCM_VIBRATION_FB, 1000209001) \ + _(XR_TYPE_DEVICE_PCM_SAMPLE_RATE_STATE_FB, 1000209002) \ + _(XR_TYPE_COMPOSITION_LAYER_DEPTH_TEST_FB, 1000212000) \ + _(XR_TYPE_LOCAL_DIMMING_FRAME_END_INFO_META, 1000216000) \ + _(XR_TYPE_PASSTHROUGH_PREFERENCES_META, 1000217000) \ + _(XR_TYPE_SYSTEM_VIRTUAL_KEYBOARD_PROPERTIES_META, 1000219001) \ + _(XR_TYPE_VIRTUAL_KEYBOARD_CREATE_INFO_META, 1000219002) \ + _(XR_TYPE_VIRTUAL_KEYBOARD_SPACE_CREATE_INFO_META, 1000219003) \ + _(XR_TYPE_VIRTUAL_KEYBOARD_LOCATION_INFO_META, 1000219004) \ + _(XR_TYPE_VIRTUAL_KEYBOARD_MODEL_VISIBILITY_SET_INFO_META, 1000219005) \ + _(XR_TYPE_VIRTUAL_KEYBOARD_ANIMATION_STATE_META, 1000219006) \ + _(XR_TYPE_VIRTUAL_KEYBOARD_MODEL_ANIMATION_STATES_META, 1000219007) \ + _(XR_TYPE_VIRTUAL_KEYBOARD_TEXTURE_DATA_META, 1000219009) \ + _(XR_TYPE_VIRTUAL_KEYBOARD_INPUT_INFO_META, 1000219010) \ + _(XR_TYPE_VIRTUAL_KEYBOARD_TEXT_CONTEXT_CHANGE_INFO_META, 1000219011) \ + _(XR_TYPE_EVENT_DATA_VIRTUAL_KEYBOARD_COMMIT_TEXT_META, 1000219014) \ + _(XR_TYPE_EVENT_DATA_VIRTUAL_KEYBOARD_BACKSPACE_META, 1000219015) \ + _(XR_TYPE_EVENT_DATA_VIRTUAL_KEYBOARD_ENTER_META, 1000219016) \ + _(XR_TYPE_EVENT_DATA_VIRTUAL_KEYBOARD_SHOWN_META, 1000219017) \ + _(XR_TYPE_EVENT_DATA_VIRTUAL_KEYBOARD_HIDDEN_META, 1000219018) \ + _(XR_TYPE_EXTERNAL_CAMERA_OCULUS, 1000226000) \ + _(XR_TYPE_VULKAN_SWAPCHAIN_CREATE_INFO_META, 1000227000) \ + _(XR_TYPE_PERFORMANCE_METRICS_STATE_META, 1000232001) \ + _(XR_TYPE_PERFORMANCE_METRICS_COUNTER_META, 1000232002) \ + _(XR_TYPE_SPACE_LIST_SAVE_INFO_FB, 1000238000) \ + _(XR_TYPE_EVENT_DATA_SPACE_LIST_SAVE_COMPLETE_FB, 1000238001) \ + _(XR_TYPE_SPACE_USER_CREATE_INFO_FB, 1000241001) \ + _(XR_TYPE_SYSTEM_HEADSET_ID_PROPERTIES_META, 1000245000) \ + _(XR_TYPE_SYSTEM_PASSTHROUGH_COLOR_LUT_PROPERTIES_META, 1000266000) \ + _(XR_TYPE_PASSTHROUGH_COLOR_LUT_CREATE_INFO_META, 1000266001) \ + _(XR_TYPE_PASSTHROUGH_COLOR_LUT_UPDATE_INFO_META, 1000266002) \ + _(XR_TYPE_PASSTHROUGH_COLOR_MAP_LUT_META, 1000266100) \ + _(XR_TYPE_PASSTHROUGH_COLOR_MAP_INTERPOLATED_LUT_META, 1000266101) \ + _(XR_TYPE_PASSTHROUGH_CREATE_INFO_HTC, 1000317001) \ + _(XR_TYPE_PASSTHROUGH_COLOR_HTC, 1000317002) \ + _(XR_TYPE_PASSTHROUGH_MESH_TRANSFORM_INFO_HTC, 1000317003) \ + _(XR_TYPE_COMPOSITION_LAYER_PASSTHROUGH_HTC, 1000317004) \ + _(XR_TYPE_FOVEATION_APPLY_INFO_HTC, 1000318000) \ + _(XR_TYPE_FOVEATION_DYNAMIC_MODE_INFO_HTC, 1000318001) \ + _(XR_TYPE_FOVEATION_CUSTOM_MODE_INFO_HTC, 1000318002) \ + _(XR_TYPE_ACTIVE_ACTION_SET_PRIORITIES_EXT, 1000373000) \ + _(XR_TYPE_SYSTEM_FORCE_FEEDBACK_CURL_PROPERTIES_MNDX, 1000375000) \ + _(XR_TYPE_FORCE_FEEDBACK_CURL_APPLY_LOCATIONS_MNDX, 1000375001) \ + _(XR_TYPE_HAND_TRACKING_DATA_SOURCE_INFO_EXT, 1000428000) \ + _(XR_TYPE_HAND_TRACKING_DATA_SOURCE_STATE_EXT, 1000428001) \ + _(XR_TYPE_PLANE_DETECTOR_CREATE_INFO_EXT, 1000429001) \ + _(XR_TYPE_PLANE_DETECTOR_BEGIN_INFO_EXT, 1000429002) \ + _(XR_TYPE_PLANE_DETECTOR_GET_INFO_EXT, 1000429003) \ + _(XR_TYPE_PLANE_DETECTOR_LOCATIONS_EXT, 1000429004) \ + _(XR_TYPE_PLANE_DETECTOR_LOCATION_EXT, 1000429005) \ + _(XR_TYPE_PLANE_DETECTOR_POLYGON_BUFFER_EXT, 1000429006) \ + _(XR_TYPE_SYSTEM_PLANE_DETECTION_PROPERTIES_EXT, 1000429007) \ + _(XR_STRUCTURE_TYPE_MAX_ENUM, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrFormFactor(_) \ + _(XR_FORM_FACTOR_HEAD_MOUNTED_DISPLAY, 1) \ + _(XR_FORM_FACTOR_HANDHELD_DISPLAY, 2) \ + _(XR_FORM_FACTOR_MAX_ENUM, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrViewConfigurationType(_) \ + _(XR_VIEW_CONFIGURATION_TYPE_PRIMARY_MONO, 1) \ + _(XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO, 2) \ + _(XR_VIEW_CONFIGURATION_TYPE_PRIMARY_QUAD_VARJO, 1000037000) \ + _(XR_VIEW_CONFIGURATION_TYPE_SECONDARY_MONO_FIRST_PERSON_OBSERVER_MSFT, 1000054000) \ + _(XR_VIEW_CONFIGURATION_TYPE_MAX_ENUM, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrEnvironmentBlendMode(_) \ + _(XR_ENVIRONMENT_BLEND_MODE_OPAQUE, 1) \ + _(XR_ENVIRONMENT_BLEND_MODE_ADDITIVE, 2) \ + _(XR_ENVIRONMENT_BLEND_MODE_ALPHA_BLEND, 3) \ + _(XR_ENVIRONMENT_BLEND_MODE_MAX_ENUM, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrReferenceSpaceType(_) \ + _(XR_REFERENCE_SPACE_TYPE_VIEW, 1) \ + _(XR_REFERENCE_SPACE_TYPE_LOCAL, 2) \ + _(XR_REFERENCE_SPACE_TYPE_STAGE, 3) \ + _(XR_REFERENCE_SPACE_TYPE_UNBOUNDED_MSFT, 1000038000) \ + _(XR_REFERENCE_SPACE_TYPE_COMBINED_EYE_VARJO, 1000121000) \ + _(XR_REFERENCE_SPACE_TYPE_LOCAL_FLOOR_EXT, 1000426000) \ + _(XR_REFERENCE_SPACE_TYPE_MAX_ENUM, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrActionType(_) \ + _(XR_ACTION_TYPE_BOOLEAN_INPUT, 1) \ + _(XR_ACTION_TYPE_FLOAT_INPUT, 2) \ + _(XR_ACTION_TYPE_VECTOR2F_INPUT, 3) \ + _(XR_ACTION_TYPE_POSE_INPUT, 4) \ + _(XR_ACTION_TYPE_VIBRATION_OUTPUT, 100) \ + _(XR_ACTION_TYPE_MAX_ENUM, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrEyeVisibility(_) \ + _(XR_EYE_VISIBILITY_BOTH, 0) \ + _(XR_EYE_VISIBILITY_LEFT, 1) \ + _(XR_EYE_VISIBILITY_RIGHT, 2) \ + _(XR_EYE_VISIBILITY_MAX_ENUM, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrSessionState(_) \ + _(XR_SESSION_STATE_UNKNOWN, 0) \ + _(XR_SESSION_STATE_IDLE, 1) \ + _(XR_SESSION_STATE_READY, 2) \ + _(XR_SESSION_STATE_SYNCHRONIZED, 3) \ + _(XR_SESSION_STATE_VISIBLE, 4) \ + _(XR_SESSION_STATE_FOCUSED, 5) \ + _(XR_SESSION_STATE_STOPPING, 6) \ + _(XR_SESSION_STATE_LOSS_PENDING, 7) \ + _(XR_SESSION_STATE_EXITING, 8) \ + _(XR_SESSION_STATE_MAX_ENUM, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrObjectType(_) \ + _(XR_OBJECT_TYPE_UNKNOWN, 0) \ + _(XR_OBJECT_TYPE_INSTANCE, 1) \ + _(XR_OBJECT_TYPE_SESSION, 2) \ + _(XR_OBJECT_TYPE_SWAPCHAIN, 3) \ + _(XR_OBJECT_TYPE_SPACE, 4) \ + _(XR_OBJECT_TYPE_ACTION_SET, 5) \ + _(XR_OBJECT_TYPE_ACTION, 6) \ + _(XR_OBJECT_TYPE_DEBUG_UTILS_MESSENGER_EXT, 1000019000) \ + _(XR_OBJECT_TYPE_SPATIAL_ANCHOR_MSFT, 1000039000) \ + _(XR_OBJECT_TYPE_SPATIAL_GRAPH_NODE_BINDING_MSFT, 1000049000) \ + _(XR_OBJECT_TYPE_HAND_TRACKER_EXT, 1000051000) \ + _(XR_OBJECT_TYPE_BODY_TRACKER_FB, 1000076000) \ + _(XR_OBJECT_TYPE_SCENE_OBSERVER_MSFT, 1000097000) \ + _(XR_OBJECT_TYPE_SCENE_MSFT, 1000097001) \ + _(XR_OBJECT_TYPE_FACIAL_TRACKER_HTC, 1000104000) \ + _(XR_OBJECT_TYPE_FOVEATION_PROFILE_FB, 1000114000) \ + _(XR_OBJECT_TYPE_TRIANGLE_MESH_FB, 1000117000) \ + _(XR_OBJECT_TYPE_PASSTHROUGH_FB, 1000118000) \ + _(XR_OBJECT_TYPE_PASSTHROUGH_LAYER_FB, 1000118002) \ + _(XR_OBJECT_TYPE_GEOMETRY_INSTANCE_FB, 1000118004) \ + _(XR_OBJECT_TYPE_SPATIAL_ANCHOR_STORE_CONNECTION_MSFT, 1000142000) \ + _(XR_OBJECT_TYPE_FACE_TRACKER_FB, 1000201000) \ + _(XR_OBJECT_TYPE_EYE_TRACKER_FB, 1000202000) \ + _(XR_OBJECT_TYPE_VIRTUAL_KEYBOARD_META, 1000219000) \ + _(XR_OBJECT_TYPE_SPACE_USER_FB, 1000241000) \ + _(XR_OBJECT_TYPE_PASSTHROUGH_COLOR_LUT_META, 1000266000) \ + _(XR_OBJECT_TYPE_PASSTHROUGH_HTC, 1000317000) \ + _(XR_OBJECT_TYPE_PLANE_DETECTOR_EXT, 1000429000) \ + _(XR_OBJECT_TYPE_MAX_ENUM, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrAndroidThreadTypeKHR(_) \ + _(XR_ANDROID_THREAD_TYPE_APPLICATION_MAIN_KHR, 1) \ + _(XR_ANDROID_THREAD_TYPE_APPLICATION_WORKER_KHR, 2) \ + _(XR_ANDROID_THREAD_TYPE_RENDERER_MAIN_KHR, 3) \ + _(XR_ANDROID_THREAD_TYPE_RENDERER_WORKER_KHR, 4) \ + _(XR_ANDROID_THREAD_TYPE_MAX_ENUM_KHR, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrVisibilityMaskTypeKHR(_) \ + _(XR_VISIBILITY_MASK_TYPE_HIDDEN_TRIANGLE_MESH_KHR, 1) \ + _(XR_VISIBILITY_MASK_TYPE_VISIBLE_TRIANGLE_MESH_KHR, 2) \ + _(XR_VISIBILITY_MASK_TYPE_LINE_LOOP_KHR, 3) \ + _(XR_VISIBILITY_MASK_TYPE_MAX_ENUM_KHR, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrPerfSettingsDomainEXT(_) \ + _(XR_PERF_SETTINGS_DOMAIN_CPU_EXT, 1) \ + _(XR_PERF_SETTINGS_DOMAIN_GPU_EXT, 2) \ + _(XR_PERF_SETTINGS_DOMAIN_MAX_ENUM_EXT, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrPerfSettingsSubDomainEXT(_) \ + _(XR_PERF_SETTINGS_SUB_DOMAIN_COMPOSITING_EXT, 1) \ + _(XR_PERF_SETTINGS_SUB_DOMAIN_RENDERING_EXT, 2) \ + _(XR_PERF_SETTINGS_SUB_DOMAIN_THERMAL_EXT, 3) \ + _(XR_PERF_SETTINGS_SUB_DOMAIN_MAX_ENUM_EXT, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrPerfSettingsLevelEXT(_) \ + _(XR_PERF_SETTINGS_LEVEL_POWER_SAVINGS_EXT, 0) \ + _(XR_PERF_SETTINGS_LEVEL_SUSTAINED_LOW_EXT, 25) \ + _(XR_PERF_SETTINGS_LEVEL_SUSTAINED_HIGH_EXT, 50) \ + _(XR_PERF_SETTINGS_LEVEL_BOOST_EXT, 75) \ + _(XR_PERF_SETTINGS_LEVEL_MAX_ENUM_EXT, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrPerfSettingsNotificationLevelEXT(_) \ + _(XR_PERF_SETTINGS_NOTIF_LEVEL_NORMAL_EXT, 0) \ + _(XR_PERF_SETTINGS_NOTIF_LEVEL_WARNING_EXT, 25) \ + _(XR_PERF_SETTINGS_NOTIF_LEVEL_IMPAIRED_EXT, 75) \ + _(XR_PERF_SETTINGS_NOTIFICATION_LEVEL_MAX_ENUM_EXT, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrBlendFactorFB(_) \ + _(XR_BLEND_FACTOR_ZERO_FB, 0) \ + _(XR_BLEND_FACTOR_ONE_FB, 1) \ + _(XR_BLEND_FACTOR_SRC_ALPHA_FB, 2) \ + _(XR_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA_FB, 3) \ + _(XR_BLEND_FACTOR_DST_ALPHA_FB, 4) \ + _(XR_BLEND_FACTOR_ONE_MINUS_DST_ALPHA_FB, 5) \ + _(XR_BLEND_FACTOR_MAX_ENUM_FB, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrSpatialGraphNodeTypeMSFT(_) \ + _(XR_SPATIAL_GRAPH_NODE_TYPE_STATIC_MSFT, 1) \ + _(XR_SPATIAL_GRAPH_NODE_TYPE_DYNAMIC_MSFT, 2) \ + _(XR_SPATIAL_GRAPH_NODE_TYPE_MAX_ENUM_MSFT, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrHandEXT(_) \ + _(XR_HAND_LEFT_EXT, 1) \ + _(XR_HAND_RIGHT_EXT, 2) \ + _(XR_HAND_MAX_ENUM_EXT, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrHandJointEXT(_) \ + _(XR_HAND_JOINT_PALM_EXT, 0) \ + _(XR_HAND_JOINT_WRIST_EXT, 1) \ + _(XR_HAND_JOINT_THUMB_METACARPAL_EXT, 2) \ + _(XR_HAND_JOINT_THUMB_PROXIMAL_EXT, 3) \ + _(XR_HAND_JOINT_THUMB_DISTAL_EXT, 4) \ + _(XR_HAND_JOINT_THUMB_TIP_EXT, 5) \ + _(XR_HAND_JOINT_INDEX_METACARPAL_EXT, 6) \ + _(XR_HAND_JOINT_INDEX_PROXIMAL_EXT, 7) \ + _(XR_HAND_JOINT_INDEX_INTERMEDIATE_EXT, 8) \ + _(XR_HAND_JOINT_INDEX_DISTAL_EXT, 9) \ + _(XR_HAND_JOINT_INDEX_TIP_EXT, 10) \ + _(XR_HAND_JOINT_MIDDLE_METACARPAL_EXT, 11) \ + _(XR_HAND_JOINT_MIDDLE_PROXIMAL_EXT, 12) \ + _(XR_HAND_JOINT_MIDDLE_INTERMEDIATE_EXT, 13) \ + _(XR_HAND_JOINT_MIDDLE_DISTAL_EXT, 14) \ + _(XR_HAND_JOINT_MIDDLE_TIP_EXT, 15) \ + _(XR_HAND_JOINT_RING_METACARPAL_EXT, 16) \ + _(XR_HAND_JOINT_RING_PROXIMAL_EXT, 17) \ + _(XR_HAND_JOINT_RING_INTERMEDIATE_EXT, 18) \ + _(XR_HAND_JOINT_RING_DISTAL_EXT, 19) \ + _(XR_HAND_JOINT_RING_TIP_EXT, 20) \ + _(XR_HAND_JOINT_LITTLE_METACARPAL_EXT, 21) \ + _(XR_HAND_JOINT_LITTLE_PROXIMAL_EXT, 22) \ + _(XR_HAND_JOINT_LITTLE_INTERMEDIATE_EXT, 23) \ + _(XR_HAND_JOINT_LITTLE_DISTAL_EXT, 24) \ + _(XR_HAND_JOINT_LITTLE_TIP_EXT, 25) \ + _(XR_HAND_JOINT_MAX_ENUM_EXT, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrHandJointSetEXT(_) \ + _(XR_HAND_JOINT_SET_DEFAULT_EXT, 0) \ + _(XR_HAND_JOINT_SET_HAND_WITH_FOREARM_ULTRALEAP, 1000149000) \ + _(XR_HAND_JOINT_SET_MAX_ENUM_EXT, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrHandPoseTypeMSFT(_) \ + _(XR_HAND_POSE_TYPE_TRACKED_MSFT, 0) \ + _(XR_HAND_POSE_TYPE_REFERENCE_OPEN_PALM_MSFT, 1) \ + _(XR_HAND_POSE_TYPE_MAX_ENUM_MSFT, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrReprojectionModeMSFT(_) \ + _(XR_REPROJECTION_MODE_DEPTH_MSFT, 1) \ + _(XR_REPROJECTION_MODE_PLANAR_FROM_DEPTH_MSFT, 2) \ + _(XR_REPROJECTION_MODE_PLANAR_MANUAL_MSFT, 3) \ + _(XR_REPROJECTION_MODE_ORIENTATION_ONLY_MSFT, 4) \ + _(XR_REPROJECTION_MODE_MAX_ENUM_MSFT, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrBodyJointFB(_) \ + _(XR_BODY_JOINT_ROOT_FB, 0) \ + _(XR_BODY_JOINT_HIPS_FB, 1) \ + _(XR_BODY_JOINT_SPINE_LOWER_FB, 2) \ + _(XR_BODY_JOINT_SPINE_MIDDLE_FB, 3) \ + _(XR_BODY_JOINT_SPINE_UPPER_FB, 4) \ + _(XR_BODY_JOINT_CHEST_FB, 5) \ + _(XR_BODY_JOINT_NECK_FB, 6) \ + _(XR_BODY_JOINT_HEAD_FB, 7) \ + _(XR_BODY_JOINT_LEFT_SHOULDER_FB, 8) \ + _(XR_BODY_JOINT_LEFT_SCAPULA_FB, 9) \ + _(XR_BODY_JOINT_LEFT_ARM_UPPER_FB, 10) \ + _(XR_BODY_JOINT_LEFT_ARM_LOWER_FB, 11) \ + _(XR_BODY_JOINT_LEFT_HAND_WRIST_TWIST_FB, 12) \ + _(XR_BODY_JOINT_RIGHT_SHOULDER_FB, 13) \ + _(XR_BODY_JOINT_RIGHT_SCAPULA_FB, 14) \ + _(XR_BODY_JOINT_RIGHT_ARM_UPPER_FB, 15) \ + _(XR_BODY_JOINT_RIGHT_ARM_LOWER_FB, 16) \ + _(XR_BODY_JOINT_RIGHT_HAND_WRIST_TWIST_FB, 17) \ + _(XR_BODY_JOINT_LEFT_HAND_PALM_FB, 18) \ + _(XR_BODY_JOINT_LEFT_HAND_WRIST_FB, 19) \ + _(XR_BODY_JOINT_LEFT_HAND_THUMB_METACARPAL_FB, 20) \ + _(XR_BODY_JOINT_LEFT_HAND_THUMB_PROXIMAL_FB, 21) \ + _(XR_BODY_JOINT_LEFT_HAND_THUMB_DISTAL_FB, 22) \ + _(XR_BODY_JOINT_LEFT_HAND_THUMB_TIP_FB, 23) \ + _(XR_BODY_JOINT_LEFT_HAND_INDEX_METACARPAL_FB, 24) \ + _(XR_BODY_JOINT_LEFT_HAND_INDEX_PROXIMAL_FB, 25) \ + _(XR_BODY_JOINT_LEFT_HAND_INDEX_INTERMEDIATE_FB, 26) \ + _(XR_BODY_JOINT_LEFT_HAND_INDEX_DISTAL_FB, 27) \ + _(XR_BODY_JOINT_LEFT_HAND_INDEX_TIP_FB, 28) \ + _(XR_BODY_JOINT_LEFT_HAND_MIDDLE_METACARPAL_FB, 29) \ + _(XR_BODY_JOINT_LEFT_HAND_MIDDLE_PROXIMAL_FB, 30) \ + _(XR_BODY_JOINT_LEFT_HAND_MIDDLE_INTERMEDIATE_FB, 31) \ + _(XR_BODY_JOINT_LEFT_HAND_MIDDLE_DISTAL_FB, 32) \ + _(XR_BODY_JOINT_LEFT_HAND_MIDDLE_TIP_FB, 33) \ + _(XR_BODY_JOINT_LEFT_HAND_RING_METACARPAL_FB, 34) \ + _(XR_BODY_JOINT_LEFT_HAND_RING_PROXIMAL_FB, 35) \ + _(XR_BODY_JOINT_LEFT_HAND_RING_INTERMEDIATE_FB, 36) \ + _(XR_BODY_JOINT_LEFT_HAND_RING_DISTAL_FB, 37) \ + _(XR_BODY_JOINT_LEFT_HAND_RING_TIP_FB, 38) \ + _(XR_BODY_JOINT_LEFT_HAND_LITTLE_METACARPAL_FB, 39) \ + _(XR_BODY_JOINT_LEFT_HAND_LITTLE_PROXIMAL_FB, 40) \ + _(XR_BODY_JOINT_LEFT_HAND_LITTLE_INTERMEDIATE_FB, 41) \ + _(XR_BODY_JOINT_LEFT_HAND_LITTLE_DISTAL_FB, 42) \ + _(XR_BODY_JOINT_LEFT_HAND_LITTLE_TIP_FB, 43) \ + _(XR_BODY_JOINT_RIGHT_HAND_PALM_FB, 44) \ + _(XR_BODY_JOINT_RIGHT_HAND_WRIST_FB, 45) \ + _(XR_BODY_JOINT_RIGHT_HAND_THUMB_METACARPAL_FB, 46) \ + _(XR_BODY_JOINT_RIGHT_HAND_THUMB_PROXIMAL_FB, 47) \ + _(XR_BODY_JOINT_RIGHT_HAND_THUMB_DISTAL_FB, 48) \ + _(XR_BODY_JOINT_RIGHT_HAND_THUMB_TIP_FB, 49) \ + _(XR_BODY_JOINT_RIGHT_HAND_INDEX_METACARPAL_FB, 50) \ + _(XR_BODY_JOINT_RIGHT_HAND_INDEX_PROXIMAL_FB, 51) \ + _(XR_BODY_JOINT_RIGHT_HAND_INDEX_INTERMEDIATE_FB, 52) \ + _(XR_BODY_JOINT_RIGHT_HAND_INDEX_DISTAL_FB, 53) \ + _(XR_BODY_JOINT_RIGHT_HAND_INDEX_TIP_FB, 54) \ + _(XR_BODY_JOINT_RIGHT_HAND_MIDDLE_METACARPAL_FB, 55) \ + _(XR_BODY_JOINT_RIGHT_HAND_MIDDLE_PROXIMAL_FB, 56) \ + _(XR_BODY_JOINT_RIGHT_HAND_MIDDLE_INTERMEDIATE_FB, 57) \ + _(XR_BODY_JOINT_RIGHT_HAND_MIDDLE_DISTAL_FB, 58) \ + _(XR_BODY_JOINT_RIGHT_HAND_MIDDLE_TIP_FB, 59) \ + _(XR_BODY_JOINT_RIGHT_HAND_RING_METACARPAL_FB, 60) \ + _(XR_BODY_JOINT_RIGHT_HAND_RING_PROXIMAL_FB, 61) \ + _(XR_BODY_JOINT_RIGHT_HAND_RING_INTERMEDIATE_FB, 62) \ + _(XR_BODY_JOINT_RIGHT_HAND_RING_DISTAL_FB, 63) \ + _(XR_BODY_JOINT_RIGHT_HAND_RING_TIP_FB, 64) \ + _(XR_BODY_JOINT_RIGHT_HAND_LITTLE_METACARPAL_FB, 65) \ + _(XR_BODY_JOINT_RIGHT_HAND_LITTLE_PROXIMAL_FB, 66) \ + _(XR_BODY_JOINT_RIGHT_HAND_LITTLE_INTERMEDIATE_FB, 67) \ + _(XR_BODY_JOINT_RIGHT_HAND_LITTLE_DISTAL_FB, 68) \ + _(XR_BODY_JOINT_RIGHT_HAND_LITTLE_TIP_FB, 69) \ + _(XR_BODY_JOINT_COUNT_FB, 70) \ + _(XR_BODY_JOINT_NONE_FB, -1) \ + _(XR_BODY_JOINT_MAX_ENUM_FB, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrBodyJointSetFB(_) \ + _(XR_BODY_JOINT_SET_DEFAULT_FB, 0) \ + _(XR_BODY_JOINT_SET_MAX_ENUM_FB, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrHandJointsMotionRangeEXT(_) \ + _(XR_HAND_JOINTS_MOTION_RANGE_UNOBSTRUCTED_EXT, 1) \ + _(XR_HAND_JOINTS_MOTION_RANGE_CONFORMING_TO_CONTROLLER_EXT, 2) \ + _(XR_HAND_JOINTS_MOTION_RANGE_MAX_ENUM_EXT, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrSceneComputeFeatureMSFT(_) \ + _(XR_SCENE_COMPUTE_FEATURE_PLANE_MSFT, 1) \ + _(XR_SCENE_COMPUTE_FEATURE_PLANE_MESH_MSFT, 2) \ + _(XR_SCENE_COMPUTE_FEATURE_VISUAL_MESH_MSFT, 3) \ + _(XR_SCENE_COMPUTE_FEATURE_COLLIDER_MESH_MSFT, 4) \ + _(XR_SCENE_COMPUTE_FEATURE_SERIALIZE_SCENE_MSFT, 1000098000) \ + _(XR_SCENE_COMPUTE_FEATURE_MAX_ENUM_MSFT, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrSceneComputeConsistencyMSFT(_) \ + _(XR_SCENE_COMPUTE_CONSISTENCY_SNAPSHOT_COMPLETE_MSFT, 1) \ + _(XR_SCENE_COMPUTE_CONSISTENCY_SNAPSHOT_INCOMPLETE_FAST_MSFT, 2) \ + _(XR_SCENE_COMPUTE_CONSISTENCY_OCCLUSION_OPTIMIZED_MSFT, 3) \ + _(XR_SCENE_COMPUTE_CONSISTENCY_MAX_ENUM_MSFT, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrMeshComputeLodMSFT(_) \ + _(XR_MESH_COMPUTE_LOD_COARSE_MSFT, 1) \ + _(XR_MESH_COMPUTE_LOD_MEDIUM_MSFT, 2) \ + _(XR_MESH_COMPUTE_LOD_FINE_MSFT, 3) \ + _(XR_MESH_COMPUTE_LOD_UNLIMITED_MSFT, 4) \ + _(XR_MESH_COMPUTE_LOD_MAX_ENUM_MSFT, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrSceneComponentTypeMSFT(_) \ + _(XR_SCENE_COMPONENT_TYPE_INVALID_MSFT, -1) \ + _(XR_SCENE_COMPONENT_TYPE_OBJECT_MSFT, 1) \ + _(XR_SCENE_COMPONENT_TYPE_PLANE_MSFT, 2) \ + _(XR_SCENE_COMPONENT_TYPE_VISUAL_MESH_MSFT, 3) \ + _(XR_SCENE_COMPONENT_TYPE_COLLIDER_MESH_MSFT, 4) \ + _(XR_SCENE_COMPONENT_TYPE_SERIALIZED_SCENE_FRAGMENT_MSFT, 1000098000) \ + _(XR_SCENE_COMPONENT_TYPE_MAX_ENUM_MSFT, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrSceneObjectTypeMSFT(_) \ + _(XR_SCENE_OBJECT_TYPE_UNCATEGORIZED_MSFT, -1) \ + _(XR_SCENE_OBJECT_TYPE_BACKGROUND_MSFT, 1) \ + _(XR_SCENE_OBJECT_TYPE_WALL_MSFT, 2) \ + _(XR_SCENE_OBJECT_TYPE_FLOOR_MSFT, 3) \ + _(XR_SCENE_OBJECT_TYPE_CEILING_MSFT, 4) \ + _(XR_SCENE_OBJECT_TYPE_PLATFORM_MSFT, 5) \ + _(XR_SCENE_OBJECT_TYPE_INFERRED_MSFT, 6) \ + _(XR_SCENE_OBJECT_TYPE_MAX_ENUM_MSFT, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrScenePlaneAlignmentTypeMSFT(_) \ + _(XR_SCENE_PLANE_ALIGNMENT_TYPE_NON_ORTHOGONAL_MSFT, 0) \ + _(XR_SCENE_PLANE_ALIGNMENT_TYPE_HORIZONTAL_MSFT, 1) \ + _(XR_SCENE_PLANE_ALIGNMENT_TYPE_VERTICAL_MSFT, 2) \ + _(XR_SCENE_PLANE_ALIGNMENT_TYPE_MAX_ENUM_MSFT, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrSceneComputeStateMSFT(_) \ + _(XR_SCENE_COMPUTE_STATE_NONE_MSFT, 0) \ + _(XR_SCENE_COMPUTE_STATE_UPDATING_MSFT, 1) \ + _(XR_SCENE_COMPUTE_STATE_COMPLETED_MSFT, 2) \ + _(XR_SCENE_COMPUTE_STATE_COMPLETED_WITH_ERROR_MSFT, 3) \ + _(XR_SCENE_COMPUTE_STATE_MAX_ENUM_MSFT, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrEyeExpressionHTC(_) \ + _(XR_EYE_EXPRESSION_LEFT_BLINK_HTC, 0) \ + _(XR_EYE_EXPRESSION_LEFT_WIDE_HTC, 1) \ + _(XR_EYE_EXPRESSION_RIGHT_BLINK_HTC, 2) \ + _(XR_EYE_EXPRESSION_RIGHT_WIDE_HTC, 3) \ + _(XR_EYE_EXPRESSION_LEFT_SQUEEZE_HTC, 4) \ + _(XR_EYE_EXPRESSION_RIGHT_SQUEEZE_HTC, 5) \ + _(XR_EYE_EXPRESSION_LEFT_DOWN_HTC, 6) \ + _(XR_EYE_EXPRESSION_RIGHT_DOWN_HTC, 7) \ + _(XR_EYE_EXPRESSION_LEFT_OUT_HTC, 8) \ + _(XR_EYE_EXPRESSION_RIGHT_IN_HTC, 9) \ + _(XR_EYE_EXPRESSION_LEFT_IN_HTC, 10) \ + _(XR_EYE_EXPRESSION_RIGHT_OUT_HTC, 11) \ + _(XR_EYE_EXPRESSION_LEFT_UP_HTC, 12) \ + _(XR_EYE_EXPRESSION_RIGHT_UP_HTC, 13) \ + _(XR_EYE_EXPRESSION_MAX_ENUM_HTC, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrLipExpressionHTC(_) \ + _(XR_LIP_EXPRESSION_JAW_RIGHT_HTC, 0) \ + _(XR_LIP_EXPRESSION_JAW_LEFT_HTC, 1) \ + _(XR_LIP_EXPRESSION_JAW_FORWARD_HTC, 2) \ + _(XR_LIP_EXPRESSION_JAW_OPEN_HTC, 3) \ + _(XR_LIP_EXPRESSION_MOUTH_APE_SHAPE_HTC, 4) \ + _(XR_LIP_EXPRESSION_MOUTH_UPPER_RIGHT_HTC, 5) \ + _(XR_LIP_EXPRESSION_MOUTH_UPPER_LEFT_HTC, 6) \ + _(XR_LIP_EXPRESSION_MOUTH_LOWER_RIGHT_HTC, 7) \ + _(XR_LIP_EXPRESSION_MOUTH_LOWER_LEFT_HTC, 8) \ + _(XR_LIP_EXPRESSION_MOUTH_UPPER_OVERTURN_HTC, 9) \ + _(XR_LIP_EXPRESSION_MOUTH_LOWER_OVERTURN_HTC, 10) \ + _(XR_LIP_EXPRESSION_MOUTH_POUT_HTC, 11) \ + _(XR_LIP_EXPRESSION_MOUTH_SMILE_RIGHT_HTC, 12) \ + _(XR_LIP_EXPRESSION_MOUTH_SMILE_LEFT_HTC, 13) \ + _(XR_LIP_EXPRESSION_MOUTH_SAD_RIGHT_HTC, 14) \ + _(XR_LIP_EXPRESSION_MOUTH_SAD_LEFT_HTC, 15) \ + _(XR_LIP_EXPRESSION_CHEEK_PUFF_RIGHT_HTC, 16) \ + _(XR_LIP_EXPRESSION_CHEEK_PUFF_LEFT_HTC, 17) \ + _(XR_LIP_EXPRESSION_CHEEK_SUCK_HTC, 18) \ + _(XR_LIP_EXPRESSION_MOUTH_UPPER_UPRIGHT_HTC, 19) \ + _(XR_LIP_EXPRESSION_MOUTH_UPPER_UPLEFT_HTC, 20) \ + _(XR_LIP_EXPRESSION_MOUTH_LOWER_DOWNRIGHT_HTC, 21) \ + _(XR_LIP_EXPRESSION_MOUTH_LOWER_DOWNLEFT_HTC, 22) \ + _(XR_LIP_EXPRESSION_MOUTH_UPPER_INSIDE_HTC, 23) \ + _(XR_LIP_EXPRESSION_MOUTH_LOWER_INSIDE_HTC, 24) \ + _(XR_LIP_EXPRESSION_MOUTH_LOWER_OVERLAY_HTC, 25) \ + _(XR_LIP_EXPRESSION_TONGUE_LONGSTEP1_HTC, 26) \ + _(XR_LIP_EXPRESSION_TONGUE_LEFT_HTC, 27) \ + _(XR_LIP_EXPRESSION_TONGUE_RIGHT_HTC, 28) \ + _(XR_LIP_EXPRESSION_TONGUE_UP_HTC, 29) \ + _(XR_LIP_EXPRESSION_TONGUE_DOWN_HTC, 30) \ + _(XR_LIP_EXPRESSION_TONGUE_ROLL_HTC, 31) \ + _(XR_LIP_EXPRESSION_TONGUE_LONGSTEP2_HTC, 32) \ + _(XR_LIP_EXPRESSION_TONGUE_UPRIGHT_MORPH_HTC, 33) \ + _(XR_LIP_EXPRESSION_TONGUE_UPLEFT_MORPH_HTC, 34) \ + _(XR_LIP_EXPRESSION_TONGUE_DOWNRIGHT_MORPH_HTC, 35) \ + _(XR_LIP_EXPRESSION_TONGUE_DOWNLEFT_MORPH_HTC, 36) \ + _(XR_LIP_EXPRESSION_MAX_ENUM_HTC, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrFacialTrackingTypeHTC(_) \ + _(XR_FACIAL_TRACKING_TYPE_EYE_DEFAULT_HTC, 1) \ + _(XR_FACIAL_TRACKING_TYPE_LIP_DEFAULT_HTC, 2) \ + _(XR_FACIAL_TRACKING_TYPE_MAX_ENUM_HTC, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrColorSpaceFB(_) \ + _(XR_COLOR_SPACE_UNMANAGED_FB, 0) \ + _(XR_COLOR_SPACE_REC2020_FB, 1) \ + _(XR_COLOR_SPACE_REC709_FB, 2) \ + _(XR_COLOR_SPACE_RIFT_CV1_FB, 3) \ + _(XR_COLOR_SPACE_RIFT_S_FB, 4) \ + _(XR_COLOR_SPACE_QUEST_FB, 5) \ + _(XR_COLOR_SPACE_P3_FB, 6) \ + _(XR_COLOR_SPACE_ADOBE_RGB_FB, 7) \ + _(XR_COLOR_SPACE_MAX_ENUM_FB, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrSpaceComponentTypeFB(_) \ + _(XR_SPACE_COMPONENT_TYPE_LOCATABLE_FB, 0) \ + _(XR_SPACE_COMPONENT_TYPE_STORABLE_FB, 1) \ + _(XR_SPACE_COMPONENT_TYPE_SHARABLE_FB, 2) \ + _(XR_SPACE_COMPONENT_TYPE_BOUNDED_2D_FB, 3) \ + _(XR_SPACE_COMPONENT_TYPE_BOUNDED_3D_FB, 4) \ + _(XR_SPACE_COMPONENT_TYPE_SEMANTIC_LABELS_FB, 5) \ + _(XR_SPACE_COMPONENT_TYPE_ROOM_LAYOUT_FB, 6) \ + _(XR_SPACE_COMPONENT_TYPE_SPACE_CONTAINER_FB, 7) \ + _(XR_SPACE_COMPONENT_TYPE_MAX_ENUM_FB, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrFoveationLevelFB(_) \ + _(XR_FOVEATION_LEVEL_NONE_FB, 0) \ + _(XR_FOVEATION_LEVEL_LOW_FB, 1) \ + _(XR_FOVEATION_LEVEL_MEDIUM_FB, 2) \ + _(XR_FOVEATION_LEVEL_HIGH_FB, 3) \ + _(XR_FOVEATION_LEVEL_MAX_ENUM_FB, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrFoveationDynamicFB(_) \ + _(XR_FOVEATION_DYNAMIC_DISABLED_FB, 0) \ + _(XR_FOVEATION_DYNAMIC_LEVEL_ENABLED_FB, 1) \ + _(XR_FOVEATION_DYNAMIC_MAX_ENUM_FB, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrWindingOrderFB(_) \ + _(XR_WINDING_ORDER_UNKNOWN_FB, 0) \ + _(XR_WINDING_ORDER_CW_FB, 1) \ + _(XR_WINDING_ORDER_CCW_FB, 2) \ + _(XR_WINDING_ORDER_MAX_ENUM_FB, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrPassthroughLayerPurposeFB(_) \ + _(XR_PASSTHROUGH_LAYER_PURPOSE_RECONSTRUCTION_FB, 0) \ + _(XR_PASSTHROUGH_LAYER_PURPOSE_PROJECTED_FB, 1) \ + _(XR_PASSTHROUGH_LAYER_PURPOSE_TRACKED_KEYBOARD_HANDS_FB, 1000203001) \ + _(XR_PASSTHROUGH_LAYER_PURPOSE_TRACKED_KEYBOARD_MASKED_HANDS_FB, 1000203002) \ + _(XR_PASSTHROUGH_LAYER_PURPOSE_MAX_ENUM_FB, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrHandForearmJointULTRALEAP(_) \ + _(XR_HAND_FOREARM_JOINT_PALM_ULTRALEAP, 0) \ + _(XR_HAND_FOREARM_JOINT_WRIST_ULTRALEAP, 1) \ + _(XR_HAND_FOREARM_JOINT_THUMB_METACARPAL_ULTRALEAP, 2) \ + _(XR_HAND_FOREARM_JOINT_THUMB_PROXIMAL_ULTRALEAP, 3) \ + _(XR_HAND_FOREARM_JOINT_THUMB_DISTAL_ULTRALEAP, 4) \ + _(XR_HAND_FOREARM_JOINT_THUMB_TIP_ULTRALEAP, 5) \ + _(XR_HAND_FOREARM_JOINT_INDEX_METACARPAL_ULTRALEAP, 6) \ + _(XR_HAND_FOREARM_JOINT_INDEX_PROXIMAL_ULTRALEAP, 7) \ + _(XR_HAND_FOREARM_JOINT_INDEX_INTERMEDIATE_ULTRALEAP, 8) \ + _(XR_HAND_FOREARM_JOINT_INDEX_DISTAL_ULTRALEAP, 9) \ + _(XR_HAND_FOREARM_JOINT_INDEX_TIP_ULTRALEAP, 10) \ + _(XR_HAND_FOREARM_JOINT_MIDDLE_METACARPAL_ULTRALEAP, 11) \ + _(XR_HAND_FOREARM_JOINT_MIDDLE_PROXIMAL_ULTRALEAP, 12) \ + _(XR_HAND_FOREARM_JOINT_MIDDLE_INTERMEDIATE_ULTRALEAP, 13) \ + _(XR_HAND_FOREARM_JOINT_MIDDLE_DISTAL_ULTRALEAP, 14) \ + _(XR_HAND_FOREARM_JOINT_MIDDLE_TIP_ULTRALEAP, 15) \ + _(XR_HAND_FOREARM_JOINT_RING_METACARPAL_ULTRALEAP, 16) \ + _(XR_HAND_FOREARM_JOINT_RING_PROXIMAL_ULTRALEAP, 17) \ + _(XR_HAND_FOREARM_JOINT_RING_INTERMEDIATE_ULTRALEAP, 18) \ + _(XR_HAND_FOREARM_JOINT_RING_DISTAL_ULTRALEAP, 19) \ + _(XR_HAND_FOREARM_JOINT_RING_TIP_ULTRALEAP, 20) \ + _(XR_HAND_FOREARM_JOINT_LITTLE_METACARPAL_ULTRALEAP, 21) \ + _(XR_HAND_FOREARM_JOINT_LITTLE_PROXIMAL_ULTRALEAP, 22) \ + _(XR_HAND_FOREARM_JOINT_LITTLE_INTERMEDIATE_ULTRALEAP, 23) \ + _(XR_HAND_FOREARM_JOINT_LITTLE_DISTAL_ULTRALEAP, 24) \ + _(XR_HAND_FOREARM_JOINT_LITTLE_TIP_ULTRALEAP, 25) \ + _(XR_HAND_FOREARM_JOINT_ELBOW_ULTRALEAP, 26) \ + _(XR_HAND_FOREARM_JOINT_MAX_ENUM_ULTRALEAP, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrSpaceQueryActionFB(_) \ + _(XR_SPACE_QUERY_ACTION_LOAD_FB, 0) \ + _(XR_SPACE_QUERY_ACTION_MAX_ENUM_FB, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrSpaceStorageLocationFB(_) \ + _(XR_SPACE_STORAGE_LOCATION_INVALID_FB, 0) \ + _(XR_SPACE_STORAGE_LOCATION_LOCAL_FB, 1) \ + _(XR_SPACE_STORAGE_LOCATION_CLOUD_FB, 2) \ + _(XR_SPACE_STORAGE_LOCATION_MAX_ENUM_FB, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrSpacePersistenceModeFB(_) \ + _(XR_SPACE_PERSISTENCE_MODE_INVALID_FB, 0) \ + _(XR_SPACE_PERSISTENCE_MODE_INDEFINITE_FB, 1) \ + _(XR_SPACE_PERSISTENCE_MODE_MAX_ENUM_FB, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrFaceExpressionFB(_) \ + _(XR_FACE_EXPRESSION_BROW_LOWERER_L_FB, 0) \ + _(XR_FACE_EXPRESSION_BROW_LOWERER_R_FB, 1) \ + _(XR_FACE_EXPRESSION_CHEEK_PUFF_L_FB, 2) \ + _(XR_FACE_EXPRESSION_CHEEK_PUFF_R_FB, 3) \ + _(XR_FACE_EXPRESSION_CHEEK_RAISER_L_FB, 4) \ + _(XR_FACE_EXPRESSION_CHEEK_RAISER_R_FB, 5) \ + _(XR_FACE_EXPRESSION_CHEEK_SUCK_L_FB, 6) \ + _(XR_FACE_EXPRESSION_CHEEK_SUCK_R_FB, 7) \ + _(XR_FACE_EXPRESSION_CHIN_RAISER_B_FB, 8) \ + _(XR_FACE_EXPRESSION_CHIN_RAISER_T_FB, 9) \ + _(XR_FACE_EXPRESSION_DIMPLER_L_FB, 10) \ + _(XR_FACE_EXPRESSION_DIMPLER_R_FB, 11) \ + _(XR_FACE_EXPRESSION_EYES_CLOSED_L_FB, 12) \ + _(XR_FACE_EXPRESSION_EYES_CLOSED_R_FB, 13) \ + _(XR_FACE_EXPRESSION_EYES_LOOK_DOWN_L_FB, 14) \ + _(XR_FACE_EXPRESSION_EYES_LOOK_DOWN_R_FB, 15) \ + _(XR_FACE_EXPRESSION_EYES_LOOK_LEFT_L_FB, 16) \ + _(XR_FACE_EXPRESSION_EYES_LOOK_LEFT_R_FB, 17) \ + _(XR_FACE_EXPRESSION_EYES_LOOK_RIGHT_L_FB, 18) \ + _(XR_FACE_EXPRESSION_EYES_LOOK_RIGHT_R_FB, 19) \ + _(XR_FACE_EXPRESSION_EYES_LOOK_UP_L_FB, 20) \ + _(XR_FACE_EXPRESSION_EYES_LOOK_UP_R_FB, 21) \ + _(XR_FACE_EXPRESSION_INNER_BROW_RAISER_L_FB, 22) \ + _(XR_FACE_EXPRESSION_INNER_BROW_RAISER_R_FB, 23) \ + _(XR_FACE_EXPRESSION_JAW_DROP_FB, 24) \ + _(XR_FACE_EXPRESSION_JAW_SIDEWAYS_LEFT_FB, 25) \ + _(XR_FACE_EXPRESSION_JAW_SIDEWAYS_RIGHT_FB, 26) \ + _(XR_FACE_EXPRESSION_JAW_THRUST_FB, 27) \ + _(XR_FACE_EXPRESSION_LID_TIGHTENER_L_FB, 28) \ + _(XR_FACE_EXPRESSION_LID_TIGHTENER_R_FB, 29) \ + _(XR_FACE_EXPRESSION_LIP_CORNER_DEPRESSOR_L_FB, 30) \ + _(XR_FACE_EXPRESSION_LIP_CORNER_DEPRESSOR_R_FB, 31) \ + _(XR_FACE_EXPRESSION_LIP_CORNER_PULLER_L_FB, 32) \ + _(XR_FACE_EXPRESSION_LIP_CORNER_PULLER_R_FB, 33) \ + _(XR_FACE_EXPRESSION_LIP_FUNNELER_LB_FB, 34) \ + _(XR_FACE_EXPRESSION_LIP_FUNNELER_LT_FB, 35) \ + _(XR_FACE_EXPRESSION_LIP_FUNNELER_RB_FB, 36) \ + _(XR_FACE_EXPRESSION_LIP_FUNNELER_RT_FB, 37) \ + _(XR_FACE_EXPRESSION_LIP_PRESSOR_L_FB, 38) \ + _(XR_FACE_EXPRESSION_LIP_PRESSOR_R_FB, 39) \ + _(XR_FACE_EXPRESSION_LIP_PUCKER_L_FB, 40) \ + _(XR_FACE_EXPRESSION_LIP_PUCKER_R_FB, 41) \ + _(XR_FACE_EXPRESSION_LIP_STRETCHER_L_FB, 42) \ + _(XR_FACE_EXPRESSION_LIP_STRETCHER_R_FB, 43) \ + _(XR_FACE_EXPRESSION_LIP_SUCK_LB_FB, 44) \ + _(XR_FACE_EXPRESSION_LIP_SUCK_LT_FB, 45) \ + _(XR_FACE_EXPRESSION_LIP_SUCK_RB_FB, 46) \ + _(XR_FACE_EXPRESSION_LIP_SUCK_RT_FB, 47) \ + _(XR_FACE_EXPRESSION_LIP_TIGHTENER_L_FB, 48) \ + _(XR_FACE_EXPRESSION_LIP_TIGHTENER_R_FB, 49) \ + _(XR_FACE_EXPRESSION_LIPS_TOWARD_FB, 50) \ + _(XR_FACE_EXPRESSION_LOWER_LIP_DEPRESSOR_L_FB, 51) \ + _(XR_FACE_EXPRESSION_LOWER_LIP_DEPRESSOR_R_FB, 52) \ + _(XR_FACE_EXPRESSION_MOUTH_LEFT_FB, 53) \ + _(XR_FACE_EXPRESSION_MOUTH_RIGHT_FB, 54) \ + _(XR_FACE_EXPRESSION_NOSE_WRINKLER_L_FB, 55) \ + _(XR_FACE_EXPRESSION_NOSE_WRINKLER_R_FB, 56) \ + _(XR_FACE_EXPRESSION_OUTER_BROW_RAISER_L_FB, 57) \ + _(XR_FACE_EXPRESSION_OUTER_BROW_RAISER_R_FB, 58) \ + _(XR_FACE_EXPRESSION_UPPER_LID_RAISER_L_FB, 59) \ + _(XR_FACE_EXPRESSION_UPPER_LID_RAISER_R_FB, 60) \ + _(XR_FACE_EXPRESSION_UPPER_LIP_RAISER_L_FB, 61) \ + _(XR_FACE_EXPRESSION_UPPER_LIP_RAISER_R_FB, 62) \ + _(XR_FACE_EXPRESSION_COUNT_FB, 63) \ + _(XR_FACE_EXPRESSION_MAX_ENUM_FB, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrFaceExpressionSetFB(_) \ + _(XR_FACE_EXPRESSION_SET_DEFAULT_FB, 0) \ + _(XR_FACE_EXPRESSION_SET_MAX_ENUM_FB, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrFaceConfidenceFB(_) \ + _(XR_FACE_CONFIDENCE_LOWER_FACE_FB, 0) \ + _(XR_FACE_CONFIDENCE_UPPER_FACE_FB, 1) \ + _(XR_FACE_CONFIDENCE_COUNT_FB, 2) \ + _(XR_FACE_CONFIDENCE_MAX_ENUM_FB, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrEyePositionFB(_) \ + _(XR_EYE_POSITION_LEFT_FB, 0) \ + _(XR_EYE_POSITION_RIGHT_FB, 1) \ + _(XR_EYE_POSITION_COUNT_FB, 2) \ + _(XR_EYE_POSITION_MAX_ENUM_FB, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrCompareOpFB(_) \ + _(XR_COMPARE_OP_NEVER_FB, 0) \ + _(XR_COMPARE_OP_LESS_FB, 1) \ + _(XR_COMPARE_OP_EQUAL_FB, 2) \ + _(XR_COMPARE_OP_LESS_OR_EQUAL_FB, 3) \ + _(XR_COMPARE_OP_GREATER_FB, 4) \ + _(XR_COMPARE_OP_NOT_EQUAL_FB, 5) \ + _(XR_COMPARE_OP_GREATER_OR_EQUAL_FB, 6) \ + _(XR_COMPARE_OP_ALWAYS_FB, 7) \ + _(XR_COMPARE_OPFB_MAX_ENUM_FB, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrLocalDimmingModeMETA(_) \ + _(XR_LOCAL_DIMMING_MODE_OFF_META, 0) \ + _(XR_LOCAL_DIMMING_MODE_ON_META, 1) \ + _(XR_LOCAL_DIMMING_MODE_MAX_ENUM_META, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrVirtualKeyboardLocationTypeMETA(_) \ + _(XR_VIRTUAL_KEYBOARD_LOCATION_TYPE_CUSTOM_META, 0) \ + _(XR_VIRTUAL_KEYBOARD_LOCATION_TYPE_FAR_META, 1) \ + _(XR_VIRTUAL_KEYBOARD_LOCATION_TYPE_DIRECT_META, 2) \ + _(XR_VIRTUAL_KEYBOARD_LOCATION_TYPE_MAX_ENUM_META, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrVirtualKeyboardInputSourceMETA(_) \ + _(XR_VIRTUAL_KEYBOARD_INPUT_SOURCE_CONTROLLER_RAY_LEFT_META, 1) \ + _(XR_VIRTUAL_KEYBOARD_INPUT_SOURCE_CONTROLLER_RAY_RIGHT_META, 2) \ + _(XR_VIRTUAL_KEYBOARD_INPUT_SOURCE_HAND_RAY_LEFT_META, 3) \ + _(XR_VIRTUAL_KEYBOARD_INPUT_SOURCE_HAND_RAY_RIGHT_META, 4) \ + _(XR_VIRTUAL_KEYBOARD_INPUT_SOURCE_CONTROLLER_DIRECT_LEFT_META, 5) \ + _(XR_VIRTUAL_KEYBOARD_INPUT_SOURCE_CONTROLLER_DIRECT_RIGHT_META, 6) \ + _(XR_VIRTUAL_KEYBOARD_INPUT_SOURCE_HAND_DIRECT_INDEX_TIP_LEFT_META, 7) \ + _(XR_VIRTUAL_KEYBOARD_INPUT_SOURCE_HAND_DIRECT_INDEX_TIP_RIGHT_META, 8) \ + _(XR_VIRTUAL_KEYBOARD_INPUT_SOURCE_MAX_ENUM_META, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrExternalCameraAttachedToDeviceOCULUS(_) \ + _(XR_EXTERNAL_CAMERA_ATTACHED_TO_DEVICE_NONE_OCULUS, 0) \ + _(XR_EXTERNAL_CAMERA_ATTACHED_TO_DEVICE_HMD_OCULUS, 1) \ + _(XR_EXTERNAL_CAMERA_ATTACHED_TO_DEVICE_LTOUCH_OCULUS, 2) \ + _(XR_EXTERNAL_CAMERA_ATTACHED_TO_DEVICE_RTOUCH_OCULUS, 3) \ + _(XR_EXTERNAL_CAMERA_ATTACHED_TODEVICE_MAX_ENUM_OCULUS, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrPerformanceMetricsCounterUnitMETA(_) \ + _(XR_PERFORMANCE_METRICS_COUNTER_UNIT_GENERIC_META, 0) \ + _(XR_PERFORMANCE_METRICS_COUNTER_UNIT_PERCENTAGE_META, 1) \ + _(XR_PERFORMANCE_METRICS_COUNTER_UNIT_MILLISECONDS_META, 2) \ + _(XR_PERFORMANCE_METRICS_COUNTER_UNIT_BYTES_META, 3) \ + _(XR_PERFORMANCE_METRICS_COUNTER_UNIT_HERTZ_META, 4) \ + _(XR_PERFORMANCE_METRICS_COUNTER_UNIT_MAX_ENUM_META, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrPassthroughColorLutChannelsMETA(_) \ + _(XR_PASSTHROUGH_COLOR_LUT_CHANNELS_RGB_META, 1) \ + _(XR_PASSTHROUGH_COLOR_LUT_CHANNELS_RGBA_META, 2) \ + _(XR_PASSTHROUGH_COLOR_LUT_CHANNELS_MAX_ENUM_META, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrTrackingOptimizationSettingsDomainQCOM(_) \ + _(XR_TRACKING_OPTIMIZATION_SETTINGS_DOMAIN_ALL_QCOM, 1) \ + _(XR_TRACKING_OPTIMIZATION_SETTINGS_DOMAIN_MAX_ENUM_QCOM, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrTrackingOptimizationSettingsHintQCOM(_) \ + _(XR_TRACKING_OPTIMIZATION_SETTINGS_HINT_NONE_QCOM, 0) \ + _(XR_TRACKING_OPTIMIZATION_SETTINGS_HINT_LONG_RANGE_PRIORIZATION_QCOM, 1) \ + _(XR_TRACKING_OPTIMIZATION_SETTINGS_HINT_CLOSE_RANGE_PRIORIZATION_QCOM, 2) \ + _(XR_TRACKING_OPTIMIZATION_SETTINGS_HINT_LOW_POWER_PRIORIZATION_QCOM, 3) \ + _(XR_TRACKING_OPTIMIZATION_SETTINGS_HINT_HIGH_POWER_PRIORIZATION_QCOM, 4) \ + _(XR_TRACKING_OPTIMIZATION_SETTINGS_HINT_MAX_ENUM_QCOM, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrPassthroughFormHTC(_) \ + _(XR_PASSTHROUGH_FORM_PLANAR_HTC, 0) \ + _(XR_PASSTHROUGH_FORM_PROJECTED_HTC, 1) \ + _(XR_PASSTHROUGH_FORM_MAX_ENUM_HTC, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrFoveationModeHTC(_) \ + _(XR_FOVEATION_MODE_DISABLE_HTC, 0) \ + _(XR_FOVEATION_MODE_FIXED_HTC, 1) \ + _(XR_FOVEATION_MODE_DYNAMIC_HTC, 2) \ + _(XR_FOVEATION_MODE_CUSTOM_HTC, 3) \ + _(XR_FOVEATION_MODE_MAX_ENUM_HTC, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrFoveationLevelHTC(_) \ + _(XR_FOVEATION_LEVEL_NONE_HTC, 0) \ + _(XR_FOVEATION_LEVEL_LOW_HTC, 1) \ + _(XR_FOVEATION_LEVEL_MEDIUM_HTC, 2) \ + _(XR_FOVEATION_LEVEL_HIGH_HTC, 3) \ + _(XR_FOVEATION_LEVEL_MAX_ENUM_HTC, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrForceFeedbackCurlLocationMNDX(_) \ + _(XR_FORCE_FEEDBACK_CURL_LOCATION_THUMB_CURL_MNDX, 0) \ + _(XR_FORCE_FEEDBACK_CURL_LOCATION_INDEX_CURL_MNDX, 1) \ + _(XR_FORCE_FEEDBACK_CURL_LOCATION_MIDDLE_CURL_MNDX, 2) \ + _(XR_FORCE_FEEDBACK_CURL_LOCATION_RING_CURL_MNDX, 3) \ + _(XR_FORCE_FEEDBACK_CURL_LOCATION_LITTLE_CURL_MNDX, 4) \ + _(XR_FORCE_FEEDBACK_CURL_LOCATION_MAX_ENUM_MNDX, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrHandTrackingDataSourceEXT(_) \ + _(XR_HAND_TRACKING_DATA_SOURCE_UNOBSTRUCTED_EXT, 1) \ + _(XR_HAND_TRACKING_DATA_SOURCE_CONTROLLER_EXT, 2) \ + _(XR_HAND_TRACKING_DATA_SOURCE_MAX_ENUM_EXT, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrPlaneDetectorOrientationEXT(_) \ + _(XR_PLANE_DETECTOR_ORIENTATION_HORIZONTAL_UPWARD_EXT, 0) \ + _(XR_PLANE_DETECTOR_ORIENTATION_HORIZONTAL_DOWNWARD_EXT, 1) \ + _(XR_PLANE_DETECTOR_ORIENTATION_VERTICAL_EXT, 2) \ + _(XR_PLANE_DETECTOR_ORIENTATION_ARBITRARY_EXT, 3) \ + _(XR_PLANE_DETECTOR_ORIENTATION_MAX_ENUM_EXT, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrPlaneDetectorSemanticTypeEXT(_) \ + _(XR_PLANE_DETECTOR_SEMANTIC_TYPE_UNDEFINED_EXT, 0) \ + _(XR_PLANE_DETECTOR_SEMANTIC_TYPE_CEILING_EXT, 1) \ + _(XR_PLANE_DETECTOR_SEMANTIC_TYPE_FLOOR_EXT, 2) \ + _(XR_PLANE_DETECTOR_SEMANTIC_TYPE_WALL_EXT, 3) \ + _(XR_PLANE_DETECTOR_SEMANTIC_TYPE_PLATFORM_EXT, 4) \ + _(XR_PLANE_DETECTOR_SEMANTIC_TYPE_MAX_ENUM_EXT, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrPlaneDetectionStateEXT(_) \ + _(XR_PLANE_DETECTION_STATE_NONE_EXT, 0) \ + _(XR_PLANE_DETECTION_STATE_PENDING_EXT, 1) \ + _(XR_PLANE_DETECTION_STATE_DONE_EXT, 2) \ + _(XR_PLANE_DETECTION_STATE_ERROR_EXT, 3) \ + _(XR_PLANE_DETECTION_STATE_FATAL_EXT, 4) \ + _(XR_PLANE_DETECTION_STATE_MAX_ENUM_EXT, 0x7FFFFFFF) + +#define XR_LIST_BITS_XrInstanceCreateFlags(_) + +#define XR_LIST_BITS_XrSessionCreateFlags(_) + +#define XR_LIST_BITS_XrSpaceVelocityFlags(_) \ + _(XR_SPACE_VELOCITY_LINEAR_VALID_BIT, 0x00000001) \ + _(XR_SPACE_VELOCITY_ANGULAR_VALID_BIT, 0x00000002) \ + +#define XR_LIST_BITS_XrSpaceLocationFlags(_) \ + _(XR_SPACE_LOCATION_ORIENTATION_VALID_BIT, 0x00000001) \ + _(XR_SPACE_LOCATION_POSITION_VALID_BIT, 0x00000002) \ + _(XR_SPACE_LOCATION_ORIENTATION_TRACKED_BIT, 0x00000004) \ + _(XR_SPACE_LOCATION_POSITION_TRACKED_BIT, 0x00000008) \ + +#define XR_LIST_BITS_XrSwapchainCreateFlags(_) \ + _(XR_SWAPCHAIN_CREATE_PROTECTED_CONTENT_BIT, 0x00000001) \ + _(XR_SWAPCHAIN_CREATE_STATIC_IMAGE_BIT, 0x00000002) \ + +#define XR_LIST_BITS_XrSwapchainUsageFlags(_) \ + _(XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT, 0x00000001) \ + _(XR_SWAPCHAIN_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, 0x00000002) \ + _(XR_SWAPCHAIN_USAGE_UNORDERED_ACCESS_BIT, 0x00000004) \ + _(XR_SWAPCHAIN_USAGE_TRANSFER_SRC_BIT, 0x00000008) \ + _(XR_SWAPCHAIN_USAGE_TRANSFER_DST_BIT, 0x00000010) \ + _(XR_SWAPCHAIN_USAGE_SAMPLED_BIT, 0x00000020) \ + _(XR_SWAPCHAIN_USAGE_MUTABLE_FORMAT_BIT, 0x00000040) \ + _(XR_SWAPCHAIN_USAGE_INPUT_ATTACHMENT_BIT_MND, 0x00000080) \ + _(XR_SWAPCHAIN_USAGE_INPUT_ATTACHMENT_BIT_KHR, XR_SWAPCHAIN_USAGE_INPUT_ATTACHMENT_BIT_MND) \ + +#define XR_LIST_BITS_XrCompositionLayerFlags(_) \ + _(XR_COMPOSITION_LAYER_CORRECT_CHROMATIC_ABERRATION_BIT, 0x00000001) \ + _(XR_COMPOSITION_LAYER_BLEND_TEXTURE_SOURCE_ALPHA_BIT, 0x00000002) \ + _(XR_COMPOSITION_LAYER_UNPREMULTIPLIED_ALPHA_BIT, 0x00000004) \ + +#define XR_LIST_BITS_XrViewStateFlags(_) \ + _(XR_VIEW_STATE_ORIENTATION_VALID_BIT, 0x00000001) \ + _(XR_VIEW_STATE_POSITION_VALID_BIT, 0x00000002) \ + _(XR_VIEW_STATE_ORIENTATION_TRACKED_BIT, 0x00000004) \ + _(XR_VIEW_STATE_POSITION_TRACKED_BIT, 0x00000008) \ + +#define XR_LIST_BITS_XrInputSourceLocalizedNameFlags(_) \ + _(XR_INPUT_SOURCE_LOCALIZED_NAME_USER_PATH_BIT, 0x00000001) \ + _(XR_INPUT_SOURCE_LOCALIZED_NAME_INTERACTION_PROFILE_BIT, 0x00000002) \ + _(XR_INPUT_SOURCE_LOCALIZED_NAME_COMPONENT_BIT, 0x00000004) \ + +#define XR_LIST_BITS_XrVulkanInstanceCreateFlagsKHR(_) + +#define XR_LIST_BITS_XrVulkanDeviceCreateFlagsKHR(_) + +#define XR_LIST_BITS_XrDebugUtilsMessageSeverityFlagsEXT(_) \ + _(XR_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT, 0x00000001) \ + _(XR_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT, 0x00000010) \ + _(XR_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT, 0x00000100) \ + _(XR_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT, 0x00001000) \ + +#define XR_LIST_BITS_XrDebugUtilsMessageTypeFlagsEXT(_) \ + _(XR_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT, 0x00000001) \ + _(XR_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT, 0x00000002) \ + _(XR_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT, 0x00000004) \ + _(XR_DEBUG_UTILS_MESSAGE_TYPE_CONFORMANCE_BIT_EXT, 0x00000008) \ + +#define XR_LIST_BITS_XrOverlaySessionCreateFlagsEXTX(_) + +#define XR_LIST_BITS_XrOverlayMainSessionFlagsEXTX(_) \ + _(XR_OVERLAY_MAIN_SESSION_ENABLED_COMPOSITION_LAYER_INFO_DEPTH_BIT_EXTX, 0x00000001) \ + +#define XR_LIST_BITS_XrCompositionLayerImageLayoutFlagsFB(_) \ + _(XR_COMPOSITION_LAYER_IMAGE_LAYOUT_VERTICAL_FLIP_BIT_FB, 0x00000001) \ + +#define XR_LIST_BITS_XrAndroidSurfaceSwapchainFlagsFB(_) \ + _(XR_ANDROID_SURFACE_SWAPCHAIN_SYNCHRONOUS_BIT_FB, 0x00000001) \ + _(XR_ANDROID_SURFACE_SWAPCHAIN_USE_TIMESTAMPS_BIT_FB, 0x00000002) \ + +#define XR_LIST_BITS_XrCompositionLayerSecureContentFlagsFB(_) \ + _(XR_COMPOSITION_LAYER_SECURE_CONTENT_EXCLUDE_LAYER_BIT_FB, 0x00000001) \ + _(XR_COMPOSITION_LAYER_SECURE_CONTENT_REPLACE_LAYER_BIT_FB, 0x00000002) \ + +#define XR_LIST_BITS_XrHandTrackingAimFlagsFB(_) \ + _(XR_HAND_TRACKING_AIM_COMPUTED_BIT_FB, 0x00000001) \ + _(XR_HAND_TRACKING_AIM_VALID_BIT_FB, 0x00000002) \ + _(XR_HAND_TRACKING_AIM_INDEX_PINCHING_BIT_FB, 0x00000004) \ + _(XR_HAND_TRACKING_AIM_MIDDLE_PINCHING_BIT_FB, 0x00000008) \ + _(XR_HAND_TRACKING_AIM_RING_PINCHING_BIT_FB, 0x00000010) \ + _(XR_HAND_TRACKING_AIM_LITTLE_PINCHING_BIT_FB, 0x00000020) \ + _(XR_HAND_TRACKING_AIM_SYSTEM_GESTURE_BIT_FB, 0x00000040) \ + _(XR_HAND_TRACKING_AIM_DOMINANT_HAND_BIT_FB, 0x00000080) \ + _(XR_HAND_TRACKING_AIM_MENU_PRESSED_BIT_FB, 0x00000100) \ + +#define XR_LIST_BITS_XrSwapchainCreateFoveationFlagsFB(_) \ + _(XR_SWAPCHAIN_CREATE_FOVEATION_SCALED_BIN_BIT_FB, 0x00000001) \ + _(XR_SWAPCHAIN_CREATE_FOVEATION_FRAGMENT_DENSITY_MAP_BIT_FB, 0x00000002) \ + +#define XR_LIST_BITS_XrSwapchainStateFoveationFlagsFB(_) + +#define XR_LIST_BITS_XrKeyboardTrackingFlagsFB(_) \ + _(XR_KEYBOARD_TRACKING_EXISTS_BIT_FB, 0x00000001) \ + _(XR_KEYBOARD_TRACKING_LOCAL_BIT_FB, 0x00000002) \ + _(XR_KEYBOARD_TRACKING_REMOTE_BIT_FB, 0x00000004) \ + _(XR_KEYBOARD_TRACKING_CONNECTED_BIT_FB, 0x00000008) \ + +#define XR_LIST_BITS_XrKeyboardTrackingQueryFlagsFB(_) \ + _(XR_KEYBOARD_TRACKING_QUERY_LOCAL_BIT_FB, 0x00000002) \ + _(XR_KEYBOARD_TRACKING_QUERY_REMOTE_BIT_FB, 0x00000004) \ + +#define XR_LIST_BITS_XrTriangleMeshFlagsFB(_) \ + _(XR_TRIANGLE_MESH_MUTABLE_BIT_FB, 0x00000001) \ + +#define XR_LIST_BITS_XrPassthroughCapabilityFlagsFB(_) \ + _(XR_PASSTHROUGH_CAPABILITY_BIT_FB, 0x00000001) \ + _(XR_PASSTHROUGH_CAPABILITY_COLOR_BIT_FB, 0x00000002) \ + _(XR_PASSTHROUGH_CAPABILITY_LAYER_DEPTH_BIT_FB, 0x00000004) \ + +#define XR_LIST_BITS_XrPassthroughFlagsFB(_) \ + _(XR_PASSTHROUGH_IS_RUNNING_AT_CREATION_BIT_FB, 0x00000001) \ + _(XR_PASSTHROUGH_LAYER_DEPTH_BIT_FB, 0x00000002) \ + +#define XR_LIST_BITS_XrPassthroughStateChangedFlagsFB(_) \ + _(XR_PASSTHROUGH_STATE_CHANGED_REINIT_REQUIRED_BIT_FB, 0x00000001) \ + _(XR_PASSTHROUGH_STATE_CHANGED_NON_RECOVERABLE_ERROR_BIT_FB, 0x00000002) \ + _(XR_PASSTHROUGH_STATE_CHANGED_RECOVERABLE_ERROR_BIT_FB, 0x00000004) \ + _(XR_PASSTHROUGH_STATE_CHANGED_RESTORED_ERROR_BIT_FB, 0x00000008) \ + +#define XR_LIST_BITS_XrRenderModelFlagsFB(_) \ + _(XR_RENDER_MODEL_SUPPORTS_GLTF_2_0_SUBSET_1_BIT_FB, 0x00000001) \ + _(XR_RENDER_MODEL_SUPPORTS_GLTF_2_0_SUBSET_2_BIT_FB, 0x00000002) \ + +#define XR_LIST_BITS_XrFrameEndInfoFlagsML(_) \ + _(XR_FRAME_END_INFO_PROTECTED_BIT_ML, 0x00000001) \ + _(XR_FRAME_END_INFO_VIGNETTE_BIT_ML, 0x00000002) \ + +#define XR_LIST_BITS_XrGlobalDimmerFrameEndInfoFlagsML(_) \ + _(XR_GLOBAL_DIMMER_FRAME_END_INFO_ENABLED_BIT_ML, 0x00000001) \ + +#define XR_LIST_BITS_XrCompositionLayerSpaceWarpInfoFlagsFB(_) \ + _(XR_COMPOSITION_LAYER_SPACE_WARP_INFO_FRAME_SKIP_BIT_FB, 0x00000001) \ + +#define XR_LIST_BITS_XrSemanticLabelsSupportFlagsFB(_) \ + _(XR_SEMANTIC_LABELS_SUPPORT_MULTIPLE_SEMANTIC_LABELS_BIT_FB, 0x00000001) \ + _(XR_SEMANTIC_LABELS_SUPPORT_ACCEPT_DESK_TO_TABLE_MIGRATION_BIT_FB, 0x00000002) \ + +#define XR_LIST_BITS_XrDigitalLensControlFlagsALMALENCE(_) \ + _(XR_DIGITAL_LENS_CONTROL_PROCESSING_DISABLE_BIT_ALMALENCE, 0x00000001) \ + +#define XR_LIST_BITS_XrFoveationEyeTrackedProfileCreateFlagsMETA(_) + +#define XR_LIST_BITS_XrFoveationEyeTrackedStateFlagsMETA(_) \ + _(XR_FOVEATION_EYE_TRACKED_STATE_VALID_BIT_META, 0x00000001) \ + +#define XR_LIST_BITS_XrCompositionLayerSettingsFlagsFB(_) \ + _(XR_COMPOSITION_LAYER_SETTINGS_NORMAL_SUPER_SAMPLING_BIT_FB, 0x00000001) \ + _(XR_COMPOSITION_LAYER_SETTINGS_QUALITY_SUPER_SAMPLING_BIT_FB, 0x00000002) \ + _(XR_COMPOSITION_LAYER_SETTINGS_NORMAL_SHARPENING_BIT_FB, 0x00000004) \ + _(XR_COMPOSITION_LAYER_SETTINGS_QUALITY_SHARPENING_BIT_FB, 0x00000008) \ + +#define XR_LIST_BITS_XrPassthroughPreferenceFlagsMETA(_) \ + _(XR_PASSTHROUGH_PREFERENCE_DEFAULT_TO_ACTIVE_BIT_META, 0x00000001) \ + +#define XR_LIST_BITS_XrVirtualKeyboardInputStateFlagsMETA(_) \ + _(XR_VIRTUAL_KEYBOARD_INPUT_STATE_PRESSED_BIT_META, 0x00000001) \ + +#define XR_LIST_BITS_XrExternalCameraStatusFlagsOCULUS(_) \ + _(XR_EXTERNAL_CAMERA_STATUS_CONNECTED_BIT_OCULUS, 0x00000001) \ + _(XR_EXTERNAL_CAMERA_STATUS_CALIBRATING_BIT_OCULUS, 0x00000002) \ + _(XR_EXTERNAL_CAMERA_STATUS_CALIBRATION_FAILED_BIT_OCULUS, 0x00000004) \ + _(XR_EXTERNAL_CAMERA_STATUS_CALIBRATED_BIT_OCULUS, 0x00000008) \ + _(XR_EXTERNAL_CAMERA_STATUS_CAPTURING_BIT_OCULUS, 0x00000010) \ + +#define XR_LIST_BITS_XrPerformanceMetricsCounterFlagsMETA(_) \ + _(XR_PERFORMANCE_METRICS_COUNTER_ANY_VALUE_VALID_BIT_META, 0x00000001) \ + _(XR_PERFORMANCE_METRICS_COUNTER_UINT_VALUE_VALID_BIT_META, 0x00000002) \ + _(XR_PERFORMANCE_METRICS_COUNTER_FLOAT_VALUE_VALID_BIT_META, 0x00000004) \ + +#define XR_LIST_BITS_XrFoveationDynamicFlagsHTC(_) \ + _(XR_FOVEATION_DYNAMIC_LEVEL_ENABLED_BIT_HTC, 0x00000001) \ + _(XR_FOVEATION_DYNAMIC_CLEAR_FOV_ENABLED_BIT_HTC, 0x00000002) \ + _(XR_FOVEATION_DYNAMIC_FOCAL_CENTER_OFFSET_ENABLED_BIT_HTC, 0x00000004) \ + +#define XR_LIST_BITS_XrPlaneDetectionCapabilityFlagsEXT(_) \ + _(XR_PLANE_DETECTION_CAPABILITY_PLANE_DETECTION_BIT_EXT, 0x00000001) \ + _(XR_PLANE_DETECTION_CAPABILITY_PLANE_HOLES_BIT_EXT, 0x00000002) \ + _(XR_PLANE_DETECTION_CAPABILITY_SEMANTIC_CEILING_BIT_EXT, 0x00000004) \ + _(XR_PLANE_DETECTION_CAPABILITY_SEMANTIC_FLOOR_BIT_EXT, 0x00000008) \ + _(XR_PLANE_DETECTION_CAPABILITY_SEMANTIC_WALL_BIT_EXT, 0x00000010) \ + _(XR_PLANE_DETECTION_CAPABILITY_SEMANTIC_PLATFORM_BIT_EXT, 0x00000020) \ + _(XR_PLANE_DETECTION_CAPABILITY_ORIENTATION_BIT_EXT, 0x00000040) \ + +#define XR_LIST_BITS_XrPlaneDetectorFlagsEXT(_) \ + _(XR_PLANE_DETECTOR_ENABLE_CONTOUR_BIT_EXT, 0x00000001) \ + +/// Calls your macro with the name of each member of XrApiLayerProperties, in order. +#define XR_LIST_STRUCT_XrApiLayerProperties(_) \ + _(type) \ + _(next) \ + _(layerName) \ + _(specVersion) \ + _(layerVersion) \ + _(description) \ + +/// Calls your macro with the name of each member of XrExtensionProperties, in order. +#define XR_LIST_STRUCT_XrExtensionProperties(_) \ + _(type) \ + _(next) \ + _(extensionName) \ + _(extensionVersion) \ + +/// Calls your macro with the name of each member of XrApplicationInfo, in order. +#define XR_LIST_STRUCT_XrApplicationInfo(_) \ + _(applicationName) \ + _(applicationVersion) \ + _(engineName) \ + _(engineVersion) \ + _(apiVersion) \ + +/// Calls your macro with the name of each member of XrInstanceCreateInfo, in order. +#define XR_LIST_STRUCT_XrInstanceCreateInfo(_) \ + _(type) \ + _(next) \ + _(createFlags) \ + _(applicationInfo) \ + _(enabledApiLayerCount) \ + _(enabledApiLayerNames) \ + _(enabledExtensionCount) \ + _(enabledExtensionNames) \ + +/// Calls your macro with the name of each member of XrInstanceProperties, in order. +#define XR_LIST_STRUCT_XrInstanceProperties(_) \ + _(type) \ + _(next) \ + _(runtimeVersion) \ + _(runtimeName) \ + +/// Calls your macro with the name of each member of XrEventDataBuffer, in order. +#define XR_LIST_STRUCT_XrEventDataBuffer(_) \ + _(type) \ + _(next) \ + _(varying) \ + +/// Calls your macro with the name of each member of XrSystemGetInfo, in order. +#define XR_LIST_STRUCT_XrSystemGetInfo(_) \ + _(type) \ + _(next) \ + _(formFactor) \ + +/// Calls your macro with the name of each member of XrSystemGraphicsProperties, in order. +#define XR_LIST_STRUCT_XrSystemGraphicsProperties(_) \ + _(maxSwapchainImageHeight) \ + _(maxSwapchainImageWidth) \ + _(maxLayerCount) \ + +/// Calls your macro with the name of each member of XrSystemTrackingProperties, in order. +#define XR_LIST_STRUCT_XrSystemTrackingProperties(_) \ + _(orientationTracking) \ + _(positionTracking) \ + +/// Calls your macro with the name of each member of XrSystemProperties, in order. +#define XR_LIST_STRUCT_XrSystemProperties(_) \ + _(type) \ + _(next) \ + _(systemId) \ + _(vendorId) \ + _(systemName) \ + _(graphicsProperties) \ + _(trackingProperties) \ + +/// Calls your macro with the name of each member of XrSessionCreateInfo, in order. +#define XR_LIST_STRUCT_XrSessionCreateInfo(_) \ + _(type) \ + _(next) \ + _(createFlags) \ + _(systemId) \ + +/// Calls your macro with the name of each member of XrVector3f, in order. +#define XR_LIST_STRUCT_XrVector3f(_) \ + _(x) \ + _(y) \ + _(z) \ + +/// Calls your macro with the name of each member of XrSpaceVelocity, in order. +#define XR_LIST_STRUCT_XrSpaceVelocity(_) \ + _(type) \ + _(next) \ + _(velocityFlags) \ + _(linearVelocity) \ + _(angularVelocity) \ + +/// Calls your macro with the name of each member of XrQuaternionf, in order. +#define XR_LIST_STRUCT_XrQuaternionf(_) \ + _(x) \ + _(y) \ + _(z) \ + _(w) \ + +/// Calls your macro with the name of each member of XrPosef, in order. +#define XR_LIST_STRUCT_XrPosef(_) \ + _(orientation) \ + _(position) \ + +/// Calls your macro with the name of each member of XrReferenceSpaceCreateInfo, in order. +#define XR_LIST_STRUCT_XrReferenceSpaceCreateInfo(_) \ + _(type) \ + _(next) \ + _(referenceSpaceType) \ + _(poseInReferenceSpace) \ + +/// Calls your macro with the name of each member of XrExtent2Df, in order. +#define XR_LIST_STRUCT_XrExtent2Df(_) \ + _(width) \ + _(height) \ + +/// Calls your macro with the name of each member of XrActionSpaceCreateInfo, in order. +#define XR_LIST_STRUCT_XrActionSpaceCreateInfo(_) \ + _(type) \ + _(next) \ + _(action) \ + _(subactionPath) \ + _(poseInActionSpace) \ + +/// Calls your macro with the name of each member of XrSpaceLocation, in order. +#define XR_LIST_STRUCT_XrSpaceLocation(_) \ + _(type) \ + _(next) \ + _(locationFlags) \ + _(pose) \ + +/// Calls your macro with the name of each member of XrViewConfigurationProperties, in order. +#define XR_LIST_STRUCT_XrViewConfigurationProperties(_) \ + _(type) \ + _(next) \ + _(viewConfigurationType) \ + _(fovMutable) \ + +/// Calls your macro with the name of each member of XrViewConfigurationView, in order. +#define XR_LIST_STRUCT_XrViewConfigurationView(_) \ + _(type) \ + _(next) \ + _(recommendedImageRectWidth) \ + _(maxImageRectWidth) \ + _(recommendedImageRectHeight) \ + _(maxImageRectHeight) \ + _(recommendedSwapchainSampleCount) \ + _(maxSwapchainSampleCount) \ + +/// Calls your macro with the name of each member of XrSwapchainCreateInfo, in order. +#define XR_LIST_STRUCT_XrSwapchainCreateInfo(_) \ + _(type) \ + _(next) \ + _(createFlags) \ + _(usageFlags) \ + _(format) \ + _(sampleCount) \ + _(width) \ + _(height) \ + _(faceCount) \ + _(arraySize) \ + _(mipCount) \ + +/// Calls your macro with the name of each member of XrSwapchainImageBaseHeader, in order. +#define XR_LIST_STRUCT_XrSwapchainImageBaseHeader(_) \ + _(type) \ + _(next) \ + +/// Calls your macro with the name of each member of XrSwapchainImageAcquireInfo, in order. +#define XR_LIST_STRUCT_XrSwapchainImageAcquireInfo(_) \ + _(type) \ + _(next) \ + +/// Calls your macro with the name of each member of XrSwapchainImageWaitInfo, in order. +#define XR_LIST_STRUCT_XrSwapchainImageWaitInfo(_) \ + _(type) \ + _(next) \ + _(timeout) \ + +/// Calls your macro with the name of each member of XrSwapchainImageReleaseInfo, in order. +#define XR_LIST_STRUCT_XrSwapchainImageReleaseInfo(_) \ + _(type) \ + _(next) \ + +/// Calls your macro with the name of each member of XrSessionBeginInfo, in order. +#define XR_LIST_STRUCT_XrSessionBeginInfo(_) \ + _(type) \ + _(next) \ + _(primaryViewConfigurationType) \ + +/// Calls your macro with the name of each member of XrFrameWaitInfo, in order. +#define XR_LIST_STRUCT_XrFrameWaitInfo(_) \ + _(type) \ + _(next) \ + +/// Calls your macro with the name of each member of XrFrameState, in order. +#define XR_LIST_STRUCT_XrFrameState(_) \ + _(type) \ + _(next) \ + _(predictedDisplayTime) \ + _(predictedDisplayPeriod) \ + _(shouldRender) \ + +/// Calls your macro with the name of each member of XrFrameBeginInfo, in order. +#define XR_LIST_STRUCT_XrFrameBeginInfo(_) \ + _(type) \ + _(next) \ + +/// Calls your macro with the name of each member of XrCompositionLayerBaseHeader, in order. +#define XR_LIST_STRUCT_XrCompositionLayerBaseHeader(_) \ + _(type) \ + _(next) \ + _(layerFlags) \ + _(space) \ + +/// Calls your macro with the name of each member of XrFrameEndInfo, in order. +#define XR_LIST_STRUCT_XrFrameEndInfo(_) \ + _(type) \ + _(next) \ + _(displayTime) \ + _(environmentBlendMode) \ + _(layerCount) \ + _(layers) \ + +/// Calls your macro with the name of each member of XrViewLocateInfo, in order. +#define XR_LIST_STRUCT_XrViewLocateInfo(_) \ + _(type) \ + _(next) \ + _(viewConfigurationType) \ + _(displayTime) \ + _(space) \ + +/// Calls your macro with the name of each member of XrViewState, in order. +#define XR_LIST_STRUCT_XrViewState(_) \ + _(type) \ + _(next) \ + _(viewStateFlags) \ + +/// Calls your macro with the name of each member of XrFovf, in order. +#define XR_LIST_STRUCT_XrFovf(_) \ + _(angleLeft) \ + _(angleRight) \ + _(angleUp) \ + _(angleDown) \ + +/// Calls your macro with the name of each member of XrView, in order. +#define XR_LIST_STRUCT_XrView(_) \ + _(type) \ + _(next) \ + _(pose) \ + _(fov) \ + +/// Calls your macro with the name of each member of XrActionSetCreateInfo, in order. +#define XR_LIST_STRUCT_XrActionSetCreateInfo(_) \ + _(type) \ + _(next) \ + _(actionSetName) \ + _(localizedActionSetName) \ + _(priority) \ + +/// Calls your macro with the name of each member of XrActionCreateInfo, in order. +#define XR_LIST_STRUCT_XrActionCreateInfo(_) \ + _(type) \ + _(next) \ + _(actionName) \ + _(actionType) \ + _(countSubactionPaths) \ + _(subactionPaths) \ + _(localizedActionName) \ + +/// Calls your macro with the name of each member of XrActionSuggestedBinding, in order. +#define XR_LIST_STRUCT_XrActionSuggestedBinding(_) \ + _(action) \ + _(binding) \ + +/// Calls your macro with the name of each member of XrInteractionProfileSuggestedBinding, in order. +#define XR_LIST_STRUCT_XrInteractionProfileSuggestedBinding(_) \ + _(type) \ + _(next) \ + _(interactionProfile) \ + _(countSuggestedBindings) \ + _(suggestedBindings) \ + +/// Calls your macro with the name of each member of XrSessionActionSetsAttachInfo, in order. +#define XR_LIST_STRUCT_XrSessionActionSetsAttachInfo(_) \ + _(type) \ + _(next) \ + _(countActionSets) \ + _(actionSets) \ + +/// Calls your macro with the name of each member of XrInteractionProfileState, in order. +#define XR_LIST_STRUCT_XrInteractionProfileState(_) \ + _(type) \ + _(next) \ + _(interactionProfile) \ + +/// Calls your macro with the name of each member of XrActionStateGetInfo, in order. +#define XR_LIST_STRUCT_XrActionStateGetInfo(_) \ + _(type) \ + _(next) \ + _(action) \ + _(subactionPath) \ + +/// Calls your macro with the name of each member of XrActionStateBoolean, in order. +#define XR_LIST_STRUCT_XrActionStateBoolean(_) \ + _(type) \ + _(next) \ + _(currentState) \ + _(changedSinceLastSync) \ + _(lastChangeTime) \ + _(isActive) \ + +/// Calls your macro with the name of each member of XrActionStateFloat, in order. +#define XR_LIST_STRUCT_XrActionStateFloat(_) \ + _(type) \ + _(next) \ + _(currentState) \ + _(changedSinceLastSync) \ + _(lastChangeTime) \ + _(isActive) \ + +/// Calls your macro with the name of each member of XrVector2f, in order. +#define XR_LIST_STRUCT_XrVector2f(_) \ + _(x) \ + _(y) \ + +/// Calls your macro with the name of each member of XrActionStateVector2f, in order. +#define XR_LIST_STRUCT_XrActionStateVector2f(_) \ + _(type) \ + _(next) \ + _(currentState) \ + _(changedSinceLastSync) \ + _(lastChangeTime) \ + _(isActive) \ + +/// Calls your macro with the name of each member of XrActionStatePose, in order. +#define XR_LIST_STRUCT_XrActionStatePose(_) \ + _(type) \ + _(next) \ + _(isActive) \ + +/// Calls your macro with the name of each member of XrActiveActionSet, in order. +#define XR_LIST_STRUCT_XrActiveActionSet(_) \ + _(actionSet) \ + _(subactionPath) \ + +/// Calls your macro with the name of each member of XrActionsSyncInfo, in order. +#define XR_LIST_STRUCT_XrActionsSyncInfo(_) \ + _(type) \ + _(next) \ + _(countActiveActionSets) \ + _(activeActionSets) \ + +/// Calls your macro with the name of each member of XrBoundSourcesForActionEnumerateInfo, in order. +#define XR_LIST_STRUCT_XrBoundSourcesForActionEnumerateInfo(_) \ + _(type) \ + _(next) \ + _(action) \ + +/// Calls your macro with the name of each member of XrInputSourceLocalizedNameGetInfo, in order. +#define XR_LIST_STRUCT_XrInputSourceLocalizedNameGetInfo(_) \ + _(type) \ + _(next) \ + _(sourcePath) \ + _(whichComponents) \ + +/// Calls your macro with the name of each member of XrHapticActionInfo, in order. +#define XR_LIST_STRUCT_XrHapticActionInfo(_) \ + _(type) \ + _(next) \ + _(action) \ + _(subactionPath) \ + +/// Calls your macro with the name of each member of XrHapticBaseHeader, in order. +#define XR_LIST_STRUCT_XrHapticBaseHeader(_) \ + _(type) \ + _(next) \ + +/// Calls your macro with the name of each member of XrBaseInStructure, in order. +#define XR_LIST_STRUCT_XrBaseInStructure(_) \ + _(type) \ + _(next) \ + +/// Calls your macro with the name of each member of XrBaseOutStructure, in order. +#define XR_LIST_STRUCT_XrBaseOutStructure(_) \ + _(type) \ + _(next) \ + +/// Calls your macro with the name of each member of XrOffset2Di, in order. +#define XR_LIST_STRUCT_XrOffset2Di(_) \ + _(x) \ + _(y) \ + +/// Calls your macro with the name of each member of XrExtent2Di, in order. +#define XR_LIST_STRUCT_XrExtent2Di(_) \ + _(width) \ + _(height) \ + +/// Calls your macro with the name of each member of XrRect2Di, in order. +#define XR_LIST_STRUCT_XrRect2Di(_) \ + _(offset) \ + _(extent) \ + +/// Calls your macro with the name of each member of XrSwapchainSubImage, in order. +#define XR_LIST_STRUCT_XrSwapchainSubImage(_) \ + _(swapchain) \ + _(imageRect) \ + _(imageArrayIndex) \ + +/// Calls your macro with the name of each member of XrCompositionLayerProjectionView, in order. +#define XR_LIST_STRUCT_XrCompositionLayerProjectionView(_) \ + _(type) \ + _(next) \ + _(pose) \ + _(fov) \ + _(subImage) \ + +/// Calls your macro with the name of each member of XrCompositionLayerProjection, in order. +#define XR_LIST_STRUCT_XrCompositionLayerProjection(_) \ + _(type) \ + _(next) \ + _(layerFlags) \ + _(space) \ + _(viewCount) \ + _(views) \ + +/// Calls your macro with the name of each member of XrCompositionLayerQuad, in order. +#define XR_LIST_STRUCT_XrCompositionLayerQuad(_) \ + _(type) \ + _(next) \ + _(layerFlags) \ + _(space) \ + _(eyeVisibility) \ + _(subImage) \ + _(pose) \ + _(size) \ + +/// Calls your macro with the name of each member of XrEventDataBaseHeader, in order. +#define XR_LIST_STRUCT_XrEventDataBaseHeader(_) \ + _(type) \ + _(next) \ + +/// Calls your macro with the name of each member of XrEventDataEventsLost, in order. +#define XR_LIST_STRUCT_XrEventDataEventsLost(_) \ + _(type) \ + _(next) \ + _(lostEventCount) \ + +/// Calls your macro with the name of each member of XrEventDataInstanceLossPending, in order. +#define XR_LIST_STRUCT_XrEventDataInstanceLossPending(_) \ + _(type) \ + _(next) \ + _(lossTime) \ + +/// Calls your macro with the name of each member of XrEventDataSessionStateChanged, in order. +#define XR_LIST_STRUCT_XrEventDataSessionStateChanged(_) \ + _(type) \ + _(next) \ + _(session) \ + _(state) \ + _(time) \ + +/// Calls your macro with the name of each member of XrEventDataReferenceSpaceChangePending, in order. +#define XR_LIST_STRUCT_XrEventDataReferenceSpaceChangePending(_) \ + _(type) \ + _(next) \ + _(session) \ + _(referenceSpaceType) \ + _(changeTime) \ + _(poseValid) \ + _(poseInPreviousSpace) \ + +/// Calls your macro with the name of each member of XrEventDataInteractionProfileChanged, in order. +#define XR_LIST_STRUCT_XrEventDataInteractionProfileChanged(_) \ + _(type) \ + _(next) \ + _(session) \ + +/// Calls your macro with the name of each member of XrHapticVibration, in order. +#define XR_LIST_STRUCT_XrHapticVibration(_) \ + _(type) \ + _(next) \ + _(duration) \ + _(frequency) \ + _(amplitude) \ + +/// Calls your macro with the name of each member of XrOffset2Df, in order. +#define XR_LIST_STRUCT_XrOffset2Df(_) \ + _(x) \ + _(y) \ + +/// Calls your macro with the name of each member of XrRect2Df, in order. +#define XR_LIST_STRUCT_XrRect2Df(_) \ + _(offset) \ + _(extent) \ + +/// Calls your macro with the name of each member of XrVector4f, in order. +#define XR_LIST_STRUCT_XrVector4f(_) \ + _(x) \ + _(y) \ + _(z) \ + _(w) \ + +/// Calls your macro with the name of each member of XrColor4f, in order. +#define XR_LIST_STRUCT_XrColor4f(_) \ + _(r) \ + _(g) \ + _(b) \ + _(a) \ + +/// Calls your macro with the name of each member of XrCompositionLayerCubeKHR, in order. +#define XR_LIST_STRUCT_XrCompositionLayerCubeKHR(_) \ + _(type) \ + _(next) \ + _(layerFlags) \ + _(space) \ + _(eyeVisibility) \ + _(swapchain) \ + _(imageArrayIndex) \ + _(orientation) \ + +/// Calls your macro with the name of each member of XrInstanceCreateInfoAndroidKHR, in order. +#define XR_LIST_STRUCT_XrInstanceCreateInfoAndroidKHR(_) \ + _(type) \ + _(next) \ + _(applicationVM) \ + _(applicationActivity) \ + +/// Calls your macro with the name of each member of XrCompositionLayerDepthInfoKHR, in order. +#define XR_LIST_STRUCT_XrCompositionLayerDepthInfoKHR(_) \ + _(type) \ + _(next) \ + _(subImage) \ + _(minDepth) \ + _(maxDepth) \ + _(nearZ) \ + _(farZ) \ + +/// Calls your macro with the name of each member of XrVulkanSwapchainFormatListCreateInfoKHR, in order. +#define XR_LIST_STRUCT_XrVulkanSwapchainFormatListCreateInfoKHR(_) \ + _(type) \ + _(next) \ + _(viewFormatCount) \ + _(viewFormats) \ + +/// Calls your macro with the name of each member of XrCompositionLayerCylinderKHR, in order. +#define XR_LIST_STRUCT_XrCompositionLayerCylinderKHR(_) \ + _(type) \ + _(next) \ + _(layerFlags) \ + _(space) \ + _(eyeVisibility) \ + _(subImage) \ + _(pose) \ + _(radius) \ + _(centralAngle) \ + _(aspectRatio) \ + +/// Calls your macro with the name of each member of XrCompositionLayerEquirectKHR, in order. +#define XR_LIST_STRUCT_XrCompositionLayerEquirectKHR(_) \ + _(type) \ + _(next) \ + _(layerFlags) \ + _(space) \ + _(eyeVisibility) \ + _(subImage) \ + _(pose) \ + _(radius) \ + _(scale) \ + _(bias) \ + +/// Calls your macro with the name of each member of XrGraphicsBindingOpenGLWin32KHR, in order. +#define XR_LIST_STRUCT_XrGraphicsBindingOpenGLWin32KHR(_) \ + _(type) \ + _(next) \ + _(hDC) \ + _(hGLRC) \ + +/// Calls your macro with the name of each member of XrGraphicsBindingOpenGLXlibKHR, in order. +#define XR_LIST_STRUCT_XrGraphicsBindingOpenGLXlibKHR(_) \ + _(type) \ + _(next) \ + _(xDisplay) \ + _(visualid) \ + _(glxFBConfig) \ + _(glxDrawable) \ + _(glxContext) \ + +/// Calls your macro with the name of each member of XrGraphicsBindingOpenGLXcbKHR, in order. +#define XR_LIST_STRUCT_XrGraphicsBindingOpenGLXcbKHR(_) \ + _(type) \ + _(next) \ + _(connection) \ + _(screenNumber) \ + _(fbconfigid) \ + _(visualid) \ + _(glxDrawable) \ + _(glxContext) \ + +/// Calls your macro with the name of each member of XrGraphicsBindingOpenGLWaylandKHR, in order. +#define XR_LIST_STRUCT_XrGraphicsBindingOpenGLWaylandKHR(_) \ + _(type) \ + _(next) \ + _(display) \ + +/// Calls your macro with the name of each member of XrSwapchainImageOpenGLKHR, in order. +#define XR_LIST_STRUCT_XrSwapchainImageOpenGLKHR(_) \ + _(type) \ + _(next) \ + _(image) \ + +/// Calls your macro with the name of each member of XrGraphicsRequirementsOpenGLKHR, in order. +#define XR_LIST_STRUCT_XrGraphicsRequirementsOpenGLKHR(_) \ + _(type) \ + _(next) \ + _(minApiVersionSupported) \ + _(maxApiVersionSupported) \ + +/// Calls your macro with the name of each member of XrGraphicsBindingOpenGLESAndroidKHR, in order. +#define XR_LIST_STRUCT_XrGraphicsBindingOpenGLESAndroidKHR(_) \ + _(type) \ + _(next) \ + _(display) \ + _(config) \ + _(context) \ + +/// Calls your macro with the name of each member of XrSwapchainImageOpenGLESKHR, in order. +#define XR_LIST_STRUCT_XrSwapchainImageOpenGLESKHR(_) \ + _(type) \ + _(next) \ + _(image) \ + +/// Calls your macro with the name of each member of XrGraphicsRequirementsOpenGLESKHR, in order. +#define XR_LIST_STRUCT_XrGraphicsRequirementsOpenGLESKHR(_) \ + _(type) \ + _(next) \ + _(minApiVersionSupported) \ + _(maxApiVersionSupported) \ + +/// Calls your macro with the name of each member of XrGraphicsBindingVulkanKHR, in order. +#define XR_LIST_STRUCT_XrGraphicsBindingVulkanKHR(_) \ + _(type) \ + _(next) \ + _(instance) \ + _(physicalDevice) \ + _(device) \ + _(queueFamilyIndex) \ + _(queueIndex) \ + +/// Calls your macro with the name of each member of XrSwapchainImageVulkanKHR, in order. +#define XR_LIST_STRUCT_XrSwapchainImageVulkanKHR(_) \ + _(type) \ + _(next) \ + _(image) \ + +/// Calls your macro with the name of each member of XrGraphicsRequirementsVulkanKHR, in order. +#define XR_LIST_STRUCT_XrGraphicsRequirementsVulkanKHR(_) \ + _(type) \ + _(next) \ + _(minApiVersionSupported) \ + _(maxApiVersionSupported) \ + +/// Calls your macro with the name of each member of XrGraphicsBindingD3D11KHR, in order. +#define XR_LIST_STRUCT_XrGraphicsBindingD3D11KHR(_) \ + _(type) \ + _(next) \ + _(device) \ + +/// Calls your macro with the name of each member of XrSwapchainImageD3D11KHR, in order. +#define XR_LIST_STRUCT_XrSwapchainImageD3D11KHR(_) \ + _(type) \ + _(next) \ + _(texture) \ + +/// Calls your macro with the name of each member of XrGraphicsRequirementsD3D11KHR, in order. +#define XR_LIST_STRUCT_XrGraphicsRequirementsD3D11KHR(_) \ + _(type) \ + _(next) \ + _(adapterLuid) \ + _(minFeatureLevel) \ + +/// Calls your macro with the name of each member of XrGraphicsBindingD3D12KHR, in order. +#define XR_LIST_STRUCT_XrGraphicsBindingD3D12KHR(_) \ + _(type) \ + _(next) \ + _(device) \ + _(queue) \ + +/// Calls your macro with the name of each member of XrSwapchainImageD3D12KHR, in order. +#define XR_LIST_STRUCT_XrSwapchainImageD3D12KHR(_) \ + _(type) \ + _(next) \ + _(texture) \ + +/// Calls your macro with the name of each member of XrGraphicsRequirementsD3D12KHR, in order. +#define XR_LIST_STRUCT_XrGraphicsRequirementsD3D12KHR(_) \ + _(type) \ + _(next) \ + _(adapterLuid) \ + _(minFeatureLevel) \ + +/// Calls your macro with the name of each member of XrVisibilityMaskKHR, in order. +#define XR_LIST_STRUCT_XrVisibilityMaskKHR(_) \ + _(type) \ + _(next) \ + _(vertexCapacityInput) \ + _(vertexCountOutput) \ + _(vertices) \ + _(indexCapacityInput) \ + _(indexCountOutput) \ + _(indices) \ + +/// Calls your macro with the name of each member of XrEventDataVisibilityMaskChangedKHR, in order. +#define XR_LIST_STRUCT_XrEventDataVisibilityMaskChangedKHR(_) \ + _(type) \ + _(next) \ + _(session) \ + _(viewConfigurationType) \ + _(viewIndex) \ + +/// Calls your macro with the name of each member of XrCompositionLayerColorScaleBiasKHR, in order. +#define XR_LIST_STRUCT_XrCompositionLayerColorScaleBiasKHR(_) \ + _(type) \ + _(next) \ + _(colorScale) \ + _(colorBias) \ + +/// Calls your macro with the name of each member of XrLoaderInitInfoBaseHeaderKHR, in order. +#define XR_LIST_STRUCT_XrLoaderInitInfoBaseHeaderKHR(_) \ + _(type) \ + _(next) \ + +/// Calls your macro with the name of each member of XrLoaderInitInfoAndroidKHR, in order. +#define XR_LIST_STRUCT_XrLoaderInitInfoAndroidKHR(_) \ + _(type) \ + _(next) \ + _(applicationVM) \ + _(applicationContext) \ + +/// Calls your macro with the name of each member of XrVulkanInstanceCreateInfoKHR, in order. +#define XR_LIST_STRUCT_XrVulkanInstanceCreateInfoKHR(_) \ + _(type) \ + _(next) \ + _(systemId) \ + _(createFlags) \ + _(pfnGetInstanceProcAddr) \ + _(vulkanCreateInfo) \ + _(vulkanAllocator) \ + +/// Calls your macro with the name of each member of XrVulkanDeviceCreateInfoKHR, in order. +#define XR_LIST_STRUCT_XrVulkanDeviceCreateInfoKHR(_) \ + _(type) \ + _(next) \ + _(systemId) \ + _(createFlags) \ + _(pfnGetInstanceProcAddr) \ + _(vulkanPhysicalDevice) \ + _(vulkanCreateInfo) \ + _(vulkanAllocator) \ + +/// Calls your macro with the name of each member of XrVulkanGraphicsDeviceGetInfoKHR, in order. +#define XR_LIST_STRUCT_XrVulkanGraphicsDeviceGetInfoKHR(_) \ + _(type) \ + _(next) \ + _(systemId) \ + _(vulkanInstance) \ + +/// Calls your macro with the name of each member of XrCompositionLayerEquirect2KHR, in order. +#define XR_LIST_STRUCT_XrCompositionLayerEquirect2KHR(_) \ + _(type) \ + _(next) \ + _(layerFlags) \ + _(space) \ + _(eyeVisibility) \ + _(subImage) \ + _(pose) \ + _(radius) \ + _(centralHorizontalAngle) \ + _(upperVerticalAngle) \ + _(lowerVerticalAngle) \ + +/// Calls your macro with the name of each member of XrBindingModificationBaseHeaderKHR, in order. +#define XR_LIST_STRUCT_XrBindingModificationBaseHeaderKHR(_) \ + _(type) \ + _(next) \ + +/// Calls your macro with the name of each member of XrBindingModificationsKHR, in order. +#define XR_LIST_STRUCT_XrBindingModificationsKHR(_) \ + _(type) \ + _(next) \ + _(bindingModificationCount) \ + _(bindingModifications) \ + +/// Calls your macro with the name of each member of XrEventDataPerfSettingsEXT, in order. +#define XR_LIST_STRUCT_XrEventDataPerfSettingsEXT(_) \ + _(type) \ + _(next) \ + _(domain) \ + _(subDomain) \ + _(fromLevel) \ + _(toLevel) \ + +/// Calls your macro with the name of each member of XrDebugUtilsObjectNameInfoEXT, in order. +#define XR_LIST_STRUCT_XrDebugUtilsObjectNameInfoEXT(_) \ + _(type) \ + _(next) \ + _(objectType) \ + _(objectHandle) \ + _(objectName) \ + +/// Calls your macro with the name of each member of XrDebugUtilsLabelEXT, in order. +#define XR_LIST_STRUCT_XrDebugUtilsLabelEXT(_) \ + _(type) \ + _(next) \ + _(labelName) \ + +/// Calls your macro with the name of each member of XrDebugUtilsMessengerCallbackDataEXT, in order. +#define XR_LIST_STRUCT_XrDebugUtilsMessengerCallbackDataEXT(_) \ + _(type) \ + _(next) \ + _(messageId) \ + _(functionName) \ + _(message) \ + _(objectCount) \ + _(objects) \ + _(sessionLabelCount) \ + _(sessionLabels) \ + +/// Calls your macro with the name of each member of XrDebugUtilsMessengerCreateInfoEXT, in order. +#define XR_LIST_STRUCT_XrDebugUtilsMessengerCreateInfoEXT(_) \ + _(type) \ + _(next) \ + _(messageSeverities) \ + _(messageTypes) \ + _(userCallback) \ + _(userData) \ + +/// Calls your macro with the name of each member of XrSystemEyeGazeInteractionPropertiesEXT, in order. +#define XR_LIST_STRUCT_XrSystemEyeGazeInteractionPropertiesEXT(_) \ + _(type) \ + _(next) \ + _(supportsEyeGazeInteraction) \ + +/// Calls your macro with the name of each member of XrEyeGazeSampleTimeEXT, in order. +#define XR_LIST_STRUCT_XrEyeGazeSampleTimeEXT(_) \ + _(type) \ + _(next) \ + _(time) \ + +/// Calls your macro with the name of each member of XrSessionCreateInfoOverlayEXTX, in order. +#define XR_LIST_STRUCT_XrSessionCreateInfoOverlayEXTX(_) \ + _(type) \ + _(next) \ + _(createFlags) \ + _(sessionLayersPlacement) \ + +/// Calls your macro with the name of each member of XrEventDataMainSessionVisibilityChangedEXTX, in order. +#define XR_LIST_STRUCT_XrEventDataMainSessionVisibilityChangedEXTX(_) \ + _(type) \ + _(next) \ + _(visible) \ + _(flags) \ + +/// Calls your macro with the name of each member of XrSpatialAnchorCreateInfoMSFT, in order. +#define XR_LIST_STRUCT_XrSpatialAnchorCreateInfoMSFT(_) \ + _(type) \ + _(next) \ + _(space) \ + _(pose) \ + _(time) \ + +/// Calls your macro with the name of each member of XrSpatialAnchorSpaceCreateInfoMSFT, in order. +#define XR_LIST_STRUCT_XrSpatialAnchorSpaceCreateInfoMSFT(_) \ + _(type) \ + _(next) \ + _(anchor) \ + _(poseInAnchorSpace) \ + +/// Calls your macro with the name of each member of XrCompositionLayerImageLayoutFB, in order. +#define XR_LIST_STRUCT_XrCompositionLayerImageLayoutFB(_) \ + _(type) \ + _(next) \ + _(flags) \ + +/// Calls your macro with the name of each member of XrCompositionLayerAlphaBlendFB, in order. +#define XR_LIST_STRUCT_XrCompositionLayerAlphaBlendFB(_) \ + _(type) \ + _(next) \ + _(srcFactorColor) \ + _(dstFactorColor) \ + _(srcFactorAlpha) \ + _(dstFactorAlpha) \ + +/// Calls your macro with the name of each member of XrViewConfigurationDepthRangeEXT, in order. +#define XR_LIST_STRUCT_XrViewConfigurationDepthRangeEXT(_) \ + _(type) \ + _(next) \ + _(recommendedNearZ) \ + _(minNearZ) \ + _(recommendedFarZ) \ + _(maxFarZ) \ + +/// Calls your macro with the name of each member of XrGraphicsBindingEGLMNDX, in order. +#define XR_LIST_STRUCT_XrGraphicsBindingEGLMNDX(_) \ + _(type) \ + _(next) \ + _(getProcAddress) \ + _(display) \ + _(config) \ + _(context) \ + +/// Calls your macro with the name of each member of XrSpatialGraphNodeSpaceCreateInfoMSFT, in order. +#define XR_LIST_STRUCT_XrSpatialGraphNodeSpaceCreateInfoMSFT(_) \ + _(type) \ + _(next) \ + _(nodeType) \ + _(nodeId) \ + _(pose) \ + +/// Calls your macro with the name of each member of XrSpatialGraphStaticNodeBindingCreateInfoMSFT, in order. +#define XR_LIST_STRUCT_XrSpatialGraphStaticNodeBindingCreateInfoMSFT(_) \ + _(type) \ + _(next) \ + _(space) \ + _(poseInSpace) \ + _(time) \ + +/// Calls your macro with the name of each member of XrSpatialGraphNodeBindingPropertiesGetInfoMSFT, in order. +#define XR_LIST_STRUCT_XrSpatialGraphNodeBindingPropertiesGetInfoMSFT(_) \ + _(type) \ + _(next) \ + +/// Calls your macro with the name of each member of XrSpatialGraphNodeBindingPropertiesMSFT, in order. +#define XR_LIST_STRUCT_XrSpatialGraphNodeBindingPropertiesMSFT(_) \ + _(type) \ + _(next) \ + _(nodeId) \ + _(poseInNodeSpace) \ + +/// Calls your macro with the name of each member of XrSystemHandTrackingPropertiesEXT, in order. +#define XR_LIST_STRUCT_XrSystemHandTrackingPropertiesEXT(_) \ + _(type) \ + _(next) \ + _(supportsHandTracking) \ + +/// Calls your macro with the name of each member of XrHandTrackerCreateInfoEXT, in order. +#define XR_LIST_STRUCT_XrHandTrackerCreateInfoEXT(_) \ + _(type) \ + _(next) \ + _(hand) \ + _(handJointSet) \ + +/// Calls your macro with the name of each member of XrHandJointsLocateInfoEXT, in order. +#define XR_LIST_STRUCT_XrHandJointsLocateInfoEXT(_) \ + _(type) \ + _(next) \ + _(baseSpace) \ + _(time) \ + +/// Calls your macro with the name of each member of XrHandJointLocationEXT, in order. +#define XR_LIST_STRUCT_XrHandJointLocationEXT(_) \ + _(locationFlags) \ + _(pose) \ + _(radius) \ + +/// Calls your macro with the name of each member of XrHandJointVelocityEXT, in order. +#define XR_LIST_STRUCT_XrHandJointVelocityEXT(_) \ + _(velocityFlags) \ + _(linearVelocity) \ + _(angularVelocity) \ + +/// Calls your macro with the name of each member of XrHandJointLocationsEXT, in order. +#define XR_LIST_STRUCT_XrHandJointLocationsEXT(_) \ + _(type) \ + _(next) \ + _(isActive) \ + _(jointCount) \ + _(jointLocations) \ + +/// Calls your macro with the name of each member of XrHandJointVelocitiesEXT, in order. +#define XR_LIST_STRUCT_XrHandJointVelocitiesEXT(_) \ + _(type) \ + _(next) \ + _(jointCount) \ + _(jointVelocities) \ + +/// Calls your macro with the name of each member of XrSystemHandTrackingMeshPropertiesMSFT, in order. +#define XR_LIST_STRUCT_XrSystemHandTrackingMeshPropertiesMSFT(_) \ + _(type) \ + _(next) \ + _(supportsHandTrackingMesh) \ + _(maxHandMeshIndexCount) \ + _(maxHandMeshVertexCount) \ + +/// Calls your macro with the name of each member of XrHandMeshSpaceCreateInfoMSFT, in order. +#define XR_LIST_STRUCT_XrHandMeshSpaceCreateInfoMSFT(_) \ + _(type) \ + _(next) \ + _(handPoseType) \ + _(poseInHandMeshSpace) \ + +/// Calls your macro with the name of each member of XrHandMeshUpdateInfoMSFT, in order. +#define XR_LIST_STRUCT_XrHandMeshUpdateInfoMSFT(_) \ + _(type) \ + _(next) \ + _(time) \ + _(handPoseType) \ + +/// Calls your macro with the name of each member of XrHandMeshIndexBufferMSFT, in order. +#define XR_LIST_STRUCT_XrHandMeshIndexBufferMSFT(_) \ + _(indexBufferKey) \ + _(indexCapacityInput) \ + _(indexCountOutput) \ + _(indices) \ + +/// Calls your macro with the name of each member of XrHandMeshVertexMSFT, in order. +#define XR_LIST_STRUCT_XrHandMeshVertexMSFT(_) \ + _(position) \ + _(normal) \ + +/// Calls your macro with the name of each member of XrHandMeshVertexBufferMSFT, in order. +#define XR_LIST_STRUCT_XrHandMeshVertexBufferMSFT(_) \ + _(vertexUpdateTime) \ + _(vertexCapacityInput) \ + _(vertexCountOutput) \ + _(vertices) \ + +/// Calls your macro with the name of each member of XrHandMeshMSFT, in order. +#define XR_LIST_STRUCT_XrHandMeshMSFT(_) \ + _(type) \ + _(next) \ + _(isActive) \ + _(indexBufferChanged) \ + _(vertexBufferChanged) \ + _(indexBuffer) \ + _(vertexBuffer) \ + +/// Calls your macro with the name of each member of XrHandPoseTypeInfoMSFT, in order. +#define XR_LIST_STRUCT_XrHandPoseTypeInfoMSFT(_) \ + _(type) \ + _(next) \ + _(handPoseType) \ + +/// Calls your macro with the name of each member of XrSecondaryViewConfigurationSessionBeginInfoMSFT, in order. +#define XR_LIST_STRUCT_XrSecondaryViewConfigurationSessionBeginInfoMSFT(_) \ + _(type) \ + _(next) \ + _(viewConfigurationCount) \ + _(enabledViewConfigurationTypes) \ + +/// Calls your macro with the name of each member of XrSecondaryViewConfigurationStateMSFT, in order. +#define XR_LIST_STRUCT_XrSecondaryViewConfigurationStateMSFT(_) \ + _(type) \ + _(next) \ + _(viewConfigurationType) \ + _(active) \ + +/// Calls your macro with the name of each member of XrSecondaryViewConfigurationFrameStateMSFT, in order. +#define XR_LIST_STRUCT_XrSecondaryViewConfigurationFrameStateMSFT(_) \ + _(type) \ + _(next) \ + _(viewConfigurationCount) \ + _(viewConfigurationStates) \ + +/// Calls your macro with the name of each member of XrSecondaryViewConfigurationLayerInfoMSFT, in order. +#define XR_LIST_STRUCT_XrSecondaryViewConfigurationLayerInfoMSFT(_) \ + _(type) \ + _(next) \ + _(viewConfigurationType) \ + _(environmentBlendMode) \ + _(layerCount) \ + _(layers) \ + +/// Calls your macro with the name of each member of XrSecondaryViewConfigurationFrameEndInfoMSFT, in order. +#define XR_LIST_STRUCT_XrSecondaryViewConfigurationFrameEndInfoMSFT(_) \ + _(type) \ + _(next) \ + _(viewConfigurationCount) \ + _(viewConfigurationLayersInfo) \ + +/// Calls your macro with the name of each member of XrSecondaryViewConfigurationSwapchainCreateInfoMSFT, in order. +#define XR_LIST_STRUCT_XrSecondaryViewConfigurationSwapchainCreateInfoMSFT(_) \ + _(type) \ + _(next) \ + _(viewConfigurationType) \ + +/// Calls your macro with the name of each member of XrControllerModelKeyStateMSFT, in order. +#define XR_LIST_STRUCT_XrControllerModelKeyStateMSFT(_) \ + _(type) \ + _(next) \ + _(modelKey) \ + +/// Calls your macro with the name of each member of XrControllerModelNodePropertiesMSFT, in order. +#define XR_LIST_STRUCT_XrControllerModelNodePropertiesMSFT(_) \ + _(type) \ + _(next) \ + _(parentNodeName) \ + _(nodeName) \ + +/// Calls your macro with the name of each member of XrControllerModelPropertiesMSFT, in order. +#define XR_LIST_STRUCT_XrControllerModelPropertiesMSFT(_) \ + _(type) \ + _(next) \ + _(nodeCapacityInput) \ + _(nodeCountOutput) \ + _(nodeProperties) \ + +/// Calls your macro with the name of each member of XrControllerModelNodeStateMSFT, in order. +#define XR_LIST_STRUCT_XrControllerModelNodeStateMSFT(_) \ + _(type) \ + _(next) \ + _(nodePose) \ + +/// Calls your macro with the name of each member of XrControllerModelStateMSFT, in order. +#define XR_LIST_STRUCT_XrControllerModelStateMSFT(_) \ + _(type) \ + _(next) \ + _(nodeCapacityInput) \ + _(nodeCountOutput) \ + _(nodeStates) \ + +/// Calls your macro with the name of each member of XrViewConfigurationViewFovEPIC, in order. +#define XR_LIST_STRUCT_XrViewConfigurationViewFovEPIC(_) \ + _(type) \ + _(next) \ + _(recommendedFov) \ + _(maxMutableFov) \ + +/// Calls your macro with the name of each member of XrHolographicWindowAttachmentMSFT, in order. +#define XR_LIST_STRUCT_XrHolographicWindowAttachmentMSFT(_) \ + _(type) \ + _(next) \ + _(holographicSpace) \ + _(coreWindow) \ + +/// Calls your macro with the name of each member of XrCompositionLayerReprojectionInfoMSFT, in order. +#define XR_LIST_STRUCT_XrCompositionLayerReprojectionInfoMSFT(_) \ + _(type) \ + _(next) \ + _(reprojectionMode) \ + +/// Calls your macro with the name of each member of XrCompositionLayerReprojectionPlaneOverrideMSFT, in order. +#define XR_LIST_STRUCT_XrCompositionLayerReprojectionPlaneOverrideMSFT(_) \ + _(type) \ + _(next) \ + _(position) \ + _(normal) \ + _(velocity) \ + +/// Calls your macro with the name of each member of XrAndroidSurfaceSwapchainCreateInfoFB, in order. +#define XR_LIST_STRUCT_XrAndroidSurfaceSwapchainCreateInfoFB(_) \ + _(type) \ + _(next) \ + _(createFlags) \ + +/// Calls your macro with the name of each member of XrSwapchainStateBaseHeaderFB, in order. +#define XR_LIST_STRUCT_XrSwapchainStateBaseHeaderFB(_) \ + _(type) \ + _(next) \ + +/// Calls your macro with the name of each member of XrCompositionLayerSecureContentFB, in order. +#define XR_LIST_STRUCT_XrCompositionLayerSecureContentFB(_) \ + _(type) \ + _(next) \ + _(flags) \ + +/// Calls your macro with the name of each member of XrBodyJointLocationFB, in order. +#define XR_LIST_STRUCT_XrBodyJointLocationFB(_) \ + _(locationFlags) \ + _(pose) \ + +/// Calls your macro with the name of each member of XrSystemBodyTrackingPropertiesFB, in order. +#define XR_LIST_STRUCT_XrSystemBodyTrackingPropertiesFB(_) \ + _(type) \ + _(next) \ + _(supportsBodyTracking) \ + +/// Calls your macro with the name of each member of XrBodyTrackerCreateInfoFB, in order. +#define XR_LIST_STRUCT_XrBodyTrackerCreateInfoFB(_) \ + _(type) \ + _(next) \ + _(bodyJointSet) \ + +/// Calls your macro with the name of each member of XrBodySkeletonJointFB, in order. +#define XR_LIST_STRUCT_XrBodySkeletonJointFB(_) \ + _(joint) \ + _(parentJoint) \ + _(pose) \ + +/// Calls your macro with the name of each member of XrBodySkeletonFB, in order. +#define XR_LIST_STRUCT_XrBodySkeletonFB(_) \ + _(type) \ + _(next) \ + _(jointCount) \ + _(joints) \ + +/// Calls your macro with the name of each member of XrBodyJointsLocateInfoFB, in order. +#define XR_LIST_STRUCT_XrBodyJointsLocateInfoFB(_) \ + _(type) \ + _(next) \ + _(baseSpace) \ + _(time) \ + +/// Calls your macro with the name of each member of XrBodyJointLocationsFB, in order. +#define XR_LIST_STRUCT_XrBodyJointLocationsFB(_) \ + _(type) \ + _(next) \ + _(isActive) \ + _(confidence) \ + _(jointCount) \ + _(jointLocations) \ + _(skeletonChangedCount) \ + _(time) \ + +/// Calls your macro with the name of each member of XrInteractionProfileDpadBindingEXT, in order. +#define XR_LIST_STRUCT_XrInteractionProfileDpadBindingEXT(_) \ + _(type) \ + _(next) \ + _(binding) \ + _(actionSet) \ + _(forceThreshold) \ + _(forceThresholdReleased) \ + _(centerRegion) \ + _(wedgeAngle) \ + _(isSticky) \ + _(onHaptic) \ + _(offHaptic) \ + +/// Calls your macro with the name of each member of XrInteractionProfileAnalogThresholdVALVE, in order. +#define XR_LIST_STRUCT_XrInteractionProfileAnalogThresholdVALVE(_) \ + _(type) \ + _(next) \ + _(action) \ + _(binding) \ + _(onThreshold) \ + _(offThreshold) \ + _(onHaptic) \ + _(offHaptic) \ + +/// Calls your macro with the name of each member of XrHandJointsMotionRangeInfoEXT, in order. +#define XR_LIST_STRUCT_XrHandJointsMotionRangeInfoEXT(_) \ + _(type) \ + _(next) \ + _(handJointsMotionRange) \ + +/// Calls your macro with the name of each member of XrUuidMSFT, in order. +#define XR_LIST_STRUCT_XrUuidMSFT(_) \ + _(bytes) \ + +/// Calls your macro with the name of each member of XrSceneObserverCreateInfoMSFT, in order. +#define XR_LIST_STRUCT_XrSceneObserverCreateInfoMSFT(_) \ + _(type) \ + _(next) \ + +/// Calls your macro with the name of each member of XrSceneCreateInfoMSFT, in order. +#define XR_LIST_STRUCT_XrSceneCreateInfoMSFT(_) \ + _(type) \ + _(next) \ + +/// Calls your macro with the name of each member of XrSceneSphereBoundMSFT, in order. +#define XR_LIST_STRUCT_XrSceneSphereBoundMSFT(_) \ + _(center) \ + _(radius) \ + +/// Calls your macro with the name of each member of XrSceneOrientedBoxBoundMSFT, in order. +#define XR_LIST_STRUCT_XrSceneOrientedBoxBoundMSFT(_) \ + _(pose) \ + _(extents) \ + +/// Calls your macro with the name of each member of XrSceneFrustumBoundMSFT, in order. +#define XR_LIST_STRUCT_XrSceneFrustumBoundMSFT(_) \ + _(pose) \ + _(fov) \ + _(farDistance) \ + +/// Calls your macro with the name of each member of XrSceneBoundsMSFT, in order. +#define XR_LIST_STRUCT_XrSceneBoundsMSFT(_) \ + _(space) \ + _(time) \ + _(sphereCount) \ + _(spheres) \ + _(boxCount) \ + _(boxes) \ + _(frustumCount) \ + _(frustums) \ + +/// Calls your macro with the name of each member of XrNewSceneComputeInfoMSFT, in order. +#define XR_LIST_STRUCT_XrNewSceneComputeInfoMSFT(_) \ + _(type) \ + _(next) \ + _(requestedFeatureCount) \ + _(requestedFeatures) \ + _(consistency) \ + _(bounds) \ + +/// Calls your macro with the name of each member of XrVisualMeshComputeLodInfoMSFT, in order. +#define XR_LIST_STRUCT_XrVisualMeshComputeLodInfoMSFT(_) \ + _(type) \ + _(next) \ + _(lod) \ + +/// Calls your macro with the name of each member of XrSceneComponentMSFT, in order. +#define XR_LIST_STRUCT_XrSceneComponentMSFT(_) \ + _(componentType) \ + _(id) \ + _(parentId) \ + _(updateTime) \ + +/// Calls your macro with the name of each member of XrSceneComponentsMSFT, in order. +#define XR_LIST_STRUCT_XrSceneComponentsMSFT(_) \ + _(type) \ + _(next) \ + _(componentCapacityInput) \ + _(componentCountOutput) \ + _(components) \ + +/// Calls your macro with the name of each member of XrSceneComponentsGetInfoMSFT, in order. +#define XR_LIST_STRUCT_XrSceneComponentsGetInfoMSFT(_) \ + _(type) \ + _(next) \ + _(componentType) \ + +/// Calls your macro with the name of each member of XrSceneComponentLocationMSFT, in order. +#define XR_LIST_STRUCT_XrSceneComponentLocationMSFT(_) \ + _(flags) \ + _(pose) \ + +/// Calls your macro with the name of each member of XrSceneComponentLocationsMSFT, in order. +#define XR_LIST_STRUCT_XrSceneComponentLocationsMSFT(_) \ + _(type) \ + _(next) \ + _(locationCount) \ + _(locations) \ + +/// Calls your macro with the name of each member of XrSceneComponentsLocateInfoMSFT, in order. +#define XR_LIST_STRUCT_XrSceneComponentsLocateInfoMSFT(_) \ + _(type) \ + _(next) \ + _(baseSpace) \ + _(time) \ + _(componentIdCount) \ + _(componentIds) \ + +/// Calls your macro with the name of each member of XrSceneObjectMSFT, in order. +#define XR_LIST_STRUCT_XrSceneObjectMSFT(_) \ + _(objectType) \ + +/// Calls your macro with the name of each member of XrSceneObjectsMSFT, in order. +#define XR_LIST_STRUCT_XrSceneObjectsMSFT(_) \ + _(type) \ + _(next) \ + _(sceneObjectCount) \ + _(sceneObjects) \ + +/// Calls your macro with the name of each member of XrSceneComponentParentFilterInfoMSFT, in order. +#define XR_LIST_STRUCT_XrSceneComponentParentFilterInfoMSFT(_) \ + _(type) \ + _(next) \ + _(parentId) \ + +/// Calls your macro with the name of each member of XrSceneObjectTypesFilterInfoMSFT, in order. +#define XR_LIST_STRUCT_XrSceneObjectTypesFilterInfoMSFT(_) \ + _(type) \ + _(next) \ + _(objectTypeCount) \ + _(objectTypes) \ + +/// Calls your macro with the name of each member of XrScenePlaneMSFT, in order. +#define XR_LIST_STRUCT_XrScenePlaneMSFT(_) \ + _(alignment) \ + _(size) \ + _(meshBufferId) \ + _(supportsIndicesUint16) \ + +/// Calls your macro with the name of each member of XrScenePlanesMSFT, in order. +#define XR_LIST_STRUCT_XrScenePlanesMSFT(_) \ + _(type) \ + _(next) \ + _(scenePlaneCount) \ + _(scenePlanes) \ + +/// Calls your macro with the name of each member of XrScenePlaneAlignmentFilterInfoMSFT, in order. +#define XR_LIST_STRUCT_XrScenePlaneAlignmentFilterInfoMSFT(_) \ + _(type) \ + _(next) \ + _(alignmentCount) \ + _(alignments) \ + +/// Calls your macro with the name of each member of XrSceneMeshMSFT, in order. +#define XR_LIST_STRUCT_XrSceneMeshMSFT(_) \ + _(meshBufferId) \ + _(supportsIndicesUint16) \ + +/// Calls your macro with the name of each member of XrSceneMeshesMSFT, in order. +#define XR_LIST_STRUCT_XrSceneMeshesMSFT(_) \ + _(type) \ + _(next) \ + _(sceneMeshCount) \ + _(sceneMeshes) \ + +/// Calls your macro with the name of each member of XrSceneMeshBuffersGetInfoMSFT, in order. +#define XR_LIST_STRUCT_XrSceneMeshBuffersGetInfoMSFT(_) \ + _(type) \ + _(next) \ + _(meshBufferId) \ + +/// Calls your macro with the name of each member of XrSceneMeshBuffersMSFT, in order. +#define XR_LIST_STRUCT_XrSceneMeshBuffersMSFT(_) \ + _(type) \ + _(next) \ + +/// Calls your macro with the name of each member of XrSceneMeshVertexBufferMSFT, in order. +#define XR_LIST_STRUCT_XrSceneMeshVertexBufferMSFT(_) \ + _(type) \ + _(next) \ + _(vertexCapacityInput) \ + _(vertexCountOutput) \ + _(vertices) \ + +/// Calls your macro with the name of each member of XrSceneMeshIndicesUint32MSFT, in order. +#define XR_LIST_STRUCT_XrSceneMeshIndicesUint32MSFT(_) \ + _(type) \ + _(next) \ + _(indexCapacityInput) \ + _(indexCountOutput) \ + _(indices) \ + +/// Calls your macro with the name of each member of XrSceneMeshIndicesUint16MSFT, in order. +#define XR_LIST_STRUCT_XrSceneMeshIndicesUint16MSFT(_) \ + _(type) \ + _(next) \ + _(indexCapacityInput) \ + _(indexCountOutput) \ + _(indices) \ + +/// Calls your macro with the name of each member of XrSerializedSceneFragmentDataGetInfoMSFT, in order. +#define XR_LIST_STRUCT_XrSerializedSceneFragmentDataGetInfoMSFT(_) \ + _(type) \ + _(next) \ + _(sceneFragmentId) \ + +/// Calls your macro with the name of each member of XrDeserializeSceneFragmentMSFT, in order. +#define XR_LIST_STRUCT_XrDeserializeSceneFragmentMSFT(_) \ + _(bufferSize) \ + _(buffer) \ + +/// Calls your macro with the name of each member of XrSceneDeserializeInfoMSFT, in order. +#define XR_LIST_STRUCT_XrSceneDeserializeInfoMSFT(_) \ + _(type) \ + _(next) \ + _(fragmentCount) \ + _(fragments) \ + +/// Calls your macro with the name of each member of XrEventDataDisplayRefreshRateChangedFB, in order. +#define XR_LIST_STRUCT_XrEventDataDisplayRefreshRateChangedFB(_) \ + _(type) \ + _(next) \ + _(fromDisplayRefreshRate) \ + _(toDisplayRefreshRate) \ + +/// Calls your macro with the name of each member of XrViveTrackerPathsHTCX, in order. +#define XR_LIST_STRUCT_XrViveTrackerPathsHTCX(_) \ + _(type) \ + _(next) \ + _(persistentPath) \ + _(rolePath) \ + +/// Calls your macro with the name of each member of XrEventDataViveTrackerConnectedHTCX, in order. +#define XR_LIST_STRUCT_XrEventDataViveTrackerConnectedHTCX(_) \ + _(type) \ + _(next) \ + _(paths) \ + +/// Calls your macro with the name of each member of XrSystemFacialTrackingPropertiesHTC, in order. +#define XR_LIST_STRUCT_XrSystemFacialTrackingPropertiesHTC(_) \ + _(type) \ + _(next) \ + _(supportEyeFacialTracking) \ + _(supportLipFacialTracking) \ + +/// Calls your macro with the name of each member of XrFacialExpressionsHTC, in order. +#define XR_LIST_STRUCT_XrFacialExpressionsHTC(_) \ + _(type) \ + _(next) \ + _(isActive) \ + _(sampleTime) \ + _(expressionCount) \ + _(expressionWeightings) \ + +/// Calls your macro with the name of each member of XrFacialTrackerCreateInfoHTC, in order. +#define XR_LIST_STRUCT_XrFacialTrackerCreateInfoHTC(_) \ + _(type) \ + _(next) \ + _(facialTrackingType) \ + +/// Calls your macro with the name of each member of XrSystemColorSpacePropertiesFB, in order. +#define XR_LIST_STRUCT_XrSystemColorSpacePropertiesFB(_) \ + _(type) \ + _(next) \ + _(colorSpace) \ + +/// Calls your macro with the name of each member of XrVector4sFB, in order. +#define XR_LIST_STRUCT_XrVector4sFB(_) \ + _(x) \ + _(y) \ + _(z) \ + _(w) \ + +/// Calls your macro with the name of each member of XrHandTrackingMeshFB, in order. +#define XR_LIST_STRUCT_XrHandTrackingMeshFB(_) \ + _(type) \ + _(next) \ + _(jointCapacityInput) \ + _(jointCountOutput) \ + _(jointBindPoses) \ + _(jointRadii) \ + _(jointParents) \ + _(vertexCapacityInput) \ + _(vertexCountOutput) \ + _(vertexPositions) \ + _(vertexNormals) \ + _(vertexUVs) \ + _(vertexBlendIndices) \ + _(vertexBlendWeights) \ + _(indexCapacityInput) \ + _(indexCountOutput) \ + _(indices) \ + +/// Calls your macro with the name of each member of XrHandTrackingScaleFB, in order. +#define XR_LIST_STRUCT_XrHandTrackingScaleFB(_) \ + _(type) \ + _(next) \ + _(sensorOutput) \ + _(currentOutput) \ + _(overrideHandScale) \ + _(overrideValueInput) \ + +/// Calls your macro with the name of each member of XrHandTrackingAimStateFB, in order. +#define XR_LIST_STRUCT_XrHandTrackingAimStateFB(_) \ + _(type) \ + _(next) \ + _(status) \ + _(aimPose) \ + _(pinchStrengthIndex) \ + _(pinchStrengthMiddle) \ + _(pinchStrengthRing) \ + _(pinchStrengthLittle) \ + +/// Calls your macro with the name of each member of XrHandCapsuleFB, in order. +#define XR_LIST_STRUCT_XrHandCapsuleFB(_) \ + _(points) \ + _(radius) \ + _(joint) \ + +/// Calls your macro with the name of each member of XrHandTrackingCapsulesStateFB, in order. +#define XR_LIST_STRUCT_XrHandTrackingCapsulesStateFB(_) \ + _(type) \ + _(next) \ + _(capsules) \ + +/// Calls your macro with the name of each member of XrSystemSpatialEntityPropertiesFB, in order. +#define XR_LIST_STRUCT_XrSystemSpatialEntityPropertiesFB(_) \ + _(type) \ + _(next) \ + _(supportsSpatialEntity) \ + +/// Calls your macro with the name of each member of XrSpatialAnchorCreateInfoFB, in order. +#define XR_LIST_STRUCT_XrSpatialAnchorCreateInfoFB(_) \ + _(type) \ + _(next) \ + _(space) \ + _(poseInSpace) \ + _(time) \ + +/// Calls your macro with the name of each member of XrSpaceComponentStatusSetInfoFB, in order. +#define XR_LIST_STRUCT_XrSpaceComponentStatusSetInfoFB(_) \ + _(type) \ + _(next) \ + _(componentType) \ + _(enabled) \ + _(timeout) \ + +/// Calls your macro with the name of each member of XrSpaceComponentStatusFB, in order. +#define XR_LIST_STRUCT_XrSpaceComponentStatusFB(_) \ + _(type) \ + _(next) \ + _(enabled) \ + _(changePending) \ + +/// Calls your macro with the name of each member of XrUuidEXT, in order. +#define XR_LIST_STRUCT_XrUuidEXT(_) \ + _(data) \ + +/// Calls your macro with the name of each member of XrEventDataSpatialAnchorCreateCompleteFB, in order. +#define XR_LIST_STRUCT_XrEventDataSpatialAnchorCreateCompleteFB(_) \ + _(type) \ + _(next) \ + _(requestId) \ + _(result) \ + _(space) \ + _(uuid) \ + +/// Calls your macro with the name of each member of XrEventDataSpaceSetStatusCompleteFB, in order. +#define XR_LIST_STRUCT_XrEventDataSpaceSetStatusCompleteFB(_) \ + _(type) \ + _(next) \ + _(requestId) \ + _(result) \ + _(space) \ + _(uuid) \ + _(componentType) \ + _(enabled) \ + +/// Calls your macro with the name of each member of XrFoveationProfileCreateInfoFB, in order. +#define XR_LIST_STRUCT_XrFoveationProfileCreateInfoFB(_) \ + _(type) \ + _(next) \ + +/// Calls your macro with the name of each member of XrSwapchainCreateInfoFoveationFB, in order. +#define XR_LIST_STRUCT_XrSwapchainCreateInfoFoveationFB(_) \ + _(type) \ + _(next) \ + _(flags) \ + +/// Calls your macro with the name of each member of XrSwapchainStateFoveationFB, in order. +#define XR_LIST_STRUCT_XrSwapchainStateFoveationFB(_) \ + _(type) \ + _(next) \ + _(flags) \ + _(profile) \ + +/// Calls your macro with the name of each member of XrFoveationLevelProfileCreateInfoFB, in order. +#define XR_LIST_STRUCT_XrFoveationLevelProfileCreateInfoFB(_) \ + _(type) \ + _(next) \ + _(level) \ + _(verticalOffset) \ + _(dynamic) \ + +/// Calls your macro with the name of each member of XrSystemKeyboardTrackingPropertiesFB, in order. +#define XR_LIST_STRUCT_XrSystemKeyboardTrackingPropertiesFB(_) \ + _(type) \ + _(next) \ + _(supportsKeyboardTracking) \ + +/// Calls your macro with the name of each member of XrKeyboardTrackingDescriptionFB, in order. +#define XR_LIST_STRUCT_XrKeyboardTrackingDescriptionFB(_) \ + _(trackedKeyboardId) \ + _(size) \ + _(flags) \ + _(name) \ + +/// Calls your macro with the name of each member of XrKeyboardSpaceCreateInfoFB, in order. +#define XR_LIST_STRUCT_XrKeyboardSpaceCreateInfoFB(_) \ + _(type) \ + _(next) \ + _(trackedKeyboardId) \ + +/// Calls your macro with the name of each member of XrKeyboardTrackingQueryFB, in order. +#define XR_LIST_STRUCT_XrKeyboardTrackingQueryFB(_) \ + _(type) \ + _(next) \ + _(flags) \ + +/// Calls your macro with the name of each member of XrTriangleMeshCreateInfoFB, in order. +#define XR_LIST_STRUCT_XrTriangleMeshCreateInfoFB(_) \ + _(type) \ + _(next) \ + _(flags) \ + _(windingOrder) \ + _(vertexCount) \ + _(vertexBuffer) \ + _(triangleCount) \ + _(indexBuffer) \ + +/// Calls your macro with the name of each member of XrSystemPassthroughPropertiesFB, in order. +#define XR_LIST_STRUCT_XrSystemPassthroughPropertiesFB(_) \ + _(type) \ + _(next) \ + _(supportsPassthrough) \ + +/// Calls your macro with the name of each member of XrSystemPassthroughProperties2FB, in order. +#define XR_LIST_STRUCT_XrSystemPassthroughProperties2FB(_) \ + _(type) \ + _(next) \ + _(capabilities) \ + +/// Calls your macro with the name of each member of XrPassthroughCreateInfoFB, in order. +#define XR_LIST_STRUCT_XrPassthroughCreateInfoFB(_) \ + _(type) \ + _(next) \ + _(flags) \ + +/// Calls your macro with the name of each member of XrPassthroughLayerCreateInfoFB, in order. +#define XR_LIST_STRUCT_XrPassthroughLayerCreateInfoFB(_) \ + _(type) \ + _(next) \ + _(passthrough) \ + _(flags) \ + _(purpose) \ + +/// Calls your macro with the name of each member of XrCompositionLayerPassthroughFB, in order. +#define XR_LIST_STRUCT_XrCompositionLayerPassthroughFB(_) \ + _(type) \ + _(next) \ + _(flags) \ + _(space) \ + _(layerHandle) \ + +/// Calls your macro with the name of each member of XrGeometryInstanceCreateInfoFB, in order. +#define XR_LIST_STRUCT_XrGeometryInstanceCreateInfoFB(_) \ + _(type) \ + _(next) \ + _(layer) \ + _(mesh) \ + _(baseSpace) \ + _(pose) \ + _(scale) \ + +/// Calls your macro with the name of each member of XrGeometryInstanceTransformFB, in order. +#define XR_LIST_STRUCT_XrGeometryInstanceTransformFB(_) \ + _(type) \ + _(next) \ + _(baseSpace) \ + _(time) \ + _(pose) \ + _(scale) \ + +/// Calls your macro with the name of each member of XrPassthroughStyleFB, in order. +#define XR_LIST_STRUCT_XrPassthroughStyleFB(_) \ + _(type) \ + _(next) \ + _(textureOpacityFactor) \ + _(edgeColor) \ + +/// Calls your macro with the name of each member of XrPassthroughColorMapMonoToRgbaFB, in order. +#define XR_LIST_STRUCT_XrPassthroughColorMapMonoToRgbaFB(_) \ + _(type) \ + _(next) \ + _(textureColorMap) \ + +/// Calls your macro with the name of each member of XrPassthroughColorMapMonoToMonoFB, in order. +#define XR_LIST_STRUCT_XrPassthroughColorMapMonoToMonoFB(_) \ + _(type) \ + _(next) \ + _(textureColorMap) \ + +/// Calls your macro with the name of each member of XrPassthroughBrightnessContrastSaturationFB, in order. +#define XR_LIST_STRUCT_XrPassthroughBrightnessContrastSaturationFB(_) \ + _(type) \ + _(next) \ + _(brightness) \ + _(contrast) \ + _(saturation) \ + +/// Calls your macro with the name of each member of XrEventDataPassthroughStateChangedFB, in order. +#define XR_LIST_STRUCT_XrEventDataPassthroughStateChangedFB(_) \ + _(type) \ + _(next) \ + _(flags) \ + +/// Calls your macro with the name of each member of XrRenderModelPathInfoFB, in order. +#define XR_LIST_STRUCT_XrRenderModelPathInfoFB(_) \ + _(type) \ + _(next) \ + _(path) \ + +/// Calls your macro with the name of each member of XrRenderModelPropertiesFB, in order. +#define XR_LIST_STRUCT_XrRenderModelPropertiesFB(_) \ + _(type) \ + _(next) \ + _(vendorId) \ + _(modelName) \ + _(modelKey) \ + _(modelVersion) \ + _(flags) \ + +/// Calls your macro with the name of each member of XrRenderModelBufferFB, in order. +#define XR_LIST_STRUCT_XrRenderModelBufferFB(_) \ + _(type) \ + _(next) \ + _(bufferCapacityInput) \ + _(bufferCountOutput) \ + _(buffer) \ + +/// Calls your macro with the name of each member of XrRenderModelLoadInfoFB, in order. +#define XR_LIST_STRUCT_XrRenderModelLoadInfoFB(_) \ + _(type) \ + _(next) \ + _(modelKey) \ + +/// Calls your macro with the name of each member of XrSystemRenderModelPropertiesFB, in order. +#define XR_LIST_STRUCT_XrSystemRenderModelPropertiesFB(_) \ + _(type) \ + _(next) \ + _(supportsRenderModelLoading) \ + +/// Calls your macro with the name of each member of XrRenderModelCapabilitiesRequestFB, in order. +#define XR_LIST_STRUCT_XrRenderModelCapabilitiesRequestFB(_) \ + _(type) \ + _(next) \ + _(flags) \ + +/// Calls your macro with the name of each member of XrViewLocateFoveatedRenderingVARJO, in order. +#define XR_LIST_STRUCT_XrViewLocateFoveatedRenderingVARJO(_) \ + _(type) \ + _(next) \ + _(foveatedRenderingActive) \ + +/// Calls your macro with the name of each member of XrFoveatedViewConfigurationViewVARJO, in order. +#define XR_LIST_STRUCT_XrFoveatedViewConfigurationViewVARJO(_) \ + _(type) \ + _(next) \ + _(foveatedRenderingActive) \ + +/// Calls your macro with the name of each member of XrSystemFoveatedRenderingPropertiesVARJO, in order. +#define XR_LIST_STRUCT_XrSystemFoveatedRenderingPropertiesVARJO(_) \ + _(type) \ + _(next) \ + _(supportsFoveatedRendering) \ + +/// Calls your macro with the name of each member of XrCompositionLayerDepthTestVARJO, in order. +#define XR_LIST_STRUCT_XrCompositionLayerDepthTestVARJO(_) \ + _(type) \ + _(next) \ + _(depthTestRangeNearZ) \ + _(depthTestRangeFarZ) \ + +/// Calls your macro with the name of each member of XrSystemMarkerTrackingPropertiesVARJO, in order. +#define XR_LIST_STRUCT_XrSystemMarkerTrackingPropertiesVARJO(_) \ + _(type) \ + _(next) \ + _(supportsMarkerTracking) \ + +/// Calls your macro with the name of each member of XrEventDataMarkerTrackingUpdateVARJO, in order. +#define XR_LIST_STRUCT_XrEventDataMarkerTrackingUpdateVARJO(_) \ + _(type) \ + _(next) \ + _(markerId) \ + _(isActive) \ + _(isPredicted) \ + _(time) \ + +/// Calls your macro with the name of each member of XrMarkerSpaceCreateInfoVARJO, in order. +#define XR_LIST_STRUCT_XrMarkerSpaceCreateInfoVARJO(_) \ + _(type) \ + _(next) \ + _(markerId) \ + _(poseInMarkerSpace) \ + +/// Calls your macro with the name of each member of XrFrameEndInfoML, in order. +#define XR_LIST_STRUCT_XrFrameEndInfoML(_) \ + _(type) \ + _(next) \ + _(focusDistance) \ + _(flags) \ + +/// Calls your macro with the name of each member of XrGlobalDimmerFrameEndInfoML, in order. +#define XR_LIST_STRUCT_XrGlobalDimmerFrameEndInfoML(_) \ + _(type) \ + _(next) \ + _(dimmerValue) \ + _(flags) \ + +/// Calls your macro with the name of each member of XrCoordinateSpaceCreateInfoML, in order. +#define XR_LIST_STRUCT_XrCoordinateSpaceCreateInfoML(_) \ + _(type) \ + _(next) \ + _(cfuid) \ + _(poseInCoordinateSpace) \ + +/// Calls your macro with the name of each member of XrSpatialAnchorPersistenceNameMSFT, in order. +#define XR_LIST_STRUCT_XrSpatialAnchorPersistenceNameMSFT(_) \ + _(name) \ + +/// Calls your macro with the name of each member of XrSpatialAnchorPersistenceInfoMSFT, in order. +#define XR_LIST_STRUCT_XrSpatialAnchorPersistenceInfoMSFT(_) \ + _(type) \ + _(next) \ + _(spatialAnchorPersistenceName) \ + _(spatialAnchor) \ + +/// Calls your macro with the name of each member of XrSpatialAnchorFromPersistedAnchorCreateInfoMSFT, in order. +#define XR_LIST_STRUCT_XrSpatialAnchorFromPersistedAnchorCreateInfoMSFT(_) \ + _(type) \ + _(next) \ + _(spatialAnchorStore) \ + _(spatialAnchorPersistenceName) \ + +/// Calls your macro with the name of each member of XrSpaceQueryInfoBaseHeaderFB, in order. +#define XR_LIST_STRUCT_XrSpaceQueryInfoBaseHeaderFB(_) \ + _(type) \ + _(next) \ + +/// Calls your macro with the name of each member of XrSpaceFilterInfoBaseHeaderFB, in order. +#define XR_LIST_STRUCT_XrSpaceFilterInfoBaseHeaderFB(_) \ + _(type) \ + _(next) \ + +/// Calls your macro with the name of each member of XrSpaceQueryInfoFB, in order. +#define XR_LIST_STRUCT_XrSpaceQueryInfoFB(_) \ + _(type) \ + _(next) \ + _(queryAction) \ + _(maxResultCount) \ + _(timeout) \ + _(filter) \ + _(excludeFilter) \ + +/// Calls your macro with the name of each member of XrSpaceStorageLocationFilterInfoFB, in order. +#define XR_LIST_STRUCT_XrSpaceStorageLocationFilterInfoFB(_) \ + _(type) \ + _(next) \ + _(location) \ + +/// Calls your macro with the name of each member of XrSpaceUuidFilterInfoFB, in order. +#define XR_LIST_STRUCT_XrSpaceUuidFilterInfoFB(_) \ + _(type) \ + _(next) \ + _(uuidCount) \ + _(uuids) \ + +/// Calls your macro with the name of each member of XrSpaceComponentFilterInfoFB, in order. +#define XR_LIST_STRUCT_XrSpaceComponentFilterInfoFB(_) \ + _(type) \ + _(next) \ + _(componentType) \ + +/// Calls your macro with the name of each member of XrSpaceQueryResultFB, in order. +#define XR_LIST_STRUCT_XrSpaceQueryResultFB(_) \ + _(space) \ + _(uuid) \ + +/// Calls your macro with the name of each member of XrSpaceQueryResultsFB, in order. +#define XR_LIST_STRUCT_XrSpaceQueryResultsFB(_) \ + _(type) \ + _(next) \ + _(resultCapacityInput) \ + _(resultCountOutput) \ + _(results) \ + +/// Calls your macro with the name of each member of XrEventDataSpaceQueryResultsAvailableFB, in order. +#define XR_LIST_STRUCT_XrEventDataSpaceQueryResultsAvailableFB(_) \ + _(type) \ + _(next) \ + _(requestId) \ + +/// Calls your macro with the name of each member of XrEventDataSpaceQueryCompleteFB, in order. +#define XR_LIST_STRUCT_XrEventDataSpaceQueryCompleteFB(_) \ + _(type) \ + _(next) \ + _(requestId) \ + _(result) \ + +/// Calls your macro with the name of each member of XrSpaceSaveInfoFB, in order. +#define XR_LIST_STRUCT_XrSpaceSaveInfoFB(_) \ + _(type) \ + _(next) \ + _(space) \ + _(location) \ + _(persistenceMode) \ + +/// Calls your macro with the name of each member of XrSpaceEraseInfoFB, in order. +#define XR_LIST_STRUCT_XrSpaceEraseInfoFB(_) \ + _(type) \ + _(next) \ + _(space) \ + _(location) \ + +/// Calls your macro with the name of each member of XrEventDataSpaceSaveCompleteFB, in order. +#define XR_LIST_STRUCT_XrEventDataSpaceSaveCompleteFB(_) \ + _(type) \ + _(next) \ + _(requestId) \ + _(result) \ + _(space) \ + _(uuid) \ + _(location) \ + +/// Calls your macro with the name of each member of XrEventDataSpaceEraseCompleteFB, in order. +#define XR_LIST_STRUCT_XrEventDataSpaceEraseCompleteFB(_) \ + _(type) \ + _(next) \ + _(requestId) \ + _(result) \ + _(space) \ + _(uuid) \ + _(location) \ + +/// Calls your macro with the name of each member of XrSwapchainImageFoveationVulkanFB, in order. +#define XR_LIST_STRUCT_XrSwapchainImageFoveationVulkanFB(_) \ + _(type) \ + _(next) \ + _(image) \ + _(width) \ + _(height) \ + +/// Calls your macro with the name of each member of XrSwapchainStateAndroidSurfaceDimensionsFB, in order. +#define XR_LIST_STRUCT_XrSwapchainStateAndroidSurfaceDimensionsFB(_) \ + _(type) \ + _(next) \ + _(width) \ + _(height) \ + +/// Calls your macro with the name of each member of XrSwapchainStateSamplerOpenGLESFB, in order. +#define XR_LIST_STRUCT_XrSwapchainStateSamplerOpenGLESFB(_) \ + _(type) \ + _(next) \ + _(minFilter) \ + _(magFilter) \ + _(wrapModeS) \ + _(wrapModeT) \ + _(swizzleRed) \ + _(swizzleGreen) \ + _(swizzleBlue) \ + _(swizzleAlpha) \ + _(maxAnisotropy) \ + _(borderColor) \ + +/// Calls your macro with the name of each member of XrSwapchainStateSamplerVulkanFB, in order. +#define XR_LIST_STRUCT_XrSwapchainStateSamplerVulkanFB(_) \ + _(type) \ + _(next) \ + _(minFilter) \ + _(magFilter) \ + _(mipmapMode) \ + _(wrapModeS) \ + _(wrapModeT) \ + _(swizzleRed) \ + _(swizzleGreen) \ + _(swizzleBlue) \ + _(swizzleAlpha) \ + _(maxAnisotropy) \ + _(borderColor) \ + +/// Calls your macro with the name of each member of XrSpaceShareInfoFB, in order. +#define XR_LIST_STRUCT_XrSpaceShareInfoFB(_) \ + _(type) \ + _(next) \ + _(spaceCount) \ + _(spaces) \ + _(userCount) \ + _(users) \ + +/// Calls your macro with the name of each member of XrEventDataSpaceShareCompleteFB, in order. +#define XR_LIST_STRUCT_XrEventDataSpaceShareCompleteFB(_) \ + _(type) \ + _(next) \ + _(requestId) \ + _(result) \ + +/// Calls your macro with the name of each member of XrCompositionLayerSpaceWarpInfoFB, in order. +#define XR_LIST_STRUCT_XrCompositionLayerSpaceWarpInfoFB(_) \ + _(type) \ + _(next) \ + _(layerFlags) \ + _(motionVectorSubImage) \ + _(appSpaceDeltaPose) \ + _(depthSubImage) \ + _(minDepth) \ + _(maxDepth) \ + _(nearZ) \ + _(farZ) \ + +/// Calls your macro with the name of each member of XrSystemSpaceWarpPropertiesFB, in order. +#define XR_LIST_STRUCT_XrSystemSpaceWarpPropertiesFB(_) \ + _(type) \ + _(next) \ + _(recommendedMotionVectorImageRectWidth) \ + _(recommendedMotionVectorImageRectHeight) \ + +/// Calls your macro with the name of each member of XrHapticAmplitudeEnvelopeVibrationFB, in order. +#define XR_LIST_STRUCT_XrHapticAmplitudeEnvelopeVibrationFB(_) \ + _(type) \ + _(next) \ + _(duration) \ + _(amplitudeCount) \ + _(amplitudes) \ + +/// Calls your macro with the name of each member of XrExtent3DfFB, in order. +#define XR_LIST_STRUCT_XrExtent3DfFB(_) \ + _(width) \ + _(height) \ + _(depth) \ + +/// Calls your macro with the name of each member of XrOffset3DfFB, in order. +#define XR_LIST_STRUCT_XrOffset3DfFB(_) \ + _(x) \ + _(y) \ + _(z) \ + +/// Calls your macro with the name of each member of XrRect3DfFB, in order. +#define XR_LIST_STRUCT_XrRect3DfFB(_) \ + _(offset) \ + _(extent) \ + +/// Calls your macro with the name of each member of XrSemanticLabelsFB, in order. +#define XR_LIST_STRUCT_XrSemanticLabelsFB(_) \ + _(type) \ + _(next) \ + _(bufferCapacityInput) \ + _(bufferCountOutput) \ + _(buffer) \ + +/// Calls your macro with the name of each member of XrRoomLayoutFB, in order. +#define XR_LIST_STRUCT_XrRoomLayoutFB(_) \ + _(type) \ + _(next) \ + _(floorUuid) \ + _(ceilingUuid) \ + _(wallUuidCapacityInput) \ + _(wallUuidCountOutput) \ + _(wallUuids) \ + +/// Calls your macro with the name of each member of XrBoundary2DFB, in order. +#define XR_LIST_STRUCT_XrBoundary2DFB(_) \ + _(type) \ + _(next) \ + _(vertexCapacityInput) \ + _(vertexCountOutput) \ + _(vertices) \ + +/// Calls your macro with the name of each member of XrSemanticLabelsSupportInfoFB, in order. +#define XR_LIST_STRUCT_XrSemanticLabelsSupportInfoFB(_) \ + _(type) \ + _(next) \ + _(flags) \ + _(recognizedLabels) \ + +/// Calls your macro with the name of each member of XrDigitalLensControlALMALENCE, in order. +#define XR_LIST_STRUCT_XrDigitalLensControlALMALENCE(_) \ + _(type) \ + _(next) \ + _(flags) \ + +/// Calls your macro with the name of each member of XrEventDataSceneCaptureCompleteFB, in order. +#define XR_LIST_STRUCT_XrEventDataSceneCaptureCompleteFB(_) \ + _(type) \ + _(next) \ + _(requestId) \ + _(result) \ + +/// Calls your macro with the name of each member of XrSceneCaptureRequestInfoFB, in order. +#define XR_LIST_STRUCT_XrSceneCaptureRequestInfoFB(_) \ + _(type) \ + _(next) \ + _(requestByteCount) \ + _(request) \ + +/// Calls your macro with the name of each member of XrSpaceContainerFB, in order. +#define XR_LIST_STRUCT_XrSpaceContainerFB(_) \ + _(type) \ + _(next) \ + _(uuidCapacityInput) \ + _(uuidCountOutput) \ + _(uuids) \ + +/// Calls your macro with the name of each member of XrFoveationEyeTrackedProfileCreateInfoMETA, in order. +#define XR_LIST_STRUCT_XrFoveationEyeTrackedProfileCreateInfoMETA(_) \ + _(type) \ + _(next) \ + _(flags) \ + +/// Calls your macro with the name of each member of XrFoveationEyeTrackedStateMETA, in order. +#define XR_LIST_STRUCT_XrFoveationEyeTrackedStateMETA(_) \ + _(type) \ + _(next) \ + _(foveationCenter) \ + _(flags) \ + +/// Calls your macro with the name of each member of XrSystemFoveationEyeTrackedPropertiesMETA, in order. +#define XR_LIST_STRUCT_XrSystemFoveationEyeTrackedPropertiesMETA(_) \ + _(type) \ + _(next) \ + _(supportsFoveationEyeTracked) \ + +/// Calls your macro with the name of each member of XrSystemFaceTrackingPropertiesFB, in order. +#define XR_LIST_STRUCT_XrSystemFaceTrackingPropertiesFB(_) \ + _(type) \ + _(next) \ + _(supportsFaceTracking) \ + +/// Calls your macro with the name of each member of XrFaceTrackerCreateInfoFB, in order. +#define XR_LIST_STRUCT_XrFaceTrackerCreateInfoFB(_) \ + _(type) \ + _(next) \ + _(faceExpressionSet) \ + +/// Calls your macro with the name of each member of XrFaceExpressionInfoFB, in order. +#define XR_LIST_STRUCT_XrFaceExpressionInfoFB(_) \ + _(type) \ + _(next) \ + _(time) \ + +/// Calls your macro with the name of each member of XrFaceExpressionStatusFB, in order. +#define XR_LIST_STRUCT_XrFaceExpressionStatusFB(_) \ + _(isValid) \ + _(isEyeFollowingBlendshapesValid) \ + +/// Calls your macro with the name of each member of XrFaceExpressionWeightsFB, in order. +#define XR_LIST_STRUCT_XrFaceExpressionWeightsFB(_) \ + _(type) \ + _(next) \ + _(weightCount) \ + _(weights) \ + _(confidenceCount) \ + _(confidences) \ + _(status) \ + _(time) \ + +/// Calls your macro with the name of each member of XrEyeGazeFB, in order. +#define XR_LIST_STRUCT_XrEyeGazeFB(_) \ + _(isValid) \ + _(gazePose) \ + _(gazeConfidence) \ + +/// Calls your macro with the name of each member of XrEyeTrackerCreateInfoFB, in order. +#define XR_LIST_STRUCT_XrEyeTrackerCreateInfoFB(_) \ + _(type) \ + _(next) \ + +/// Calls your macro with the name of each member of XrEyeGazesInfoFB, in order. +#define XR_LIST_STRUCT_XrEyeGazesInfoFB(_) \ + _(type) \ + _(next) \ + _(baseSpace) \ + _(time) \ + +/// Calls your macro with the name of each member of XrSystemEyeTrackingPropertiesFB, in order. +#define XR_LIST_STRUCT_XrSystemEyeTrackingPropertiesFB(_) \ + _(type) \ + _(next) \ + _(supportsEyeTracking) \ + +/// Calls your macro with the name of each member of XrEyeGazesFB, in order. +#define XR_LIST_STRUCT_XrEyeGazesFB(_) \ + _(type) \ + _(next) \ + _(gaze) \ + _(time) \ + +/// Calls your macro with the name of each member of XrPassthroughKeyboardHandsIntensityFB, in order. +#define XR_LIST_STRUCT_XrPassthroughKeyboardHandsIntensityFB(_) \ + _(type) \ + _(next) \ + _(leftHandIntensity) \ + _(rightHandIntensity) \ + +/// Calls your macro with the name of each member of XrCompositionLayerSettingsFB, in order. +#define XR_LIST_STRUCT_XrCompositionLayerSettingsFB(_) \ + _(type) \ + _(next) \ + _(layerFlags) \ + +/// Calls your macro with the name of each member of XrHapticPcmVibrationFB, in order. +#define XR_LIST_STRUCT_XrHapticPcmVibrationFB(_) \ + _(type) \ + _(next) \ + _(bufferSize) \ + _(buffer) \ + _(sampleRate) \ + _(append) \ + _(samplesConsumed) \ + +/// Calls your macro with the name of each member of XrDevicePcmSampleRateStateFB, in order. +#define XR_LIST_STRUCT_XrDevicePcmSampleRateStateFB(_) \ + _(type) \ + _(next) \ + _(sampleRate) \ + +/// Calls your macro with the name of each member of XrCompositionLayerDepthTestFB, in order. +#define XR_LIST_STRUCT_XrCompositionLayerDepthTestFB(_) \ + _(type) \ + _(next) \ + _(depthMask) \ + _(compareOp) \ + +/// Calls your macro with the name of each member of XrLocalDimmingFrameEndInfoMETA, in order. +#define XR_LIST_STRUCT_XrLocalDimmingFrameEndInfoMETA(_) \ + _(type) \ + _(next) \ + _(localDimmingMode) \ + +/// Calls your macro with the name of each member of XrPassthroughPreferencesMETA, in order. +#define XR_LIST_STRUCT_XrPassthroughPreferencesMETA(_) \ + _(type) \ + _(next) \ + _(flags) \ + +/// Calls your macro with the name of each member of XrSystemVirtualKeyboardPropertiesMETA, in order. +#define XR_LIST_STRUCT_XrSystemVirtualKeyboardPropertiesMETA(_) \ + _(type) \ + _(next) \ + _(supportsVirtualKeyboard) \ + +/// Calls your macro with the name of each member of XrVirtualKeyboardCreateInfoMETA, in order. +#define XR_LIST_STRUCT_XrVirtualKeyboardCreateInfoMETA(_) \ + _(type) \ + _(next) \ + +/// Calls your macro with the name of each member of XrVirtualKeyboardSpaceCreateInfoMETA, in order. +#define XR_LIST_STRUCT_XrVirtualKeyboardSpaceCreateInfoMETA(_) \ + _(type) \ + _(next) \ + _(locationType) \ + _(space) \ + _(poseInSpace) \ + +/// Calls your macro with the name of each member of XrVirtualKeyboardLocationInfoMETA, in order. +#define XR_LIST_STRUCT_XrVirtualKeyboardLocationInfoMETA(_) \ + _(type) \ + _(next) \ + _(locationType) \ + _(space) \ + _(poseInSpace) \ + _(scale) \ + +/// Calls your macro with the name of each member of XrVirtualKeyboardModelVisibilitySetInfoMETA, in order. +#define XR_LIST_STRUCT_XrVirtualKeyboardModelVisibilitySetInfoMETA(_) \ + _(type) \ + _(next) \ + _(visible) \ + +/// Calls your macro with the name of each member of XrVirtualKeyboardAnimationStateMETA, in order. +#define XR_LIST_STRUCT_XrVirtualKeyboardAnimationStateMETA(_) \ + _(type) \ + _(next) \ + _(animationIndex) \ + _(fraction) \ + +/// Calls your macro with the name of each member of XrVirtualKeyboardModelAnimationStatesMETA, in order. +#define XR_LIST_STRUCT_XrVirtualKeyboardModelAnimationStatesMETA(_) \ + _(type) \ + _(next) \ + _(stateCapacityInput) \ + _(stateCountOutput) \ + _(states) \ + +/// Calls your macro with the name of each member of XrVirtualKeyboardTextureDataMETA, in order. +#define XR_LIST_STRUCT_XrVirtualKeyboardTextureDataMETA(_) \ + _(type) \ + _(next) \ + _(textureWidth) \ + _(textureHeight) \ + _(bufferCapacityInput) \ + _(bufferCountOutput) \ + _(buffer) \ + +/// Calls your macro with the name of each member of XrVirtualKeyboardInputInfoMETA, in order. +#define XR_LIST_STRUCT_XrVirtualKeyboardInputInfoMETA(_) \ + _(type) \ + _(next) \ + _(inputSource) \ + _(inputSpace) \ + _(inputPoseInSpace) \ + _(inputState) \ + +/// Calls your macro with the name of each member of XrVirtualKeyboardTextContextChangeInfoMETA, in order. +#define XR_LIST_STRUCT_XrVirtualKeyboardTextContextChangeInfoMETA(_) \ + _(type) \ + _(next) \ + _(textContext) \ + +/// Calls your macro with the name of each member of XrEventDataVirtualKeyboardCommitTextMETA, in order. +#define XR_LIST_STRUCT_XrEventDataVirtualKeyboardCommitTextMETA(_) \ + _(type) \ + _(next) \ + _(keyboard) \ + _(text) \ + +/// Calls your macro with the name of each member of XrEventDataVirtualKeyboardBackspaceMETA, in order. +#define XR_LIST_STRUCT_XrEventDataVirtualKeyboardBackspaceMETA(_) \ + _(type) \ + _(next) \ + _(keyboard) \ + +/// Calls your macro with the name of each member of XrEventDataVirtualKeyboardEnterMETA, in order. +#define XR_LIST_STRUCT_XrEventDataVirtualKeyboardEnterMETA(_) \ + _(type) \ + _(next) \ + _(keyboard) \ + +/// Calls your macro with the name of each member of XrEventDataVirtualKeyboardShownMETA, in order. +#define XR_LIST_STRUCT_XrEventDataVirtualKeyboardShownMETA(_) \ + _(type) \ + _(next) \ + _(keyboard) \ + +/// Calls your macro with the name of each member of XrEventDataVirtualKeyboardHiddenMETA, in order. +#define XR_LIST_STRUCT_XrEventDataVirtualKeyboardHiddenMETA(_) \ + _(type) \ + _(next) \ + _(keyboard) \ + +/// Calls your macro with the name of each member of XrExternalCameraIntrinsicsOCULUS, in order. +#define XR_LIST_STRUCT_XrExternalCameraIntrinsicsOCULUS(_) \ + _(lastChangeTime) \ + _(fov) \ + _(virtualNearPlaneDistance) \ + _(virtualFarPlaneDistance) \ + _(imageSensorPixelResolution) \ + +/// Calls your macro with the name of each member of XrExternalCameraExtrinsicsOCULUS, in order. +#define XR_LIST_STRUCT_XrExternalCameraExtrinsicsOCULUS(_) \ + _(lastChangeTime) \ + _(cameraStatusFlags) \ + _(attachedToDevice) \ + _(relativePose) \ + +/// Calls your macro with the name of each member of XrExternalCameraOCULUS, in order. +#define XR_LIST_STRUCT_XrExternalCameraOCULUS(_) \ + _(type) \ + _(next) \ + _(name) \ + _(intrinsics) \ + _(extrinsics) \ + +/// Calls your macro with the name of each member of XrVulkanSwapchainCreateInfoMETA, in order. +#define XR_LIST_STRUCT_XrVulkanSwapchainCreateInfoMETA(_) \ + _(type) \ + _(next) \ + _(additionalCreateFlags) \ + _(additionalUsageFlags) \ + +/// Calls your macro with the name of each member of XrPerformanceMetricsStateMETA, in order. +#define XR_LIST_STRUCT_XrPerformanceMetricsStateMETA(_) \ + _(type) \ + _(next) \ + _(enabled) \ + +/// Calls your macro with the name of each member of XrPerformanceMetricsCounterMETA, in order. +#define XR_LIST_STRUCT_XrPerformanceMetricsCounterMETA(_) \ + _(type) \ + _(next) \ + _(counterFlags) \ + _(counterUnit) \ + _(uintValue) \ + _(floatValue) \ + +/// Calls your macro with the name of each member of XrSpaceListSaveInfoFB, in order. +#define XR_LIST_STRUCT_XrSpaceListSaveInfoFB(_) \ + _(type) \ + _(next) \ + _(spaceCount) \ + _(spaces) \ + _(location) \ + +/// Calls your macro with the name of each member of XrEventDataSpaceListSaveCompleteFB, in order. +#define XR_LIST_STRUCT_XrEventDataSpaceListSaveCompleteFB(_) \ + _(type) \ + _(next) \ + _(requestId) \ + _(result) \ + +/// Calls your macro with the name of each member of XrSpaceUserCreateInfoFB, in order. +#define XR_LIST_STRUCT_XrSpaceUserCreateInfoFB(_) \ + _(type) \ + _(next) \ + _(userId) \ + +/// Calls your macro with the name of each member of XrSystemHeadsetIdPropertiesMETA, in order. +#define XR_LIST_STRUCT_XrSystemHeadsetIdPropertiesMETA(_) \ + _(type) \ + _(next) \ + _(id) \ + +/// Calls your macro with the name of each member of XrPassthroughColorLutDataMETA, in order. +#define XR_LIST_STRUCT_XrPassthroughColorLutDataMETA(_) \ + _(bufferSize) \ + _(buffer) \ + +/// Calls your macro with the name of each member of XrPassthroughColorLutCreateInfoMETA, in order. +#define XR_LIST_STRUCT_XrPassthroughColorLutCreateInfoMETA(_) \ + _(type) \ + _(next) \ + _(channels) \ + _(resolution) \ + _(data) \ + +/// Calls your macro with the name of each member of XrPassthroughColorLutUpdateInfoMETA, in order. +#define XR_LIST_STRUCT_XrPassthroughColorLutUpdateInfoMETA(_) \ + _(type) \ + _(next) \ + _(data) \ + +/// Calls your macro with the name of each member of XrPassthroughColorMapLutMETA, in order. +#define XR_LIST_STRUCT_XrPassthroughColorMapLutMETA(_) \ + _(type) \ + _(next) \ + _(colorLut) \ + _(weight) \ + +/// Calls your macro with the name of each member of XrPassthroughColorMapInterpolatedLutMETA, in order. +#define XR_LIST_STRUCT_XrPassthroughColorMapInterpolatedLutMETA(_) \ + _(type) \ + _(next) \ + _(sourceColorLut) \ + _(targetColorLut) \ + _(weight) \ + +/// Calls your macro with the name of each member of XrSystemPassthroughColorLutPropertiesMETA, in order. +#define XR_LIST_STRUCT_XrSystemPassthroughColorLutPropertiesMETA(_) \ + _(type) \ + _(next) \ + _(maxColorLutResolution) \ + +/// Calls your macro with the name of each member of XrPassthroughCreateInfoHTC, in order. +#define XR_LIST_STRUCT_XrPassthroughCreateInfoHTC(_) \ + _(type) \ + _(next) \ + _(form) \ + +/// Calls your macro with the name of each member of XrPassthroughColorHTC, in order. +#define XR_LIST_STRUCT_XrPassthroughColorHTC(_) \ + _(type) \ + _(next) \ + _(alpha) \ + +/// Calls your macro with the name of each member of XrPassthroughMeshTransformInfoHTC, in order. +#define XR_LIST_STRUCT_XrPassthroughMeshTransformInfoHTC(_) \ + _(type) \ + _(next) \ + _(vertexCount) \ + _(vertices) \ + _(indexCount) \ + _(indices) \ + _(baseSpace) \ + _(time) \ + _(pose) \ + _(scale) \ + +/// Calls your macro with the name of each member of XrCompositionLayerPassthroughHTC, in order. +#define XR_LIST_STRUCT_XrCompositionLayerPassthroughHTC(_) \ + _(type) \ + _(next) \ + _(layerFlags) \ + _(space) \ + _(passthrough) \ + _(color) \ + +/// Calls your macro with the name of each member of XrFoveationApplyInfoHTC, in order. +#define XR_LIST_STRUCT_XrFoveationApplyInfoHTC(_) \ + _(type) \ + _(next) \ + _(mode) \ + _(subImageCount) \ + _(subImages) \ + +/// Calls your macro with the name of each member of XrFoveationConfigurationHTC, in order. +#define XR_LIST_STRUCT_XrFoveationConfigurationHTC(_) \ + _(level) \ + _(clearFovDegree) \ + _(focalCenterOffset) \ + +/// Calls your macro with the name of each member of XrFoveationDynamicModeInfoHTC, in order. +#define XR_LIST_STRUCT_XrFoveationDynamicModeInfoHTC(_) \ + _(type) \ + _(next) \ + _(dynamicFlags) \ + +/// Calls your macro with the name of each member of XrFoveationCustomModeInfoHTC, in order. +#define XR_LIST_STRUCT_XrFoveationCustomModeInfoHTC(_) \ + _(type) \ + _(next) \ + _(configCount) \ + _(configs) \ + +/// Calls your macro with the name of each member of XrActiveActionSetPriorityEXT, in order. +#define XR_LIST_STRUCT_XrActiveActionSetPriorityEXT(_) \ + _(actionSet) \ + _(priorityOverride) \ + +/// Calls your macro with the name of each member of XrActiveActionSetPrioritiesEXT, in order. +#define XR_LIST_STRUCT_XrActiveActionSetPrioritiesEXT(_) \ + _(type) \ + _(next) \ + _(actionSetPriorityCount) \ + _(actionSetPriorities) \ + +/// Calls your macro with the name of each member of XrSystemForceFeedbackCurlPropertiesMNDX, in order. +#define XR_LIST_STRUCT_XrSystemForceFeedbackCurlPropertiesMNDX(_) \ + _(type) \ + _(next) \ + _(supportsForceFeedbackCurl) \ + +/// Calls your macro with the name of each member of XrForceFeedbackCurlApplyLocationMNDX, in order. +#define XR_LIST_STRUCT_XrForceFeedbackCurlApplyLocationMNDX(_) \ + _(location) \ + _(value) \ + +/// Calls your macro with the name of each member of XrForceFeedbackCurlApplyLocationsMNDX, in order. +#define XR_LIST_STRUCT_XrForceFeedbackCurlApplyLocationsMNDX(_) \ + _(type) \ + _(next) \ + _(locationCount) \ + _(locations) \ + +/// Calls your macro with the name of each member of XrHandTrackingDataSourceInfoEXT, in order. +#define XR_LIST_STRUCT_XrHandTrackingDataSourceInfoEXT(_) \ + _(type) \ + _(next) \ + _(requestedDataSourceCount) \ + _(requestedDataSources) \ + +/// Calls your macro with the name of each member of XrHandTrackingDataSourceStateEXT, in order. +#define XR_LIST_STRUCT_XrHandTrackingDataSourceStateEXT(_) \ + _(type) \ + _(next) \ + _(isActive) \ + _(dataSource) \ + +/// Calls your macro with the name of each member of XrSystemPlaneDetectionPropertiesEXT, in order. +#define XR_LIST_STRUCT_XrSystemPlaneDetectionPropertiesEXT(_) \ + _(type) \ + _(next) \ + _(supportedFeatures) \ + +/// Calls your macro with the name of each member of XrPlaneDetectorCreateInfoEXT, in order. +#define XR_LIST_STRUCT_XrPlaneDetectorCreateInfoEXT(_) \ + _(type) \ + _(next) \ + _(flags) \ + +/// Calls your macro with the name of each member of XrExtent3DfEXT, in order. +#define XR_LIST_STRUCT_XrExtent3DfEXT(_) \ + _(width) \ + _(height) \ + _(depth) \ + +/// Calls your macro with the name of each member of XrPlaneDetectorBeginInfoEXT, in order. +#define XR_LIST_STRUCT_XrPlaneDetectorBeginInfoEXT(_) \ + _(type) \ + _(next) \ + _(baseSpace) \ + _(time) \ + _(orientationCount) \ + _(orientations) \ + _(semanticTypeCount) \ + _(semanticTypes) \ + _(maxPlanes) \ + _(minArea) \ + _(boundingBoxPose) \ + _(boundingBoxExtent) \ + +/// Calls your macro with the name of each member of XrPlaneDetectorGetInfoEXT, in order. +#define XR_LIST_STRUCT_XrPlaneDetectorGetInfoEXT(_) \ + _(type) \ + _(next) \ + _(baseSpace) \ + _(time) \ + +/// Calls your macro with the name of each member of XrPlaneDetectorLocationEXT, in order. +#define XR_LIST_STRUCT_XrPlaneDetectorLocationEXT(_) \ + _(type) \ + _(next) \ + _(planeId) \ + _(locationFlags) \ + _(pose) \ + _(extents) \ + _(orientation) \ + _(semanticType) \ + _(polygonBufferCount) \ + +/// Calls your macro with the name of each member of XrPlaneDetectorLocationsEXT, in order. +#define XR_LIST_STRUCT_XrPlaneDetectorLocationsEXT(_) \ + _(type) \ + _(next) \ + _(planeLocationCapacityInput) \ + _(planeLocationCountOutput) \ + _(planeLocations) \ + +/// Calls your macro with the name of each member of XrPlaneDetectorPolygonBufferEXT, in order. +#define XR_LIST_STRUCT_XrPlaneDetectorPolygonBufferEXT(_) \ + _(type) \ + _(next) \ + _(vertexCapacityInput) \ + _(vertexCountOutput) \ + _(vertices) \ + + + +/// Calls your macro with the structure type name and the XrStructureType constant for +/// each known/available structure type, excluding those unavailable due to preprocessor definitions. +#define XR_LIST_STRUCTURE_TYPES(_) \ + XR_LIST_STRUCTURE_TYPES_CORE(_) \ + XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_D3D11(_) \ + XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_D3D12(_) \ + XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL(_) \ + XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_XR_USE_PLATFORM_WAYLAND(_) \ + XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_XR_USE_PLATFORM_WIN32(_) \ + XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_XR_USE_PLATFORM_XCB(_) \ + XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_XR_USE_PLATFORM_XLIB(_) \ + XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_ES(_) \ + XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_ES_XR_USE_PLATFORM_ANDROID(_) \ + XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_VULKAN(_) \ + XR_LIST_STRUCTURE_TYPES_XR_USE_PLATFORM_ANDROID(_) \ + XR_LIST_STRUCTURE_TYPES_XR_USE_PLATFORM_EGL(_) \ + XR_LIST_STRUCTURE_TYPES_XR_USE_PLATFORM_ML(_) \ + XR_LIST_STRUCTURE_TYPES_XR_USE_PLATFORM_WIN32(_) \ + + +/// Implementation detail of XR_LIST_STRUCTURE_TYPES() - structure types available without any preprocessor definitions +#define XR_LIST_STRUCTURE_TYPES_CORE(_) \ + _(XrApiLayerProperties, XR_TYPE_API_LAYER_PROPERTIES) \ + _(XrExtensionProperties, XR_TYPE_EXTENSION_PROPERTIES) \ + _(XrInstanceCreateInfo, XR_TYPE_INSTANCE_CREATE_INFO) \ + _(XrInstanceProperties, XR_TYPE_INSTANCE_PROPERTIES) \ + _(XrEventDataBuffer, XR_TYPE_EVENT_DATA_BUFFER) \ + _(XrSystemGetInfo, XR_TYPE_SYSTEM_GET_INFO) \ + _(XrSystemProperties, XR_TYPE_SYSTEM_PROPERTIES) \ + _(XrSessionCreateInfo, XR_TYPE_SESSION_CREATE_INFO) \ + _(XrSpaceVelocity, XR_TYPE_SPACE_VELOCITY) \ + _(XrReferenceSpaceCreateInfo, XR_TYPE_REFERENCE_SPACE_CREATE_INFO) \ + _(XrActionSpaceCreateInfo, XR_TYPE_ACTION_SPACE_CREATE_INFO) \ + _(XrSpaceLocation, XR_TYPE_SPACE_LOCATION) \ + _(XrViewConfigurationProperties, XR_TYPE_VIEW_CONFIGURATION_PROPERTIES) \ + _(XrViewConfigurationView, XR_TYPE_VIEW_CONFIGURATION_VIEW) \ + _(XrSwapchainCreateInfo, XR_TYPE_SWAPCHAIN_CREATE_INFO) \ + _(XrSwapchainImageAcquireInfo, XR_TYPE_SWAPCHAIN_IMAGE_ACQUIRE_INFO) \ + _(XrSwapchainImageWaitInfo, XR_TYPE_SWAPCHAIN_IMAGE_WAIT_INFO) \ + _(XrSwapchainImageReleaseInfo, XR_TYPE_SWAPCHAIN_IMAGE_RELEASE_INFO) \ + _(XrSessionBeginInfo, XR_TYPE_SESSION_BEGIN_INFO) \ + _(XrFrameWaitInfo, XR_TYPE_FRAME_WAIT_INFO) \ + _(XrFrameState, XR_TYPE_FRAME_STATE) \ + _(XrFrameBeginInfo, XR_TYPE_FRAME_BEGIN_INFO) \ + _(XrFrameEndInfo, XR_TYPE_FRAME_END_INFO) \ + _(XrViewLocateInfo, XR_TYPE_VIEW_LOCATE_INFO) \ + _(XrViewState, XR_TYPE_VIEW_STATE) \ + _(XrView, XR_TYPE_VIEW) \ + _(XrActionSetCreateInfo, XR_TYPE_ACTION_SET_CREATE_INFO) \ + _(XrActionCreateInfo, XR_TYPE_ACTION_CREATE_INFO) \ + _(XrInteractionProfileSuggestedBinding, XR_TYPE_INTERACTION_PROFILE_SUGGESTED_BINDING) \ + _(XrSessionActionSetsAttachInfo, XR_TYPE_SESSION_ACTION_SETS_ATTACH_INFO) \ + _(XrInteractionProfileState, XR_TYPE_INTERACTION_PROFILE_STATE) \ + _(XrActionStateGetInfo, XR_TYPE_ACTION_STATE_GET_INFO) \ + _(XrActionStateBoolean, XR_TYPE_ACTION_STATE_BOOLEAN) \ + _(XrActionStateFloat, XR_TYPE_ACTION_STATE_FLOAT) \ + _(XrActionStateVector2f, XR_TYPE_ACTION_STATE_VECTOR2F) \ + _(XrActionStatePose, XR_TYPE_ACTION_STATE_POSE) \ + _(XrActionsSyncInfo, XR_TYPE_ACTIONS_SYNC_INFO) \ + _(XrBoundSourcesForActionEnumerateInfo, XR_TYPE_BOUND_SOURCES_FOR_ACTION_ENUMERATE_INFO) \ + _(XrInputSourceLocalizedNameGetInfo, XR_TYPE_INPUT_SOURCE_LOCALIZED_NAME_GET_INFO) \ + _(XrHapticActionInfo, XR_TYPE_HAPTIC_ACTION_INFO) \ + _(XrCompositionLayerProjectionView, XR_TYPE_COMPOSITION_LAYER_PROJECTION_VIEW) \ + _(XrCompositionLayerProjection, XR_TYPE_COMPOSITION_LAYER_PROJECTION) \ + _(XrCompositionLayerQuad, XR_TYPE_COMPOSITION_LAYER_QUAD) \ + _(XrEventDataEventsLost, XR_TYPE_EVENT_DATA_EVENTS_LOST) \ + _(XrEventDataInstanceLossPending, XR_TYPE_EVENT_DATA_INSTANCE_LOSS_PENDING) \ + _(XrEventDataSessionStateChanged, XR_TYPE_EVENT_DATA_SESSION_STATE_CHANGED) \ + _(XrEventDataReferenceSpaceChangePending, XR_TYPE_EVENT_DATA_REFERENCE_SPACE_CHANGE_PENDING) \ + _(XrEventDataInteractionProfileChanged, XR_TYPE_EVENT_DATA_INTERACTION_PROFILE_CHANGED) \ + _(XrHapticVibration, XR_TYPE_HAPTIC_VIBRATION) \ + _(XrCompositionLayerCubeKHR, XR_TYPE_COMPOSITION_LAYER_CUBE_KHR) \ + _(XrCompositionLayerDepthInfoKHR, XR_TYPE_COMPOSITION_LAYER_DEPTH_INFO_KHR) \ + _(XrCompositionLayerCylinderKHR, XR_TYPE_COMPOSITION_LAYER_CYLINDER_KHR) \ + _(XrCompositionLayerEquirectKHR, XR_TYPE_COMPOSITION_LAYER_EQUIRECT_KHR) \ + _(XrVisibilityMaskKHR, XR_TYPE_VISIBILITY_MASK_KHR) \ + _(XrEventDataVisibilityMaskChangedKHR, XR_TYPE_EVENT_DATA_VISIBILITY_MASK_CHANGED_KHR) \ + _(XrCompositionLayerColorScaleBiasKHR, XR_TYPE_COMPOSITION_LAYER_COLOR_SCALE_BIAS_KHR) \ + _(XrCompositionLayerEquirect2KHR, XR_TYPE_COMPOSITION_LAYER_EQUIRECT2_KHR) \ + _(XrBindingModificationsKHR, XR_TYPE_BINDING_MODIFICATIONS_KHR) \ + _(XrEventDataPerfSettingsEXT, XR_TYPE_EVENT_DATA_PERF_SETTINGS_EXT) \ + _(XrDebugUtilsObjectNameInfoEXT, XR_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT) \ + _(XrDebugUtilsLabelEXT, XR_TYPE_DEBUG_UTILS_LABEL_EXT) \ + _(XrDebugUtilsMessengerCallbackDataEXT, XR_TYPE_DEBUG_UTILS_MESSENGER_CALLBACK_DATA_EXT) \ + _(XrDebugUtilsMessengerCreateInfoEXT, XR_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT) \ + _(XrSystemEyeGazeInteractionPropertiesEXT, XR_TYPE_SYSTEM_EYE_GAZE_INTERACTION_PROPERTIES_EXT) \ + _(XrEyeGazeSampleTimeEXT, XR_TYPE_EYE_GAZE_SAMPLE_TIME_EXT) \ + _(XrSessionCreateInfoOverlayEXTX, XR_TYPE_SESSION_CREATE_INFO_OVERLAY_EXTX) \ + _(XrEventDataMainSessionVisibilityChangedEXTX, XR_TYPE_EVENT_DATA_MAIN_SESSION_VISIBILITY_CHANGED_EXTX) \ + _(XrSpatialAnchorCreateInfoMSFT, XR_TYPE_SPATIAL_ANCHOR_CREATE_INFO_MSFT) \ + _(XrSpatialAnchorSpaceCreateInfoMSFT, XR_TYPE_SPATIAL_ANCHOR_SPACE_CREATE_INFO_MSFT) \ + _(XrCompositionLayerImageLayoutFB, XR_TYPE_COMPOSITION_LAYER_IMAGE_LAYOUT_FB) \ + _(XrCompositionLayerAlphaBlendFB, XR_TYPE_COMPOSITION_LAYER_ALPHA_BLEND_FB) \ + _(XrViewConfigurationDepthRangeEXT, XR_TYPE_VIEW_CONFIGURATION_DEPTH_RANGE_EXT) \ + _(XrSpatialGraphNodeSpaceCreateInfoMSFT, XR_TYPE_SPATIAL_GRAPH_NODE_SPACE_CREATE_INFO_MSFT) \ + _(XrSpatialGraphStaticNodeBindingCreateInfoMSFT, XR_TYPE_SPATIAL_GRAPH_STATIC_NODE_BINDING_CREATE_INFO_MSFT) \ + _(XrSpatialGraphNodeBindingPropertiesGetInfoMSFT, XR_TYPE_SPATIAL_GRAPH_NODE_BINDING_PROPERTIES_GET_INFO_MSFT) \ + _(XrSpatialGraphNodeBindingPropertiesMSFT, XR_TYPE_SPATIAL_GRAPH_NODE_BINDING_PROPERTIES_MSFT) \ + _(XrSystemHandTrackingPropertiesEXT, XR_TYPE_SYSTEM_HAND_TRACKING_PROPERTIES_EXT) \ + _(XrHandTrackerCreateInfoEXT, XR_TYPE_HAND_TRACKER_CREATE_INFO_EXT) \ + _(XrHandJointsLocateInfoEXT, XR_TYPE_HAND_JOINTS_LOCATE_INFO_EXT) \ + _(XrHandJointLocationsEXT, XR_TYPE_HAND_JOINT_LOCATIONS_EXT) \ + _(XrHandJointVelocitiesEXT, XR_TYPE_HAND_JOINT_VELOCITIES_EXT) \ + _(XrSystemHandTrackingMeshPropertiesMSFT, XR_TYPE_SYSTEM_HAND_TRACKING_MESH_PROPERTIES_MSFT) \ + _(XrHandMeshSpaceCreateInfoMSFT, XR_TYPE_HAND_MESH_SPACE_CREATE_INFO_MSFT) \ + _(XrHandMeshUpdateInfoMSFT, XR_TYPE_HAND_MESH_UPDATE_INFO_MSFT) \ + _(XrHandMeshMSFT, XR_TYPE_HAND_MESH_MSFT) \ + _(XrHandPoseTypeInfoMSFT, XR_TYPE_HAND_POSE_TYPE_INFO_MSFT) \ + _(XrSecondaryViewConfigurationSessionBeginInfoMSFT, XR_TYPE_SECONDARY_VIEW_CONFIGURATION_SESSION_BEGIN_INFO_MSFT) \ + _(XrSecondaryViewConfigurationStateMSFT, XR_TYPE_SECONDARY_VIEW_CONFIGURATION_STATE_MSFT) \ + _(XrSecondaryViewConfigurationFrameStateMSFT, XR_TYPE_SECONDARY_VIEW_CONFIGURATION_FRAME_STATE_MSFT) \ + _(XrSecondaryViewConfigurationLayerInfoMSFT, XR_TYPE_SECONDARY_VIEW_CONFIGURATION_LAYER_INFO_MSFT) \ + _(XrSecondaryViewConfigurationFrameEndInfoMSFT, XR_TYPE_SECONDARY_VIEW_CONFIGURATION_FRAME_END_INFO_MSFT) \ + _(XrSecondaryViewConfigurationSwapchainCreateInfoMSFT, XR_TYPE_SECONDARY_VIEW_CONFIGURATION_SWAPCHAIN_CREATE_INFO_MSFT) \ + _(XrControllerModelKeyStateMSFT, XR_TYPE_CONTROLLER_MODEL_KEY_STATE_MSFT) \ + _(XrControllerModelNodePropertiesMSFT, XR_TYPE_CONTROLLER_MODEL_NODE_PROPERTIES_MSFT) \ + _(XrControllerModelPropertiesMSFT, XR_TYPE_CONTROLLER_MODEL_PROPERTIES_MSFT) \ + _(XrControllerModelNodeStateMSFT, XR_TYPE_CONTROLLER_MODEL_NODE_STATE_MSFT) \ + _(XrControllerModelStateMSFT, XR_TYPE_CONTROLLER_MODEL_STATE_MSFT) \ + _(XrViewConfigurationViewFovEPIC, XR_TYPE_VIEW_CONFIGURATION_VIEW_FOV_EPIC) \ + _(XrCompositionLayerReprojectionInfoMSFT, XR_TYPE_COMPOSITION_LAYER_REPROJECTION_INFO_MSFT) \ + _(XrCompositionLayerReprojectionPlaneOverrideMSFT, XR_TYPE_COMPOSITION_LAYER_REPROJECTION_PLANE_OVERRIDE_MSFT) \ + _(XrCompositionLayerSecureContentFB, XR_TYPE_COMPOSITION_LAYER_SECURE_CONTENT_FB) \ + _(XrSystemBodyTrackingPropertiesFB, XR_TYPE_SYSTEM_BODY_TRACKING_PROPERTIES_FB) \ + _(XrBodyTrackerCreateInfoFB, XR_TYPE_BODY_TRACKER_CREATE_INFO_FB) \ + _(XrBodySkeletonFB, XR_TYPE_BODY_SKELETON_FB) \ + _(XrBodyJointsLocateInfoFB, XR_TYPE_BODY_JOINTS_LOCATE_INFO_FB) \ + _(XrBodyJointLocationsFB, XR_TYPE_BODY_JOINT_LOCATIONS_FB) \ + _(XrInteractionProfileDpadBindingEXT, XR_TYPE_INTERACTION_PROFILE_DPAD_BINDING_EXT) \ + _(XrInteractionProfileAnalogThresholdVALVE, XR_TYPE_INTERACTION_PROFILE_ANALOG_THRESHOLD_VALVE) \ + _(XrHandJointsMotionRangeInfoEXT, XR_TYPE_HAND_JOINTS_MOTION_RANGE_INFO_EXT) \ + _(XrSceneObserverCreateInfoMSFT, XR_TYPE_SCENE_OBSERVER_CREATE_INFO_MSFT) \ + _(XrSceneCreateInfoMSFT, XR_TYPE_SCENE_CREATE_INFO_MSFT) \ + _(XrNewSceneComputeInfoMSFT, XR_TYPE_NEW_SCENE_COMPUTE_INFO_MSFT) \ + _(XrVisualMeshComputeLodInfoMSFT, XR_TYPE_VISUAL_MESH_COMPUTE_LOD_INFO_MSFT) \ + _(XrSceneComponentsMSFT, XR_TYPE_SCENE_COMPONENTS_MSFT) \ + _(XrSceneComponentsGetInfoMSFT, XR_TYPE_SCENE_COMPONENTS_GET_INFO_MSFT) \ + _(XrSceneComponentLocationsMSFT, XR_TYPE_SCENE_COMPONENT_LOCATIONS_MSFT) \ + _(XrSceneComponentsLocateInfoMSFT, XR_TYPE_SCENE_COMPONENTS_LOCATE_INFO_MSFT) \ + _(XrSceneObjectsMSFT, XR_TYPE_SCENE_OBJECTS_MSFT) \ + _(XrSceneComponentParentFilterInfoMSFT, XR_TYPE_SCENE_COMPONENT_PARENT_FILTER_INFO_MSFT) \ + _(XrSceneObjectTypesFilterInfoMSFT, XR_TYPE_SCENE_OBJECT_TYPES_FILTER_INFO_MSFT) \ + _(XrScenePlanesMSFT, XR_TYPE_SCENE_PLANES_MSFT) \ + _(XrScenePlaneAlignmentFilterInfoMSFT, XR_TYPE_SCENE_PLANE_ALIGNMENT_FILTER_INFO_MSFT) \ + _(XrSceneMeshesMSFT, XR_TYPE_SCENE_MESHES_MSFT) \ + _(XrSceneMeshBuffersGetInfoMSFT, XR_TYPE_SCENE_MESH_BUFFERS_GET_INFO_MSFT) \ + _(XrSceneMeshBuffersMSFT, XR_TYPE_SCENE_MESH_BUFFERS_MSFT) \ + _(XrSceneMeshVertexBufferMSFT, XR_TYPE_SCENE_MESH_VERTEX_BUFFER_MSFT) \ + _(XrSceneMeshIndicesUint32MSFT, XR_TYPE_SCENE_MESH_INDICES_UINT32_MSFT) \ + _(XrSceneMeshIndicesUint16MSFT, XR_TYPE_SCENE_MESH_INDICES_UINT16_MSFT) \ + _(XrSerializedSceneFragmentDataGetInfoMSFT, XR_TYPE_SERIALIZED_SCENE_FRAGMENT_DATA_GET_INFO_MSFT) \ + _(XrSceneDeserializeInfoMSFT, XR_TYPE_SCENE_DESERIALIZE_INFO_MSFT) \ + _(XrEventDataDisplayRefreshRateChangedFB, XR_TYPE_EVENT_DATA_DISPLAY_REFRESH_RATE_CHANGED_FB) \ + _(XrViveTrackerPathsHTCX, XR_TYPE_VIVE_TRACKER_PATHS_HTCX) \ + _(XrEventDataViveTrackerConnectedHTCX, XR_TYPE_EVENT_DATA_VIVE_TRACKER_CONNECTED_HTCX) \ + _(XrSystemFacialTrackingPropertiesHTC, XR_TYPE_SYSTEM_FACIAL_TRACKING_PROPERTIES_HTC) \ + _(XrFacialExpressionsHTC, XR_TYPE_FACIAL_EXPRESSIONS_HTC) \ + _(XrFacialTrackerCreateInfoHTC, XR_TYPE_FACIAL_TRACKER_CREATE_INFO_HTC) \ + _(XrSystemColorSpacePropertiesFB, XR_TYPE_SYSTEM_COLOR_SPACE_PROPERTIES_FB) \ + _(XrHandTrackingMeshFB, XR_TYPE_HAND_TRACKING_MESH_FB) \ + _(XrHandTrackingScaleFB, XR_TYPE_HAND_TRACKING_SCALE_FB) \ + _(XrHandTrackingAimStateFB, XR_TYPE_HAND_TRACKING_AIM_STATE_FB) \ + _(XrHandTrackingCapsulesStateFB, XR_TYPE_HAND_TRACKING_CAPSULES_STATE_FB) \ + _(XrSystemSpatialEntityPropertiesFB, XR_TYPE_SYSTEM_SPATIAL_ENTITY_PROPERTIES_FB) \ + _(XrSpatialAnchorCreateInfoFB, XR_TYPE_SPATIAL_ANCHOR_CREATE_INFO_FB) \ + _(XrSpaceComponentStatusSetInfoFB, XR_TYPE_SPACE_COMPONENT_STATUS_SET_INFO_FB) \ + _(XrSpaceComponentStatusFB, XR_TYPE_SPACE_COMPONENT_STATUS_FB) \ + _(XrEventDataSpatialAnchorCreateCompleteFB, XR_TYPE_EVENT_DATA_SPATIAL_ANCHOR_CREATE_COMPLETE_FB) \ + _(XrEventDataSpaceSetStatusCompleteFB, XR_TYPE_EVENT_DATA_SPACE_SET_STATUS_COMPLETE_FB) \ + _(XrFoveationProfileCreateInfoFB, XR_TYPE_FOVEATION_PROFILE_CREATE_INFO_FB) \ + _(XrSwapchainCreateInfoFoveationFB, XR_TYPE_SWAPCHAIN_CREATE_INFO_FOVEATION_FB) \ + _(XrSwapchainStateFoveationFB, XR_TYPE_SWAPCHAIN_STATE_FOVEATION_FB) \ + _(XrFoveationLevelProfileCreateInfoFB, XR_TYPE_FOVEATION_LEVEL_PROFILE_CREATE_INFO_FB) \ + _(XrSystemKeyboardTrackingPropertiesFB, XR_TYPE_SYSTEM_KEYBOARD_TRACKING_PROPERTIES_FB) \ + _(XrKeyboardSpaceCreateInfoFB, XR_TYPE_KEYBOARD_SPACE_CREATE_INFO_FB) \ + _(XrKeyboardTrackingQueryFB, XR_TYPE_KEYBOARD_TRACKING_QUERY_FB) \ + _(XrTriangleMeshCreateInfoFB, XR_TYPE_TRIANGLE_MESH_CREATE_INFO_FB) \ + _(XrSystemPassthroughPropertiesFB, XR_TYPE_SYSTEM_PASSTHROUGH_PROPERTIES_FB) \ + _(XrSystemPassthroughProperties2FB, XR_TYPE_SYSTEM_PASSTHROUGH_PROPERTIES2_FB) \ + _(XrPassthroughCreateInfoFB, XR_TYPE_PASSTHROUGH_CREATE_INFO_FB) \ + _(XrPassthroughLayerCreateInfoFB, XR_TYPE_PASSTHROUGH_LAYER_CREATE_INFO_FB) \ + _(XrCompositionLayerPassthroughFB, XR_TYPE_COMPOSITION_LAYER_PASSTHROUGH_FB) \ + _(XrGeometryInstanceCreateInfoFB, XR_TYPE_GEOMETRY_INSTANCE_CREATE_INFO_FB) \ + _(XrGeometryInstanceTransformFB, XR_TYPE_GEOMETRY_INSTANCE_TRANSFORM_FB) \ + _(XrPassthroughStyleFB, XR_TYPE_PASSTHROUGH_STYLE_FB) \ + _(XrPassthroughColorMapMonoToRgbaFB, XR_TYPE_PASSTHROUGH_COLOR_MAP_MONO_TO_RGBA_FB) \ + _(XrPassthroughColorMapMonoToMonoFB, XR_TYPE_PASSTHROUGH_COLOR_MAP_MONO_TO_MONO_FB) \ + _(XrPassthroughBrightnessContrastSaturationFB, XR_TYPE_PASSTHROUGH_BRIGHTNESS_CONTRAST_SATURATION_FB) \ + _(XrEventDataPassthroughStateChangedFB, XR_TYPE_EVENT_DATA_PASSTHROUGH_STATE_CHANGED_FB) \ + _(XrRenderModelPathInfoFB, XR_TYPE_RENDER_MODEL_PATH_INFO_FB) \ + _(XrRenderModelPropertiesFB, XR_TYPE_RENDER_MODEL_PROPERTIES_FB) \ + _(XrRenderModelBufferFB, XR_TYPE_RENDER_MODEL_BUFFER_FB) \ + _(XrRenderModelLoadInfoFB, XR_TYPE_RENDER_MODEL_LOAD_INFO_FB) \ + _(XrSystemRenderModelPropertiesFB, XR_TYPE_SYSTEM_RENDER_MODEL_PROPERTIES_FB) \ + _(XrRenderModelCapabilitiesRequestFB, XR_TYPE_RENDER_MODEL_CAPABILITIES_REQUEST_FB) \ + _(XrViewLocateFoveatedRenderingVARJO, XR_TYPE_VIEW_LOCATE_FOVEATED_RENDERING_VARJO) \ + _(XrFoveatedViewConfigurationViewVARJO, XR_TYPE_FOVEATED_VIEW_CONFIGURATION_VIEW_VARJO) \ + _(XrSystemFoveatedRenderingPropertiesVARJO, XR_TYPE_SYSTEM_FOVEATED_RENDERING_PROPERTIES_VARJO) \ + _(XrCompositionLayerDepthTestVARJO, XR_TYPE_COMPOSITION_LAYER_DEPTH_TEST_VARJO) \ + _(XrSystemMarkerTrackingPropertiesVARJO, XR_TYPE_SYSTEM_MARKER_TRACKING_PROPERTIES_VARJO) \ + _(XrEventDataMarkerTrackingUpdateVARJO, XR_TYPE_EVENT_DATA_MARKER_TRACKING_UPDATE_VARJO) \ + _(XrMarkerSpaceCreateInfoVARJO, XR_TYPE_MARKER_SPACE_CREATE_INFO_VARJO) \ + _(XrFrameEndInfoML, XR_TYPE_FRAME_END_INFO_ML) \ + _(XrGlobalDimmerFrameEndInfoML, XR_TYPE_GLOBAL_DIMMER_FRAME_END_INFO_ML) \ + _(XrSpatialAnchorPersistenceInfoMSFT, XR_TYPE_SPATIAL_ANCHOR_PERSISTENCE_INFO_MSFT) \ + _(XrSpatialAnchorFromPersistedAnchorCreateInfoMSFT, XR_TYPE_SPATIAL_ANCHOR_FROM_PERSISTED_ANCHOR_CREATE_INFO_MSFT) \ + _(XrSpaceQueryInfoFB, XR_TYPE_SPACE_QUERY_INFO_FB) \ + _(XrSpaceStorageLocationFilterInfoFB, XR_TYPE_SPACE_STORAGE_LOCATION_FILTER_INFO_FB) \ + _(XrSpaceUuidFilterInfoFB, XR_TYPE_SPACE_UUID_FILTER_INFO_FB) \ + _(XrSpaceComponentFilterInfoFB, XR_TYPE_SPACE_COMPONENT_FILTER_INFO_FB) \ + _(XrSpaceQueryResultsFB, XR_TYPE_SPACE_QUERY_RESULTS_FB) \ + _(XrEventDataSpaceQueryResultsAvailableFB, XR_TYPE_EVENT_DATA_SPACE_QUERY_RESULTS_AVAILABLE_FB) \ + _(XrEventDataSpaceQueryCompleteFB, XR_TYPE_EVENT_DATA_SPACE_QUERY_COMPLETE_FB) \ + _(XrSpaceSaveInfoFB, XR_TYPE_SPACE_SAVE_INFO_FB) \ + _(XrSpaceEraseInfoFB, XR_TYPE_SPACE_ERASE_INFO_FB) \ + _(XrEventDataSpaceSaveCompleteFB, XR_TYPE_EVENT_DATA_SPACE_SAVE_COMPLETE_FB) \ + _(XrEventDataSpaceEraseCompleteFB, XR_TYPE_EVENT_DATA_SPACE_ERASE_COMPLETE_FB) \ + _(XrSpaceShareInfoFB, XR_TYPE_SPACE_SHARE_INFO_FB) \ + _(XrEventDataSpaceShareCompleteFB, XR_TYPE_EVENT_DATA_SPACE_SHARE_COMPLETE_FB) \ + _(XrCompositionLayerSpaceWarpInfoFB, XR_TYPE_COMPOSITION_LAYER_SPACE_WARP_INFO_FB) \ + _(XrSystemSpaceWarpPropertiesFB, XR_TYPE_SYSTEM_SPACE_WARP_PROPERTIES_FB) \ + _(XrHapticAmplitudeEnvelopeVibrationFB, XR_TYPE_HAPTIC_AMPLITUDE_ENVELOPE_VIBRATION_FB) \ + _(XrSemanticLabelsFB, XR_TYPE_SEMANTIC_LABELS_FB) \ + _(XrRoomLayoutFB, XR_TYPE_ROOM_LAYOUT_FB) \ + _(XrBoundary2DFB, XR_TYPE_BOUNDARY_2D_FB) \ + _(XrSemanticLabelsSupportInfoFB, XR_TYPE_SEMANTIC_LABELS_SUPPORT_INFO_FB) \ + _(XrDigitalLensControlALMALENCE, XR_TYPE_DIGITAL_LENS_CONTROL_ALMALENCE) \ + _(XrEventDataSceneCaptureCompleteFB, XR_TYPE_EVENT_DATA_SCENE_CAPTURE_COMPLETE_FB) \ + _(XrSceneCaptureRequestInfoFB, XR_TYPE_SCENE_CAPTURE_REQUEST_INFO_FB) \ + _(XrSpaceContainerFB, XR_TYPE_SPACE_CONTAINER_FB) \ + _(XrFoveationEyeTrackedProfileCreateInfoMETA, XR_TYPE_FOVEATION_EYE_TRACKED_PROFILE_CREATE_INFO_META) \ + _(XrFoveationEyeTrackedStateMETA, XR_TYPE_FOVEATION_EYE_TRACKED_STATE_META) \ + _(XrSystemFoveationEyeTrackedPropertiesMETA, XR_TYPE_SYSTEM_FOVEATION_EYE_TRACKED_PROPERTIES_META) \ + _(XrSystemFaceTrackingPropertiesFB, XR_TYPE_SYSTEM_FACE_TRACKING_PROPERTIES_FB) \ + _(XrFaceTrackerCreateInfoFB, XR_TYPE_FACE_TRACKER_CREATE_INFO_FB) \ + _(XrFaceExpressionInfoFB, XR_TYPE_FACE_EXPRESSION_INFO_FB) \ + _(XrFaceExpressionWeightsFB, XR_TYPE_FACE_EXPRESSION_WEIGHTS_FB) \ + _(XrEyeTrackerCreateInfoFB, XR_TYPE_EYE_TRACKER_CREATE_INFO_FB) \ + _(XrEyeGazesInfoFB, XR_TYPE_EYE_GAZES_INFO_FB) \ + _(XrSystemEyeTrackingPropertiesFB, XR_TYPE_SYSTEM_EYE_TRACKING_PROPERTIES_FB) \ + _(XrEyeGazesFB, XR_TYPE_EYE_GAZES_FB) \ + _(XrPassthroughKeyboardHandsIntensityFB, XR_TYPE_PASSTHROUGH_KEYBOARD_HANDS_INTENSITY_FB) \ + _(XrCompositionLayerSettingsFB, XR_TYPE_COMPOSITION_LAYER_SETTINGS_FB) \ + _(XrHapticPcmVibrationFB, XR_TYPE_HAPTIC_PCM_VIBRATION_FB) \ + _(XrDevicePcmSampleRateStateFB, XR_TYPE_DEVICE_PCM_SAMPLE_RATE_STATE_FB) \ + _(XrCompositionLayerDepthTestFB, XR_TYPE_COMPOSITION_LAYER_DEPTH_TEST_FB) \ + _(XrLocalDimmingFrameEndInfoMETA, XR_TYPE_LOCAL_DIMMING_FRAME_END_INFO_META) \ + _(XrPassthroughPreferencesMETA, XR_TYPE_PASSTHROUGH_PREFERENCES_META) \ + _(XrSystemVirtualKeyboardPropertiesMETA, XR_TYPE_SYSTEM_VIRTUAL_KEYBOARD_PROPERTIES_META) \ + _(XrVirtualKeyboardCreateInfoMETA, XR_TYPE_VIRTUAL_KEYBOARD_CREATE_INFO_META) \ + _(XrVirtualKeyboardSpaceCreateInfoMETA, XR_TYPE_VIRTUAL_KEYBOARD_SPACE_CREATE_INFO_META) \ + _(XrVirtualKeyboardLocationInfoMETA, XR_TYPE_VIRTUAL_KEYBOARD_LOCATION_INFO_META) \ + _(XrVirtualKeyboardModelVisibilitySetInfoMETA, XR_TYPE_VIRTUAL_KEYBOARD_MODEL_VISIBILITY_SET_INFO_META) \ + _(XrVirtualKeyboardAnimationStateMETA, XR_TYPE_VIRTUAL_KEYBOARD_ANIMATION_STATE_META) \ + _(XrVirtualKeyboardModelAnimationStatesMETA, XR_TYPE_VIRTUAL_KEYBOARD_MODEL_ANIMATION_STATES_META) \ + _(XrVirtualKeyboardTextureDataMETA, XR_TYPE_VIRTUAL_KEYBOARD_TEXTURE_DATA_META) \ + _(XrVirtualKeyboardInputInfoMETA, XR_TYPE_VIRTUAL_KEYBOARD_INPUT_INFO_META) \ + _(XrVirtualKeyboardTextContextChangeInfoMETA, XR_TYPE_VIRTUAL_KEYBOARD_TEXT_CONTEXT_CHANGE_INFO_META) \ + _(XrEventDataVirtualKeyboardCommitTextMETA, XR_TYPE_EVENT_DATA_VIRTUAL_KEYBOARD_COMMIT_TEXT_META) \ + _(XrEventDataVirtualKeyboardBackspaceMETA, XR_TYPE_EVENT_DATA_VIRTUAL_KEYBOARD_BACKSPACE_META) \ + _(XrEventDataVirtualKeyboardEnterMETA, XR_TYPE_EVENT_DATA_VIRTUAL_KEYBOARD_ENTER_META) \ + _(XrEventDataVirtualKeyboardShownMETA, XR_TYPE_EVENT_DATA_VIRTUAL_KEYBOARD_SHOWN_META) \ + _(XrEventDataVirtualKeyboardHiddenMETA, XR_TYPE_EVENT_DATA_VIRTUAL_KEYBOARD_HIDDEN_META) \ + _(XrExternalCameraOCULUS, XR_TYPE_EXTERNAL_CAMERA_OCULUS) \ + _(XrPerformanceMetricsStateMETA, XR_TYPE_PERFORMANCE_METRICS_STATE_META) \ + _(XrPerformanceMetricsCounterMETA, XR_TYPE_PERFORMANCE_METRICS_COUNTER_META) \ + _(XrSpaceListSaveInfoFB, XR_TYPE_SPACE_LIST_SAVE_INFO_FB) \ + _(XrEventDataSpaceListSaveCompleteFB, XR_TYPE_EVENT_DATA_SPACE_LIST_SAVE_COMPLETE_FB) \ + _(XrSpaceUserCreateInfoFB, XR_TYPE_SPACE_USER_CREATE_INFO_FB) \ + _(XrSystemHeadsetIdPropertiesMETA, XR_TYPE_SYSTEM_HEADSET_ID_PROPERTIES_META) \ + _(XrPassthroughColorLutCreateInfoMETA, XR_TYPE_PASSTHROUGH_COLOR_LUT_CREATE_INFO_META) \ + _(XrPassthroughColorLutUpdateInfoMETA, XR_TYPE_PASSTHROUGH_COLOR_LUT_UPDATE_INFO_META) \ + _(XrPassthroughColorMapLutMETA, XR_TYPE_PASSTHROUGH_COLOR_MAP_LUT_META) \ + _(XrPassthroughColorMapInterpolatedLutMETA, XR_TYPE_PASSTHROUGH_COLOR_MAP_INTERPOLATED_LUT_META) \ + _(XrSystemPassthroughColorLutPropertiesMETA, XR_TYPE_SYSTEM_PASSTHROUGH_COLOR_LUT_PROPERTIES_META) \ + _(XrPassthroughCreateInfoHTC, XR_TYPE_PASSTHROUGH_CREATE_INFO_HTC) \ + _(XrPassthroughColorHTC, XR_TYPE_PASSTHROUGH_COLOR_HTC) \ + _(XrPassthroughMeshTransformInfoHTC, XR_TYPE_PASSTHROUGH_MESH_TRANSFORM_INFO_HTC) \ + _(XrCompositionLayerPassthroughHTC, XR_TYPE_COMPOSITION_LAYER_PASSTHROUGH_HTC) \ + _(XrFoveationApplyInfoHTC, XR_TYPE_FOVEATION_APPLY_INFO_HTC) \ + _(XrFoveationDynamicModeInfoHTC, XR_TYPE_FOVEATION_DYNAMIC_MODE_INFO_HTC) \ + _(XrFoveationCustomModeInfoHTC, XR_TYPE_FOVEATION_CUSTOM_MODE_INFO_HTC) \ + _(XrActiveActionSetPrioritiesEXT, XR_TYPE_ACTIVE_ACTION_SET_PRIORITIES_EXT) \ + _(XrSystemForceFeedbackCurlPropertiesMNDX, XR_TYPE_SYSTEM_FORCE_FEEDBACK_CURL_PROPERTIES_MNDX) \ + _(XrForceFeedbackCurlApplyLocationsMNDX, XR_TYPE_FORCE_FEEDBACK_CURL_APPLY_LOCATIONS_MNDX) \ + _(XrHandTrackingDataSourceInfoEXT, XR_TYPE_HAND_TRACKING_DATA_SOURCE_INFO_EXT) \ + _(XrHandTrackingDataSourceStateEXT, XR_TYPE_HAND_TRACKING_DATA_SOURCE_STATE_EXT) \ + _(XrSystemPlaneDetectionPropertiesEXT, XR_TYPE_SYSTEM_PLANE_DETECTION_PROPERTIES_EXT) \ + _(XrPlaneDetectorCreateInfoEXT, XR_TYPE_PLANE_DETECTOR_CREATE_INFO_EXT) \ + _(XrPlaneDetectorBeginInfoEXT, XR_TYPE_PLANE_DETECTOR_BEGIN_INFO_EXT) \ + _(XrPlaneDetectorGetInfoEXT, XR_TYPE_PLANE_DETECTOR_GET_INFO_EXT) \ + _(XrPlaneDetectorLocationEXT, XR_TYPE_PLANE_DETECTOR_LOCATION_EXT) \ + _(XrPlaneDetectorLocationsEXT, XR_TYPE_PLANE_DETECTOR_LOCATIONS_EXT) \ + _(XrPlaneDetectorPolygonBufferEXT, XR_TYPE_PLANE_DETECTOR_POLYGON_BUFFER_EXT) \ + + +#if defined(XR_USE_GRAPHICS_API_D3D11) +/// Implementation detail of XR_LIST_STRUCTURE_TYPES() +/// Structure types available only when XR_USE_GRAPHICS_API_D3D11 is defined +#define XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_D3D11(_) \ + _(XrGraphicsBindingD3D11KHR, XR_TYPE_GRAPHICS_BINDING_D3D11_KHR) \ + _(XrSwapchainImageD3D11KHR, XR_TYPE_SWAPCHAIN_IMAGE_D3D11_KHR) \ + _(XrGraphicsRequirementsD3D11KHR, XR_TYPE_GRAPHICS_REQUIREMENTS_D3D11_KHR) \ + +#else +#define XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_D3D11(_) +#endif + +#if defined(XR_USE_GRAPHICS_API_D3D12) +/// Implementation detail of XR_LIST_STRUCTURE_TYPES() +/// Structure types available only when XR_USE_GRAPHICS_API_D3D12 is defined +#define XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_D3D12(_) \ + _(XrGraphicsBindingD3D12KHR, XR_TYPE_GRAPHICS_BINDING_D3D12_KHR) \ + _(XrSwapchainImageD3D12KHR, XR_TYPE_SWAPCHAIN_IMAGE_D3D12_KHR) \ + _(XrGraphicsRequirementsD3D12KHR, XR_TYPE_GRAPHICS_REQUIREMENTS_D3D12_KHR) \ + +#else +#define XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_D3D12(_) +#endif + +#if defined(XR_USE_GRAPHICS_API_OPENGL) +/// Implementation detail of XR_LIST_STRUCTURE_TYPES() +/// Structure types available only when XR_USE_GRAPHICS_API_OPENGL is defined +#define XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL(_) \ + _(XrSwapchainImageOpenGLKHR, XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_KHR) \ + _(XrGraphicsRequirementsOpenGLKHR, XR_TYPE_GRAPHICS_REQUIREMENTS_OPENGL_KHR) \ + +#else +#define XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL(_) +#endif + +#if defined(XR_USE_GRAPHICS_API_OPENGL) && defined(XR_USE_PLATFORM_WAYLAND) +/// Implementation detail of XR_LIST_STRUCTURE_TYPES() +/// Structure types available only when XR_USE_GRAPHICS_API_OPENGL and XR_USE_PLATFORM_WAYLAND are defined +#define XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_XR_USE_PLATFORM_WAYLAND(_) \ + _(XrGraphicsBindingOpenGLWaylandKHR, XR_TYPE_GRAPHICS_BINDING_OPENGL_WAYLAND_KHR) \ + +#else +#define XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_XR_USE_PLATFORM_WAYLAND(_) +#endif + +#if defined(XR_USE_GRAPHICS_API_OPENGL) && defined(XR_USE_PLATFORM_WIN32) +/// Implementation detail of XR_LIST_STRUCTURE_TYPES() +/// Structure types available only when XR_USE_GRAPHICS_API_OPENGL and XR_USE_PLATFORM_WIN32 are defined +#define XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_XR_USE_PLATFORM_WIN32(_) \ + _(XrGraphicsBindingOpenGLWin32KHR, XR_TYPE_GRAPHICS_BINDING_OPENGL_WIN32_KHR) \ + +#else +#define XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_XR_USE_PLATFORM_WIN32(_) +#endif + +#if defined(XR_USE_GRAPHICS_API_OPENGL) && defined(XR_USE_PLATFORM_XCB) +/// Implementation detail of XR_LIST_STRUCTURE_TYPES() +/// Structure types available only when XR_USE_GRAPHICS_API_OPENGL and XR_USE_PLATFORM_XCB are defined +#define XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_XR_USE_PLATFORM_XCB(_) \ + _(XrGraphicsBindingOpenGLXcbKHR, XR_TYPE_GRAPHICS_BINDING_OPENGL_XCB_KHR) \ + +#else +#define XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_XR_USE_PLATFORM_XCB(_) +#endif + +#if defined(XR_USE_GRAPHICS_API_OPENGL) && defined(XR_USE_PLATFORM_XLIB) +/// Implementation detail of XR_LIST_STRUCTURE_TYPES() +/// Structure types available only when XR_USE_GRAPHICS_API_OPENGL and XR_USE_PLATFORM_XLIB are defined +#define XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_XR_USE_PLATFORM_XLIB(_) \ + _(XrGraphicsBindingOpenGLXlibKHR, XR_TYPE_GRAPHICS_BINDING_OPENGL_XLIB_KHR) \ + +#else +#define XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_XR_USE_PLATFORM_XLIB(_) +#endif + +#if defined(XR_USE_GRAPHICS_API_OPENGL_ES) +/// Implementation detail of XR_LIST_STRUCTURE_TYPES() +/// Structure types available only when XR_USE_GRAPHICS_API_OPENGL_ES is defined +#define XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_ES(_) \ + _(XrSwapchainImageOpenGLESKHR, XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_ES_KHR) \ + _(XrGraphicsRequirementsOpenGLESKHR, XR_TYPE_GRAPHICS_REQUIREMENTS_OPENGL_ES_KHR) \ + _(XrSwapchainStateSamplerOpenGLESFB, XR_TYPE_SWAPCHAIN_STATE_SAMPLER_OPENGL_ES_FB) \ + +#else +#define XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_ES(_) +#endif + +#if defined(XR_USE_GRAPHICS_API_OPENGL_ES) && defined(XR_USE_PLATFORM_ANDROID) +/// Implementation detail of XR_LIST_STRUCTURE_TYPES() +/// Structure types available only when XR_USE_GRAPHICS_API_OPENGL_ES and XR_USE_PLATFORM_ANDROID are defined +#define XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_ES_XR_USE_PLATFORM_ANDROID(_) \ + _(XrGraphicsBindingOpenGLESAndroidKHR, XR_TYPE_GRAPHICS_BINDING_OPENGL_ES_ANDROID_KHR) \ + +#else +#define XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_ES_XR_USE_PLATFORM_ANDROID(_) +#endif + +#if defined(XR_USE_GRAPHICS_API_VULKAN) +/// Implementation detail of XR_LIST_STRUCTURE_TYPES() +/// Structure types available only when XR_USE_GRAPHICS_API_VULKAN is defined +#define XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_VULKAN(_) \ + _(XrVulkanSwapchainFormatListCreateInfoKHR, XR_TYPE_VULKAN_SWAPCHAIN_FORMAT_LIST_CREATE_INFO_KHR) \ + _(XrGraphicsBindingVulkanKHR, XR_TYPE_GRAPHICS_BINDING_VULKAN_KHR) \ + _(XrSwapchainImageVulkanKHR, XR_TYPE_SWAPCHAIN_IMAGE_VULKAN_KHR) \ + _(XrGraphicsRequirementsVulkanKHR, XR_TYPE_GRAPHICS_REQUIREMENTS_VULKAN_KHR) \ + _(XrVulkanInstanceCreateInfoKHR, XR_TYPE_VULKAN_INSTANCE_CREATE_INFO_KHR) \ + _(XrVulkanDeviceCreateInfoKHR, XR_TYPE_VULKAN_DEVICE_CREATE_INFO_KHR) \ + _(XrVulkanGraphicsDeviceGetInfoKHR, XR_TYPE_VULKAN_GRAPHICS_DEVICE_GET_INFO_KHR) \ + _(XrSwapchainImageFoveationVulkanFB, XR_TYPE_SWAPCHAIN_IMAGE_FOVEATION_VULKAN_FB) \ + _(XrSwapchainStateSamplerVulkanFB, XR_TYPE_SWAPCHAIN_STATE_SAMPLER_VULKAN_FB) \ + _(XrVulkanSwapchainCreateInfoMETA, XR_TYPE_VULKAN_SWAPCHAIN_CREATE_INFO_META) \ + +#else +#define XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_VULKAN(_) +#endif + +#if defined(XR_USE_PLATFORM_ANDROID) +/// Implementation detail of XR_LIST_STRUCTURE_TYPES() +/// Structure types available only when XR_USE_PLATFORM_ANDROID is defined +#define XR_LIST_STRUCTURE_TYPES_XR_USE_PLATFORM_ANDROID(_) \ + _(XrInstanceCreateInfoAndroidKHR, XR_TYPE_INSTANCE_CREATE_INFO_ANDROID_KHR) \ + _(XrLoaderInitInfoAndroidKHR, XR_TYPE_LOADER_INIT_INFO_ANDROID_KHR) \ + _(XrAndroidSurfaceSwapchainCreateInfoFB, XR_TYPE_ANDROID_SURFACE_SWAPCHAIN_CREATE_INFO_FB) \ + _(XrSwapchainStateAndroidSurfaceDimensionsFB, XR_TYPE_SWAPCHAIN_STATE_ANDROID_SURFACE_DIMENSIONS_FB) \ + +#else +#define XR_LIST_STRUCTURE_TYPES_XR_USE_PLATFORM_ANDROID(_) +#endif + +#if defined(XR_USE_PLATFORM_EGL) +/// Implementation detail of XR_LIST_STRUCTURE_TYPES() +/// Structure types available only when XR_USE_PLATFORM_EGL is defined +#define XR_LIST_STRUCTURE_TYPES_XR_USE_PLATFORM_EGL(_) \ + _(XrGraphicsBindingEGLMNDX, XR_TYPE_GRAPHICS_BINDING_EGL_MNDX) \ + +#else +#define XR_LIST_STRUCTURE_TYPES_XR_USE_PLATFORM_EGL(_) +#endif + +#if defined(XR_USE_PLATFORM_ML) +/// Implementation detail of XR_LIST_STRUCTURE_TYPES() +/// Structure types available only when XR_USE_PLATFORM_ML is defined +#define XR_LIST_STRUCTURE_TYPES_XR_USE_PLATFORM_ML(_) \ + _(XrCoordinateSpaceCreateInfoML, XR_TYPE_COORDINATE_SPACE_CREATE_INFO_ML) \ + +#else +#define XR_LIST_STRUCTURE_TYPES_XR_USE_PLATFORM_ML(_) +#endif + +#if defined(XR_USE_PLATFORM_WIN32) +/// Implementation detail of XR_LIST_STRUCTURE_TYPES() +/// Structure types available only when XR_USE_PLATFORM_WIN32 is defined +#define XR_LIST_STRUCTURE_TYPES_XR_USE_PLATFORM_WIN32(_) \ + _(XrHolographicWindowAttachmentMSFT, XR_TYPE_HOLOGRAPHIC_WINDOW_ATTACHMENT_MSFT) \ + +#else +#define XR_LIST_STRUCTURE_TYPES_XR_USE_PLATFORM_WIN32(_) +#endif + + + +/// Calls your macro with the name and extension number of all known +/// extensions in this version of the spec. +#define XR_LIST_EXTENSIONS(_) \ + _(XR_KHR_android_thread_settings, 4) \ + _(XR_KHR_android_surface_swapchain, 5) \ + _(XR_KHR_composition_layer_cube, 7) \ + _(XR_KHR_android_create_instance, 9) \ + _(XR_KHR_composition_layer_depth, 11) \ + _(XR_KHR_vulkan_swapchain_format_list, 15) \ + _(XR_EXT_performance_settings, 16) \ + _(XR_EXT_thermal_query, 17) \ + _(XR_KHR_composition_layer_cylinder, 18) \ + _(XR_KHR_composition_layer_equirect, 19) \ + _(XR_EXT_debug_utils, 20) \ + _(XR_KHR_opengl_enable, 24) \ + _(XR_KHR_opengl_es_enable, 25) \ + _(XR_KHR_vulkan_enable, 26) \ + _(XR_KHR_D3D11_enable, 28) \ + _(XR_KHR_D3D12_enable, 29) \ + _(XR_EXT_eye_gaze_interaction, 31) \ + _(XR_KHR_visibility_mask, 32) \ + _(XR_EXTX_overlay, 34) \ + _(XR_KHR_composition_layer_color_scale_bias, 35) \ + _(XR_KHR_win32_convert_performance_counter_time, 36) \ + _(XR_KHR_convert_timespec_time, 37) \ + _(XR_VARJO_quad_views, 38) \ + _(XR_MSFT_unbounded_reference_space, 39) \ + _(XR_MSFT_spatial_anchor, 40) \ + _(XR_FB_composition_layer_image_layout, 41) \ + _(XR_FB_composition_layer_alpha_blend, 42) \ + _(XR_MND_headless, 43) \ + _(XR_OCULUS_android_session_state_enable, 45) \ + _(XR_EXT_view_configuration_depth_range, 47) \ + _(XR_EXT_conformance_automation, 48) \ + _(XR_MNDX_egl_enable, 49) \ + _(XR_MSFT_spatial_graph_bridge, 50) \ + _(XR_MSFT_hand_interaction, 51) \ + _(XR_EXT_hand_tracking, 52) \ + _(XR_MSFT_hand_tracking_mesh, 53) \ + _(XR_MSFT_secondary_view_configuration, 54) \ + _(XR_MSFT_first_person_observer, 55) \ + _(XR_MSFT_controller_model, 56) \ + _(XR_MSFT_perception_anchor_interop, 57) \ + _(XR_EXT_win32_appcontainer_compatible, 58) \ + _(XR_EPIC_view_configuration_fov, 60) \ + _(XR_MSFT_holographic_window_attachment, 64) \ + _(XR_MSFT_composition_layer_reprojection, 67) \ + _(XR_HUAWEI_controller_interaction, 70) \ + _(XR_FB_android_surface_swapchain_create, 71) \ + _(XR_FB_swapchain_update_state, 72) \ + _(XR_FB_composition_layer_secure_content, 73) \ + _(XR_FB_body_tracking, 77) \ + _(XR_EXT_dpad_binding, 79) \ + _(XR_VALVE_analog_threshold, 80) \ + _(XR_EXT_hand_joints_motion_range, 81) \ + _(XR_KHR_loader_init, 89) \ + _(XR_KHR_loader_init_android, 90) \ + _(XR_KHR_vulkan_enable2, 91) \ + _(XR_KHR_composition_layer_equirect2, 92) \ + _(XR_EXT_samsung_odyssey_controller, 95) \ + _(XR_EXT_hp_mixed_reality_controller, 96) \ + _(XR_MND_swapchain_usage_input_attachment_bit, 97) \ + _(XR_MSFT_scene_understanding, 98) \ + _(XR_MSFT_scene_understanding_serialization, 99) \ + _(XR_FB_display_refresh_rate, 102) \ + _(XR_HTC_vive_cosmos_controller_interaction, 103) \ + _(XR_HTCX_vive_tracker_interaction, 104) \ + _(XR_HTC_facial_tracking, 105) \ + _(XR_HTC_vive_focus3_controller_interaction, 106) \ + _(XR_HTC_hand_interaction, 107) \ + _(XR_HTC_vive_wrist_tracker_interaction, 108) \ + _(XR_FB_color_space, 109) \ + _(XR_FB_hand_tracking_mesh, 111) \ + _(XR_FB_hand_tracking_aim, 112) \ + _(XR_FB_hand_tracking_capsules, 113) \ + _(XR_FB_spatial_entity, 114) \ + _(XR_FB_foveation, 115) \ + _(XR_FB_foveation_configuration, 116) \ + _(XR_FB_keyboard_tracking, 117) \ + _(XR_FB_triangle_mesh, 118) \ + _(XR_FB_passthrough, 119) \ + _(XR_FB_render_model, 120) \ + _(XR_KHR_binding_modification, 121) \ + _(XR_VARJO_foveated_rendering, 122) \ + _(XR_VARJO_composition_layer_depth_test, 123) \ + _(XR_VARJO_environment_depth_estimation, 124) \ + _(XR_VARJO_marker_tracking, 125) \ + _(XR_VARJO_view_offset, 126) \ + _(XR_ML_ml2_controller_interaction, 135) \ + _(XR_ML_frame_end_info, 136) \ + _(XR_ML_global_dimmer, 137) \ + _(XR_ML_compat, 138) \ + _(XR_MSFT_spatial_anchor_persistence, 143) \ + _(XR_ULTRALEAP_hand_tracking_forearm, 150) \ + _(XR_FB_spatial_entity_query, 157) \ + _(XR_FB_spatial_entity_storage, 159) \ + _(XR_OCULUS_audio_device_guid, 160) \ + _(XR_FB_foveation_vulkan, 161) \ + _(XR_FB_swapchain_update_state_android_surface, 162) \ + _(XR_FB_swapchain_update_state_opengl_es, 163) \ + _(XR_FB_swapchain_update_state_vulkan, 164) \ + _(XR_KHR_swapchain_usage_input_attachment_bit, 166) \ + _(XR_FB_touch_controller_pro, 168) \ + _(XR_FB_spatial_entity_sharing, 170) \ + _(XR_FB_space_warp, 172) \ + _(XR_FB_haptic_amplitude_envelope, 174) \ + _(XR_FB_scene, 176) \ + _(XR_EXT_palm_pose, 177) \ + _(XR_ALMALENCE_digital_lens_control, 197) \ + _(XR_FB_scene_capture, 199) \ + _(XR_FB_spatial_entity_container, 200) \ + _(XR_META_foveation_eye_tracked, 201) \ + _(XR_FB_face_tracking, 202) \ + _(XR_FB_eye_tracking_social, 203) \ + _(XR_FB_passthrough_keyboard_hands, 204) \ + _(XR_FB_composition_layer_settings, 205) \ + _(XR_FB_touch_controller_proximity, 207) \ + _(XR_FB_haptic_pcm, 210) \ + _(XR_FB_composition_layer_depth_test, 213) \ + _(XR_META_local_dimming, 217) \ + _(XR_META_passthrough_preferences, 218) \ + _(XR_META_virtual_keyboard, 220) \ + _(XR_OCULUS_external_camera, 227) \ + _(XR_META_vulkan_swapchain_create_info, 228) \ + _(XR_META_performance_metrics, 233) \ + _(XR_FB_spatial_entity_storage_batch, 239) \ + _(XR_FB_spatial_entity_user, 242) \ + _(XR_META_headset_id, 246) \ + _(XR_META_passthrough_color_lut, 267) \ + _(XR_EXT_uuid, 300) \ + _(XR_EXT_hand_interaction, 303) \ + _(XR_QCOM_tracking_optimization_settings, 307) \ + _(XR_HTC_passthrough, 318) \ + _(XR_HTC_foveation, 319) \ + _(XR_EXT_active_action_set_priority, 374) \ + _(XR_MNDX_force_feedback_curl, 376) \ + _(XR_BD_controller_interaction, 385) \ + _(XR_EXT_local_floor, 427) \ + _(XR_EXT_hand_tracking_data_source, 429) \ + _(XR_EXT_plane_detection, 430) \ + _(XR_OPPO_controller_interaction, 454) \ + + +#endif + diff --git a/Plugins/MetaXR/Source/Thirdparty/KhronosOpenXR/include/khronos/openxr/openxr_reflection_parent_structs.h b/Plugins/MetaXR/Source/Thirdparty/KhronosOpenXR/include/khronos/openxr/openxr_reflection_parent_structs.h new file mode 100644 index 0000000..d0d05e9 --- /dev/null +++ b/Plugins/MetaXR/Source/Thirdparty/KhronosOpenXR/include/khronos/openxr/openxr_reflection_parent_structs.h @@ -0,0 +1,265 @@ +#ifndef OPENXR_REFLECTION_PARENT_STRUCTS_H_ +#define OPENXR_REFLECTION_PARENT_STRUCTS_H_ 1 + +/* +** Copyright (c) 2017-2023, The Khronos Group Inc. +** +** SPDX-License-Identifier: Apache-2.0 OR MIT +*/ + +/* +** This header is generated from the Khronos OpenXR XML API Registry. +** +*/ + +#include "openxr.h" + +/* +This file contains expansion macros (X Macros) for OpenXR structures that have a parent type. +*/ + + +/// Like XR_LIST_ALL_STRUCTURE_TYPES, but only includes types whose parent struct type is XrCompositionLayerBaseHeader +#define XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrCompositionLayerBaseHeader(_avail, _unavail) \ + _impl_XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrCompositionLayerBaseHeader_CORE(_avail, _unavail) \ + + +// Implementation detail of XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrCompositionLayerBaseHeader() +#define _impl_XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrCompositionLayerBaseHeader_CORE(_avail, _unavail) \ + _avail(XrCompositionLayerProjection, XR_TYPE_COMPOSITION_LAYER_PROJECTION) \ + _avail(XrCompositionLayerQuad, XR_TYPE_COMPOSITION_LAYER_QUAD) \ + _avail(XrCompositionLayerCubeKHR, XR_TYPE_COMPOSITION_LAYER_CUBE_KHR) \ + _avail(XrCompositionLayerCylinderKHR, XR_TYPE_COMPOSITION_LAYER_CYLINDER_KHR) \ + _avail(XrCompositionLayerEquirectKHR, XR_TYPE_COMPOSITION_LAYER_EQUIRECT_KHR) \ + _avail(XrCompositionLayerEquirect2KHR, XR_TYPE_COMPOSITION_LAYER_EQUIRECT2_KHR) \ + _avail(XrCompositionLayerPassthroughHTC, XR_TYPE_COMPOSITION_LAYER_PASSTHROUGH_HTC) \ + + + + + +/// Like XR_LIST_ALL_STRUCTURE_TYPES, but only includes types whose parent struct type is XrEventDataBaseHeader +#define XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrEventDataBaseHeader(_avail, _unavail) \ + _impl_XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrEventDataBaseHeader_CORE(_avail, _unavail) \ + + +// Implementation detail of XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrEventDataBaseHeader() +#define _impl_XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrEventDataBaseHeader_CORE(_avail, _unavail) \ + _avail(XrEventDataEventsLost, XR_TYPE_EVENT_DATA_EVENTS_LOST) \ + _avail(XrEventDataInstanceLossPending, XR_TYPE_EVENT_DATA_INSTANCE_LOSS_PENDING) \ + _avail(XrEventDataSessionStateChanged, XR_TYPE_EVENT_DATA_SESSION_STATE_CHANGED) \ + _avail(XrEventDataReferenceSpaceChangePending, XR_TYPE_EVENT_DATA_REFERENCE_SPACE_CHANGE_PENDING) \ + _avail(XrEventDataInteractionProfileChanged, XR_TYPE_EVENT_DATA_INTERACTION_PROFILE_CHANGED) \ + _avail(XrEventDataVisibilityMaskChangedKHR, XR_TYPE_EVENT_DATA_VISIBILITY_MASK_CHANGED_KHR) \ + _avail(XrEventDataPerfSettingsEXT, XR_TYPE_EVENT_DATA_PERF_SETTINGS_EXT) \ + _avail(XrEventDataMainSessionVisibilityChangedEXTX, XR_TYPE_EVENT_DATA_MAIN_SESSION_VISIBILITY_CHANGED_EXTX) \ + _avail(XrEventDataDisplayRefreshRateChangedFB, XR_TYPE_EVENT_DATA_DISPLAY_REFRESH_RATE_CHANGED_FB) \ + _avail(XrEventDataViveTrackerConnectedHTCX, XR_TYPE_EVENT_DATA_VIVE_TRACKER_CONNECTED_HTCX) \ + _avail(XrEventDataSpatialAnchorCreateCompleteFB, XR_TYPE_EVENT_DATA_SPATIAL_ANCHOR_CREATE_COMPLETE_FB) \ + _avail(XrEventDataSpaceSetStatusCompleteFB, XR_TYPE_EVENT_DATA_SPACE_SET_STATUS_COMPLETE_FB) \ + _avail(XrEventDataMarkerTrackingUpdateVARJO, XR_TYPE_EVENT_DATA_MARKER_TRACKING_UPDATE_VARJO) \ + _avail(XrEventDataSpaceQueryResultsAvailableFB, XR_TYPE_EVENT_DATA_SPACE_QUERY_RESULTS_AVAILABLE_FB) \ + _avail(XrEventDataSpaceQueryCompleteFB, XR_TYPE_EVENT_DATA_SPACE_QUERY_COMPLETE_FB) \ + _avail(XrEventDataSpaceSaveCompleteFB, XR_TYPE_EVENT_DATA_SPACE_SAVE_COMPLETE_FB) \ + _avail(XrEventDataSpaceEraseCompleteFB, XR_TYPE_EVENT_DATA_SPACE_ERASE_COMPLETE_FB) \ + _avail(XrEventDataSpaceShareCompleteFB, XR_TYPE_EVENT_DATA_SPACE_SHARE_COMPLETE_FB) \ + _avail(XrEventDataSpaceListSaveCompleteFB, XR_TYPE_EVENT_DATA_SPACE_LIST_SAVE_COMPLETE_FB) \ + + + + + +/// Like XR_LIST_ALL_STRUCTURE_TYPES, but only includes types whose parent struct type is XrHapticBaseHeader +#define XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrHapticBaseHeader(_avail, _unavail) \ + _impl_XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrHapticBaseHeader_CORE(_avail, _unavail) \ + + +// Implementation detail of XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrHapticBaseHeader() +#define _impl_XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrHapticBaseHeader_CORE(_avail, _unavail) \ + _avail(XrHapticVibration, XR_TYPE_HAPTIC_VIBRATION) \ + _avail(XrHapticAmplitudeEnvelopeVibrationFB, XR_TYPE_HAPTIC_AMPLITUDE_ENVELOPE_VIBRATION_FB) \ + _avail(XrHapticPcmVibrationFB, XR_TYPE_HAPTIC_PCM_VIBRATION_FB) \ + + + + + +/// Like XR_LIST_ALL_STRUCTURE_TYPES, but only includes types whose parent struct type is XrSwapchainImageBaseHeader +#define XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrSwapchainImageBaseHeader(_avail, _unavail) \ + _impl_XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrSwapchainImageBaseHeader_CORE(_avail, _unavail) \ + _impl_XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrSwapchainImageBaseHeader_XR_USE_GRAPHICS_API_D3D11(_avail, _unavail) \ + _impl_XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrSwapchainImageBaseHeader_XR_USE_GRAPHICS_API_D3D12(_avail, _unavail) \ + _impl_XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrSwapchainImageBaseHeader_XR_USE_GRAPHICS_API_OPENGL(_avail, _unavail) \ + _impl_XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrSwapchainImageBaseHeader_XR_USE_GRAPHICS_API_OPENGL_ES(_avail, _unavail) \ + _impl_XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrSwapchainImageBaseHeader_XR_USE_GRAPHICS_API_VULKAN(_avail, _unavail) \ + + +// Implementation detail of XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrSwapchainImageBaseHeader() +#define _impl_XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrSwapchainImageBaseHeader_CORE(_avail, _unavail) \ + + +#if defined(XR_USE_GRAPHICS_API_D3D11) +#define _impl_XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrSwapchainImageBaseHeader_XR_USE_GRAPHICS_API_D3D11(_avail, _unavail) \ + _avail(XrSwapchainImageD3D11KHR, XR_TYPE_SWAPCHAIN_IMAGE_D3D11_KHR) \ + +#else +#define _impl_XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrSwapchainImageBaseHeader_XR_USE_GRAPHICS_API_D3D11(_avail, _unavail) \ + _unavail(XrSwapchainImageD3D11KHR, XR_TYPE_SWAPCHAIN_IMAGE_D3D11_KHR) \ + +#endif + +#if defined(XR_USE_GRAPHICS_API_D3D12) +#define _impl_XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrSwapchainImageBaseHeader_XR_USE_GRAPHICS_API_D3D12(_avail, _unavail) \ + _avail(XrSwapchainImageD3D12KHR, XR_TYPE_SWAPCHAIN_IMAGE_D3D12_KHR) \ + +#else +#define _impl_XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrSwapchainImageBaseHeader_XR_USE_GRAPHICS_API_D3D12(_avail, _unavail) \ + _unavail(XrSwapchainImageD3D12KHR, XR_TYPE_SWAPCHAIN_IMAGE_D3D12_KHR) \ + +#endif + +#if defined(XR_USE_GRAPHICS_API_OPENGL) +#define _impl_XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrSwapchainImageBaseHeader_XR_USE_GRAPHICS_API_OPENGL(_avail, _unavail) \ + _avail(XrSwapchainImageOpenGLKHR, XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_KHR) \ + +#else +#define _impl_XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrSwapchainImageBaseHeader_XR_USE_GRAPHICS_API_OPENGL(_avail, _unavail) \ + _unavail(XrSwapchainImageOpenGLKHR, XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_KHR) \ + +#endif + +#if defined(XR_USE_GRAPHICS_API_OPENGL_ES) +#define _impl_XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrSwapchainImageBaseHeader_XR_USE_GRAPHICS_API_OPENGL_ES(_avail, _unavail) \ + _avail(XrSwapchainImageOpenGLESKHR, XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_ES_KHR) \ + +#else +#define _impl_XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrSwapchainImageBaseHeader_XR_USE_GRAPHICS_API_OPENGL_ES(_avail, _unavail) \ + _unavail(XrSwapchainImageOpenGLESKHR, XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_ES_KHR) \ + +#endif + +#if defined(XR_USE_GRAPHICS_API_VULKAN) +#define _impl_XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrSwapchainImageBaseHeader_XR_USE_GRAPHICS_API_VULKAN(_avail, _unavail) \ + _avail(XrSwapchainImageVulkanKHR, XR_TYPE_SWAPCHAIN_IMAGE_VULKAN_KHR) \ + +#else +#define _impl_XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrSwapchainImageBaseHeader_XR_USE_GRAPHICS_API_VULKAN(_avail, _unavail) \ + _unavail(XrSwapchainImageVulkanKHR, XR_TYPE_SWAPCHAIN_IMAGE_VULKAN_KHR) \ + +#endif + + + + +/// Like XR_LIST_ALL_STRUCTURE_TYPES, but only includes types whose parent struct type is XrLoaderInitInfoBaseHeaderKHR +#define XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrLoaderInitInfoBaseHeaderKHR(_avail, _unavail) \ + _impl_XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrLoaderInitInfoBaseHeaderKHR_CORE(_avail, _unavail) \ + _impl_XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrLoaderInitInfoBaseHeaderKHR_XR_USE_PLATFORM_ANDROID(_avail, _unavail) \ + + +// Implementation detail of XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrLoaderInitInfoBaseHeaderKHR() +#define _impl_XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrLoaderInitInfoBaseHeaderKHR_CORE(_avail, _unavail) \ + + +#if defined(XR_USE_PLATFORM_ANDROID) +#define _impl_XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrLoaderInitInfoBaseHeaderKHR_XR_USE_PLATFORM_ANDROID(_avail, _unavail) \ + _avail(XrLoaderInitInfoAndroidKHR, XR_TYPE_LOADER_INIT_INFO_ANDROID_KHR) \ + +#else +#define _impl_XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrLoaderInitInfoBaseHeaderKHR_XR_USE_PLATFORM_ANDROID(_avail, _unavail) \ + _unavail(XrLoaderInitInfoAndroidKHR, XR_TYPE_LOADER_INIT_INFO_ANDROID_KHR) \ + +#endif + + + + +/// Like XR_LIST_ALL_STRUCTURE_TYPES, but only includes types whose parent struct type is XrBindingModificationBaseHeaderKHR +#define XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrBindingModificationBaseHeaderKHR(_avail, _unavail) \ + _impl_XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrBindingModificationBaseHeaderKHR_CORE(_avail, _unavail) \ + + +// Implementation detail of XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrBindingModificationBaseHeaderKHR() +#define _impl_XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrBindingModificationBaseHeaderKHR_CORE(_avail, _unavail) \ + _avail(XrInteractionProfileDpadBindingEXT, XR_TYPE_INTERACTION_PROFILE_DPAD_BINDING_EXT) \ + _avail(XrInteractionProfileAnalogThresholdVALVE, XR_TYPE_INTERACTION_PROFILE_ANALOG_THRESHOLD_VALVE) \ + + + + + +/// Like XR_LIST_ALL_STRUCTURE_TYPES, but only includes types whose parent struct type is XrSwapchainStateBaseHeaderFB +#define XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrSwapchainStateBaseHeaderFB(_avail, _unavail) \ + _impl_XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrSwapchainStateBaseHeaderFB_CORE(_avail, _unavail) \ + _impl_XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrSwapchainStateBaseHeaderFB_XR_USE_GRAPHICS_API_OPENGL_ES(_avail, _unavail) \ + _impl_XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrSwapchainStateBaseHeaderFB_XR_USE_GRAPHICS_API_VULKAN(_avail, _unavail) \ + _impl_XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrSwapchainStateBaseHeaderFB_XR_USE_PLATFORM_ANDROID(_avail, _unavail) \ + + +// Implementation detail of XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrSwapchainStateBaseHeaderFB() +#define _impl_XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrSwapchainStateBaseHeaderFB_CORE(_avail, _unavail) \ + _avail(XrSwapchainStateFoveationFB, XR_TYPE_SWAPCHAIN_STATE_FOVEATION_FB) \ + + +#if defined(XR_USE_GRAPHICS_API_OPENGL_ES) +#define _impl_XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrSwapchainStateBaseHeaderFB_XR_USE_GRAPHICS_API_OPENGL_ES(_avail, _unavail) \ + _avail(XrSwapchainStateSamplerOpenGLESFB, XR_TYPE_SWAPCHAIN_STATE_SAMPLER_OPENGL_ES_FB) \ + +#else +#define _impl_XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrSwapchainStateBaseHeaderFB_XR_USE_GRAPHICS_API_OPENGL_ES(_avail, _unavail) \ + _unavail(XrSwapchainStateSamplerOpenGLESFB, XR_TYPE_SWAPCHAIN_STATE_SAMPLER_OPENGL_ES_FB) \ + +#endif + +#if defined(XR_USE_GRAPHICS_API_VULKAN) +#define _impl_XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrSwapchainStateBaseHeaderFB_XR_USE_GRAPHICS_API_VULKAN(_avail, _unavail) \ + _avail(XrSwapchainStateSamplerVulkanFB, XR_TYPE_SWAPCHAIN_STATE_SAMPLER_VULKAN_FB) \ + +#else +#define _impl_XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrSwapchainStateBaseHeaderFB_XR_USE_GRAPHICS_API_VULKAN(_avail, _unavail) \ + _unavail(XrSwapchainStateSamplerVulkanFB, XR_TYPE_SWAPCHAIN_STATE_SAMPLER_VULKAN_FB) \ + +#endif + +#if defined(XR_USE_PLATFORM_ANDROID) +#define _impl_XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrSwapchainStateBaseHeaderFB_XR_USE_PLATFORM_ANDROID(_avail, _unavail) \ + _avail(XrSwapchainStateAndroidSurfaceDimensionsFB, XR_TYPE_SWAPCHAIN_STATE_ANDROID_SURFACE_DIMENSIONS_FB) \ + +#else +#define _impl_XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrSwapchainStateBaseHeaderFB_XR_USE_PLATFORM_ANDROID(_avail, _unavail) \ + _unavail(XrSwapchainStateAndroidSurfaceDimensionsFB, XR_TYPE_SWAPCHAIN_STATE_ANDROID_SURFACE_DIMENSIONS_FB) \ + +#endif + + + + +/// Like XR_LIST_ALL_STRUCTURE_TYPES, but only includes types whose parent struct type is XrSpaceQueryInfoBaseHeaderFB +#define XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrSpaceQueryInfoBaseHeaderFB(_avail, _unavail) \ + _impl_XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrSpaceQueryInfoBaseHeaderFB_CORE(_avail, _unavail) \ + + +// Implementation detail of XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrSpaceQueryInfoBaseHeaderFB() +#define _impl_XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrSpaceQueryInfoBaseHeaderFB_CORE(_avail, _unavail) \ + _avail(XrSpaceQueryInfoFB, XR_TYPE_SPACE_QUERY_INFO_FB) \ + + + + + +/// Like XR_LIST_ALL_STRUCTURE_TYPES, but only includes types whose parent struct type is XrSpaceFilterInfoBaseHeaderFB +#define XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrSpaceFilterInfoBaseHeaderFB(_avail, _unavail) \ + _impl_XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrSpaceFilterInfoBaseHeaderFB_CORE(_avail, _unavail) \ + + +// Implementation detail of XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrSpaceFilterInfoBaseHeaderFB() +#define _impl_XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrSpaceFilterInfoBaseHeaderFB_CORE(_avail, _unavail) \ + _avail(XrSpaceUuidFilterInfoFB, XR_TYPE_SPACE_UUID_FILTER_INFO_FB) \ + _avail(XrSpaceComponentFilterInfoFB, XR_TYPE_SPACE_COMPONENT_FILTER_INFO_FB) \ + + + + + +#endif + diff --git a/Plugins/MetaXR/Source/Thirdparty/KhronosOpenXR/include/khronos/openxr/openxr_reflection_structs.h b/Plugins/MetaXR/Source/Thirdparty/KhronosOpenXR/include/khronos/openxr/openxr_reflection_structs.h new file mode 100644 index 0000000..7028a6e --- /dev/null +++ b/Plugins/MetaXR/Source/Thirdparty/KhronosOpenXR/include/khronos/openxr/openxr_reflection_structs.h @@ -0,0 +1,502 @@ +#ifndef OPENXR_REFLECTION_STRUCTS_H_ +#define OPENXR_REFLECTION_STRUCTS_H_ 1 + +/* +** Copyright (c) 2017-2023, The Khronos Group Inc. +** +** SPDX-License-Identifier: Apache-2.0 OR MIT +*/ + +/* +** This header is generated from the Khronos OpenXR XML API Registry. +** +*/ + +#include "openxr.h" + +/* +This file contains expansion macros (X Macros) for OpenXR structures. +*/ + + + +/// Calls one of your macros with the structure type name and the XrStructureType constant for +/// each known structure type. The first macro (_avail) is called for those that are available, +/// while the second macro (_unavail) is called for those unavailable due to preprocessor definitions. +#define XR_LIST_ALL_STRUCTURE_TYPES(_avail, _unavail) \ + _impl_XR_LIST_ALL_STRUCTURE_TYPES_CORE(_avail, _unavail) \ + _impl_XR_LIST_ALL_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_D3D11(_avail, _unavail) \ + _impl_XR_LIST_ALL_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_D3D12(_avail, _unavail) \ + _impl_XR_LIST_ALL_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL(_avail, _unavail) \ + _impl_XR_LIST_ALL_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_XR_USE_PLATFORM_WAYLAND(_avail, _unavail) \ + _impl_XR_LIST_ALL_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_XR_USE_PLATFORM_WIN32(_avail, _unavail) \ + _impl_XR_LIST_ALL_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_XR_USE_PLATFORM_XCB(_avail, _unavail) \ + _impl_XR_LIST_ALL_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_XR_USE_PLATFORM_XLIB(_avail, _unavail) \ + _impl_XR_LIST_ALL_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_ES(_avail, _unavail) \ + _impl_XR_LIST_ALL_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_ES_XR_USE_PLATFORM_ANDROID(_avail, _unavail) \ + _impl_XR_LIST_ALL_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_VULKAN(_avail, _unavail) \ + _impl_XR_LIST_ALL_STRUCTURE_TYPES_XR_USE_PLATFORM_ANDROID(_avail, _unavail) \ + _impl_XR_LIST_ALL_STRUCTURE_TYPES_XR_USE_PLATFORM_EGL(_avail, _unavail) \ + _impl_XR_LIST_ALL_STRUCTURE_TYPES_XR_USE_PLATFORM_ML(_avail, _unavail) \ + _impl_XR_LIST_ALL_STRUCTURE_TYPES_XR_USE_PLATFORM_WIN32(_avail, _unavail) \ + + +// Implementation detail of XR_LIST_ALL_STRUCTURE_TYPES() +#define _impl_XR_LIST_ALL_STRUCTURE_TYPES_CORE(_avail, _unavail) \ + _avail(XrApiLayerProperties, XR_TYPE_API_LAYER_PROPERTIES) \ + _avail(XrExtensionProperties, XR_TYPE_EXTENSION_PROPERTIES) \ + _avail(XrInstanceCreateInfo, XR_TYPE_INSTANCE_CREATE_INFO) \ + _avail(XrInstanceProperties, XR_TYPE_INSTANCE_PROPERTIES) \ + _avail(XrEventDataBuffer, XR_TYPE_EVENT_DATA_BUFFER) \ + _avail(XrSystemGetInfo, XR_TYPE_SYSTEM_GET_INFO) \ + _avail(XrSystemProperties, XR_TYPE_SYSTEM_PROPERTIES) \ + _avail(XrSessionCreateInfo, XR_TYPE_SESSION_CREATE_INFO) \ + _avail(XrSpaceVelocity, XR_TYPE_SPACE_VELOCITY) \ + _avail(XrReferenceSpaceCreateInfo, XR_TYPE_REFERENCE_SPACE_CREATE_INFO) \ + _avail(XrActionSpaceCreateInfo, XR_TYPE_ACTION_SPACE_CREATE_INFO) \ + _avail(XrSpaceLocation, XR_TYPE_SPACE_LOCATION) \ + _avail(XrViewConfigurationProperties, XR_TYPE_VIEW_CONFIGURATION_PROPERTIES) \ + _avail(XrViewConfigurationView, XR_TYPE_VIEW_CONFIGURATION_VIEW) \ + _avail(XrSwapchainCreateInfo, XR_TYPE_SWAPCHAIN_CREATE_INFO) \ + _avail(XrSwapchainImageAcquireInfo, XR_TYPE_SWAPCHAIN_IMAGE_ACQUIRE_INFO) \ + _avail(XrSwapchainImageWaitInfo, XR_TYPE_SWAPCHAIN_IMAGE_WAIT_INFO) \ + _avail(XrSwapchainImageReleaseInfo, XR_TYPE_SWAPCHAIN_IMAGE_RELEASE_INFO) \ + _avail(XrSessionBeginInfo, XR_TYPE_SESSION_BEGIN_INFO) \ + _avail(XrFrameWaitInfo, XR_TYPE_FRAME_WAIT_INFO) \ + _avail(XrFrameState, XR_TYPE_FRAME_STATE) \ + _avail(XrFrameBeginInfo, XR_TYPE_FRAME_BEGIN_INFO) \ + _avail(XrFrameEndInfo, XR_TYPE_FRAME_END_INFO) \ + _avail(XrViewLocateInfo, XR_TYPE_VIEW_LOCATE_INFO) \ + _avail(XrViewState, XR_TYPE_VIEW_STATE) \ + _avail(XrView, XR_TYPE_VIEW) \ + _avail(XrActionSetCreateInfo, XR_TYPE_ACTION_SET_CREATE_INFO) \ + _avail(XrActionCreateInfo, XR_TYPE_ACTION_CREATE_INFO) \ + _avail(XrInteractionProfileSuggestedBinding, XR_TYPE_INTERACTION_PROFILE_SUGGESTED_BINDING) \ + _avail(XrSessionActionSetsAttachInfo, XR_TYPE_SESSION_ACTION_SETS_ATTACH_INFO) \ + _avail(XrInteractionProfileState, XR_TYPE_INTERACTION_PROFILE_STATE) \ + _avail(XrActionStateGetInfo, XR_TYPE_ACTION_STATE_GET_INFO) \ + _avail(XrActionStateBoolean, XR_TYPE_ACTION_STATE_BOOLEAN) \ + _avail(XrActionStateFloat, XR_TYPE_ACTION_STATE_FLOAT) \ + _avail(XrActionStateVector2f, XR_TYPE_ACTION_STATE_VECTOR2F) \ + _avail(XrActionStatePose, XR_TYPE_ACTION_STATE_POSE) \ + _avail(XrActionsSyncInfo, XR_TYPE_ACTIONS_SYNC_INFO) \ + _avail(XrBoundSourcesForActionEnumerateInfo, XR_TYPE_BOUND_SOURCES_FOR_ACTION_ENUMERATE_INFO) \ + _avail(XrInputSourceLocalizedNameGetInfo, XR_TYPE_INPUT_SOURCE_LOCALIZED_NAME_GET_INFO) \ + _avail(XrHapticActionInfo, XR_TYPE_HAPTIC_ACTION_INFO) \ + _avail(XrCompositionLayerProjectionView, XR_TYPE_COMPOSITION_LAYER_PROJECTION_VIEW) \ + _avail(XrCompositionLayerProjection, XR_TYPE_COMPOSITION_LAYER_PROJECTION) \ + _avail(XrCompositionLayerQuad, XR_TYPE_COMPOSITION_LAYER_QUAD) \ + _avail(XrEventDataEventsLost, XR_TYPE_EVENT_DATA_EVENTS_LOST) \ + _avail(XrEventDataInstanceLossPending, XR_TYPE_EVENT_DATA_INSTANCE_LOSS_PENDING) \ + _avail(XrEventDataSessionStateChanged, XR_TYPE_EVENT_DATA_SESSION_STATE_CHANGED) \ + _avail(XrEventDataReferenceSpaceChangePending, XR_TYPE_EVENT_DATA_REFERENCE_SPACE_CHANGE_PENDING) \ + _avail(XrEventDataInteractionProfileChanged, XR_TYPE_EVENT_DATA_INTERACTION_PROFILE_CHANGED) \ + _avail(XrHapticVibration, XR_TYPE_HAPTIC_VIBRATION) \ + _avail(XrCompositionLayerCubeKHR, XR_TYPE_COMPOSITION_LAYER_CUBE_KHR) \ + _avail(XrCompositionLayerDepthInfoKHR, XR_TYPE_COMPOSITION_LAYER_DEPTH_INFO_KHR) \ + _avail(XrCompositionLayerCylinderKHR, XR_TYPE_COMPOSITION_LAYER_CYLINDER_KHR) \ + _avail(XrCompositionLayerEquirectKHR, XR_TYPE_COMPOSITION_LAYER_EQUIRECT_KHR) \ + _avail(XrVisibilityMaskKHR, XR_TYPE_VISIBILITY_MASK_KHR) \ + _avail(XrEventDataVisibilityMaskChangedKHR, XR_TYPE_EVENT_DATA_VISIBILITY_MASK_CHANGED_KHR) \ + _avail(XrCompositionLayerColorScaleBiasKHR, XR_TYPE_COMPOSITION_LAYER_COLOR_SCALE_BIAS_KHR) \ + _avail(XrCompositionLayerEquirect2KHR, XR_TYPE_COMPOSITION_LAYER_EQUIRECT2_KHR) \ + _avail(XrBindingModificationsKHR, XR_TYPE_BINDING_MODIFICATIONS_KHR) \ + _avail(XrEventDataPerfSettingsEXT, XR_TYPE_EVENT_DATA_PERF_SETTINGS_EXT) \ + _avail(XrDebugUtilsObjectNameInfoEXT, XR_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT) \ + _avail(XrDebugUtilsLabelEXT, XR_TYPE_DEBUG_UTILS_LABEL_EXT) \ + _avail(XrDebugUtilsMessengerCallbackDataEXT, XR_TYPE_DEBUG_UTILS_MESSENGER_CALLBACK_DATA_EXT) \ + _avail(XrDebugUtilsMessengerCreateInfoEXT, XR_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT) \ + _avail(XrSystemEyeGazeInteractionPropertiesEXT, XR_TYPE_SYSTEM_EYE_GAZE_INTERACTION_PROPERTIES_EXT) \ + _avail(XrEyeGazeSampleTimeEXT, XR_TYPE_EYE_GAZE_SAMPLE_TIME_EXT) \ + _avail(XrSessionCreateInfoOverlayEXTX, XR_TYPE_SESSION_CREATE_INFO_OVERLAY_EXTX) \ + _avail(XrEventDataMainSessionVisibilityChangedEXTX, XR_TYPE_EVENT_DATA_MAIN_SESSION_VISIBILITY_CHANGED_EXTX) \ + _avail(XrSpatialAnchorCreateInfoMSFT, XR_TYPE_SPATIAL_ANCHOR_CREATE_INFO_MSFT) \ + _avail(XrSpatialAnchorSpaceCreateInfoMSFT, XR_TYPE_SPATIAL_ANCHOR_SPACE_CREATE_INFO_MSFT) \ + _avail(XrCompositionLayerImageLayoutFB, XR_TYPE_COMPOSITION_LAYER_IMAGE_LAYOUT_FB) \ + _avail(XrCompositionLayerAlphaBlendFB, XR_TYPE_COMPOSITION_LAYER_ALPHA_BLEND_FB) \ + _avail(XrViewConfigurationDepthRangeEXT, XR_TYPE_VIEW_CONFIGURATION_DEPTH_RANGE_EXT) \ + _avail(XrSpatialGraphNodeSpaceCreateInfoMSFT, XR_TYPE_SPATIAL_GRAPH_NODE_SPACE_CREATE_INFO_MSFT) \ + _avail(XrSpatialGraphStaticNodeBindingCreateInfoMSFT, XR_TYPE_SPATIAL_GRAPH_STATIC_NODE_BINDING_CREATE_INFO_MSFT) \ + _avail(XrSpatialGraphNodeBindingPropertiesGetInfoMSFT, XR_TYPE_SPATIAL_GRAPH_NODE_BINDING_PROPERTIES_GET_INFO_MSFT) \ + _avail(XrSpatialGraphNodeBindingPropertiesMSFT, XR_TYPE_SPATIAL_GRAPH_NODE_BINDING_PROPERTIES_MSFT) \ + _avail(XrSystemHandTrackingPropertiesEXT, XR_TYPE_SYSTEM_HAND_TRACKING_PROPERTIES_EXT) \ + _avail(XrHandTrackerCreateInfoEXT, XR_TYPE_HAND_TRACKER_CREATE_INFO_EXT) \ + _avail(XrHandJointsLocateInfoEXT, XR_TYPE_HAND_JOINTS_LOCATE_INFO_EXT) \ + _avail(XrHandJointLocationsEXT, XR_TYPE_HAND_JOINT_LOCATIONS_EXT) \ + _avail(XrHandJointVelocitiesEXT, XR_TYPE_HAND_JOINT_VELOCITIES_EXT) \ + _avail(XrSystemHandTrackingMeshPropertiesMSFT, XR_TYPE_SYSTEM_HAND_TRACKING_MESH_PROPERTIES_MSFT) \ + _avail(XrHandMeshSpaceCreateInfoMSFT, XR_TYPE_HAND_MESH_SPACE_CREATE_INFO_MSFT) \ + _avail(XrHandMeshUpdateInfoMSFT, XR_TYPE_HAND_MESH_UPDATE_INFO_MSFT) \ + _avail(XrHandMeshMSFT, XR_TYPE_HAND_MESH_MSFT) \ + _avail(XrHandPoseTypeInfoMSFT, XR_TYPE_HAND_POSE_TYPE_INFO_MSFT) \ + _avail(XrSecondaryViewConfigurationSessionBeginInfoMSFT, XR_TYPE_SECONDARY_VIEW_CONFIGURATION_SESSION_BEGIN_INFO_MSFT) \ + _avail(XrSecondaryViewConfigurationStateMSFT, XR_TYPE_SECONDARY_VIEW_CONFIGURATION_STATE_MSFT) \ + _avail(XrSecondaryViewConfigurationFrameStateMSFT, XR_TYPE_SECONDARY_VIEW_CONFIGURATION_FRAME_STATE_MSFT) \ + _avail(XrSecondaryViewConfigurationLayerInfoMSFT, XR_TYPE_SECONDARY_VIEW_CONFIGURATION_LAYER_INFO_MSFT) \ + _avail(XrSecondaryViewConfigurationFrameEndInfoMSFT, XR_TYPE_SECONDARY_VIEW_CONFIGURATION_FRAME_END_INFO_MSFT) \ + _avail(XrSecondaryViewConfigurationSwapchainCreateInfoMSFT, XR_TYPE_SECONDARY_VIEW_CONFIGURATION_SWAPCHAIN_CREATE_INFO_MSFT) \ + _avail(XrControllerModelKeyStateMSFT, XR_TYPE_CONTROLLER_MODEL_KEY_STATE_MSFT) \ + _avail(XrControllerModelNodePropertiesMSFT, XR_TYPE_CONTROLLER_MODEL_NODE_PROPERTIES_MSFT) \ + _avail(XrControllerModelPropertiesMSFT, XR_TYPE_CONTROLLER_MODEL_PROPERTIES_MSFT) \ + _avail(XrControllerModelNodeStateMSFT, XR_TYPE_CONTROLLER_MODEL_NODE_STATE_MSFT) \ + _avail(XrControllerModelStateMSFT, XR_TYPE_CONTROLLER_MODEL_STATE_MSFT) \ + _avail(XrViewConfigurationViewFovEPIC, XR_TYPE_VIEW_CONFIGURATION_VIEW_FOV_EPIC) \ + _avail(XrCompositionLayerReprojectionInfoMSFT, XR_TYPE_COMPOSITION_LAYER_REPROJECTION_INFO_MSFT) \ + _avail(XrCompositionLayerReprojectionPlaneOverrideMSFT, XR_TYPE_COMPOSITION_LAYER_REPROJECTION_PLANE_OVERRIDE_MSFT) \ + _avail(XrCompositionLayerSecureContentFB, XR_TYPE_COMPOSITION_LAYER_SECURE_CONTENT_FB) \ + _avail(XrSystemBodyTrackingPropertiesFB, XR_TYPE_SYSTEM_BODY_TRACKING_PROPERTIES_FB) \ + _avail(XrBodyTrackerCreateInfoFB, XR_TYPE_BODY_TRACKER_CREATE_INFO_FB) \ + _avail(XrBodySkeletonFB, XR_TYPE_BODY_SKELETON_FB) \ + _avail(XrBodyJointsLocateInfoFB, XR_TYPE_BODY_JOINTS_LOCATE_INFO_FB) \ + _avail(XrBodyJointLocationsFB, XR_TYPE_BODY_JOINT_LOCATIONS_FB) \ + _avail(XrInteractionProfileDpadBindingEXT, XR_TYPE_INTERACTION_PROFILE_DPAD_BINDING_EXT) \ + _avail(XrInteractionProfileAnalogThresholdVALVE, XR_TYPE_INTERACTION_PROFILE_ANALOG_THRESHOLD_VALVE) \ + _avail(XrHandJointsMotionRangeInfoEXT, XR_TYPE_HAND_JOINTS_MOTION_RANGE_INFO_EXT) \ + _avail(XrSceneObserverCreateInfoMSFT, XR_TYPE_SCENE_OBSERVER_CREATE_INFO_MSFT) \ + _avail(XrSceneCreateInfoMSFT, XR_TYPE_SCENE_CREATE_INFO_MSFT) \ + _avail(XrNewSceneComputeInfoMSFT, XR_TYPE_NEW_SCENE_COMPUTE_INFO_MSFT) \ + _avail(XrVisualMeshComputeLodInfoMSFT, XR_TYPE_VISUAL_MESH_COMPUTE_LOD_INFO_MSFT) \ + _avail(XrSceneComponentsMSFT, XR_TYPE_SCENE_COMPONENTS_MSFT) \ + _avail(XrSceneComponentsGetInfoMSFT, XR_TYPE_SCENE_COMPONENTS_GET_INFO_MSFT) \ + _avail(XrSceneComponentLocationsMSFT, XR_TYPE_SCENE_COMPONENT_LOCATIONS_MSFT) \ + _avail(XrSceneComponentsLocateInfoMSFT, XR_TYPE_SCENE_COMPONENTS_LOCATE_INFO_MSFT) \ + _avail(XrSceneObjectsMSFT, XR_TYPE_SCENE_OBJECTS_MSFT) \ + _avail(XrSceneComponentParentFilterInfoMSFT, XR_TYPE_SCENE_COMPONENT_PARENT_FILTER_INFO_MSFT) \ + _avail(XrSceneObjectTypesFilterInfoMSFT, XR_TYPE_SCENE_OBJECT_TYPES_FILTER_INFO_MSFT) \ + _avail(XrScenePlanesMSFT, XR_TYPE_SCENE_PLANES_MSFT) \ + _avail(XrScenePlaneAlignmentFilterInfoMSFT, XR_TYPE_SCENE_PLANE_ALIGNMENT_FILTER_INFO_MSFT) \ + _avail(XrSceneMeshesMSFT, XR_TYPE_SCENE_MESHES_MSFT) \ + _avail(XrSceneMeshBuffersGetInfoMSFT, XR_TYPE_SCENE_MESH_BUFFERS_GET_INFO_MSFT) \ + _avail(XrSceneMeshBuffersMSFT, XR_TYPE_SCENE_MESH_BUFFERS_MSFT) \ + _avail(XrSceneMeshVertexBufferMSFT, XR_TYPE_SCENE_MESH_VERTEX_BUFFER_MSFT) \ + _avail(XrSceneMeshIndicesUint32MSFT, XR_TYPE_SCENE_MESH_INDICES_UINT32_MSFT) \ + _avail(XrSceneMeshIndicesUint16MSFT, XR_TYPE_SCENE_MESH_INDICES_UINT16_MSFT) \ + _avail(XrSerializedSceneFragmentDataGetInfoMSFT, XR_TYPE_SERIALIZED_SCENE_FRAGMENT_DATA_GET_INFO_MSFT) \ + _avail(XrSceneDeserializeInfoMSFT, XR_TYPE_SCENE_DESERIALIZE_INFO_MSFT) \ + _avail(XrEventDataDisplayRefreshRateChangedFB, XR_TYPE_EVENT_DATA_DISPLAY_REFRESH_RATE_CHANGED_FB) \ + _avail(XrViveTrackerPathsHTCX, XR_TYPE_VIVE_TRACKER_PATHS_HTCX) \ + _avail(XrEventDataViveTrackerConnectedHTCX, XR_TYPE_EVENT_DATA_VIVE_TRACKER_CONNECTED_HTCX) \ + _avail(XrSystemFacialTrackingPropertiesHTC, XR_TYPE_SYSTEM_FACIAL_TRACKING_PROPERTIES_HTC) \ + _avail(XrFacialExpressionsHTC, XR_TYPE_FACIAL_EXPRESSIONS_HTC) \ + _avail(XrFacialTrackerCreateInfoHTC, XR_TYPE_FACIAL_TRACKER_CREATE_INFO_HTC) \ + _avail(XrSystemColorSpacePropertiesFB, XR_TYPE_SYSTEM_COLOR_SPACE_PROPERTIES_FB) \ + _avail(XrHandTrackingMeshFB, XR_TYPE_HAND_TRACKING_MESH_FB) \ + _avail(XrHandTrackingScaleFB, XR_TYPE_HAND_TRACKING_SCALE_FB) \ + _avail(XrHandTrackingAimStateFB, XR_TYPE_HAND_TRACKING_AIM_STATE_FB) \ + _avail(XrHandTrackingCapsulesStateFB, XR_TYPE_HAND_TRACKING_CAPSULES_STATE_FB) \ + _avail(XrSystemSpatialEntityPropertiesFB, XR_TYPE_SYSTEM_SPATIAL_ENTITY_PROPERTIES_FB) \ + _avail(XrSpatialAnchorCreateInfoFB, XR_TYPE_SPATIAL_ANCHOR_CREATE_INFO_FB) \ + _avail(XrSpaceComponentStatusSetInfoFB, XR_TYPE_SPACE_COMPONENT_STATUS_SET_INFO_FB) \ + _avail(XrSpaceComponentStatusFB, XR_TYPE_SPACE_COMPONENT_STATUS_FB) \ + _avail(XrEventDataSpatialAnchorCreateCompleteFB, XR_TYPE_EVENT_DATA_SPATIAL_ANCHOR_CREATE_COMPLETE_FB) \ + _avail(XrEventDataSpaceSetStatusCompleteFB, XR_TYPE_EVENT_DATA_SPACE_SET_STATUS_COMPLETE_FB) \ + _avail(XrFoveationProfileCreateInfoFB, XR_TYPE_FOVEATION_PROFILE_CREATE_INFO_FB) \ + _avail(XrSwapchainCreateInfoFoveationFB, XR_TYPE_SWAPCHAIN_CREATE_INFO_FOVEATION_FB) \ + _avail(XrSwapchainStateFoveationFB, XR_TYPE_SWAPCHAIN_STATE_FOVEATION_FB) \ + _avail(XrFoveationLevelProfileCreateInfoFB, XR_TYPE_FOVEATION_LEVEL_PROFILE_CREATE_INFO_FB) \ + _avail(XrSystemKeyboardTrackingPropertiesFB, XR_TYPE_SYSTEM_KEYBOARD_TRACKING_PROPERTIES_FB) \ + _avail(XrKeyboardSpaceCreateInfoFB, XR_TYPE_KEYBOARD_SPACE_CREATE_INFO_FB) \ + _avail(XrKeyboardTrackingQueryFB, XR_TYPE_KEYBOARD_TRACKING_QUERY_FB) \ + _avail(XrTriangleMeshCreateInfoFB, XR_TYPE_TRIANGLE_MESH_CREATE_INFO_FB) \ + _avail(XrSystemPassthroughPropertiesFB, XR_TYPE_SYSTEM_PASSTHROUGH_PROPERTIES_FB) \ + _avail(XrSystemPassthroughProperties2FB, XR_TYPE_SYSTEM_PASSTHROUGH_PROPERTIES2_FB) \ + _avail(XrPassthroughCreateInfoFB, XR_TYPE_PASSTHROUGH_CREATE_INFO_FB) \ + _avail(XrPassthroughLayerCreateInfoFB, XR_TYPE_PASSTHROUGH_LAYER_CREATE_INFO_FB) \ + _avail(XrCompositionLayerPassthroughFB, XR_TYPE_COMPOSITION_LAYER_PASSTHROUGH_FB) \ + _avail(XrGeometryInstanceCreateInfoFB, XR_TYPE_GEOMETRY_INSTANCE_CREATE_INFO_FB) \ + _avail(XrGeometryInstanceTransformFB, XR_TYPE_GEOMETRY_INSTANCE_TRANSFORM_FB) \ + _avail(XrPassthroughStyleFB, XR_TYPE_PASSTHROUGH_STYLE_FB) \ + _avail(XrPassthroughColorMapMonoToRgbaFB, XR_TYPE_PASSTHROUGH_COLOR_MAP_MONO_TO_RGBA_FB) \ + _avail(XrPassthroughColorMapMonoToMonoFB, XR_TYPE_PASSTHROUGH_COLOR_MAP_MONO_TO_MONO_FB) \ + _avail(XrPassthroughBrightnessContrastSaturationFB, XR_TYPE_PASSTHROUGH_BRIGHTNESS_CONTRAST_SATURATION_FB) \ + _avail(XrEventDataPassthroughStateChangedFB, XR_TYPE_EVENT_DATA_PASSTHROUGH_STATE_CHANGED_FB) \ + _avail(XrRenderModelPathInfoFB, XR_TYPE_RENDER_MODEL_PATH_INFO_FB) \ + _avail(XrRenderModelPropertiesFB, XR_TYPE_RENDER_MODEL_PROPERTIES_FB) \ + _avail(XrRenderModelBufferFB, XR_TYPE_RENDER_MODEL_BUFFER_FB) \ + _avail(XrRenderModelLoadInfoFB, XR_TYPE_RENDER_MODEL_LOAD_INFO_FB) \ + _avail(XrSystemRenderModelPropertiesFB, XR_TYPE_SYSTEM_RENDER_MODEL_PROPERTIES_FB) \ + _avail(XrRenderModelCapabilitiesRequestFB, XR_TYPE_RENDER_MODEL_CAPABILITIES_REQUEST_FB) \ + _avail(XrViewLocateFoveatedRenderingVARJO, XR_TYPE_VIEW_LOCATE_FOVEATED_RENDERING_VARJO) \ + _avail(XrFoveatedViewConfigurationViewVARJO, XR_TYPE_FOVEATED_VIEW_CONFIGURATION_VIEW_VARJO) \ + _avail(XrSystemFoveatedRenderingPropertiesVARJO, XR_TYPE_SYSTEM_FOVEATED_RENDERING_PROPERTIES_VARJO) \ + _avail(XrCompositionLayerDepthTestVARJO, XR_TYPE_COMPOSITION_LAYER_DEPTH_TEST_VARJO) \ + _avail(XrSystemMarkerTrackingPropertiesVARJO, XR_TYPE_SYSTEM_MARKER_TRACKING_PROPERTIES_VARJO) \ + _avail(XrEventDataMarkerTrackingUpdateVARJO, XR_TYPE_EVENT_DATA_MARKER_TRACKING_UPDATE_VARJO) \ + _avail(XrMarkerSpaceCreateInfoVARJO, XR_TYPE_MARKER_SPACE_CREATE_INFO_VARJO) \ + _avail(XrFrameEndInfoML, XR_TYPE_FRAME_END_INFO_ML) \ + _avail(XrGlobalDimmerFrameEndInfoML, XR_TYPE_GLOBAL_DIMMER_FRAME_END_INFO_ML) \ + _avail(XrSpatialAnchorPersistenceInfoMSFT, XR_TYPE_SPATIAL_ANCHOR_PERSISTENCE_INFO_MSFT) \ + _avail(XrSpatialAnchorFromPersistedAnchorCreateInfoMSFT, XR_TYPE_SPATIAL_ANCHOR_FROM_PERSISTED_ANCHOR_CREATE_INFO_MSFT) \ + _avail(XrSpaceQueryInfoFB, XR_TYPE_SPACE_QUERY_INFO_FB) \ + _avail(XrSpaceStorageLocationFilterInfoFB, XR_TYPE_SPACE_STORAGE_LOCATION_FILTER_INFO_FB) \ + _avail(XrSpaceUuidFilterInfoFB, XR_TYPE_SPACE_UUID_FILTER_INFO_FB) \ + _avail(XrSpaceComponentFilterInfoFB, XR_TYPE_SPACE_COMPONENT_FILTER_INFO_FB) \ + _avail(XrSpaceQueryResultsFB, XR_TYPE_SPACE_QUERY_RESULTS_FB) \ + _avail(XrEventDataSpaceQueryResultsAvailableFB, XR_TYPE_EVENT_DATA_SPACE_QUERY_RESULTS_AVAILABLE_FB) \ + _avail(XrEventDataSpaceQueryCompleteFB, XR_TYPE_EVENT_DATA_SPACE_QUERY_COMPLETE_FB) \ + _avail(XrSpaceSaveInfoFB, XR_TYPE_SPACE_SAVE_INFO_FB) \ + _avail(XrSpaceEraseInfoFB, XR_TYPE_SPACE_ERASE_INFO_FB) \ + _avail(XrEventDataSpaceSaveCompleteFB, XR_TYPE_EVENT_DATA_SPACE_SAVE_COMPLETE_FB) \ + _avail(XrEventDataSpaceEraseCompleteFB, XR_TYPE_EVENT_DATA_SPACE_ERASE_COMPLETE_FB) \ + _avail(XrSpaceShareInfoFB, XR_TYPE_SPACE_SHARE_INFO_FB) \ + _avail(XrEventDataSpaceShareCompleteFB, XR_TYPE_EVENT_DATA_SPACE_SHARE_COMPLETE_FB) \ + _avail(XrCompositionLayerSpaceWarpInfoFB, XR_TYPE_COMPOSITION_LAYER_SPACE_WARP_INFO_FB) \ + _avail(XrSystemSpaceWarpPropertiesFB, XR_TYPE_SYSTEM_SPACE_WARP_PROPERTIES_FB) \ + _avail(XrHapticAmplitudeEnvelopeVibrationFB, XR_TYPE_HAPTIC_AMPLITUDE_ENVELOPE_VIBRATION_FB) \ + _avail(XrSemanticLabelsFB, XR_TYPE_SEMANTIC_LABELS_FB) \ + _avail(XrRoomLayoutFB, XR_TYPE_ROOM_LAYOUT_FB) \ + _avail(XrBoundary2DFB, XR_TYPE_BOUNDARY_2D_FB) \ + _avail(XrSemanticLabelsSupportInfoFB, XR_TYPE_SEMANTIC_LABELS_SUPPORT_INFO_FB) \ + _avail(XrDigitalLensControlALMALENCE, XR_TYPE_DIGITAL_LENS_CONTROL_ALMALENCE) \ + _avail(XrEventDataSceneCaptureCompleteFB, XR_TYPE_EVENT_DATA_SCENE_CAPTURE_COMPLETE_FB) \ + _avail(XrSceneCaptureRequestInfoFB, XR_TYPE_SCENE_CAPTURE_REQUEST_INFO_FB) \ + _avail(XrSpaceContainerFB, XR_TYPE_SPACE_CONTAINER_FB) \ + _avail(XrFoveationEyeTrackedProfileCreateInfoMETA, XR_TYPE_FOVEATION_EYE_TRACKED_PROFILE_CREATE_INFO_META) \ + _avail(XrFoveationEyeTrackedStateMETA, XR_TYPE_FOVEATION_EYE_TRACKED_STATE_META) \ + _avail(XrSystemFoveationEyeTrackedPropertiesMETA, XR_TYPE_SYSTEM_FOVEATION_EYE_TRACKED_PROPERTIES_META) \ + _avail(XrSystemFaceTrackingPropertiesFB, XR_TYPE_SYSTEM_FACE_TRACKING_PROPERTIES_FB) \ + _avail(XrFaceTrackerCreateInfoFB, XR_TYPE_FACE_TRACKER_CREATE_INFO_FB) \ + _avail(XrFaceExpressionInfoFB, XR_TYPE_FACE_EXPRESSION_INFO_FB) \ + _avail(XrFaceExpressionWeightsFB, XR_TYPE_FACE_EXPRESSION_WEIGHTS_FB) \ + _avail(XrEyeTrackerCreateInfoFB, XR_TYPE_EYE_TRACKER_CREATE_INFO_FB) \ + _avail(XrEyeGazesInfoFB, XR_TYPE_EYE_GAZES_INFO_FB) \ + _avail(XrSystemEyeTrackingPropertiesFB, XR_TYPE_SYSTEM_EYE_TRACKING_PROPERTIES_FB) \ + _avail(XrEyeGazesFB, XR_TYPE_EYE_GAZES_FB) \ + _avail(XrPassthroughKeyboardHandsIntensityFB, XR_TYPE_PASSTHROUGH_KEYBOARD_HANDS_INTENSITY_FB) \ + _avail(XrCompositionLayerSettingsFB, XR_TYPE_COMPOSITION_LAYER_SETTINGS_FB) \ + _avail(XrHapticPcmVibrationFB, XR_TYPE_HAPTIC_PCM_VIBRATION_FB) \ + _avail(XrDevicePcmSampleRateStateFB, XR_TYPE_DEVICE_PCM_SAMPLE_RATE_STATE_FB) \ + _avail(XrCompositionLayerDepthTestFB, XR_TYPE_COMPOSITION_LAYER_DEPTH_TEST_FB) \ + _avail(XrLocalDimmingFrameEndInfoMETA, XR_TYPE_LOCAL_DIMMING_FRAME_END_INFO_META) \ + _avail(XrPassthroughPreferencesMETA, XR_TYPE_PASSTHROUGH_PREFERENCES_META) \ + _avail(XrSystemVirtualKeyboardPropertiesMETA, XR_TYPE_SYSTEM_VIRTUAL_KEYBOARD_PROPERTIES_META) \ + _avail(XrVirtualKeyboardCreateInfoMETA, XR_TYPE_VIRTUAL_KEYBOARD_CREATE_INFO_META) \ + _avail(XrVirtualKeyboardSpaceCreateInfoMETA, XR_TYPE_VIRTUAL_KEYBOARD_SPACE_CREATE_INFO_META) \ + _avail(XrVirtualKeyboardLocationInfoMETA, XR_TYPE_VIRTUAL_KEYBOARD_LOCATION_INFO_META) \ + _avail(XrVirtualKeyboardModelVisibilitySetInfoMETA, XR_TYPE_VIRTUAL_KEYBOARD_MODEL_VISIBILITY_SET_INFO_META) \ + _avail(XrVirtualKeyboardAnimationStateMETA, XR_TYPE_VIRTUAL_KEYBOARD_ANIMATION_STATE_META) \ + _avail(XrVirtualKeyboardModelAnimationStatesMETA, XR_TYPE_VIRTUAL_KEYBOARD_MODEL_ANIMATION_STATES_META) \ + _avail(XrVirtualKeyboardTextureDataMETA, XR_TYPE_VIRTUAL_KEYBOARD_TEXTURE_DATA_META) \ + _avail(XrVirtualKeyboardInputInfoMETA, XR_TYPE_VIRTUAL_KEYBOARD_INPUT_INFO_META) \ + _avail(XrVirtualKeyboardTextContextChangeInfoMETA, XR_TYPE_VIRTUAL_KEYBOARD_TEXT_CONTEXT_CHANGE_INFO_META) \ + _avail(XrEventDataVirtualKeyboardCommitTextMETA, XR_TYPE_EVENT_DATA_VIRTUAL_KEYBOARD_COMMIT_TEXT_META) \ + _avail(XrEventDataVirtualKeyboardBackspaceMETA, XR_TYPE_EVENT_DATA_VIRTUAL_KEYBOARD_BACKSPACE_META) \ + _avail(XrEventDataVirtualKeyboardEnterMETA, XR_TYPE_EVENT_DATA_VIRTUAL_KEYBOARD_ENTER_META) \ + _avail(XrEventDataVirtualKeyboardShownMETA, XR_TYPE_EVENT_DATA_VIRTUAL_KEYBOARD_SHOWN_META) \ + _avail(XrEventDataVirtualKeyboardHiddenMETA, XR_TYPE_EVENT_DATA_VIRTUAL_KEYBOARD_HIDDEN_META) \ + _avail(XrExternalCameraOCULUS, XR_TYPE_EXTERNAL_CAMERA_OCULUS) \ + _avail(XrPerformanceMetricsStateMETA, XR_TYPE_PERFORMANCE_METRICS_STATE_META) \ + _avail(XrPerformanceMetricsCounterMETA, XR_TYPE_PERFORMANCE_METRICS_COUNTER_META) \ + _avail(XrSpaceListSaveInfoFB, XR_TYPE_SPACE_LIST_SAVE_INFO_FB) \ + _avail(XrEventDataSpaceListSaveCompleteFB, XR_TYPE_EVENT_DATA_SPACE_LIST_SAVE_COMPLETE_FB) \ + _avail(XrSpaceUserCreateInfoFB, XR_TYPE_SPACE_USER_CREATE_INFO_FB) \ + _avail(XrSystemHeadsetIdPropertiesMETA, XR_TYPE_SYSTEM_HEADSET_ID_PROPERTIES_META) \ + _avail(XrPassthroughColorLutCreateInfoMETA, XR_TYPE_PASSTHROUGH_COLOR_LUT_CREATE_INFO_META) \ + _avail(XrPassthroughColorLutUpdateInfoMETA, XR_TYPE_PASSTHROUGH_COLOR_LUT_UPDATE_INFO_META) \ + _avail(XrPassthroughColorMapLutMETA, XR_TYPE_PASSTHROUGH_COLOR_MAP_LUT_META) \ + _avail(XrPassthroughColorMapInterpolatedLutMETA, XR_TYPE_PASSTHROUGH_COLOR_MAP_INTERPOLATED_LUT_META) \ + _avail(XrSystemPassthroughColorLutPropertiesMETA, XR_TYPE_SYSTEM_PASSTHROUGH_COLOR_LUT_PROPERTIES_META) \ + _avail(XrPassthroughCreateInfoHTC, XR_TYPE_PASSTHROUGH_CREATE_INFO_HTC) \ + _avail(XrPassthroughColorHTC, XR_TYPE_PASSTHROUGH_COLOR_HTC) \ + _avail(XrPassthroughMeshTransformInfoHTC, XR_TYPE_PASSTHROUGH_MESH_TRANSFORM_INFO_HTC) \ + _avail(XrCompositionLayerPassthroughHTC, XR_TYPE_COMPOSITION_LAYER_PASSTHROUGH_HTC) \ + _avail(XrFoveationApplyInfoHTC, XR_TYPE_FOVEATION_APPLY_INFO_HTC) \ + _avail(XrFoveationDynamicModeInfoHTC, XR_TYPE_FOVEATION_DYNAMIC_MODE_INFO_HTC) \ + _avail(XrFoveationCustomModeInfoHTC, XR_TYPE_FOVEATION_CUSTOM_MODE_INFO_HTC) \ + _avail(XrActiveActionSetPrioritiesEXT, XR_TYPE_ACTIVE_ACTION_SET_PRIORITIES_EXT) \ + _avail(XrSystemForceFeedbackCurlPropertiesMNDX, XR_TYPE_SYSTEM_FORCE_FEEDBACK_CURL_PROPERTIES_MNDX) \ + _avail(XrForceFeedbackCurlApplyLocationsMNDX, XR_TYPE_FORCE_FEEDBACK_CURL_APPLY_LOCATIONS_MNDX) \ + _avail(XrHandTrackingDataSourceInfoEXT, XR_TYPE_HAND_TRACKING_DATA_SOURCE_INFO_EXT) \ + _avail(XrHandTrackingDataSourceStateEXT, XR_TYPE_HAND_TRACKING_DATA_SOURCE_STATE_EXT) \ + _avail(XrSystemPlaneDetectionPropertiesEXT, XR_TYPE_SYSTEM_PLANE_DETECTION_PROPERTIES_EXT) \ + _avail(XrPlaneDetectorCreateInfoEXT, XR_TYPE_PLANE_DETECTOR_CREATE_INFO_EXT) \ + _avail(XrPlaneDetectorBeginInfoEXT, XR_TYPE_PLANE_DETECTOR_BEGIN_INFO_EXT) \ + _avail(XrPlaneDetectorGetInfoEXT, XR_TYPE_PLANE_DETECTOR_GET_INFO_EXT) \ + _avail(XrPlaneDetectorLocationEXT, XR_TYPE_PLANE_DETECTOR_LOCATION_EXT) \ + _avail(XrPlaneDetectorLocationsEXT, XR_TYPE_PLANE_DETECTOR_LOCATIONS_EXT) \ + _avail(XrPlaneDetectorPolygonBufferEXT, XR_TYPE_PLANE_DETECTOR_POLYGON_BUFFER_EXT) \ + + +#if defined(XR_USE_GRAPHICS_API_D3D11) +#define _impl_XR_LIST_ALL_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_D3D11(_avail, _unavail) \ + _avail(XrGraphicsBindingD3D11KHR, XR_TYPE_GRAPHICS_BINDING_D3D11_KHR) \ + _avail(XrSwapchainImageD3D11KHR, XR_TYPE_SWAPCHAIN_IMAGE_D3D11_KHR) \ + _avail(XrGraphicsRequirementsD3D11KHR, XR_TYPE_GRAPHICS_REQUIREMENTS_D3D11_KHR) \ + +#else +#define _impl_XR_LIST_ALL_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_D3D11(_avail, _unavail) \ + _unavail(XrGraphicsBindingD3D11KHR, XR_TYPE_GRAPHICS_BINDING_D3D11_KHR) \ + _unavail(XrSwapchainImageD3D11KHR, XR_TYPE_SWAPCHAIN_IMAGE_D3D11_KHR) \ + _unavail(XrGraphicsRequirementsD3D11KHR, XR_TYPE_GRAPHICS_REQUIREMENTS_D3D11_KHR) \ + +#endif + +#if defined(XR_USE_GRAPHICS_API_D3D12) +#define _impl_XR_LIST_ALL_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_D3D12(_avail, _unavail) \ + _avail(XrGraphicsBindingD3D12KHR, XR_TYPE_GRAPHICS_BINDING_D3D12_KHR) \ + _avail(XrSwapchainImageD3D12KHR, XR_TYPE_SWAPCHAIN_IMAGE_D3D12_KHR) \ + _avail(XrGraphicsRequirementsD3D12KHR, XR_TYPE_GRAPHICS_REQUIREMENTS_D3D12_KHR) \ + +#else +#define _impl_XR_LIST_ALL_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_D3D12(_avail, _unavail) \ + _unavail(XrGraphicsBindingD3D12KHR, XR_TYPE_GRAPHICS_BINDING_D3D12_KHR) \ + _unavail(XrSwapchainImageD3D12KHR, XR_TYPE_SWAPCHAIN_IMAGE_D3D12_KHR) \ + _unavail(XrGraphicsRequirementsD3D12KHR, XR_TYPE_GRAPHICS_REQUIREMENTS_D3D12_KHR) \ + +#endif + +#if defined(XR_USE_GRAPHICS_API_OPENGL) +#define _impl_XR_LIST_ALL_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL(_avail, _unavail) \ + _avail(XrSwapchainImageOpenGLKHR, XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_KHR) \ + _avail(XrGraphicsRequirementsOpenGLKHR, XR_TYPE_GRAPHICS_REQUIREMENTS_OPENGL_KHR) \ + +#else +#define _impl_XR_LIST_ALL_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL(_avail, _unavail) \ + _unavail(XrSwapchainImageOpenGLKHR, XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_KHR) \ + _unavail(XrGraphicsRequirementsOpenGLKHR, XR_TYPE_GRAPHICS_REQUIREMENTS_OPENGL_KHR) \ + +#endif + +#if defined(XR_USE_GRAPHICS_API_OPENGL) && defined(XR_USE_PLATFORM_WAYLAND) +#define _impl_XR_LIST_ALL_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_XR_USE_PLATFORM_WAYLAND(_avail, _unavail) \ + _avail(XrGraphicsBindingOpenGLWaylandKHR, XR_TYPE_GRAPHICS_BINDING_OPENGL_WAYLAND_KHR) \ + +#else +#define _impl_XR_LIST_ALL_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_XR_USE_PLATFORM_WAYLAND(_avail, _unavail) \ + _unavail(XrGraphicsBindingOpenGLWaylandKHR, XR_TYPE_GRAPHICS_BINDING_OPENGL_WAYLAND_KHR) \ + +#endif + +#if defined(XR_USE_GRAPHICS_API_OPENGL) && defined(XR_USE_PLATFORM_WIN32) +#define _impl_XR_LIST_ALL_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_XR_USE_PLATFORM_WIN32(_avail, _unavail) \ + _avail(XrGraphicsBindingOpenGLWin32KHR, XR_TYPE_GRAPHICS_BINDING_OPENGL_WIN32_KHR) \ + +#else +#define _impl_XR_LIST_ALL_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_XR_USE_PLATFORM_WIN32(_avail, _unavail) \ + _unavail(XrGraphicsBindingOpenGLWin32KHR, XR_TYPE_GRAPHICS_BINDING_OPENGL_WIN32_KHR) \ + +#endif + +#if defined(XR_USE_GRAPHICS_API_OPENGL) && defined(XR_USE_PLATFORM_XCB) +#define _impl_XR_LIST_ALL_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_XR_USE_PLATFORM_XCB(_avail, _unavail) \ + _avail(XrGraphicsBindingOpenGLXcbKHR, XR_TYPE_GRAPHICS_BINDING_OPENGL_XCB_KHR) \ + +#else +#define _impl_XR_LIST_ALL_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_XR_USE_PLATFORM_XCB(_avail, _unavail) \ + _unavail(XrGraphicsBindingOpenGLXcbKHR, XR_TYPE_GRAPHICS_BINDING_OPENGL_XCB_KHR) \ + +#endif + +#if defined(XR_USE_GRAPHICS_API_OPENGL) && defined(XR_USE_PLATFORM_XLIB) +#define _impl_XR_LIST_ALL_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_XR_USE_PLATFORM_XLIB(_avail, _unavail) \ + _avail(XrGraphicsBindingOpenGLXlibKHR, XR_TYPE_GRAPHICS_BINDING_OPENGL_XLIB_KHR) \ + +#else +#define _impl_XR_LIST_ALL_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_XR_USE_PLATFORM_XLIB(_avail, _unavail) \ + _unavail(XrGraphicsBindingOpenGLXlibKHR, XR_TYPE_GRAPHICS_BINDING_OPENGL_XLIB_KHR) \ + +#endif + +#if defined(XR_USE_GRAPHICS_API_OPENGL_ES) +#define _impl_XR_LIST_ALL_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_ES(_avail, _unavail) \ + _avail(XrSwapchainImageOpenGLESKHR, XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_ES_KHR) \ + _avail(XrGraphicsRequirementsOpenGLESKHR, XR_TYPE_GRAPHICS_REQUIREMENTS_OPENGL_ES_KHR) \ + _avail(XrSwapchainStateSamplerOpenGLESFB, XR_TYPE_SWAPCHAIN_STATE_SAMPLER_OPENGL_ES_FB) \ + +#else +#define _impl_XR_LIST_ALL_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_ES(_avail, _unavail) \ + _unavail(XrSwapchainImageOpenGLESKHR, XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_ES_KHR) \ + _unavail(XrGraphicsRequirementsOpenGLESKHR, XR_TYPE_GRAPHICS_REQUIREMENTS_OPENGL_ES_KHR) \ + _unavail(XrSwapchainStateSamplerOpenGLESFB, XR_TYPE_SWAPCHAIN_STATE_SAMPLER_OPENGL_ES_FB) \ + +#endif + +#if defined(XR_USE_GRAPHICS_API_OPENGL_ES) && defined(XR_USE_PLATFORM_ANDROID) +#define _impl_XR_LIST_ALL_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_ES_XR_USE_PLATFORM_ANDROID(_avail, _unavail) \ + _avail(XrGraphicsBindingOpenGLESAndroidKHR, XR_TYPE_GRAPHICS_BINDING_OPENGL_ES_ANDROID_KHR) \ + +#else +#define _impl_XR_LIST_ALL_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_ES_XR_USE_PLATFORM_ANDROID(_avail, _unavail) \ + _unavail(XrGraphicsBindingOpenGLESAndroidKHR, XR_TYPE_GRAPHICS_BINDING_OPENGL_ES_ANDROID_KHR) \ + +#endif + +#if defined(XR_USE_GRAPHICS_API_VULKAN) +#define _impl_XR_LIST_ALL_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_VULKAN(_avail, _unavail) \ + _avail(XrVulkanSwapchainFormatListCreateInfoKHR, XR_TYPE_VULKAN_SWAPCHAIN_FORMAT_LIST_CREATE_INFO_KHR) \ + _avail(XrGraphicsBindingVulkanKHR, XR_TYPE_GRAPHICS_BINDING_VULKAN_KHR) \ + _avail(XrSwapchainImageVulkanKHR, XR_TYPE_SWAPCHAIN_IMAGE_VULKAN_KHR) \ + _avail(XrGraphicsRequirementsVulkanKHR, XR_TYPE_GRAPHICS_REQUIREMENTS_VULKAN_KHR) \ + _avail(XrVulkanInstanceCreateInfoKHR, XR_TYPE_VULKAN_INSTANCE_CREATE_INFO_KHR) \ + _avail(XrVulkanDeviceCreateInfoKHR, XR_TYPE_VULKAN_DEVICE_CREATE_INFO_KHR) \ + _avail(XrVulkanGraphicsDeviceGetInfoKHR, XR_TYPE_VULKAN_GRAPHICS_DEVICE_GET_INFO_KHR) \ + _avail(XrSwapchainImageFoveationVulkanFB, XR_TYPE_SWAPCHAIN_IMAGE_FOVEATION_VULKAN_FB) \ + _avail(XrSwapchainStateSamplerVulkanFB, XR_TYPE_SWAPCHAIN_STATE_SAMPLER_VULKAN_FB) \ + _avail(XrVulkanSwapchainCreateInfoMETA, XR_TYPE_VULKAN_SWAPCHAIN_CREATE_INFO_META) \ + +#else +#define _impl_XR_LIST_ALL_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_VULKAN(_avail, _unavail) \ + _unavail(XrVulkanSwapchainFormatListCreateInfoKHR, XR_TYPE_VULKAN_SWAPCHAIN_FORMAT_LIST_CREATE_INFO_KHR) \ + _unavail(XrGraphicsBindingVulkanKHR, XR_TYPE_GRAPHICS_BINDING_VULKAN_KHR) \ + _unavail(XrSwapchainImageVulkanKHR, XR_TYPE_SWAPCHAIN_IMAGE_VULKAN_KHR) \ + _unavail(XrGraphicsRequirementsVulkanKHR, XR_TYPE_GRAPHICS_REQUIREMENTS_VULKAN_KHR) \ + _unavail(XrVulkanInstanceCreateInfoKHR, XR_TYPE_VULKAN_INSTANCE_CREATE_INFO_KHR) \ + _unavail(XrVulkanDeviceCreateInfoKHR, XR_TYPE_VULKAN_DEVICE_CREATE_INFO_KHR) \ + _unavail(XrVulkanGraphicsDeviceGetInfoKHR, XR_TYPE_VULKAN_GRAPHICS_DEVICE_GET_INFO_KHR) \ + _unavail(XrSwapchainImageFoveationVulkanFB, XR_TYPE_SWAPCHAIN_IMAGE_FOVEATION_VULKAN_FB) \ + _unavail(XrSwapchainStateSamplerVulkanFB, XR_TYPE_SWAPCHAIN_STATE_SAMPLER_VULKAN_FB) \ + _unavail(XrVulkanSwapchainCreateInfoMETA, XR_TYPE_VULKAN_SWAPCHAIN_CREATE_INFO_META) \ + +#endif + +#if defined(XR_USE_PLATFORM_ANDROID) +#define _impl_XR_LIST_ALL_STRUCTURE_TYPES_XR_USE_PLATFORM_ANDROID(_avail, _unavail) \ + _avail(XrInstanceCreateInfoAndroidKHR, XR_TYPE_INSTANCE_CREATE_INFO_ANDROID_KHR) \ + _avail(XrLoaderInitInfoAndroidKHR, XR_TYPE_LOADER_INIT_INFO_ANDROID_KHR) \ + _avail(XrAndroidSurfaceSwapchainCreateInfoFB, XR_TYPE_ANDROID_SURFACE_SWAPCHAIN_CREATE_INFO_FB) \ + _avail(XrSwapchainStateAndroidSurfaceDimensionsFB, XR_TYPE_SWAPCHAIN_STATE_ANDROID_SURFACE_DIMENSIONS_FB) \ + +#else +#define _impl_XR_LIST_ALL_STRUCTURE_TYPES_XR_USE_PLATFORM_ANDROID(_avail, _unavail) \ + _unavail(XrInstanceCreateInfoAndroidKHR, XR_TYPE_INSTANCE_CREATE_INFO_ANDROID_KHR) \ + _unavail(XrLoaderInitInfoAndroidKHR, XR_TYPE_LOADER_INIT_INFO_ANDROID_KHR) \ + _unavail(XrAndroidSurfaceSwapchainCreateInfoFB, XR_TYPE_ANDROID_SURFACE_SWAPCHAIN_CREATE_INFO_FB) \ + _unavail(XrSwapchainStateAndroidSurfaceDimensionsFB, XR_TYPE_SWAPCHAIN_STATE_ANDROID_SURFACE_DIMENSIONS_FB) \ + +#endif + +#if defined(XR_USE_PLATFORM_EGL) +#define _impl_XR_LIST_ALL_STRUCTURE_TYPES_XR_USE_PLATFORM_EGL(_avail, _unavail) \ + _avail(XrGraphicsBindingEGLMNDX, XR_TYPE_GRAPHICS_BINDING_EGL_MNDX) \ + +#else +#define _impl_XR_LIST_ALL_STRUCTURE_TYPES_XR_USE_PLATFORM_EGL(_avail, _unavail) \ + _unavail(XrGraphicsBindingEGLMNDX, XR_TYPE_GRAPHICS_BINDING_EGL_MNDX) \ + +#endif + +#if defined(XR_USE_PLATFORM_ML) +#define _impl_XR_LIST_ALL_STRUCTURE_TYPES_XR_USE_PLATFORM_ML(_avail, _unavail) \ + _avail(XrCoordinateSpaceCreateInfoML, XR_TYPE_COORDINATE_SPACE_CREATE_INFO_ML) \ + +#else +#define _impl_XR_LIST_ALL_STRUCTURE_TYPES_XR_USE_PLATFORM_ML(_avail, _unavail) \ + _unavail(XrCoordinateSpaceCreateInfoML, XR_TYPE_COORDINATE_SPACE_CREATE_INFO_ML) \ + +#endif + +#if defined(XR_USE_PLATFORM_WIN32) +#define _impl_XR_LIST_ALL_STRUCTURE_TYPES_XR_USE_PLATFORM_WIN32(_avail, _unavail) \ + _avail(XrHolographicWindowAttachmentMSFT, XR_TYPE_HOLOGRAPHIC_WINDOW_ATTACHMENT_MSFT) \ + +#else +#define _impl_XR_LIST_ALL_STRUCTURE_TYPES_XR_USE_PLATFORM_WIN32(_avail, _unavail) \ + _unavail(XrHolographicWindowAttachmentMSFT, XR_TYPE_HOLOGRAPHIC_WINDOW_ATTACHMENT_MSFT) \ + +#endif + + + + +#endif + diff --git a/Plugins/MetaXR/Source/Thirdparty/OVRPlugin/OVRPlugin/Include/OVR_Plugin.h b/Plugins/MetaXR/Source/Thirdparty/OVRPlugin/OVRPlugin/Include/OVR_Plugin.h new file mode 100644 index 0000000..60e9a6d --- /dev/null +++ b/Plugins/MetaXR/Source/Thirdparty/OVRPlugin/OVRPlugin/Include/OVR_Plugin.h @@ -0,0 +1,1205 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * Licensed under the Oculus SDK License Agreement (the "License"); + * you may not use the Oculus SDK except in compliance with the License, + * which is provided at the time of installation or download, or which + * otherwise accompanies this software in either electronic or hard copy form. + * + * You may obtain a copy of the License at + * + * https://developer.oculus.com/licenses/oculussdk/ + * + * Unless required by applicable law or agreed to in writing, the Oculus SDK + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OVR_Plugin_h +#define OVR_Plugin_h + +#include "OVR_Plugin_Types.h" + +// OVR_Plugin.h: Minimal high-level plugin proxy to LibOVR. Use instead of OVR_CAPI.h. +// All functions must be called from the same thread as your graphics device, except as noted. + +#ifdef __cplusplus +extern "C" { +#endif + +// The following macros are only defined when building in UE4 and UE5 +#if ( \ + defined(UE_BUILD_DEBUG) || defined(UE_BUILD_DEVELOPMENT) || defined(UE_BUILD_TEST) || \ + defined(UE_BUILD_SHIPPING)) && \ + defined(PLATFORM_ANDROID) +// OVRPlugin does not support Android system callbacks in UE4 and UE5. +// Please use Optional Mobile Features Blueprint Library Plugin or include FAndroidMisc.h in your project +#define OVRPLUGIN_JNI_LIB_EXCLUDED +#endif + +/// Initializes the Oculus display driver before graphics initialization, if applicable. +OVRP_EXPORT ovrpResult +ovrp_PreInitialize5(void* activity, ovrpRenderAPIType apiType, ovrpPreinitializeFlags preinitializeFlags); + +/// Gets the current initialization state of the Oculus runtime, VR tracking, and graphics +/// resources. +OVRP_EXPORT ovrpBool ovrp_GetInitialized(); + +/// Sets up the Oculus runtime, VR tracking, and graphics resources. +/// You must call this before any other function except ovrp_PreInitialize() or +/// ovrp_GetInitialized(). +/// @note In case of D3D12, d3dDevice is an ID3D12CommandQueue object +OVRP_EXPORT ovrpResult ovrp_Initialize7( + ovrpRenderAPIType apiType, + ovrpLogCallback logCallback, + void* activity, + void* vkInstance, + void* vkPhysicalDevice, + void* vkDevice, + void* vkQueue, + void* vkGetInstanceProcAddr, // PFN_vkGetInstanceProcAddr + unsigned int vkQueueFamilyIndex, + void* d3dDevice, + int initializeFlags, + OVRP_CONSTREF(ovrpVersion) version); + +/// Tears down the Oculus runtime, VR tracking, and graphics resources. +OVRP_EXPORT ovrpResult ovrp_Shutdown2(); + +/// Set a function pointer which captures the OVRPlugin log lines. +OVRP_EXPORT ovrpResult ovrp_SetLogCallback2(ovrpLogCallback2 logFunc); + +/// Gets the version of OVRPlugin currently in use. Format: "major.minor.release" +OVRP_EXPORT ovrpResult ovrp_GetVersion2(char const** version); + +/// Gets the version of the underlying VR SDK currently in use. +OVRP_EXPORT ovrpResult ovrp_GetNativeSDKVersion2(char const** nativeSDKVersion); + +/// Returns a pointer that can be used to access the underlying VR SDK +/// (e.g. ovrSession in CAPI, ovrMobile* in VRAPI, XrSession* in OpenXR). +OVRP_EXPORT ovrpResult ovrp_GetNativeSDKPointer2(void** nativeSDKPointer); + +/// Retrieve the current XR API being used by OVRPlugin +OVRP_EXPORT ovrpResult ovrp_GetNativeXrApiType(ovrpXrApi* xrApi); + +/// Retrive XrInstance / XrSession when OpenXR is being used +OVRP_EXPORT ovrpResult ovrp_GetNativeOpenXRHandles(ovrpUInt64* xrInstance, ovrpUInt64* xrSession); + +/// Retrieves the expected Display Adapter ID associated with the Oculus HMD. +/// On Windows systems, this will return a DX11 LUID, otherwise nullptr. +/// @note ovrp_PreInitialize must be called and return a successful result before calling this +/// function. +OVRP_EXPORT ovrpResult ovrp_GetDisplayAdapterId2(void const** displayAdapterId); + +/// Retrieves the expected audio device ID associated with the Oculus HMD's headphones. +/// On Windows systems, this will return the GUID* for the IMMDevice of an audio endpoint. +/// @note ovrp_PreInitialize must be called and return a successful result before calling this +/// function. +OVRP_EXPORT ovrpResult ovrp_GetAudioOutId2(void const** audioOutId); + +/// Retrieves the expected audio device ID associated with the Oculus HMD's headphones. +/// On Windows systems, this will return a LPCWSTR containing the device identifier. +/// @note ovrp_PreInitialize must be called and return a successful result before calling this +/// function. +OVRP_EXPORT ovrpResult ovrp_GetAudioOutDeviceId2(void const** audioOutDeviceId); + +/// Retrieves the expected audio device ID associated with the Oculus HMD's microphone. +/// On Windows systems, this will return the GUID* for the IMMDevice of an audio endpoint. +/// @note ovrp_PreInitialize must be called and return a successful result before calling this +/// function. +OVRP_EXPORT ovrpResult ovrp_GetAudioInId2(void const** audioInId); + +/// Retrieves the expected audio device ID associated with the Oculus HMD's microphone. +/// On Windows systems, this will return a LPCWSTR containing the device identifier. +/// @note ovrp_PreInitialize must be called and return a successful result before calling this +/// function. +OVRP_EXPORT ovrpResult ovrp_GetAudioInDeviceId2(void const** audioInDeviceId); + +/// Returns an array of pointers to extension names which need to be enabled for the instance +/// in order for the VR runtime to support Vulkan-based applications. +/// @note ovrp_PreInitialize must be called and return a successful result before calling this +/// function. +OVRP_EXPORT ovrpResult ovrp_GetInstanceExtensionsVk(char const** instanceExtensions, int* instanceExtensionCount); + +/// Returns an array of pointers to extension names which need to be enabled for the device +/// in order for the VR runtime to support Vulkan-based applications. +/// @note ovrp_PreInitialize must be called and return a successful result before calling this +/// function. +OVRP_EXPORT ovrpResult ovrp_GetDeviceExtensionsVk(char const** deviceExtensions, int* deviceExtensionCount); + +/// Creates a dedicated window for rendering 3D content to the VR display. +OVRP_EXPORT ovrpResult ovrp_SetupDistortionWindow3(int flags); + +/// Destroys the dedicated VR window. +OVRP_EXPORT ovrpResult ovrp_DestroyDistortionWindow2(); + +// Returns handedness as specified in the mobile device +OVRP_EXPORT ovrpResult ovrp_GetDominantHand(ovrpHandedness* dominantHand); + +/// Used by System Activities application for setting the Remote Handedness. +OVRP_EXPORT ovrpResult ovrp_SetRemoteHandedness(ovrpHandedness handedness); + +// Sets color scale parameters; can be used for effects like fade-to-black. Final pixel color will be multiplied by +// colorScale and added to offset. If applyToAllLayers is false, this applies only for the eyefov layer. If it's true, +// it's for every layer submitted. +OVRP_EXPORT ovrpResult ovrp_SetColorScaleAndOffset( + const ovrpVector4f colorScale, + const ovrpVector4f colorOffset, + const ovrpBool applyToAllLayers); + +/// Creates a layer. +/// The desc remains constant for the lifetime of the layer. +/// @note In case of D3D12, device is an ID3D12CommandQueue object +OVRP_EXPORT ovrpResult ovrp_SetupLayer(void* device, OVRP_CONSTREF(ovrpLayerDesc) desc, int* layerId); + +/// Create depth swap chain for a layer +OVRP_EXPORT ovrpResult ovrp_SetupLayerDepth(void* device, ovrpTextureFormat depthFormat, int layerId); + +/// Get Eye Fov layer index if created +/// Otherwise return fail +OVRP_EXPORT ovrpResult ovrp_GetEyeFovLayerId(int* layerId); + +/// Set blending mode of Eye Fov layer to use premultiplied alpha or not +OVRP_EXPORT ovrpResult ovrp_SetEyeFovPremultipliedAlphaMode(const ovrpBool enabled); + +/// Get premultiplied alpha mode of the Eye Fov layer +OVRP_EXPORT ovrpResult ovrp_GetEyeFovPremultipliedAlphaMode(ovrpBool* enabled); + +/// Gets the number of texture stages in the layer. +/// Layers have multiple stages, unless the ovrpLayer_Static flag was specified. +OVRP_EXPORT ovrpResult ovrp_GetLayerTextureStageCount(int layerId, int* layerTextureStageCount); + +/// Gets the texture handle for a specific layer stage and eye. +OVRP_EXPORT ovrpResult ovrp_GetLayerTexture2( + int layerId, + int stage, + ovrpEye eyeId, + ovrpTextureHandle* textureHandle, + ovrpTextureHandle* depthTextureHandle); + +/// Gets the texture handle for a specific layer stage and eye. +OVRP_EXPORT ovrpResult ovrp_GetLayerTextureFoveation( + int layerId, + int stage, + ovrpEye eyeId, + ovrpTextureHandle* foveationTextureHandle, + ovrpSizei* foveationResultSize); + +/// Gets the space warp texture handles for a specific layer stage and eye. +OVRP_EXPORT ovrpResult ovrp_GetLayerTextureSpaceWarp( + int layerId, + int stage, + ovrpEye eyeId, + ovrpTextureHandle* motionVectorTextureHandle, + ovrpSizei* motionVectorResultSize, + ovrpTextureHandle* depthTextureHandle, + ovrpSizei* depthResultSize); + +/// Gets the texture handle for a specific layer stage and eye. +OVRP_EXPORT ovrpResult ovrp_GetLayerAndroidSurfaceObject(int layerId, void** surfaceObject); + +/// Return the vertices and indices for the eye occlusion mesh. +OVRP_EXPORT ovrpResult ovrp_GetLayerOcclusionMesh( + int layerId, + ovrpEye eyeId, + ovrpVector2f const** vertices, + int* vertexCount, + int const** indices, + int* indexCount); + +/// Destroys a layer +OVRP_EXPORT ovrpResult ovrp_DestroyLayer(int layerId); + +/// Calculates layer description +OVRP_EXPORT ovrpResult ovrp_CalculateLayerDesc( + ovrpShape shape, + ovrpLayout layout, + OVRP_CONSTREF(ovrpSizei) textureSize, + int mipLevels, + int sampleCount, + ovrpTextureFormat format, + int layerFlags, + ovrpLayerDescUnion* layerDesc); + +/// Calculates eye layer description +OVRP_EXPORT ovrpResult ovrp_CalculateEyeLayerDesc2( + ovrpLayout layout, + float textureScale, + int mipLevels, + int sampleCount, + ovrpTextureFormat format, + ovrpTextureFormat depthFormat, + int layerFlags, + ovrpLayerDesc_EyeFov* layerDesc); + +/// Calculates eye layer description +OVRP_EXPORT ovrpResult ovrp_CalculateEyeLayerDesc3( + ovrpLayout layout, + float textureScale, + int mipLevels, + int sampleCount, + ovrpTextureFormat format, + ovrpTextureFormat depthFormat, + ovrpTextureFormat motionVectorFormat, + ovrpTextureFormat motionVectorDepthFormat, + float motionVectorTextureScale, + int layerFlags, + ovrpLayerDesc_EyeFov* layerDesc); + +/// Calculates the recommended viewport rect for the specified eye +OVRP_EXPORT ovrpResult ovrp_CalculateEyeViewportRect( + OVRP_CONSTREF(ovrpLayerDesc_EyeFov) layerDesc, + ovrpEye eyeId, + float viewportScale, + ovrpRecti* viewportRect); + +/// Calculates the area of the viewport unobstructed by the occlusion mesh +OVRP_EXPORT ovrpResult ovrp_CalculateEyePreviewRect( + OVRP_CONSTREF(ovrpLayerDesc_EyeFov) layerDesc, + ovrpEye eyeId, + OVRP_CONSTREF(ovrpRecti) viewportRect, + ovrpRecti* previewRect); + +/// Allocates mirror texture +/// If you called ovrp_Initialize with ovrpRenderAPI_D3D11, pass device argument +/// here to have the texture allocated by that device. +/// If you called ovrp_Initialize with ovrpRenderAPI_OpenGL, you can pass +/// a texture ID allocated by glGenTextures in the device argument and the texture will be +/// associated with that ID. +/// @note In case of D3D12, device is an ID3D12CommandQueue object +OVRP_EXPORT ovrpResult ovrp_SetupMirrorTexture2( + void* device, + int height, + int width, + ovrpTextureFormat format, + ovrpTextureHandle* textureHandle); + +/// Destroys mirror texture. +OVRP_EXPORT ovrpResult ovrp_DestroyMirrorTexture2(); + +/// Returns the recommended amount to scale GPU work in order to maintain framerate. +/// Can be used to adjust viewportScale and textureScale +OVRP_EXPORT ovrpResult ovrp_GetAdaptiveGpuPerformanceScale2(float* adapiveGpuPerformanceScale); + +/// Returns the time from CPU start to GPU end, a meaningful performance metric under OVR +OVRP_EXPORT ovrpResult ovrp_GetAppCpuStartToGpuEndTime2(float* appCpuStartToGpuEndTime); + +/// Return how many display pixels will fit in tan(angle) = 1 +OVRP_EXPORT ovrpResult ovrp_GetEyePixelsPerTanAngleAtCenter2(int eyeIndex, ovrpVector2f* pixelsPerTanAngleAtCenter); + +/// Return the offset HMD to the eye, in meters +OVRP_EXPORT ovrpResult ovrp_GetHmdToEyeOffset2(int eyeIndex, ovrpVector3f* hmdToEyeOffset); + +/// Ensures VR rendering is configured and updates tracking to reflect the latest reported poses. +/// You must call ovrp_Update before calling ovrp_GetNode* for a new frame. +/// Call with ovrpStep_Render from end of frame on Game thread, to hand off state to Render thread +/// Call with ovrpStep_Physics from any thread, using predictionSeconds specify offset from start of +/// frame. +OVRP_EXPORT ovrpResult ovrp_Update3(ovrpStep step, int frameIndex, double predictionSeconds); + +/// Marks the beginning of a frame. Call this before issuing any graphics commands in a given frame. +OVRP_EXPORT ovrpResult ovrp_WaitToBeginFrame(int frameIndex); + +/// Marks the beginning of a frame. Call this before issuing any graphics commands in a given frame. +OVRP_EXPORT ovrpResult ovrp_BeginFrame4(int frameIndex, void* commandQueue); + +/// Late update of foveation parameters, both GL and Vulkan +OVRP_EXPORT ovrpResult ovrp_UpdateFoveation(int frameIndex); + +/// Marks the end of a frame and performs TimeWarp. Call this before Present or SwapBuffers to +/// update the VR window. +OVRP_EXPORT ovrpResult +ovrp_EndFrame4(int frameIndex, ovrpLayerSubmit const* const* layerSubmitPtrs, int layerSubmitCount, void* commandQueue); + +/// If true, the HMD supports orientation tracking. +OVRP_EXPORT ovrpResult ovrp_GetTrackingOrientationSupported2(ovrpBool* trackingOrientationSupported); + +/// If true, head tracking affects the rotation reported by ovrp_GetEyePose. +OVRP_EXPORT ovrpResult ovrp_GetTrackingOrientationEnabled2(ovrpBool* trackingOrientationEnabled); + +/// If true, head tracking affects the rotation reported by ovrp_GetEyePose. +OVRP_EXPORT ovrpResult ovrp_SetTrackingOrientationEnabled2(ovrpBool trackingOrientationEnabled); + +/// If true, the HMD supports position tracking +OVRP_EXPORT ovrpResult ovrp_GetTrackingPositionSupported2(ovrpBool* trackingPositionSupported); + +/// If true, head tracking affects the position reported by ovrp_GetEyePose. +OVRP_EXPORT ovrpResult ovrp_GetTrackingPositionEnabled2(ovrpBool* trackingPositionEnabled); + +/// If true, head tracking affects the position reported by ovrp_GetEyePose. +OVRP_EXPORT ovrpResult ovrp_SetTrackingPositionEnabled2(ovrpBool trackingPositionEnabled); + +/// If true, the inter-pupillary distance affects the position reported by ovrp_GetEyePose. +OVRP_EXPORT ovrpResult ovrp_GetTrackingIPDEnabled2(ovrpBool* trackingIPDEnabled); + +/// If true, the inter-pupillary distance affects the position reported by ovrp_GetEyePose. +OVRP_EXPORT ovrpResult ovrp_SetTrackingIPDEnabled2(ovrpBool trackingIPDEnabled); + +/// Gets the calibrated origin pose. +OVRP_EXPORT ovrpResult ovrp_GetTrackingCalibratedOrigin2(ovrpPosef* trackingCalibratedOrigin); + +/// Oculus Internal. Sets the system-wide calibrated origin for the currently active tracking origin +/// type. +OVRP_EXPORT ovrpResult ovrp_SetTrackingCalibratedOrigin2(); + +/// Gets the currently active tracking origin type. +OVRP_EXPORT ovrpResult ovrp_GetTrackingOriginType2(ovrpTrackingOrigin* trackingOriginType); + +/// Sets the currently active tracking origin type. +OVRP_EXPORT ovrpResult ovrp_SetTrackingOriginType2(ovrpTrackingOrigin trackingOriginType); + +/// Changes the frame of reference used by tracking. +/// See the ovrpRecenterFlag enum for details about available flags. +OVRP_EXPORT ovrpResult ovrp_RecenterTrackingOrigin2(unsigned int flags); + +/// If true, the node is considered present and available. +OVRP_EXPORT ovrpResult ovrp_GetNodePresent2(ovrpNode nodeId, ovrpBool* nodePresent); + +/// If true, the node's orientation is tracked. +OVRP_EXPORT ovrpResult ovrp_GetNodeOrientationTracked2(ovrpNode nodeId, ovrpBool* nodeOrientationTracked); + +/// If true, the node's orientation is valid. +OVRP_EXPORT ovrpResult ovrp_GetNodeOrientationValid(ovrpNode nodeId, ovrpBool* nodeOrientationValid); + +/// If true, the node's position is tracked. +OVRP_EXPORT ovrpResult ovrp_GetNodePositionTracked2(ovrpNode nodeId, ovrpBool* nodePositionTracked); + +/// If true, the node's position is valid. +OVRP_EXPORT ovrpResult ovrp_GetNodePositionValid(ovrpNode nodeId, ovrpBool* nodePositionValid); + +/// Force a node position to be tracked or not. Return false if the node's position tracking cannot +/// be changed. +OVRP_EXPORT ovrpResult ovrp_SetNodePositionTracked2(ovrpNode nodeId, ovrpBool nodePositionTracked); + +/// Gets the current pose, acceleration, and velocity of the given node on the given update cadence. +OVRP_EXPORT ovrpResult +ovrp_GetNodePoseState3(ovrpStep step, int frameIndex, ovrpNode nodeId, ovrpPoseStatef* nodePoseState); + +/// Gets the current pose, acceleration, and velocity of the given node on the given update cadence, without applying +/// any modifier (e.g. HeadPoseModifier) +OVRP_EXPORT ovrpResult +ovrp_GetNodePoseStateRaw(ovrpStep step, int frameIndex, ovrpNode nodeId, ovrpPoseStatef* nodePoseState); + +/// Gets the current frustum for the given node, if available. +OVRP_EXPORT ovrpResult ovrp_GetNodeFrustum2(ovrpNode nodeId, ovrpFrustum2f* nodeFrustum); + + + + + + + + + + + + + + +/// Set relative rotation/translation to the eye pose +OVRP_EXPORT ovrpResult +ovrp_SetHeadPoseModifier(const ovrpQuatf* relativeRotation, const ovrpVector3f* relativeTranslation); + +/// Get current relative rotation/translation to the eye pose +OVRP_EXPORT ovrpResult ovrp_GetHeadPoseModifier(ovrpQuatf* relativeRotation, ovrpVector3f* relativeTranslation); + +/// Gets the controller state for the given controllers. +OVRP_EXPORT ovrpResult ovrp_GetControllerState4(ovrpController controllerMask, ovrpControllerState4* controllerState); + +/// Gets the controller state for the given controllers. +OVRP_EXPORT ovrpResult ovrp_GetControllerState5(ovrpController controllerMask, ovrpControllerState5* controllerState); + +/// Gets the controller state for the given controllers. +OVRP_EXPORT ovrpResult ovrp_GetControllerState6(ovrpController controllerMask, ovrpControllerState6* controllerState); + +/// Gets the currently active controller type. +OVRP_EXPORT ovrpResult ovrp_GetActiveController2(ovrpController* activeController); + +/// Gets the currently connected controller types as a bitmask. +OVRP_EXPORT ovrpResult ovrp_GetConnectedControllers2(ovrpController* connectedControllers); + +/// Sets the vibration state for the given controllers. +OVRP_EXPORT ovrpResult ovrp_SetControllerVibration2(ovrpController controllerMask, float frequency, float amplitude); + +/// Sets the vibration state for the specified haptics locations on the given controllers. +OVRP_EXPORT ovrpResult ovrp_SetControllerLocalizedVibration( + ovrpController controllerMask, + ovrpHapticsLocation hapticsLocationMask, + float frequency, + float amplitude); + +OVRP_EXPORT ovrpResult ovrp_SetControllerHapticsAmplitudeEnvelope( + ovrpController controllerMask, + ovrpHapticsAmplitudeEnvelopeVibration hapticsVibration); + +OVRP_EXPORT ovrpResult +ovrp_SetControllerHapticsPcm(ovrpController controllerMask, ovrpHapticsPcmVibration hapticsVibration); + + + + + + +/// Gets the current haptics desc for the given controllers. +OVRP_EXPORT ovrpResult +ovrp_GetControllerHapticsDesc2(ovrpController controllerMask, ovrpHapticsDesc* controllerHapticsDesc); + +/// Gets the current haptics state for the given controllers. +OVRP_EXPORT ovrpResult +ovrp_GetControllerHapticsState2(ovrpController controllerMask, ovrpHapticsState* controllerHapticsState); + +/// Gets the preferred sample rate (in Hz) for the given controller. +OVRP_EXPORT ovrpResult ovrp_GetControllerSampleRateHz(ovrpController controller, float* sampleRateHz); + +/// Sets the haptics buffer state for the given controllers. +OVRP_EXPORT ovrpResult ovrp_SetControllerHaptics2(ovrpController controllerMask, ovrpHapticsBuffer hapticsBuffer); + +/// Sets the suggested CPU performance level +OVRP_EXPORT ovrpResult ovrp_SetSuggestedCpuPerformanceLevel(ovrpProcessorPerformanceLevel perfLevel); + +/// Gets the suggested CPU performance level +OVRP_EXPORT ovrpResult ovrp_GetSuggestedCpuPerformanceLevel(ovrpProcessorPerformanceLevel* perfLevel); + +/// Sets the suggested CPU performance level +OVRP_EXPORT ovrpResult ovrp_SetSuggestedGpuPerformanceLevel(ovrpProcessorPerformanceLevel perfLevel); + +/// Gets the suggested CPU performance level +OVRP_EXPORT ovrpResult ovrp_GetSuggestedGpuPerformanceLevel(ovrpProcessorPerformanceLevel* perfLevel); + +/// Gets the current CPU performance level, integer in the range 0 - 3 (deprecated). +OVRP_EXPORT ovrpResult ovrp_GetSystemCpuLevel2(int* systemCpuLevel); + +/// Sets the current CPU performance level, integer in the range 0 - 3 (deprecated). +OVRP_EXPORT ovrpResult ovrp_SetSystemCpuLevel2(int systemCpuLevel); + +/// Returns true if the application should run at the maximum possible CPU level. +OVRP_EXPORT ovrpResult ovrp_GetAppCPUPriority2(ovrpBool* appCPUPriority); + +/// Determines whether the application should run at the maximum possible CPU level. +OVRP_EXPORT ovrpResult ovrp_SetAppCPUPriority2(ovrpBool appCPUPriority); + +/// Gets the current GPU performance level, integer in the range 0 - 3 (deprecated). +OVRP_EXPORT ovrpResult ovrp_GetSystemGpuLevel2(int* systemGpuLevel); + +/// Sets the current GPU performance level, integer in the range 0 - 3 (deprecated). +OVRP_EXPORT ovrpResult ovrp_SetSystemGpuLevel2(int systemGpuLevel); + +/// If true, the system is running in a reduced performance mode to save power. +OVRP_EXPORT ovrpResult ovrp_GetSystemPowerSavingMode2(ovrpBool* systemPowerSavingMode); + +/// Gets the current refresh rate of the HMD. +OVRP_EXPORT ovrpResult ovrp_GetSystemDisplayFrequency2(float* systemDisplayFrequency); + +/// Gets the available refresh rates of the HMD. +OVRP_EXPORT ovrpResult +ovrp_GetSystemDisplayAvailableFrequencies(float* systemDisplayAvailableFrequencies, int* arraySize); + +/// Sets the refresh rate for the HMD +OVRP_EXPORT ovrpResult ovrp_SetSystemDisplayFrequency(float requestedFrequency); + +/// Gets the minimum number of vsyncs to wait after each frame. +OVRP_EXPORT ovrpResult ovrp_GetSystemVSyncCount2(int* systemVSyncCount); + +/// Sets the minimum number of vsyncs to wait after each frame. +OVRP_EXPORT ovrpResult ovrp_SetSystemVSyncCount2(int systemVSyncCount); + +/// OVRPlugin does not support Android system callbacks in UE4 and UE5. +/// Please use Optional Mobile Features Blueprint Library Plugin or include FAndroidMisc.h in your project +#ifndef OVRPLUGIN_JNI_LIB_EXCLUDED +/// Gets the current system volume level. +OVRP_EXPORT ovrpResult ovrp_GetSystemVolume2(float* systemVolume); + +/// If true, headphones are currently attached to the device. +OVRP_EXPORT ovrpResult ovrp_GetSystemHeadphonesPresent2(ovrpBool* systemHeadphonesPresent); + +/// Gets the status of the system's battery or "Unknown" if there is none. +OVRP_EXPORT ovrpResult ovrp_GetSystemBatteryStatus2(ovrpBatteryStatus* systemBatteryStatus); + +/// Gets the current available battery charge, ranging from 0 (empty) to 1 (full). +OVRP_EXPORT ovrpResult ovrp_GetSystemBatteryLevel2(float* systemBatteryLevel); + +/// Gets the current battery temperature in degrees Celsius. +OVRP_EXPORT ovrpResult ovrp_GetSystemBatteryTemperature2(float* systemBatteryTemperature); +#endif + +/// Gets the current product name for the device, if available. +OVRP_EXPORT ovrpResult ovrp_GetSystemProductName2(char const** systemProductName); + +/// Gets the current region for the device, if available. +OVRP_EXPORT ovrpResult ovrp_GetSystemRegion2(ovrpSystemRegion* systemRegion); + +/// Shows a given platform user interface. +OVRP_EXPORT ovrpResult ovrp_ShowSystemUI2(ovrpUI ui); + +/// If true, the app has VR focus. +OVRP_EXPORT ovrpResult ovrp_GetAppHasVrFocus2(ovrpBool* appHasVrFocus); + +/// True if the application is the foreground application and receives input (e.g. Touch +/// controller state). If this is false then the application is in the background (but possibly +/// still visible) should hide any input representations such as hands. +OVRP_EXPORT ovrpResult ovrp_GetAppHasInputFocus(ovrpBool* appHasInputFocus); + +/// True if a system overlay is present, such as a dashboard. In this case the application +/// (if visible) should pause while still drawing, avoid drawing near-field graphics so they +/// don't visually fight with the system overlay, and consume fewer CPU and GPU resources. +OVRP_EXPORT ovrpResult ovrp_GetAppHasSystemOverlayPresent(ovrpBool* appHasOverlayPresent); + +/// If true, the app should quit as soon as possible. +OVRP_EXPORT ovrpResult ovrp_GetAppShouldQuit2(ovrpBool* appShouldQuit); + +/// If true, the app should recenter as soon as possible. +OVRP_EXPORT ovrpResult ovrp_GetAppShouldRecenter2(ovrpBool* appShouldRecenter); + +/// If true, the app should recreate the distortion window as soon as possible. +OVRP_EXPORT ovrpResult ovrp_GetAppShouldRecreateDistortionWindow2(ovrpBool* appShouldRecreateDistortionWindow); + +/// Gets the latest measured latency timings. +OVRP_EXPORT ovrpResult ovrp_GetAppLatencyTimings2(ovrpAppLatencyTimings* appLatencyTimings); + +/// Sets the engine info for the current app. +OVRP_EXPORT ovrpResult ovrp_SetAppEngineInfo2(const char* engineName, const char* engineVersion, ovrpBool isEditor); + +/// If true, the user is currently wearing the VR display and it is not idle. +OVRP_EXPORT ovrpResult ovrp_GetUserPresent2(ovrpBool* userPresent); + +/// Gets the physical inter-pupillary distance (IPD) separating the user's eyes in meters. +OVRP_EXPORT ovrpResult ovrp_GetUserIPD2(float* userIPD); + +/// Sets the physical inter-pupillary distance (IPD) separating the user's eyes in meters. +OVRP_EXPORT ovrpResult ovrp_SetUserIPD2(float value); + +/// Gets the physical height of the player's eyes from the ground in meters. +OVRP_EXPORT ovrpResult ovrp_GetUserEyeHeight2(float* userEyeHeight); + +/// Sets the physical height of the player's eyes from the ground in meters. +OVRP_EXPORT ovrpResult ovrp_SetUserEyeHeight2(float userEyeHeight); + +/// Gets the physical distance from the base of the neck to the center of the player's eyes in +/// meters. +OVRP_EXPORT ovrpResult ovrp_GetUserNeckEyeDistance2(ovrpVector2f* userEyeNeckDistance); + +/// Sets the physical distance from the base of the neck to the center of the player's eyes in +/// meters. +OVRP_EXPORT ovrpResult ovrp_SetUserNeckEyeDistance2(ovrpVector2f userEyeNeckDistance); + +/// Setup the current display objects +OVRP_EXPORT ovrpResult ovrp_SetupDisplayObjects2(void* device, void* display, void* window); + +/// Return true if the device supports multi-view rendering +OVRP_EXPORT ovrpResult ovrp_GetSystemMultiViewSupported2(ovrpBool* systemMultiViewSupported); + +/// Return true is the plugin supports submitting texture arrays +OVRP_EXPORT ovrpResult ovrp_GetEyeTextureArraySupported2(ovrpBool* eyeTextureArraySupported); + +/// If true, the boundary system is configured with valid boundary data. +OVRP_EXPORT ovrpResult ovrp_GetBoundaryConfigured2(ovrpBool* boundaryConfigured); + +/// Return success if the device supports depth compositing +OVRP_EXPORT ovrpResult ovrp_GetDepthCompositingSupported(ovrpBool* depthCompositingSupported); + +/// Performs a boundary test between the specified node and boundary types. +OVRP_EXPORT ovrpResult +ovrp_TestBoundaryNode2(ovrpNode node, ovrpBoundaryType boundaryType, ovrpBoundaryTestResult* boundaryTestResult); + +/// Performs a boundary test between the specified point and boundary types. +OVRP_EXPORT ovrpResult +ovrp_TestBoundaryPoint2(ovrpVector3f point, ovrpBoundaryType boundaryType, ovrpBoundaryTestResult* boundaryTestResult); + +/// Gets the geometry data for the specified boundary type. +OVRP_EXPORT ovrpResult ovrp_GetBoundaryGeometry3(ovrpBoundaryType boundaryType, ovrpVector3f* points, int* pointsCount); + +/// Gets the dimensions for the specified boundary type. Returned x,y,z values correspond to width, +/// height, depth. +OVRP_EXPORT ovrpResult ovrp_GetBoundaryDimensions2(ovrpBoundaryType boundaryType, ovrpVector3f* bounaryDimensions); + +/// Gets the current visiblity status for the boundary system. +OVRP_EXPORT ovrpResult ovrp_GetBoundaryVisible2(ovrpBool* boundaryVisible); + +/// Requests that the boundary system visibility be set to the specified value. Can be overridden by +/// the boundary system or the user. +OVRP_EXPORT ovrpResult ovrp_SetBoundaryVisible2(ovrpBool boundaryVisible); + +/// Returns the currently present headset type. +OVRP_EXPORT ovrpResult ovrp_GetSystemHeadsetType2(ovrpSystemHeadset* systemHeadsetType); + +/// Returns information useful for performance analysis and dynamic quality adjustments. +OVRP_EXPORT ovrpResult ovrp_GetAppPerfStats2(ovrpAppPerfStats* appPerfStats); + +/// Resets internal performance counters to clear previous data from impacting the current reported +/// state. +OVRP_EXPORT ovrpResult ovrp_ResetAppPerfStats2(); + +/// Return the app FPS, thread safe +OVRP_EXPORT ovrpResult ovrp_GetAppFramerate2(float* appFramerate); + +/// Returns if a certain perf metrics is supported +OVRP_EXPORT ovrpResult ovrp_IsPerfMetricsSupported(ovrpPerfMetrics perfMetrics, ovrpBool* supported); + +/// Returns if a floating point perf metrics +OVRP_EXPORT ovrpResult ovrp_GetPerfMetricsFloat(ovrpPerfMetrics perfMetrics, float* value); + +/// Returns if an integer perf metrics +OVRP_EXPORT ovrpResult ovrp_GetPerfMetricsInt(ovrpPerfMetrics perfMetrics, int* value); + +/// Set a latency when getting the hand node poses through ovrp_GetNodePoseState2(ovrpStep_Render, ...) +OVRP_EXPORT ovrpResult ovrp_SetHandNodePoseStateLatency(double latencyInSeconds); + +/// Get the current latency when getting the hand node poses through ovrp_GetNodePoseState2(ovrpStep_Render, ...) +OVRP_EXPORT ovrpResult ovrp_GetHandNodePoseStateLatency(double* latencyInSeconds); + +/// Returns the recommended multisample antialiasing level for the current device. +OVRP_EXPORT ovrpResult ovrp_GetSystemRecommendedMSAALevel2(int* systemRecommendedMSAALevel); + +/// Inhibits system UX behavior. +OVRP_EXPORT ovrpResult ovrp_SetInhibitSystemUX2(ovrpBool inhibitSystemUX); + +/// Return true if the device supports tiled multires +OVRP_EXPORT ovrpResult ovrp_GetTiledMultiResSupported(ovrpBool* foveationSupported); + +/// Returns the current multires level on the device +OVRP_EXPORT ovrpResult ovrp_GetTiledMultiResLevel(ovrpTiledMultiResLevel* level); + +/// Sets MultiRes levels +OVRP_EXPORT ovrpResult ovrp_SetTiledMultiResLevel(ovrpTiledMultiResLevel level); + +/// Return if MultiRes is dynamic or not +OVRP_EXPORT ovrpResult ovrp_GetTiledMultiResDynamic(ovrpBool* isDynamic); + +/// Sets if MultiRes is dynamic or not +OVRP_EXPORT ovrpResult ovrp_SetTiledMultiResDynamic(ovrpBool isDynamic); + +/// Return true if the device supports eye tracked foveation +OVRP_EXPORT ovrpResult ovrp_GetFoveationEyeTrackedSupported(ovrpBool* foveationSupported); + +/// Return if foveation is eye tracked +OVRP_EXPORT ovrpResult ovrp_GetFoveationEyeTracked(ovrpBool* isEyeTracked); + +/// Sets if foveation is eye tracked +OVRP_EXPORT ovrpResult ovrp_SetFoveationEyeTracked(ovrpBool isEyeTracked); + +/// Gets the eye tracked foveation center (used for tile offset) +OVRP_EXPORT ovrpResult ovrp_GetFoveationEyeTrackedCenter(ovrpVector2f fovCenter[2]); + + + + + + + + + + + + +/// Return true if the device supports GPU Util querying +OVRP_EXPORT ovrpResult ovrp_GetGPUUtilSupported(ovrpBool* gpuUtilSupported); + +/// Return the GPU util if the device supports it +OVRP_EXPORT ovrpResult ovrp_GetGPUUtilLevel(float* gpuUtil); + +/// Set thread's performance level, for example, put the performance critical thread on golden cores, +/// future policy might change for future hardware +OVRP_EXPORT ovrpResult ovrp_SetThreadPerformance(int threadId, ovrpThreadPerf perf); + +/// This is specifically for Unity to fix Core Affinity wrong assignment. +OVRP_EXPORT ovrpResult ovrp_AutoThreadScheduling( + unsigned int bigCoreMaskFromEngine, + unsigned int* threadIds, + ovrpThreadPerf* threadPerfFlags, + int threadCount); + +OVRP_EXPORT ovrpResult ovrp_GetGPUFrameTime(float* gpuTime); + +/// This is to request vertices and indices for the triangle mesh +OVRP_EXPORT ovrpResult ovrp_GetViewportStencil( + ovrpEye eyeId, + ovrpViewportStencilType type, + ovrpVector2f* vertices, + int* vertexCount, + ovrpUInt16* indices, + int* indexCount); + +OVRP_EXPORT ovrpResult ovrp_SetDeveloperTelemetryConsent(ovrpBool consent); + +OVRP_EXPORT ovrpResult ovrp_SendEvent(const char* eventName, const char* param); + +OVRP_EXPORT ovrpResult ovrp_SendEvent2(const char* eventName, const char* param, const char* source); + +OVRP_EXPORT ovrpResult ovrp_AddCustomMetadata(const char* metadataName, const char* metadataParam); + +OVRP_EXPORT ovrpResult ovrp_SetDeveloperMode(ovrpBool active); + +OVRP_EXPORT ovrpResult ovrp_SetDeveloperModeStrict(ovrpBool active); + +OVRP_EXPORT ovrpResult ovrp_SetVrApiPropertyInt(int propertyEnum, int value); + +OVRP_EXPORT ovrpResult ovrp_SetVrApiPropertyFloat(int propertyEnum, float value); + +OVRP_EXPORT ovrpResult ovrp_GetVrApiPropertyInt(int propertyEnum, int* value); + + + + + + + +OVRP_EXPORT ovrpResult ovrp_GetCurrentTrackingTransformPose(ovrpPosef* trackingTransformPose); + +OVRP_EXPORT ovrpResult ovrp_GetTrackingTransformRawPose(ovrpPosef* trackingTransformRawPose); + +OVRP_EXPORT ovrpResult +ovrp_GetTrackingTransformRelativePose(ovrpPosef* trackingTransformRelativePose, ovrpTrackingOrigin trackingOrigin); + +OVRP_EXPORT ovrpResult ovrp_GetTimeInSeconds(double* timeInSeconds); + +OVRP_EXPORT ovrpResult ovrp_GetASWVelocityScale(float* aswVelocityScale); +OVRP_EXPORT ovrpResult ovrp_GetASWDepthScale(float* aswDepthScale); +OVRP_EXPORT ovrpResult ovrp_GetASWAdaptiveMode(ovrpBool* aswAdaptiveMode); +OVRP_EXPORT ovrpResult ovrp_SetASWAdaptiveMode(ovrpBool aswAdaptiveMode); +OVRP_EXPORT ovrpResult ovrp_IsRequestingASWData(ovrpBool* needASWData); + +OVRP_EXPORT ovrpResult ovrp_GetPredictedDisplayTime(int frameIndex, double* predictedDisplayTime); + +/// Set whether the system should be querying for hand poses powered by controller data +OVRP_EXPORT ovrpResult ovrp_SetControllerDrivenHandPoses(ovrpBool controllerDrivenHandPoses); +OVRP_EXPORT ovrpResult ovrp_SetControllerDrivenHandPosesAreNatural(ovrpBool controllerDrivenHandPosesAreNatural); +OVRP_EXPORT ovrpResult ovrp_IsControllerDrivenHandPosesEnabled(ovrpBool* enabled); +OVRP_EXPORT ovrpResult ovrp_AreControllerDrivenHandPosesNatural(ovrpBool* natural); + +OVRP_EXPORT ovrpResult ovrp_SetWideMotionModeHandPoses(ovrpBool wideMotionModeHandPoses); +OVRP_EXPORT ovrpResult ovrp_IsWideMotionModeHandPosesEnabled(ovrpBool* enabled); + + + + + + + + + + +OVRP_EXPORT ovrpResult ovrp_SetMultimodalHandsControllersSupported(ovrpBool supported); +OVRP_EXPORT ovrpResult ovrp_IsMultimodalHandsControllersSupported(ovrpBool* supported); +OVRP_EXPORT ovrpResult +ovrp_GetCurrentDetachedInteractionProfile(ovrpHand hand, ovrpInteractionProfile* interactionProfile); + +OVRP_EXPORT ovrpResult ovrp_GetHandTrackingEnabled(ovrpBool* handTrackingEnabled); +OVRP_EXPORT ovrpResult ovrp_GetHandState(ovrpStep step, ovrpHand hand, ovrpHandState* handState); +OVRP_EXPORT ovrpResult ovrp_GetHandState2(ovrpStep step, int frameIndex, ovrpHand hand, ovrpHandState* handState); + + + + +OVRP_EXPORT ovrpResult ovrp_GetSkeleton2(ovrpSkeletonType skeletonType, ovrpSkeleton2* skeleton); +OVRP_EXPORT ovrpResult ovrp_GetSkeleton3(ovrpSkeletonType skeletonType, ovrpSkeleton3* skeleton); +OVRP_EXPORT ovrpResult ovrp_GetMesh(ovrpMeshType meshType, ovrpMesh* mesh); + +OVRP_EXPORT ovrpResult ovrp_GetBodyState(ovrpStep step, int frameIndex, ovrpBodyState* bodyState); + + + + +OVRP_EXPORT ovrpResult ovrp_GetBodyState4(ovrpStep step, int frameIndex, ovrpBodyState4* bodyState); +OVRP_EXPORT ovrpResult ovrp_GetBodyTrackingEnabled(ovrpBool* enabled); +OVRP_EXPORT ovrpResult ovrp_GetBodyTrackingSupported(ovrpBool* supported); +OVRP_EXPORT ovrpResult ovrp_GetFullBodyTrackingEnabled(ovrpBool* enabled); + +OVRP_EXPORT ovrpResult ovrp_StartFaceTracking(); +OVRP_EXPORT ovrpResult ovrp_StopFaceTracking(); +OVRP_EXPORT ovrpResult ovrp_GetFaceTracking2Enabled(ovrpBool* faceTracking2Enabled); +OVRP_EXPORT ovrpResult ovrp_GetFaceTracking2Supported(ovrpBool* faceTracking2Supported); +OVRP_EXPORT ovrpResult ovrp_StartFaceTracking2( + const ovrpFaceTrackingDataSource2* const requestedDataSources, + unsigned int requestedDataSourcesCount); +OVRP_EXPORT ovrpResult ovrp_StopFaceTracking2(); +OVRP_EXPORT ovrpResult ovrp_StartBodyTracking(); + + + + +OVRP_EXPORT ovrpResult ovrp_StartBodyTracking2(ovrpBodyJointSet jointSet); + +OVRP_EXPORT ovrpResult ovrp_RequestBodyTrackingFidelity(ovrpBodyTrackingFidelity2 bodyTrackingFidelity); + + + + + +OVRP_EXPORT ovrpResult ovrp_SuggestBodyTrackingCalibrationOverride(ovrpBodyTrackingCalibrationInfo calibrationInfo); +OVRP_EXPORT ovrpResult ovrp_ResetBodyTrackingCalibration(); + +OVRP_EXPORT ovrpResult ovrp_StopBodyTracking(); +OVRP_EXPORT ovrpResult ovrp_StartEyeTracking(); +OVRP_EXPORT ovrpResult ovrp_StopEyeTracking(); + +OVRP_EXPORT ovrpResult ovrp_GetLocalTrackingSpaceRecenterCount(int* recenterCount); + +// Returns true if the system Hmd is in 3dof mode +OVRP_EXPORT ovrpResult ovrp_GetSystemHmd3DofModeEnabled(ovrpBool* enabled); + +OVRP_EXPORT ovrpResult ovrp_SetClientColorDesc(ovrpColorSpace colorSpace); +OVRP_EXPORT ovrpResult ovrp_GetHmdColorDesc(ovrpColorSpace* colorSpace); + +OVRP_EXPORT ovrpResult ovrp_SetEyeBufferSharpenType(ovrpLayerSubmitFlags sharpenType); + +// app should call this in a loop until there are no more events, which will return ovrpSuccess_EventUnavailable and an +// event of type ovrpEventType_None ovrp_PollEvent and ovrp_PollEvent2 are both in use, Unity needed ovrp_PollEvent2 due +// to memory allocation issues +OVRP_EXPORT ovrpResult ovrp_PollEvent(ovrpEventDataBuffer* eventBuffer); +OVRP_EXPORT ovrpResult ovrp_PollEvent2(ovrpEventType* eventType, unsigned char** eventBuffer); + +OVRP_EXPORT ovrpResult ovrp_SetKeyboardOverlayUV(ovrpVector2f uv); +OVRP_EXPORT ovrpResult ovrp_SetKeyboardOverlayPose(ovrpPosef pose); + + + + + + + +OVRP_EXPORT ovrpResult ovrp_StartKeyboardTracking(ovrpUInt64 trackedKeyboardId); +OVRP_EXPORT ovrpResult ovrp_StopKeyboardTracking(); +OVRP_EXPORT ovrpResult ovrp_GetKeyboardState(ovrpStep step, int frameIndex, ovrpKeyboardState* keyboardState); +OVRP_EXPORT ovrpResult ovrp_GetSystemKeyboardDescription( + ovrpTrackedKeyboardQueryFlags queryFlags, + ovrpKeyboardDescription* keyboardDescription); + +OVRP_EXPORT ovrpResult ovrp_CreateVirtualKeyboard(const ovrpVirtualKeyboardCreateInfo* createInfo); +OVRP_EXPORT ovrpResult ovrp_DestroyVirtualKeyboard(); +OVRP_EXPORT ovrpResult +ovrp_SendVirtualKeyboardInput(const ovrpVirtualKeyboardInputInfo* info, ovrpPosef* interactorRootPose); +OVRP_EXPORT ovrpResult ovrp_ChangeVirtualKeyboardTextContext(const char* textContext); +OVRP_EXPORT ovrpResult +ovrp_CreateVirtualKeyboardSpace(const ovrpVirtualKeyboardSpaceCreateInfo* createInfo, ovrpUInt64* keyboardSpace); +OVRP_EXPORT ovrpResult ovrp_SuggestVirtualKeyboardLocation(const ovrpVirtualKeyboardLocationInfo* locationInfo); +OVRP_EXPORT ovrpResult ovrp_GetVirtualKeyboardScale(float* scale); +OVRP_EXPORT ovrpResult +ovrp_GetVirtualKeyboardModelAnimationStates(ovrpVirtualKeyboardModelAnimationStates* animationStates); +OVRP_EXPORT ovrpResult ovrp_GetVirtualKeyboardDirtyTextures(ovrpVirtualKeyboardTextureIds* textureIds); +OVRP_EXPORT ovrpResult +ovrp_GetVirtualKeyboardTextureData(ovrpUInt64 textureId, ovrpVirtualKeyboardTextureData* textureData); +OVRP_EXPORT ovrpResult ovrp_SetVirtualKeyboardModelVisibility(const ovrpVirtualKeyboardModelVisibility* visibility); + +OVRP_EXPORT ovrpResult ovrp_QplSetConsent(ovrpBool qplConsent); +OVRP_EXPORT ovrpResult ovrp_QplMarkerStart(int markerId, int instanceKey, ovrpInt64 timestampMs); +OVRP_EXPORT ovrpResult ovrp_QplMarkerEnd(int markerId, ovrpInt16 actionId, int instanceKey, ovrpInt64 timestampMs); +OVRP_EXPORT ovrpResult ovrp_QplMarkerPoint(int markerId, const char* name, int instanceKey, ovrpInt64 timestampMs); +OVRP_EXPORT ovrpResult ovrp_QplMarkerPointCached(int markerId, int nameHandle, int instanceKey, ovrpInt64 timestampMs); +OVRP_EXPORT ovrpResult +ovrp_QplMarkerAnnotation(int markerId, const char* annotationKey, const char* annotationValue, int instanceKey); +OVRP_EXPORT ovrpResult ovrp_QplMarkerAnnotationVariant( + int markerId, + const char* annotationKey, + const ovrpQplVariant* annotationValue, + int instanceKey); +OVRP_EXPORT ovrpResult ovrp_QplMarkerPointData( + int markerId, + const char* name, + const ovrpQplAnnotation* annotations, + int annotationCount, + int instanceKey, + ovrpInt64 timestampMs); + +OVRP_EXPORT ovrpResult ovrp_QplCreateMarkerHandle(const char* name, int* nameHandle); +OVRP_EXPORT ovrpResult ovrp_QplDestroyMarkerHandle(int nameHandle); +OVRP_EXPORT ovrpResult ovrp_OnEditorShutdown(); + +/// Gets the current recent pose, acceleration, and velocity of the given node for the current time without any +/// prediction +OVRP_EXPORT ovrpResult ovrp_GetNodePoseStateImmediate(ovrpNode nodeId, ovrpPoseStatef* nodePoseState); + +OVRP_EXPORT ovrpResult ovrp_GetNodePoseStateAtTime(double time, ovrpNode nodeId, ovrpPoseStatef* pose); + +OVRP_EXPORT ovrpResult +ovrp_AreHandPosesGeneratedByControllerData(ovrpStep step, ovrpNode nodeId, ovrpBool* generatedByControllerData); + + +OVRP_EXPORT ovrpResult ovrp_SetSimultaneousHandsAndControllersEnabled(ovrpBool enabled); +OVRP_EXPORT ovrpResult ovrp_GetControllerIsInHand(ovrpStep step, ovrpNode nodeId, ovrpBool* isInHand); + + + + + +OVRP_EXPORT ovrpResult ovrp_GetRenderModelPaths(unsigned int index, char* path); +OVRP_EXPORT ovrpResult ovrp_GetRenderModelProperties(const char* path, ovrpRenderModelProperties* properties); +OVRP_EXPORT ovrpResult ovrp_GetRenderModelProperties2( + const char* path, + ovrpRenderModelFlags renderModelFlags, + ovrpRenderModelProperties* properties); +OVRP_EXPORT ovrpResult ovrp_LoadRenderModel( + ovrpUInt64 modelKey, + ovrpUInt32 bufferInputCapacity, + ovrpUInt32* bufferCountOutput, + unsigned char* buffer); + +OVRP_EXPORT ovrpResult ovrp_LocateSpace(ovrpPosef* location, const ovrpSpace* space, ovrpTrackingOrigin baseSpaceType); +OVRP_EXPORT ovrpResult +ovrp_LocateSpace2(ovrpSpaceLocationf* location, const ovrpSpace* space, ovrpTrackingOrigin baseSpaceType); +OVRP_EXPORT ovrpResult ovrp_CreateSpatialAnchor(const ovrpSpatialAnchorCreateInfo* createInfo, ovrpUInt64* requestId); +OVRP_EXPORT ovrpResult ovrp_DestroySpace(ovrpSpace* space); +OVRP_EXPORT ovrpResult ovrp_SetSpaceComponentStatus( + const ovrpSpace* space, + ovrpSpaceComponentType componentType, + const ovrpBool enable, + const double timeout, + ovrpUInt64* requestId); +OVRP_EXPORT ovrpResult ovrp_GetSpaceComponentStatus( + const ovrpSpace* space, + ovrpSpaceComponentType componentType, + ovrpBool* enabled, + ovrpBool* changePending); +OVRP_EXPORT ovrpResult ovrp_EnumerateSpaceSupportedComponents( + const ovrpSpace* space, + ovrpUInt32 componentTypesCapacityInput, + ovrpUInt32* componentTypesCountOutput, + ovrpSpaceComponentType* componentTypes); +OVRP_EXPORT ovrpResult ovrp_QuerySpaces(const ovrpSpaceQueryInfo* queryInfo, ovrpUInt64* requestId); + + + +OVRP_EXPORT ovrpResult ovrp_RetrieveSpaceQueryResults( + ovrpUInt64* requestId, + ovrpUInt32 resultCapacityInput, + ovrpUInt32* resultCountOutput, + ovrpSpaceQueryResult* results); +OVRP_EXPORT ovrpResult ovrp_SaveSpace( + const ovrpSpace* space, + ovrpSpaceStorageLocation location, + ovrpSpaceStoragePersistenceMode mode, + ovrpUInt64* requestId); +OVRP_EXPORT ovrpResult +ovrp_EraseSpace(const ovrpSpace* space, ovrpSpaceStorageLocation location, ovrpUInt64* requestId); +OVRP_EXPORT ovrpResult ovrp_GetSpaceUuid(const ovrpSpace* space, ovrpUuid* uuid); +OVRP_EXPORT ovrpResult ovrp_GetSpaceUserId(const ovrpUser* spaceUser, ovrpUInt64* spaceUserId); +OVRP_EXPORT ovrpResult ovrp_CreateSpaceUser(const ovrpUInt64* spaceUserId, ovrpUser* spaceUser); +OVRP_EXPORT ovrpResult ovrp_DestroySpaceUser(const ovrpUser* spaceUser); +OVRP_EXPORT ovrpResult ovrp_SaveSpaceList( + const ovrpSpace* spaces, + ovrpUInt32 numSpaces, + ovrpSpaceStorageLocation location, + ovrpUInt64* requestId); +OVRP_EXPORT ovrpResult ovrp_ShareSpaces( + const ovrpSpace* spaces, + ovrpUInt32 numSpaces, + const ovrpUser* users, + ovrpUInt32 numUsers, + ovrpUInt64* requestId); + +OVRP_EXPORT ovrpResult ovrp_GetSpaceContainer(const ovrpSpace* space, ovrpSpaceContainer* container); + +OVRP_EXPORT ovrpResult ovrp_GetSpaceBoundingBox2D(const ovrpSpace* space, ovrpRectf* rect); + +OVRP_EXPORT ovrpResult ovrp_GetSpaceBoundingBox3D(const ovrpSpace* space, ovrpBoundsf* bounds); + +OVRP_EXPORT ovrpResult ovrp_GetSpaceSemanticLabels(const ovrpSpace* space, ovrpSemanticLabels* labels); + +OVRP_EXPORT ovrpResult ovrp_GetSpaceRoomLayout(const ovrpSpace* space, ovrpRoomLayout* layout); + +OVRP_EXPORT ovrpResult ovrp_GetSpaceBoundary2D(const ovrpSpace* space, ovrpBoundary2D* boundary); + +OVRP_EXPORT ovrpResult ovrp_RequestSceneCapture(const ovrpSceneCaptureRequest* request, ovrpUInt64* requestId); + + + + + + + + + + + + + + + + + + +OVRP_EXPORT ovrpResult ovrp_GetSpaceTriangleMesh(const ovrpSpace* space, ovrpTriangleMesh* triangleMeshOutput); + + + + + + + + + + + + + + + + + +OVRP_EXPORT ovrpResult ovrp_GetFaceTrackingEnabled(ovrpBool* faceTrackingEnabled); + +OVRP_EXPORT ovrpResult ovrp_GetFaceTrackingSupported(ovrpBool* faceTrackingSupported); + + + + + +OVRP_EXPORT ovrpResult ovrp_GetFaceState(ovrpStep step, int frameIndex, ovrpFaceState* faceState); + +OVRP_EXPORT ovrpResult ovrp_GetFaceState2(ovrpStep step, int frameIndex, ovrpFaceState2* faceState); + +OVRP_EXPORT ovrpResult ovrp_GetEyeTrackingEnabled(ovrpBool* eyeTrackingEnabled); + +OVRP_EXPORT ovrpResult ovrp_GetEyeTrackingSupported(ovrpBool* eyeTrackingSupported); + +OVRP_EXPORT ovrpResult ovrp_GetEyeGazesState(ovrpStep step, int frameIndex, ovrpEyeGazesState* eyeGazesState); + + + + + + + + + + + + + + + + + + + + + + + + + + + + +OVRP_EXPORT ovrpResult +ovrp_FeatureFidelitySetFeatureEnable(ovrpFeatureType feature, ovrpFeatureEnableState featureEnableState); +OVRP_EXPORT ovrpResult +ovrp_FeatureFidelitySetFeatureFidelity(ovrpFeatureType feature, ovrpFeatureFidelity featureFidelity); +OVRP_EXPORT ovrpResult ovrp_FeatureFidelityGetFeatureState( + ovrpFeatureType feature, + ovrpFeatureState* outIdealState, + ovrpFeatureState* outCurrentState); + + + + + + + + + + + + + + + + +OVRP_EXPORT ovrpResult ovrp_GetLocalDimmingSupported(ovrpBool* localDimmingSupported); +OVRP_EXPORT ovrpResult ovrp_SetLocalDimming(ovrpBool localDimmingMode); +OVRP_EXPORT ovrpResult ovrp_GetLocalDimming(ovrpBool* localDimmingMode); + +OVRP_EXPORT ovrpResult ovrp_GetCurrentInteractionProfile(ovrpHand hand, ovrpInteractionProfile* interactionProfile); + + + + + + + + + + + + + +OVRP_EXPORT ovrpResult ovrp_GetLayerRecommendedResolution(int layerId, ovrpSizei* recommendedDimensions); +OVRP_EXPORT ovrpResult ovrp_GetEyeLayerRecommendedResolution(ovrpSizei* recommendedDimensions); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +OVRP_EXPORT ovrpResult ovrp_IsLayerShapeSupported(ovrpShape shape, ovrpBool* isLayerShapeSupported); + +OVRP_EXPORT ovrpResult ovrp_GetEnvironmentDepthSupported(ovrpBool* supported); +OVRP_EXPORT ovrpResult ovrp_GetEnvironmentDepthHandRemovalSupported(ovrpBool* supported); +OVRP_EXPORT ovrpResult ovrp_InitializeEnvironmentDepth(int createFlags); +OVRP_EXPORT ovrpResult ovrp_DestroyEnvironmentDepth(); +OVRP_EXPORT ovrpResult ovrp_GetEnvironmentDepthTextureDesc(ovrpEnvironmentDepthTextureDesc* desc); +OVRP_EXPORT ovrpResult ovrp_GetEnvironmentDepthTextureStageCount(int* stageCount); +OVRP_EXPORT ovrpResult ovrp_GetEnvironmentDepthTexture(int stage, ovrpEye eyeId, ovrpTextureHandle* texture); +OVRP_EXPORT ovrpResult ovrp_SetEnvironmentDepthHandRemoval(ovrpBool enabled); +OVRP_EXPORT ovrpResult ovrp_StartEnvironmentDepth(); +OVRP_EXPORT ovrpResult ovrp_StopEnvironmentDepth(); +OVRP_EXPORT ovrpResult ovrp_GetEnvironmentDepthFrameDesc(ovrpEye eyeId, ovrpEnvironmentDepthFrameDesc* frameDesc); + + + + + + + + + + + + + + + + + + + + + + + + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Plugins/MetaXR/Source/Thirdparty/OVRPlugin/OVRPlugin/Include/OVR_Plugin_Deprecated.h b/Plugins/MetaXR/Source/Thirdparty/OVRPlugin/OVRPlugin/Include/OVR_Plugin_Deprecated.h new file mode 100644 index 0000000..5e35ad8 --- /dev/null +++ b/Plugins/MetaXR/Source/Thirdparty/OVRPlugin/OVRPlugin/Include/OVR_Plugin_Deprecated.h @@ -0,0 +1,430 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * Licensed under the Oculus SDK License Agreement (the "License"); + * you may not use the Oculus SDK except in compliance with the License, + * which is provided at the time of installation or download, or which + * otherwise accompanies this software in either electronic or hard copy form. + * + * You may obtain a copy of the License at + * + * https://developer.oculus.com/licenses/oculussdk/ + * + * Unless required by applicable law or agreed to in writing, the Oculus SDK + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OVR_Plugin_Deprecated_h +#define OVR_Plugin_Deprecated_h + +#include "OVR_Plugin.h" +#include "OVR_Plugin_Types_Deprecated.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// Deprecated to avoid an extra shutdown/initialize on the mobile side +OVRP_EXPORT ovrpResult ovrp_PreInitialize3(void* activity); + +// Deprecated for adding an ovrpPreinitializeFlags parameter +OVRP_EXPORT ovrpResult ovrp_PreInitialize4(void* activity, ovrpRenderAPIType apiType); + +// Deprecated for getting extra Vulkan paramters from Unity Oculus XR Plugin +OVRP_EXPORT ovrpResult ovrp_Initialize6( + ovrpRenderAPIType apiType, + ovrpLogCallback logCallback, + void* activity, + void* vkInstance, + void* vkPhysicalDevice, + void* vkDevice, + void* vkQueue, + void* vkGetInstanceProcAddr, // PFN_vkGetInstanceProcAddr + unsigned int vkQueueFamilyIndex, + int initializeFlags, + OVRP_CONSTREF(ovrpVersion) version); + +OVRP_EXPORT ovrpResult ovrp_Initialize5( + ovrpRenderAPIType apiType, + ovrpLogCallback logCallback, + void* activity, + void* vkInstance, + void* vkPhysicalDevice, + void* vkDevice, + void* vkQueue, + int initializeFlags, + OVRP_CONSTREF(ovrpVersion) version); + +// Deprecated by VRAPI_Vulkan changes +OVRP_EXPORT ovrpResult ovrp_PreInitialize2(); + +OVRP_EXPORT ovrpResult ovrp_Initialize4( + ovrpRenderAPIType apiType, + ovrpLogCallback logCallback, + void* activity, + void* instance, + int initializeFlags, + OVRP_CONSTREF(ovrpVersion) version); + +// Deprecated by CAPI_Vulkan changes +OVRP_EXPORT ovrpResult ovrp_Initialize3( + ovrpRenderAPIType apiType, + ovrpLogCallback logCallback, + void* activity, + int initializeFlags, + OVRP_CONSTREF(ovrpVersion)); + +OVRP_EXPORT ovrpResult ovrp_BeginFrame3(int frameIndex); + +OVRP_EXPORT ovrpResult +ovrp_EndFrame3(int frameIndex, ovrpLayerSubmit const* const* layerSubmitPtrs, int layerSubmitCount); + +// Deprecated by WaitToBeginFrame/BeginFrame/EndFrame changes +OVRP_EXPORT ovrpResult ovrp_BeginFrame2(int frameIndex); + +OVRP_EXPORT ovrpResult +ovrp_EndFrame2(int frameIndex, ovrpLayerSubmit const* const* layerSubmitPtrs, int layerSubmitCount); + +// Deprecated by ovrpResult changes +OVRP_EXPORT ovrpBool ovrp_PreInitialize(); +OVRP_EXPORT ovrpBool ovrp_Shutdown(); +OVRP_EXPORT const char* ovrp_GetVersion(); +OVRP_EXPORT const char* ovrp_GetNativeSDKVersion(); +OVRP_EXPORT void* ovrp_GetNativeSDKPointer(); +OVRP_EXPORT const void* ovrp_GetDisplayAdapterId(); +OVRP_EXPORT const void* ovrp_GetAudioOutId(); +OVRP_EXPORT const void* ovrp_GetAudioOutDeviceId(); +OVRP_EXPORT const void* ovrp_GetAudioInId(); +OVRP_EXPORT const void* ovrp_GetAudioInDeviceId(); +OVRP_EXPORT ovrpBool ovrp_SetupDistortionWindow2(int flags); +OVRP_EXPORT ovrpBool ovrp_DestroyDistortionWindow(); + +OVRP_EXPORT ovrpBool +ovrp_SetupMirrorTexture(void* device, int height, int width, ovrpTextureFormat format, ovrpTextureHandle* result); + +OVRP_EXPORT ovrpBool ovrp_DestroyMirrorTexture(); +OVRP_EXPORT float ovrp_GetAdaptiveGpuPerformanceScale(); +OVRP_EXPORT float ovrp_GetAppCpuStartToGpuEndTime(); +OVRP_EXPORT ovrpVector2f ovrp_GetEyePixelsPerTanAngleAtCenter(int eyeIndex); +OVRP_EXPORT ovrpVector3f ovrp_GetHmdToEyeOffset(int eyeIndex); +OVRP_EXPORT ovrpBool ovrp_Update2(ovrpStep step, int frameIndex, double predictionSeconds); +OVRP_EXPORT ovrpBool ovrp_BeginFrame(int frameIndex); +OVRP_EXPORT ovrpBool ovrp_GetTrackingOrientationSupported(); +OVRP_EXPORT ovrpBool ovrp_GetTrackingOrientationEnabled(); +OVRP_EXPORT ovrpBool ovrp_SetTrackingOrientationEnabled(ovrpBool value); +OVRP_EXPORT ovrpBool ovrp_GetTrackingPositionSupported(); +OVRP_EXPORT ovrpBool ovrp_GetTrackingPositionEnabled(); +OVRP_EXPORT ovrpBool ovrp_SetTrackingPositionEnabled(ovrpBool value); +OVRP_EXPORT ovrpBool ovrp_GetTrackingIPDEnabled(); +OVRP_EXPORT ovrpBool ovrp_SetTrackingIPDEnabled(ovrpBool value); +OVRP_EXPORT ovrpPosef ovrp_GetTrackingCalibratedOrigin(); +OVRP_EXPORT ovrpBool ovrpi_SetTrackingCalibratedOrigin(); +OVRP_EXPORT ovrpTrackingOrigin ovrp_GetTrackingOriginType(); +OVRP_EXPORT ovrpBool ovrp_SetTrackingOriginType(ovrpTrackingOrigin originType); +OVRP_EXPORT ovrpBool ovrp_RecenterTrackingOrigin(unsigned int flags); +OVRP_EXPORT ovrpBool ovrp_GetNodePresent(ovrpNode nodeId); +OVRP_EXPORT ovrpBool ovrp_GetNodeOrientationTracked(ovrpNode nodeId); +OVRP_EXPORT ovrpBool ovrp_GetNodePositionTracked(ovrpNode nodeId); +OVRP_EXPORT ovrpBool ovrp_SetNodePositionTracked(ovrpNode nodeId, ovrpBool tracked); +OVRP_EXPORT ovrpPoseStatef ovrp_GetNodePoseState(ovrpStep step, ovrpNode nodeId); +OVRP_EXPORT ovrpControllerState ovrp_GetControllerState(ovrpController controllerMask); +OVRP_EXPORT ovrpControllerState2 ovrp_GetControllerState2(ovrpController controllerMask); +OVRP_EXPORT ovrpResult ovrp_GetControllerState3(ovrpController controllerMask, ovrpControllerState2* controllerState); +OVRP_EXPORT ovrpController ovrp_GetActiveController(); +OVRP_EXPORT ovrpController ovrp_GetConnectedControllers(); + +OVRP_EXPORT ovrpBool ovrp_SetControllerVibration(ovrpController controllerMask, float frequency, float amplitude); + +OVRP_EXPORT ovrpHapticsDesc ovrp_GetControllerHapticsDesc(ovrpController controllerMask); +OVRP_EXPORT ovrpHapticsState ovrp_GetControllerHapticsState(ovrpController controllerMask); + +OVRP_EXPORT ovrpBool ovrp_SetControllerHaptics(ovrpController controllerMask, ovrpHapticsBuffer hapticsBuffer); + +OVRP_EXPORT int ovrp_GetSystemCpuLevel(); +OVRP_EXPORT ovrpBool ovrp_SetSystemCpuLevel(int value); +OVRP_EXPORT ovrpBool ovrp_SetAppCPUPriority(ovrpBool priority); +OVRP_EXPORT ovrpBool ovrp_GetAppCPUPriority(); +OVRP_EXPORT int ovrp_GetSystemGpuLevel(); +OVRP_EXPORT ovrpBool ovrp_SetSystemGpuLevel(int value); +OVRP_EXPORT ovrpBool ovrp_GetSystemPowerSavingMode(); +OVRP_EXPORT float ovrp_GetSystemDisplayFrequency(); +OVRP_EXPORT int ovrp_GetSystemVSyncCount(); +OVRP_EXPORT ovrpBool ovrp_SetSystemVSyncCount(int value); +OVRP_EXPORT float ovrp_GetSystemVolume(); +OVRP_EXPORT ovrpBool ovrp_GetSystemHeadphonesPresent(); +OVRP_EXPORT ovrpBatteryStatus ovrp_GetSystemBatteryStatus(); +OVRP_EXPORT float ovrp_GetSystemBatteryLevel(); +OVRP_EXPORT float ovrp_GetSystemBatteryTemperature(); +OVRP_EXPORT const char* ovrp_GetSystemProductName(); +OVRP_EXPORT ovrpSystemRegion ovrp_GetSystemRegion(); +OVRP_EXPORT ovrpBool ovrp_ShowSystemUI(ovrpUI ui); +OVRP_EXPORT ovrpBool ovrp_GetAppHasVrFocus(); +OVRP_EXPORT ovrpBool ovrp_GetAppShouldQuit(); +OVRP_EXPORT ovrpBool ovrp_GetAppShouldRecenter(); +OVRP_EXPORT ovrpBool ovrp_GetAppShouldRecreateDistortionWindow(); +OVRP_EXPORT const char* ovrp_GetAppLatencyTimings(); + +OVRP_EXPORT ovrpBool ovrp_SetAppEngineInfo(const char* engineName, const char* engineVersion, ovrpBool isEditor); + +OVRP_EXPORT ovrpBool ovrp_GetUserPresent(); +OVRP_EXPORT float ovrp_GetUserIPD(); +OVRP_EXPORT ovrpBool ovrp_SetUserIPD(float value); +OVRP_EXPORT float ovrp_GetUserEyeHeight(); +OVRP_EXPORT ovrpBool ovrp_SetUserEyeHeight(float value); +OVRP_EXPORT ovrpVector2f ovrp_GetUserNeckEyeDistance(); +OVRP_EXPORT ovrpBool ovrp_SetUserNeckEyeDistance(ovrpVector2f value); +OVRP_EXPORT ovrpBool ovrp_SetupDisplayObjects(void* device, void* display, void* window); +OVRP_EXPORT ovrpBool ovrp_GetSystemMultiViewSupported(); +OVRP_EXPORT ovrpBool ovrp_GetEyeTextureArraySupported(); +OVRP_EXPORT ovrpBool ovrp_GetBoundaryConfigured(); + +OVRP_EXPORT ovrpBoundaryTestResult ovrp_TestBoundaryNode(ovrpNode node, ovrpBoundaryType boundaryType); + +OVRP_EXPORT ovrpBoundaryTestResult ovrp_TestBoundaryPoint(ovrpVector3f point, ovrpBoundaryType boundaryType); + +OVRP_EXPORT ovrpBool ovrp_GetBoundaryGeometry2(ovrpBoundaryType boundaryType, ovrpVector3f* points, int* pointsCount); + +OVRP_EXPORT ovrpVector3f ovrp_GetBoundaryDimensions(ovrpBoundaryType boundaryType); +OVRP_EXPORT ovrpBool ovrp_GetBoundaryVisible(); +OVRP_EXPORT ovrpBool ovrp_SetBoundaryVisible(ovrpBool value); +OVRP_EXPORT ovrpSystemHeadset ovrp_GetSystemHeadsetType(); +OVRP_EXPORT ovrpAppPerfStats ovrp_GetAppPerfStats(); +OVRP_EXPORT ovrpBool ovrp_ResetAppPerfStats(); +OVRP_EXPORT float ovrp_GetAppFramerate(); +OVRP_EXPORT int ovrp_GetSystemRecommendedMSAALevel(); +OVRP_EXPORT ovrpBool ovrp_SetInhibitSystemUX(ovrpBool value); +OVRP_EXPORT ovrpBool ovrp_SetDebugDumpEnabled(ovrpBool value); + +// Deprecated by UE4 integration changes +OVRP_EXPORT ovrpBool +ovrp_Initialize2(ovrpRenderAPIType apiType, ovrpLogCallback logCallback, ovrpBool supportsMixedRendering); + +OVRP_EXPORT ovrpBool ovrp_SetupDistortionWindow(); + +OVRP_EXPORT ovrpBool ovrp_SetupEyeTexture2( + ovrpEye eyeId, + int stage, + void* device, + int height, + int width, + int samples, + ovrpTextureFormat format, + void* result); + +OVRP_EXPORT ovrpBool ovrp_DestroyEyeTexture(ovrpEye eyeId, int stage); +OVRP_EXPORT ovrpSizei ovrp_GetEyeTextureSize(ovrpEye eyeId); +OVRP_EXPORT int ovrp_GetEyeTextureStageCount(); +OVRP_EXPORT float ovrp_GetEyeRecommendedResolutionScale(); +OVRP_EXPORT ovrpBool ovrp_GetEyeTextureFlippedY(); +OVRP_EXPORT ovrpBool ovrp_SetEyeTextureFlippedY(ovrpBool value); +OVRP_EXPORT ovrpBool ovrp_GetEyeTextureShared(); +OVRP_EXPORT ovrpBool ovrp_SetEyeTextureShared(ovrpBool value); +OVRP_EXPORT float ovrp_GetEyeTextureScale(); +OVRP_EXPORT ovrpBool ovrp_SetEyeTextureScale(float value); +OVRP_EXPORT float ovrp_GetEyeViewportScale(); +OVRP_EXPORT ovrpBool ovrp_SetEyeViewportScale(float value); + +OVRP_EXPORT ovrpBool ovrp_GetEyeOcclusionMesh(int eyeIndex, float** vertices, int** indices, int* indexCount); + +OVRP_EXPORT ovrpBool ovrp_GetEyeOcclusionMeshEnabled(); +OVRP_EXPORT ovrpBool ovrp_SetEyeOcclusionMeshEnabled(ovrpBool value); +OVRP_EXPORT ovrpTextureFormat ovrp_GetDesiredEyeTextureFormat(); +OVRP_EXPORT ovrpBool ovrp_SetDesiredEyeTextureFormat(ovrpTextureFormat value); +OVRP_EXPORT ovrpBool ovrp_GetEyePreviewRect(int eyeIndex, ovrpRecti* outputRect); +OVRP_EXPORT ovrpBool ovrp_GetAppChromaticCorrection(); +OVRP_EXPORT ovrpBool ovrp_SetAppChromaticCorrection(ovrpBool value); +OVRP_EXPORT ovrpResult ovrp_GetReorientHMDOnControllerRecenter(ovrpBool* recenter); +OVRP_EXPORT ovrpResult ovrp_SetReorientHMDOnControllerRecenter(ovrpBool recenter); +OVRP_EXPORT ovrpBool ovrp_EndEye(ovrpEye eye); +OVRP_EXPORT ovrpBool ovrp_EndFrame(int frameIndex); +OVRP_EXPORT ovrpBool ovrpi_SetTrackingCalibratedOrigin(); +OVRP_EXPORT ovrpPosef ovrp_GetNodeVelocity2(ovrpStep step, ovrpNode nodeId); +OVRP_EXPORT ovrpPosef ovrp_GetNodeAcceleration2(ovrpStep step, ovrpNode nodeId); +OVRP_EXPORT ovrpFrustumf ovrp_GetNodeFrustum(ovrpNode nodeId); +OVRP_EXPORT ovrpBool ovrp_GetAppMonoscopic(); +OVRP_EXPORT ovrpBool ovrp_SetAppMonoscopic(ovrpBool value); +OVRP_EXPORT ovrpBool ovrp_GetAppSRGB(); +OVRP_EXPORT ovrpBool ovrp_SetAppSRGB(ovrpBool value); +OVRP_EXPORT float ovrp_GetUserEyeDepth(); +OVRP_EXPORT ovrpBool ovrp_SetUserEyeDepth(float value); +OVRP_EXPORT ovrpBool ovrp_SetEyeTextureArrayEnabled(ovrpBool value); +OVRP_EXPORT ovrpBool ovrp_GetEyeTextureArrayEnabled(); +OVRP_EXPORT ovrpResult ovrp_GetAppAsymmetricFov(ovrpBool* useAsymmetricFov); +OVRP_EXPORT ovrpResult ovrp_SetAppAsymmetricFov(ovrpBool value); + + +OVRP_EXPORT ovrpBool ovrp_SetOverlayQuad3( + unsigned int flags, + void* textureLeft, + void* textureRight, + void* device, + ovrpPosef pose, + ovrpVector3f scale, + int layerIndex); + +OVRP_EXPORT ovrpResult ovrp_EnqueueSetupLayer(ovrpLayerDesc* desc, int* layerId); + +OVRP_EXPORT ovrpResult ovrp_EnqueueSetupLayer2(ovrpLayerDesc* desc, int compositionDepth, int* layerId); + +OVRP_EXPORT ovrpResult ovrp_EnqueueDestroyLayer(int* layerId); + +OVRP_EXPORT ovrpResult ovrp_GetLayerTexturePtr(int layerId, int stage, ovrpEye eyeId, void** texturePtr); + +OVRP_EXPORT ovrpResult ovrp_EnqueueSubmitLayer( + unsigned int flags, + void* textureLeft, + void* textureRight, + int layerId, + int frameIndex, + OVRP_CONSTREF(ovrpPosef) pose, + OVRP_CONSTREF(ovrpVector3f) scale, + int layerIndex); + +OVRP_EXPORT ovrpResult ovrp_EnqueueSubmitLayer2( + unsigned int flags, + void* textureLeft, + void* textureRight, + int layerId, + int frameIndex, + OVRP_CONSTREF(ovrpPosef) pose, + OVRP_CONSTREF(ovrpVector3f) scale, + int layerIndex, + ovrpBool overrideTextureRectMatrix, + OVRP_CONSTREF(ovrpTextureRectMatrixf) textureRectMatrix, + ovrpBool overridePerLayerColorScaleAndOffset, + OVRP_CONSTREF(ovrpVector4f) colorScale, + OVRP_CONSTREF(ovrpVector4f) colorOffset); + + + + + + + + + + + + + + + + + + + + + +// Previously deprecated +OVRP_EXPORT ovrpBool ovrp_Initialize(ovrpRenderAPIType apiType, void* platformArgs); +OVRP_EXPORT ovrpBoundaryGeometry ovrp_GetBoundaryGeometry(ovrpBoundaryType boundaryType); +OVRP_EXPORT void* ovrp_GetNativePointer(); +OVRP_EXPORT ovrpBool ovrp_DismissHSW(); +OVRP_EXPORT void* ovrp_GetAdapterId(); +OVRP_EXPORT int ovrp_GetBufferCount(); +OVRP_EXPORT ovrpBool ovrp_SetEyeTexture(ovrpEye eyeId, void* texture, void* device); + +OVRP_EXPORT ovrpBool ovrp_RecreateEyeTexture( + ovrpEye eyeId, + int stage, + void* device, + int height, + int width, + int samples, + ovrpBool isSRGB, + void* result); + +OVRP_EXPORT ovrpBool ovrp_ReleaseEyeTexture(ovrpEye eyeId, int stage); +OVRP_EXPORT ovrpPosef ovrp_GetEyePose(ovrpEye eyeId); +OVRP_EXPORT ovrpPosef ovrp_GetEyeVelocity(ovrpEye eyeId); +OVRP_EXPORT ovrpPosef ovrp_GetEyeAcceleration(ovrpEye eyeId); +OVRP_EXPORT ovrpFrustumf ovrp_GetEyeFrustum(ovrpEye eyeId); +OVRP_EXPORT ovrpPosef ovrp_GetTrackerPose(ovrpTracker trackerId); +OVRP_EXPORT ovrpFrustumf ovrp_GetTrackerFrustum(ovrpTracker trackerId); +OVRP_EXPORT ovrpBool ovrp_RecenterPose(); +OVRP_EXPORT ovrpInputState ovrp_GetInputState(ovrpController controllerMask); +OVRP_EXPORT ovrpBatteryStatus ovrp_GetBatteryStatus(); +OVRP_EXPORT ovrpBool ovrp_ShowUI(ovrpUI ui); +OVRP_EXPORT ovrpCaps ovrp_GetCaps(); +OVRP_EXPORT unsigned int ovrp_GetCaps2(unsigned int query); +OVRP_EXPORT ovrpBool ovrp_SetCaps(ovrpCaps caps); +OVRP_EXPORT ovrpStatus ovrp_GetStatus(); +OVRP_EXPORT unsigned int ovrp_GetStatus2(unsigned int query); +OVRP_EXPORT float ovrp_GetFloat(ovrpKey key); +OVRP_EXPORT ovrpBool ovrp_SetFloat(ovrpKey key, float value); +OVRP_EXPORT const char* ovrp_GetString(ovrpKey key); + +OVRP_EXPORT ovrpBool +ovrp_SetOverlayQuad(ovrpBool onTop, void* texture, void* device, ovrpPosef pose, ovrpVector3f scale); + +OVRP_EXPORT ovrpBool ovrp_SetOverlayQuad2( + ovrpBool onTop, + ovrpBool headLocked, + void* texture, + void* device, + ovrpPosef pose, + ovrpVector3f scale); + +OVRP_EXPORT ovrpResult ovrp_CalculateEyeLayerDesc( + ovrpLayout layout, + float textureScale, + int mipLevels, + int sampleCount, + ovrpTextureFormat format, + int layerFlags, + ovrpLayerDesc_EyeFov* layerDesc); + +OVRP_EXPORT ovrpBool ovrp_SetAppIgnoreVrFocus(ovrpBool value); +OVRP_EXPORT ovrpBool ovrp_GetHeadphonesPresent(); +OVRP_EXPORT ovrpBool ovrp_Update(int frameIndex); +OVRP_EXPORT ovrpPosef ovrp_GetNodePose(ovrpNode nodeId); +OVRP_EXPORT ovrpPosef ovrp_GetNodeVelocity(ovrpNode nodeId); +OVRP_EXPORT ovrpPosef ovrp_GetNodeAcceleration(ovrpNode nodeId); + +/// Gets the texture handle for a specific layer stage and eye. +OVRP_EXPORT ovrpResult ovrp_GetLayerTexture(int layerId, int stage, ovrpEye eyeId, ovrpTextureHandle* textureHandle); + +OVRP_EXPORT ovrpBool ovrp_SetupEyeTexture( + ovrpEye eyeId, + int stage, + void* device, + int height, + int width, + int samples, + ovrpBool isSRGB, + void* result); + +OVRP_EXPORT ovrpPosef ovrp_GetNodePose2(ovrpStep step, ovrpNode nodeId); + +OVRP_EXPORT ovrpResult ovrp_SetFunctionPointer(ovrpFunctionType funcType, void* funcPtr); + +// Return success if updating depth info is finished +OVRP_EXPORT ovrpResult ovrp_SetDepthCompositingInfo(float zNear, float zFar, ovrpBool isReverseZ); + +OVRP_EXPORT ovrpResult ovrp_SetOctilinearInfo(ovrpOctilinearLayout OctilinearLayout[ovrpEye_Count]); + +/// Gets the current pose, acceleration, and velocity of the given node on the given update cadence. +OVRP_EXPORT ovrpResult ovrp_GetNodePoseState2(ovrpStep step, ovrpNode nodeId, ovrpPoseStatef* nodePoseState); + +// Called by Unity render thread after finished each eye rendering +OVRP_EXPORT ovrpResult ovrp_EndEye2(ovrpEye eye, int frameIndex); + +// Update depth projection info, this is a replacement of ovrp_SetDepthCompositingInfo for more generic purpose +OVRP_EXPORT ovrpResult ovrp_SetDepthProjInfo(float zNear, float zFar, ovrpBool isReverseZ); + +// Deprecated +OVRP_EXPORT ovrpResult ovrp_SetASWEnable(ovrpBool enable); + +// Deprecated +OVRP_EXPORT ovrpResult ovrp_GetASWEnable(ovrpBool* enable); + +OVRP_EXPORT ovrpResult ovrp_GetSkeleton(ovrpSkeletonType skeletonType, ovrpSkeleton* skeleton); +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Plugins/MetaXR/Source/Thirdparty/OVRPlugin/OVRPlugin/Include/OVR_Plugin_Insight.h b/Plugins/MetaXR/Source/Thirdparty/OVRPlugin/OVRPlugin/Include/OVR_Plugin_Insight.h new file mode 100644 index 0000000..dae6808 --- /dev/null +++ b/Plugins/MetaXR/Source/Thirdparty/OVRPlugin/OVRPlugin/Include/OVR_Plugin_Insight.h @@ -0,0 +1,119 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * Licensed under the Oculus SDK License Agreement (the "License"); + * you may not use the Oculus SDK except in compliance with the License, + * which is provided at the time of installation or download, or which + * otherwise accompanies this software in either electronic or hard copy form. + * + * You may obtain a copy of the License at + * + * https://developer.oculus.com/licenses/oculussdk/ + * + * Unless required by applicable law or agreed to in writing, the Oculus SDK + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OVR_Plugin_Insight_h +#define OVR_Plugin_Insight_h + +#include "OVR_Plugin_Types.h" + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/// Tests if Insight Passthrough is supported on the device +OVRP_EXPORT ovrpResult ovrp_IsInsightPassthroughSupported(ovrpBool* supported); + +/// Initialize Insight Passthrough functionality +OVRP_EXPORT ovrpResult ovrp_InitializeInsightPassthrough(); + +/// Shutdown Insight Passthrough functionality +OVRP_EXPORT ovrpResult ovrp_ShutdownInsightPassthrough(); + +/// Check whether Insight Passthrough functionality has been initialized +OVRP_EXPORT ovrpBool ovrp_GetInsightPassthroughInitialized(); + +/// Check whether Insight Passthrough functionality has been initialized +OVRP_EXPORT ovrpResult ovrp_GetInsightPassthroughInitializationState(); + +/// Create and initialize an Insight Passthrough triangle mesh +OVRP_EXPORT ovrpResult ovrp_CreateInsightTriangleMesh( + int layerId, + float* vertices, + int vertexCount, + int* triangles, + int triangleCount, + uint64_t* outMeshHandle); + +/// Destroy a triangle mesh +OVRP_EXPORT ovrpResult ovrp_DestroyInsightTriangleMesh(uint64_t meshHandle); + +/// Add a triangle mesh to the passthrough projection surface +OVRP_EXPORT ovrpResult ovrp_AddInsightPassthroughSurfaceGeometry( + int layerId, + uint64_t meshHandle, + ovrpMatrix4f transformation, + uint64_t* geometryInstanceHandle); + +/// Remove a geometry instance from the passthrough projection surface and destroy it. +OVRP_EXPORT ovrpResult ovrp_DestroyInsightPassthroughGeometryInstance(uint64_t geometryInstanceHandle); + +/// Update a transform of a geometry instance. +OVRP_EXPORT ovrpResult +ovrp_UpdateInsightPassthroughGeometryTransform(uint64_t geometryInstanceHandle, ovrpMatrix4f transformation); + +OVRP_EXPORT ovrpResult ovrp_SetInsightPassthroughStyle(int layerId, ovrpInsightPassthroughStyle style); + +// Set hands intensity +OVRP_EXPORT ovrpResult +ovrp_SetInsightPassthroughKeyboardHandsIntensity(int layerId, ovrpInsightPassthroughKeyboardHandsIntensity intensity); + +// Gets passthrough capabilities. +OVRP_EXPORT ovrpResult ovrp_GetPassthroughCapabilityFlags(ovrpInsightPassthroughCapabilityFlags* capabilities); +OVRP_EXPORT ovrpResult ovrp_GetPassthroughCapabilities(ovrpInsightPassthroughCapabilities* capabilities); + +OVRP_EXPORT ovrpResult ovrp_SetInsightPassthroughStyle2(int layerId, const ovrpInsightPassthroughStyle* style); + +OVRP_EXPORT ovrpResult ovrp_CreatePassthroughColorLut( + ovrpPassthroughColorLutChannels channels, + ovrpUInt32 resolution, + ovrpPassthroughColorLutData data, + ovrpPassthroughColorLut* colorLut); + +OVRP_EXPORT ovrpResult ovrp_DestroyPassthroughColorLut(ovrpPassthroughColorLut colorLut); + +OVRP_EXPORT ovrpResult +ovrp_UpdatePassthroughColorLut(ovrpPassthroughColorLut colorLut, ovrpPassthroughColorLutData data); + + + + + + + + + + + + + + + + + + +OVRP_EXPORT ovrpResult ovrp_GetPassthroughPreferences(ovrpPassthroughPreferences* preferences); + +#ifdef __cplusplus +} +#endif + +#endif // OVR_Plugin_Insight_h diff --git a/Plugins/MetaXR/Source/Thirdparty/OVRPlugin/OVRPlugin/Include/OVR_Plugin_Ktx.h b/Plugins/MetaXR/Source/Thirdparty/OVRPlugin/OVRPlugin/Include/OVR_Plugin_Ktx.h new file mode 100644 index 0000000..ceaee7a --- /dev/null +++ b/Plugins/MetaXR/Source/Thirdparty/OVRPlugin/OVRPlugin/Include/OVR_Plugin_Ktx.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * Licensed under the Oculus SDK License Agreement (the "License"); + * you may not use the Oculus SDK except in compliance with the License, + * which is provided at the time of installation or download, or which + * otherwise accompanies this software in either electronic or hard copy form. + * + * You may obtain a copy of the License at + * + * https://developer.oculus.com/licenses/oculussdk/ + * + * Unless required by applicable law or agreed to in writing, the Oculus SDK + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OVR_Plugin_KtxLoader_h +#define OVR_Plugin_KtxLoader_h + +#include "OVR_Plugin_Types.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +OVRP_EXPORT ovrpResult ovrp_KtxLoadFromMemory(unsigned char** data, unsigned int length, ktxTexture2** texture); +OVRP_EXPORT ovrpResult ovrp_KtxDestroy(ktxTexture2* texture); + +OVRP_EXPORT ovrpResult ovrp_KtxNeedsTranscoding(ktxTexture2* texture, bool* needsTranscoding); +OVRP_EXPORT ovrpResult ovrp_KtxTranscode(ktxTexture2* texture, unsigned int format); + +OVRP_EXPORT ovrpResult ovrp_KtxTextureWidth(ktxTexture2* texture, unsigned int* width); +OVRP_EXPORT ovrpResult ovrp_KtxTextureHeight(ktxTexture2* texture, unsigned int* height); +OVRP_EXPORT ovrpResult ovrp_KtxTextureSize(ktxTexture2* texture, unsigned int* size); + +OVRP_EXPORT ovrpResult ovrp_KtxGetTextureData(ktxTexture2* texture, unsigned char* data, unsigned int bufferSize); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Plugins/MetaXR/Source/Thirdparty/OVRPlugin/OVRPlugin/Include/OVR_Plugin_Media.h b/Plugins/MetaXR/Source/Thirdparty/OVRPlugin/OVRPlugin/Include/OVR_Plugin_Media.h new file mode 100644 index 0000000..2f3acba --- /dev/null +++ b/Plugins/MetaXR/Source/Thirdparty/OVRPlugin/OVRPlugin/Include/OVR_Plugin_Media.h @@ -0,0 +1,112 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * Licensed under the Oculus SDK License Agreement (the "License"); + * you may not use the Oculus SDK except in compliance with the License, + * which is provided at the time of installation or download, or which + * otherwise accompanies this software in either electronic or hard copy form. + * + * You may obtain a copy of the License at + * + * https://developer.oculus.com/licenses/oculussdk/ + * + * Unless required by applicable law or agreed to in writing, the Oculus SDK + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OVR_Plugin_Media_h +#define OVR_Plugin_Media_h + +#include "OVR_Plugin_Types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +OVRP_EXPORT ovrpResult ovrp_Media_Initialize(); +OVRP_EXPORT ovrpResult ovrp_Media_Shutdown(); +OVRP_EXPORT ovrpResult ovrp_Media_GetInitialized(ovrpBool* initialized); +OVRP_EXPORT ovrpResult ovrp_Media_Update(); + +OVRP_EXPORT ovrpResult ovrp_Media_GetMrcActivationMode(ovrpMediaMrcActivationMode* activationMode); +OVRP_EXPORT ovrpResult ovrp_Media_SetMrcActivationMode(ovrpMediaMrcActivationMode activationMode); +OVRP_EXPORT ovrpResult ovrp_Media_SetPlatformInitialized(); +OVRP_EXPORT ovrpResult ovrp_Media_GetPlatformCameraMode(ovrpPlatformCameraMode* platformCameraMode); +OVRP_EXPORT ovrpResult ovrp_Media_SetPlatformCameraMode(ovrpPlatformCameraMode platformCameraMode); +OVRP_EXPORT ovrpResult ovrp_Media_IsMrcEnabled(ovrpBool* mrcEnabled); +OVRP_EXPORT ovrpResult ovrp_Media_IsMrcActivated(ovrpBool* mrcActivated); +OVRP_EXPORT ovrpResult ovrp_Media_UseMrcDebugCamera(ovrpBool* useMrcDebugCamera); + +OVRP_EXPORT ovrpResult ovrp_Media_SetMrcInputVideoBufferType(ovrpMediaInputVideoBufferType inputVideoBufferType); +OVRP_EXPORT ovrpResult ovrp_Media_GetMrcInputVideoBufferType(ovrpMediaInputVideoBufferType* inputVideoBufferType); +OVRP_EXPORT ovrpResult ovrp_Media_SetMrcFrameSize(int frameWidth, int frameHeight); +OVRP_EXPORT ovrpResult ovrp_Media_GetMrcFrameSize(int* frameWidth, int* frameHeight); +OVRP_EXPORT ovrpResult ovrp_Media_SetMrcAudioSampleRate(int sampleRate); +OVRP_EXPORT ovrpResult ovrp_Media_GetMrcAudioSampleRate(int* sampleRate); +OVRP_EXPORT ovrpResult ovrp_Media_SetMrcFrameImageFlipped(ovrpBool flipped); +OVRP_EXPORT ovrpResult ovrp_Media_GetMrcFrameImageFlipped(ovrpBool* flipped); +OVRP_EXPORT ovrpResult ovrp_Media_SetMrcFrameInverseAlpha(ovrpBool inverseAlpha); +OVRP_EXPORT ovrpResult ovrp_Media_GetMrcFrameInverseAlpha(ovrpBool* inverseAlpha); +OVRP_EXPORT ovrpResult ovrp_Media_SetAvailableQueueIndexVulkan(unsigned int queueIndexVk); +OVRP_EXPORT ovrpResult ovrp_Media_EncodeMrcFrame( + void* videoData, + float* audioData, + int audioDataLen, + int audioChannels, + double timestamp, + int* outSyncId); +OVRP_EXPORT ovrpResult ovrp_Media_EncodeMrcFrameWithDualTextures( + void* backgroundTextureHandle, + void* foregroundTextureHandle, + float* audioData, + int audioDataLen, + int audioChannels, + double timestamp, + int* outSyncId); +OVRP_EXPORT ovrpResult ovrp_Media_SyncMrcFrame(int syncId); +OVRP_EXPORT ovrpResult ovrp_Media_EncodeMrcFrameWithPoseTime( + void* videoData, + float* audioData, + int audioDataLen, + int audioChannels, + double timestamp, + double poseTime, + int* outSyncId); +OVRP_EXPORT ovrpResult ovrp_Media_EncodeMrcFrameDualTexturesWithPoseTime( + void* backgroundTextureHandle, + void* foregroundTextureHandle, + float* audioData, + int audioDataLen, + int audioChannels, + double timestamp, + double poseTime, + int* outSyncId); +OVRP_EXPORT ovrpResult +ovrp_Media_SetHeadsetControllerPose(ovrpPosef headsetPose, ovrpPosef leftControllerPose, ovrpPosef rightControllerPose); +OVRP_EXPORT ovrpResult +ovrp_Media_EnumerateCameraAnchorHandles(int* inoutAnchorCount, ovrpCameraAnchorHandle* outHandleArray); +OVRP_EXPORT ovrpResult ovrp_Media_GetCurrentCameraAnchorHandle(ovrpCameraAnchorHandle* outHandle); +OVRP_EXPORT ovrpResult +ovrp_Media_GetCameraAnchorName(ovrpCameraAnchorHandle anchorHandle, char outAnchorName[OVRP_ANCHOR_NAME_SIZE]); +OVRP_EXPORT ovrpResult ovrp_Media_GetCameraAnchorHandle(const char* anchorName, ovrpCameraAnchorHandle* outHandle); +OVRP_EXPORT ovrpResult +ovrp_Media_GetCameraAnchorType(ovrpCameraAnchorHandle anchorHandle, ovrpCameraAnchorType* outAnchorType); +OVRP_EXPORT ovrpResult ovrp_Media_CreateCustomCameraAnchor(const char* anchorName, ovrpCameraAnchorHandle* outHandle); +OVRP_EXPORT ovrpResult ovrp_Media_DestroyCustomCameraAnchor(ovrpCameraAnchorHandle anchorHandle); +OVRP_EXPORT ovrpResult ovrp_Media_GetCustomCameraAnchorPose(ovrpCameraAnchorHandle anchorHandle, ovrpPosef* outPose); +OVRP_EXPORT ovrpResult ovrp_Media_SetCustomCameraAnchorPose(ovrpCameraAnchorHandle anchorHandle, ovrpPosef pose); +OVRP_EXPORT ovrpResult +ovrp_Media_GetCameraMinMaxDistance(ovrpCameraAnchorHandle anchorHandle, double* outMinDistance, double* outMaxDistance); +OVRP_EXPORT ovrpResult +ovrp_Media_SetCameraMinMaxDistance(ovrpCameraAnchorHandle anchorHandle, double minDistance, double maxDistance); +OVRP_EXPORT ovrpResult ovrp_Media_IsCastingToRemoteClient(ovrpBool* isCasting); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Plugins/MetaXR/Source/Thirdparty/OVRPlugin/OVRPlugin/Include/OVR_Plugin_MixedReality.h b/Plugins/MetaXR/Source/Thirdparty/OVRPlugin/OVRPlugin/Include/OVR_Plugin_MixedReality.h new file mode 100644 index 0000000..28d9213 --- /dev/null +++ b/Plugins/MetaXR/Source/Thirdparty/OVRPlugin/OVRPlugin/Include/OVR_Plugin_MixedReality.h @@ -0,0 +1,146 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * Licensed under the Oculus SDK License Agreement (the "License"); + * you may not use the Oculus SDK except in compliance with the License, + * which is provided at the time of installation or download, or which + * otherwise accompanies this software in either electronic or hard copy form. + * + * You may obtain a copy of the License at + * + * https://developer.oculus.com/licenses/oculussdk/ + * + * Unless required by applicable law or agreed to in writing, the Oculus SDK + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OVR_Plugin_MixedReality_h +#define OVR_Plugin_MixedReality_h + +#include "OVR_Plugin_Types.h" + +#if OVRP_MIXED_REALITY_PRIVATE +#include "OVR_Plugin_MixedReality_Private.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +//////////////////// Tracked Camera ////////////////////////// + +/// Initialize Mixed Reality functionalities +OVRP_EXPORT ovrpResult ovrp_InitializeMixedReality(); + +/// Shutdown Mixed Reality functionalities +OVRP_EXPORT ovrpResult ovrp_ShutdownMixedReality(); + +/// Check whether Mixed Reality functionalities has been initialized +OVRP_EXPORT ovrpBool ovrp_GetMixedRealityInitialized(); + +/// Update external camera. Need to be called before accessing the camera count or individual camera information +OVRP_EXPORT ovrpResult ovrp_UpdateExternalCamera(); + +/// Get the number of external cameras +OVRP_EXPORT ovrpResult ovrp_GetExternalCameraCount(int* cameraCount); + +/// Get the name of an external camera +OVRP_EXPORT ovrpResult ovrp_GetExternalCameraName(int cameraId, char cameraName[OVRP_EXTERNAL_CAMERA_NAME_SIZE]); + +/// Get intrinsics of an external camera +OVRP_EXPORT ovrpResult ovrp_GetExternalCameraIntrinsics(int cameraId, ovrpCameraIntrinsics* cameraIntrinsics); + +/// Get extrinsics of an external camera +OVRP_EXPORT ovrpResult ovrp_GetExternalCameraExtrinsics(int cameraId, ovrpCameraExtrinsics* cameraExtrinsics); + +/// Get the raw transform pose when the external camera was calibrated +OVRP_EXPORT ovrpResult ovrp_GetExternalCameraCalibrationRawPose(int cameraId, ovrpPosef* rawPose); + +/// Override the FOV of the external camera +OVRP_EXPORT ovrpResult ovrp_OverrideExternalCameraFov(int cameraId, ovrpBool useOverriddenFov, const ovrpFovf* fov); + +/// Get if the FOV of the external camera is overridden +OVRP_EXPORT ovrpResult ovrp_GetUseOverriddenExternalCameraFov(int cameraId, ovrpBool* useOverriddenFov); + +/// Override the Pose of the external camera. +OVRP_EXPORT ovrpResult +ovrp_OverrideExternalCameraStaticPose(int cameraId, ovrpBool useOverriddenPose, const ovrpPosef* pose); + +/// Get if the Pose of the external camera is overridden +OVRP_EXPORT ovrpResult ovrp_GetUseOverriddenExternalCameraStaticPose(int cameraId, ovrpBool* useOverriddenStaticPose); + +/// Helper function to get the camera pose in the tracking space +OVRP_EXPORT ovrpResult ovrp_GetExternalCameraPose(int cameraId, ovrpPosef* cameraPose); + +/// Helper function to get convert a pose in tracking space to camera space +OVRP_EXPORT ovrpResult +ovrp_ConvertPoseToCameraSpace(int cameraId, ovrpPosef* trackingSpacePose, ovrpPosef* cameraSpacePose); + +/// Reset the manual external camera +/// On Quest, it would stop listenting to the MRC port if needed +OVRP_EXPORT ovrpResult ovrp_ResetDefaultExternalCamera(); + +/// Set a manual external camera to the system. The manual external camera is valid when there is no camera +/// configuration can be loaded On Quest, it would start listenting to the MRC port if needed +OVRP_EXPORT ovrpResult ovrp_SetDefaultExternalCamera( + const char* cameraName, + const ovrpCameraIntrinsics* cameraIntrinsics, + const ovrpCameraExtrinsics* cameraExtrinsics); + +/// (PC only) set external camera intrinsics and extrinsics +OVRP_EXPORT ovrpResult ovrp_SetExternalCameraProperties( + const char* cameraName, + const ovrpCameraIntrinsics* cameraIntrinsics, + const ovrpCameraExtrinsics* cameraExtrinsics); + +// {{ DEPRECATED +// The following functions will be moved to OVR_Plugin_MixedReality_Deprecated.h after Unreal Plugin revision +OVRP_EXPORT ovrpResult +ovrp_EnumerateAllCameraDevices(ovrpCameraDevice* deviceArray, int deviceArraySize, int* deviceCount); +OVRP_EXPORT ovrpResult +ovrp_EnumerateAvailableCameraDevices(ovrpCameraDevice* deviceArray, int deviceArraySize, int* deviceCount); +OVRP_EXPORT ovrpResult ovrp_UpdateCameraDevices(); +OVRP_EXPORT ovrpResult ovrp_IsCameraDeviceAvailable2(ovrpCameraDevice camera, ovrpBool* available); +OVRP_EXPORT ovrpResult +ovrp_SetCameraDevicePreferredColorFrameSize(ovrpCameraDevice camera, ovrpSizei preferredColorFrameSize); +OVRP_EXPORT ovrpResult ovrp_OpenCameraDevice(ovrpCameraDevice camera); +OVRP_EXPORT ovrpResult ovrp_CloseCameraDevice(ovrpCameraDevice camera); +OVRP_EXPORT ovrpResult ovrp_HasCameraDeviceOpened2(ovrpCameraDevice camera, ovrpBool* opened); +OVRP_EXPORT ovrpResult ovrp_GetCameraDeviceIntrinsicsParameters( + ovrpCameraDevice camera, + ovrpBool* supportIntrinsics, + ovrpCameraDeviceIntrinsicsParameters* intrinsicsParameters); +OVRP_EXPORT ovrpResult ovrp_IsCameraDeviceColorFrameAvailable2(ovrpCameraDevice camera, ovrpBool* available); +OVRP_EXPORT ovrpResult ovrp_GetCameraDeviceColorFrameSize(ovrpCameraDevice camera, ovrpSizei* colorFrameSize); +OVRP_EXPORT ovrpResult ovrp_GetCameraDeviceColorFrameBgraPixels( + ovrpCameraDevice camera, + const ovrpByte** colorFrameBgraPixels, + int* colorFrameRowPitch); +OVRP_EXPORT ovrpResult ovrp_DoesCameraDeviceSupportDepth(ovrpCameraDevice camera, ovrpBool* supportDepth); +OVRP_EXPORT ovrpResult +ovrp_GetCameraDeviceDepthSensingMode(ovrpCameraDevice camera, ovrpCameraDeviceDepthSensingMode* depthSensingMode); +OVRP_EXPORT ovrpResult +ovrp_SetCameraDeviceDepthSensingMode(ovrpCameraDevice camera, ovrpCameraDeviceDepthSensingMode depthSensingMode); +OVRP_EXPORT ovrpResult +ovrp_GetCameraDevicePreferredDepthQuality(ovrpCameraDevice camera, ovrpCameraDeviceDepthQuality* depthQuality); +OVRP_EXPORT ovrpResult +ovrp_SetCameraDevicePreferredDepthQuality(ovrpCameraDevice camera, ovrpCameraDeviceDepthQuality depthQuality); +OVRP_EXPORT ovrpResult ovrp_IsCameraDeviceDepthFrameAvailable(ovrpCameraDevice camera, ovrpBool* available); +OVRP_EXPORT ovrpResult ovrp_GetCameraDeviceDepthFrameSize(ovrpCameraDevice camera, ovrpSizei* depthFrameSize); +OVRP_EXPORT ovrpResult +ovrp_GetCameraDeviceDepthFramePixels(ovrpCameraDevice camera, const float** depthFramePixels, int* depthFrameRowPitch); +OVRP_EXPORT ovrpResult ovrp_GetCameraDeviceDepthConfidencePixels( + ovrpCameraDevice camera, + const float** depthConfidencePixels, + int* depthConfidenceRowPitch); +// }} DEPRECATED + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Plugins/MetaXR/Source/Thirdparty/OVRPlugin/OVRPlugin/Include/OVR_Plugin_MixedReality_Deprecated.h b/Plugins/MetaXR/Source/Thirdparty/OVRPlugin/OVRPlugin/Include/OVR_Plugin_MixedReality_Deprecated.h new file mode 100644 index 0000000..83c2b49 --- /dev/null +++ b/Plugins/MetaXR/Source/Thirdparty/OVRPlugin/OVRPlugin/Include/OVR_Plugin_MixedReality_Deprecated.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * Licensed under the Oculus SDK License Agreement (the "License"); + * you may not use the Oculus SDK except in compliance with the License, + * which is provided at the time of installation or download, or which + * otherwise accompanies this software in either electronic or hard copy form. + * + * You may obtain a copy of the License at + * + * https://developer.oculus.com/licenses/oculussdk/ + * + * Unless required by applicable law or agreed to in writing, the Oculus SDK + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OVR_Plugin_MixedReality_Deprecated_h +#define OVR_Plugin_MixedReality_Deprecated_h + +#include "OVR_Plugin_MixedReality.h" + +#ifdef __cplusplus +extern "C" { +#endif + +OVRP_EXPORT ovrpBool ovrp_IsCameraDeviceAvailable(ovrpCameraDevice camera); +OVRP_EXPORT ovrpBool ovrp_HasCameraDeviceOpened(ovrpCameraDevice camera); +OVRP_EXPORT ovrpBool ovrp_IsCameraDeviceColorFrameAvailable(ovrpCameraDevice camera); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Plugins/MetaXR/Source/Thirdparty/OVRPlugin/OVRPlugin/Include/OVR_Plugin_Types.h b/Plugins/MetaXR/Source/Thirdparty/OVRPlugin/OVRPlugin/Include/OVR_Plugin_Types.h new file mode 100644 index 0000000..7b947d7 --- /dev/null +++ b/Plugins/MetaXR/Source/Thirdparty/OVRPlugin/OVRPlugin/Include/OVR_Plugin_Types.h @@ -0,0 +1,3619 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * Licensed under the Oculus SDK License Agreement (the "License"); + * you may not use the Oculus SDK except in compliance with the License, + * which is provided at the time of installation or download, or which + * otherwise accompanies this software in either electronic or hard copy form. + * + * You may obtain a copy of the License at + * + * https://developer.oculus.com/licenses/oculussdk/ + * + * Unless required by applicable law or agreed to in writing, the Oculus SDK + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OVR_Plugin_Types_h +#define OVR_Plugin_Types_h + +#if !defined(OVRP_STRINGIFY) +#define OVRP_STRINGIFYIMPL(x) #x +#define OVRP_STRINGIFY(x) OVRP_STRINGIFYIMPL(x) +#endif + +// Note: OVRP_MINOR_VERSION == OCULUS_SDK_VERSION + 32 + +#define OVRP_MAJOR_VERSION 1 +#define OVRP_MINOR_VERSION 96 +#define OVRP_PATCH_VERSION 0 + +#define OVRP_VERSION OVRP_MAJOR_VERSION, OVRP_MINOR_VERSION, OVRP_PATCH_VERSION +#define OVRP_VERSION_STR OVRP_STRINGIFY(OVRP_MAJOR_VERSION.OVRP_MINOR_VERSION.OVRP_PATCH_VERSION) + + + + + + +#define OVRP_VERSION_CHANNEL "Release" + + +#define OVRP_CURRENT_FRAMEINDEX -1 + +#ifndef OVRP_EXPORT +#ifdef _WIN32 +#define OVRP_EXPORT __declspec(dllexport) +#elif defined(__ANDROID__) || defined(__APPLE__) +#define OVRP_EXPORT __attribute__((visibility("default"))) +#else +#define OVRP_EXPORT +#endif +#endif + +#if defined ANDROID || defined __linux__ +#define __cdecl +#endif + +#ifdef __cplusplus +#define OVRP_REF(Type) Type& +#define OVRP_CONSTREF(Type) const Type& +#define OVRP_DEFAULTVALUE(Value) = Value +#else +#define OVRP_REF(Type) Type* +#define OVRP_CONSTREF(Type) const Type* +#define OVRP_DEFAULTVALUE(Value) +#endif + +#define OVRP_UNUSED(x) ((void)(x)) + +#define OVRP_FILE_AND_LINE __FILE__ ":" OVRP_STRINGIFY(__LINE__) + +#ifndef OVRP_MIXED_REALITY_PRIVATE +#define OVRP_MIXED_REALITY_PRIVATE 0 +#endif + +#ifndef OVR_PLUGIN_PC_OPENXR +#define OVR_PLUGIN_PC_OPENXR 0 +#endif + +#ifndef OVR_PLUGIN_MOBILE_OPENXR +#define OVR_PLUGIN_MOBILE_OPENXR 0 +#endif + +#if OVR_PLUGIN_PC_OPENXR || OVR_PLUGIN_MOBILE_OPENXR +#define OVR_PLUGIN_USE_OPENXR 1 +#endif + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wnested-anon-types" +#pragma clang diagnostic ignored "-Wpedantic" +#endif // __clang__ + +/// True or false +enum { + ovrpBool_False = 0, + ovrpBool_True = 1, +}; +typedef int ovrpBool; + +/// Byte +typedef unsigned char ovrpByte; + +/// UInt32 +typedef unsigned int ovrpUInt32; + +/// Int16 +typedef short ovrpInt16; + +/// UInt16 +typedef unsigned short ovrpUInt16; + +/// Int64 +typedef long long ovrpInt64; + +/// UInt64 +typedef unsigned long long ovrpUInt64; + +/// Epsilon for floating point comparison +#define OVRP_FLOAT_EPSILON (1e-5f) + +/// Success and failure +typedef enum { + /// Success + ovrpSuccess = 0, + ovrpSuccess_EventUnavailable = 1, + ovrpSuccess_Pending = 2, + + /// Failure + ovrpFailure = -1000, + ovrpFailure_InvalidParameter = -1001, + ovrpFailure_NotInitialized = -1002, + ovrpFailure_InvalidOperation = -1003, + ovrpFailure_Unsupported = -1004, + ovrpFailure_NotYetImplemented = -1005, + ovrpFailure_OperationFailed = -1006, + ovrpFailure_InsufficientSize = -1007, + ovrpFailure_DataIsInvalid = -1008, + ovrpFailure_DeprecatedOperation = -1009, + ovrpFailure_ErrorLimitReached = -1010, + ovrpFailure_ErrorInitializationFailed = -1011, + ovrpFailure_RuntimeUnavailable = -1012, + ovrpFailure_HandleInvalid = -1013, + + /// Space error cases + ovrpFailure_SpaceCloudStorageDisabled = -2000, + ovrpFailure_SpaceMappingInsufficient = -2001, + ovrpFailure_SpaceLocalizationFailed = -2002, + ovrpFailure_SpaceNetworkTimeout = -2003, + ovrpFailure_SpaceNetworkRequestFailed = -2004, + + /// XR_FB_spatial_entity extension + ovrpFailure_SpaceComponentNotSupported = -2005, + ovrpFailure_SpaceComponentNotEnabled = -2006, + ovrpFailure_SpaceComponentStatusPending = -2007, + ovrpFailure_SpaceComponentStatusAlreadySet = -2008, + + + + + + + + + + + + + + + + + + + + + + +} ovrpResult; + +#define OVRP_SUCCESS(result) ((result) >= 0) +#define OVRP_FAILURE(result) ((result) < 0) + +/// XR API types +typedef enum { + ovrpXrApi_Unknown = 0, + ovrpXrApi_CAPI = 1, + ovrpXrApi_VRAPI = 2, + ovrpXrApi_OpenXR = 3, + ovrpXrApi_EnumSize = 0x7fffffff +} ovrpXrApi; + +/// Pre-initialization flags +typedef enum { + ovrpPreinitializeFlag_None = 0, + /// Unity native OpenXR Plugin is being used + ovrpPreinitializeFlag_UseUnityOpenXR = (1 << 0), + /// Unreal native OpenXR Plugin is being used + ovrpPreinitializeFlag_UseUnrealOpenXR = (1 << 1), + + + + + + /// Allow OVRPlugin (OpenXR backend) runs with non-Oculus OpenXR runtime + ovrpPreinitializeFlag_SupportNonOculusRuntime = (1 << 3), + ovrpPreinitializeFlag_EnumSize = 0x7fffffff +} ovrpPreinitializeFlags; + +/// Initialization flags +typedef enum { + /// Start GearVR battery and volume receivers + ovrpInitializeFlag_StartGearVRReceivers = (1 << 0), + /// Supports 2D/3D switching + ovrpInitializeFlag_SupportsVRToggle = (1 << 1), + /// Supports Life Cycle Focus (Dash) + ovrpInitializeFlag_FocusAware = (1 << 2), + /// DEPRECATED - Turn off Legacy Core Affinity Patch + /// Background: Some legacy unity versions set thread affinities wrong on newer hardware like Oculus Go + /// We need patch it in the runtime for published legacy apps. + /// This flag will be passed from fixed Unity versions explicitly, so we can skip the runtime patch mechanism since we + /// already have proper fixes. + /// Deprecated Background: Several Unity versions incorrectly indicated they handled applying thread affinity, so this + /// flag has been deprecated + /// in order to fallback to runtime thread affinity handling. In the future, a new flag will be introduced to allow + /// engine opt-out of + /// runtime affinity handling. + ovrpInitializeFlag_NoLegacyCoreAffinityPatch = (1 << 3), // DEPRECATED + + /// Allow to use sRGB frame buffer, we use it as an initialization flag because we need make the window surface + /// sRGB compilable, this can't be changed after window created. + ovrpInitializeFlag_SupportSRGBFrameBuffer = (1 << 4), + + + + + + + /// Enable Application SpaceWarp support + ovrpInitializeFlag_SupportAppSpaceWarp = (1 << 6), + + /// XR instance / session would be created by external engine, to support their OpenXR Plugins + ovrpInitializeFlag_ExternalXrObjects = (1 << 7), + + ovrpInitializeFlag_EnumSize = 0x7fffffff + +} ovrpInitializeFlags; + + +/// Thread Performance +typedef enum { + ovrpThreadPef_DeadLine_Normal = 0, + ovrpThreadPef_DeadLine_Hard = 1, + ovrpThreadPef_DeadLine_Soft = 2, + ovrpThreadPef_EnumSize = 0x7fffffff +} ovrpThreadPerf; + +/// Identifies an eye in a stereo pair. +typedef enum { + ovrpEye_Center = -2, + ovrpEye_None = -1, + ovrpEye_Left = 0, + ovrpEye_Right = 1, + ovrpEye_Count, + ovrpEye_EnumSize = 0x7fffffff +} ovrpEye; + +/// Identifies a hand. +typedef enum { + ovrpHand_None = -1, + ovrpHand_Left = 0, + ovrpHand_Right = 1, + ovrpHand_Count, + ovrpHand_EnumSize = 0x7fffffff +} ovrpHand; + +/// Identifies a tracked device object. +typedef enum { + ovrpDeviceObject_None = -1, + ovrpDeviceObject_Zero = 0, + ovrpDeviceObject_Count, + ovrpDeviceObject_EnumSize = 0x7fffffff +} ovrpDeviceObject; + +/// Identifies a tracking sensor. +typedef enum { + ovrpTracker_None = -1, + ovrpTracker_Zero = 0, + ovrpTracker_One = 1, + ovrpTracker_Two = 2, + ovrpTracker_Three = 3, + ovrpTracker_Count, + ovrpTracker_EnumSize = 0x7fffffff +} ovrpTracker; + +/// Identifies a tracked VR Node. +typedef enum { + ovrpNode_None = -1, + ovrpNode_EyeLeft = 0, + ovrpNode_EyeRight = 1, + ovrpNode_EyeCenter = 2, + ovrpNode_HandLeft = 3, + ovrpNode_HandRight = 4, + ovrpNode_TrackerZero = 5, + ovrpNode_TrackerOne = 6, + ovrpNode_TrackerTwo = 7, + ovrpNode_TrackerThree = 8, + ovrpNode_Head = 9, + ovrpNode_DeviceObjectZero = 10, + + + + ovrpNode_ControllerLeft = 12, + ovrpNode_ControllerRight = 13, + ovrpNode_Count, + ovrpNode_EnumSize = 0x7fffffff +} ovrpNode; + +/// Identifies a tracking origin +typedef enum { + ovrpTrackingOrigin_EyeLevel = 0, + ovrpTrackingOrigin_FloorLevel = 1, + ovrpTrackingOrigin_Stage = 2, + + + + ovrpTrackingOrigin_View = 4, + ovrpTrackingOrigin_Count, + ovrpTrackingOrigin_EnumSize = 0x7fffffff +} ovrpTrackingOrigin; + +/// The charge status of a battery. +typedef enum { + ovrpBatteryStatus_Charging, + ovrpBatteryStatus_Discharging, + ovrpBatteryStatus_Full, + ovrpBatteryStatus_NotCharging, + ovrpBatteryStatus_Unknown, + ovrpBatteryStatus_EnumSize = 0x7fffffff +} ovrpBatteryStatus; + +// Handedness of user as specified in the mobile device +typedef enum { + ovrpHandedness_Unsupported = 0, + ovrpHandedness_LeftHanded = 1, + ovrpHandedness_RightHanded = 2 +} ovrpHandedness; + +/// An oculus platform UI. +typedef enum { + ovrpUI_None = -1, + ovrpUI_GlobalMenu = 0, + ovrpUI_ConfirmQuit, + ovrpUI_GlobalMenuTutorial, // Deprecated + ovrpUI_EnumSize = 0x7fffffff +} ovrpUI; + +/// A geographical region associated with the current system device. +typedef enum { + ovrpSystemRegion_Unspecified, + ovrpSystemRegion_Japan, + ovrpSystemRegion_China, + ovrpSystemRegion_EnumSize = 0x7fffffff +} ovrpSystemRegion; + +typedef enum { + ovrpSystemHeadset_None = 0, + + // Mobile & Standalone headsets + ovrpSystemHeadset_GearVR_R320, // Note4 Innovator + ovrpSystemHeadset_GearVR_R321, // S6 Innovator + ovrpSystemHeadset_GearVR_R322, // GearVR Commercial 1 + ovrpSystemHeadset_GearVR_R323, // GearVR Commercial 2 (USB Type C) + ovrpSystemHeadset_GearVR_R324, // GearVR Commercial 3 (USB Type C) + ovrpSystemHeadset_GearVR_R325, // GearVR Commercial 4 (USB Type C) + ovrpSystemHeadset_Oculus_Go, // Oculus Go Commercial 1 + ovrpSystemHeadset_Oculus_Quest, // Oculus Quest + ovrpSystemHeadset_Oculus_Quest_2, // Oculus Quest 2 + ovrpSystemHeadset_Meta_Quest_Pro, // Meta Quest Pro + ovrpSystemHeadset_Meta_Quest_3, // Meta Quest 3 + ovrpSystemHeadset_Placeholder_12, + ovrpSystemHeadset_Placeholder_13, + ovrpSystemHeadset_Placeholder_14, + + // PC headsets + ovrpSystemHeadset_Rift_DK1 = 0x1000, + ovrpSystemHeadset_Rift_DK2, + ovrpSystemHeadset_Rift_CV1, + ovrpSystemHeadset_Rift_CB, + ovrpSystemHeadset_Rift_S, + ovrpSystemHeadset_Oculus_Link_Quest, // Quest connected through Oculus Link + ovrpSystemHeadset_Oculus_Link_Quest_2, + ovrpSystemHeadset_Meta_Link_Quest_Pro, + ovrpSystemHeadset_Meta_Link_Quest_3, + ovrpSystemHeadset_PC_Placeholder_4105, + ovrpSystemHeadset_PC_Placeholder_4106, + ovrpSystemHeadset_PC_Placeholder_4107, + ovrpSystemHeadset_EnumSize = 0x7fffffff +} ovrpSystemHeadset; + +/// These types are used to hide platform-specific details when passing +/// render device, OS, and texture data to the API. +/// +/// The benefit of having these wrappers versus platform-specific API functions is +/// that they allow game glue code to be portable. A typical example is an +/// engine that has multiple back ends, say GL and D3D. Portable code that calls +/// these back ends may also use LibOVR. To do this, back ends can be modified +/// to return portable types such as ovrTexture and ovrRenderAPIConfig. +typedef enum { + ovrpRenderAPI_None, + ovrpRenderAPI_OpenGL, + ovrpRenderAPI_Android_GLES, // Deprecated, use ovrpRenderAPI_OpenGL instead + ovrpRenderAPI_D3D9, // Deprecated, unsupported + ovrpRenderAPI_D3D10, // Deprecated, unsupported + ovrpRenderAPI_D3D11, + ovrpRenderAPI_D3D12, + ovrpRenderAPI_Vulkan, + ovrpRenderAPI_Count, + ovrpRenderAPI_EnumSize = 0x7fffffff +} ovrpRenderAPIType; + +/// Identifies a controller button. +typedef enum { + ovrpButton_None = 0, + ovrpButton_A = 0x00000001, + ovrpButton_B = 0x00000002, + ovrpButton_X = 0x00000100, + ovrpButton_Y = 0x00000200, + ovrpButton_Up = 0x00010000, + ovrpButton_Down = 0x00020000, + ovrpButton_Left = 0x00040000, + ovrpButton_Right = 0x00080000, + ovrpButton_Start = 0x00100000, + ovrpButton_Back = 0x00200000, + ovrpButton_LShoulder = 0x00000800, + ovrpButton_LThumb = 0x00000400, + ovrpButton_LTouchpad = 0x40000000, + ovrpButton_RShoulder = 0x00000008, + ovrpButton_RThumb = 0x00000004, + ovrpButton_RTouchpad = 0x80000000, + ovrpButton_VolUp = 0x00400000, + ovrpButton_VolDown = 0x00800000, + ovrpButton_Home = 0x01000000, + ovrpButton_EnumSize = 0x7fffffff +} ovrpButton; + +/// Identifies a controller touch. +typedef enum { + ovrpTouch_None = 0, + ovrpTouch_A = ovrpButton_A, + ovrpTouch_B = ovrpButton_B, + ovrpTouch_X = ovrpButton_X, + ovrpTouch_Y = ovrpButton_Y, + ovrpTouch_LIndexTrigger = 0x00001000, + ovrpTouch_LThumb = ovrpButton_LThumb, + ovrpTouch_LThumbRest = 0x00000800, + ovrpTouch_LTouchpad = ovrpButton_LTouchpad, + ovrpTouch_RIndexTrigger = 0x00000010, + ovrpTouch_RThumb = ovrpButton_RThumb, + ovrpTouch_RThumbRest = 0x00000008, + ovrpTouch_RTouchpad = ovrpButton_RTouchpad, + ovrpTouch_EnumSize = 0x7fffffff +} ovrpTouch; + +/// Identifies a controller near touch. +typedef enum { + ovrpNearTouch_None = 0, + ovrpNearTouch_LIndexTrigger = 0x00000001, + ovrpNearTouch_LThumbButtons = 0x00000002, + ovrpNearTouch_RIndexTrigger = 0x00000004, + ovrpNearTouch_RThumbButtons = 0x00000008, + ovrpNearTouch_EnumSize = 0x7fffffff +} ovrpNearTouch; + +/// Identifies a controller. +typedef enum { + ovrpController_None = 0, + ovrpController_LTouch = 0x01, + ovrpController_RTouch = 0x02, + ovrpController_Touch = ovrpController_LTouch | ovrpController_RTouch, + ovrpController_Remote = 0x04, + ovrpController_Gamepad = 0x10, + ovrpController_LHand = 0x20, + ovrpController_RHand = 0x40, + ovrpController_Hands = ovrpController_LHand | ovrpController_RHand, + ovrpController_Touchpad_DEPRECATED = 0x08000000, + ovrpController_LTrackedRemote = 0x01000000, + ovrpController_RTrackedRemote = 0x02000000, + ovrpController_Active = 0x80000000, + ovrpController_EnumSize = 0x7fffffff +} ovrpController; + + +/// Identifies a haptics location on a controller. +typedef enum { + ovrpHapticsLocation_None = 0, + ovrpHapticsLocation_Hand = 0x01, + ovrpHapticsLocation_Thumb = 0x02, + ovrpHapticsLocation_Index = 0x04, + ovrpHapticsLocation_EnumSize = 0x7fffffff +} ovrpHapticsLocation; + +/// Used to specify recentering behavior. +typedef enum { + /// Recenter all default axes as defined by the current tracking origin type. + ovrpRecenterFlag_Default = 0x00000000, + /// Recenter only controllers that require drift correction. + ovrpRecenterFlag_Controllers = 0x40000000, + /// Clear the ShouldRecenter flag and leave all axes unchanged. Useful for apps that perform + /// custom recentering logic. + ovrpRecenterFlag_IgnoreAll = 0x80000000, + ovrpRecenterFlag_EnumSize = 0x7fffffff +} ovrpRecenterFlag; + +/// Logging levels +typedef enum { + ovrpLogLevel_Debug = 0, + ovrpLogLevel_Info = 1, + ovrpLogLevel_Error = 2, + ovrpLogLevel_EnumSize = 0x7fffffff +} ovrpLogLevel; + +/// Foveation levels +/// +/// Levels should be consecutive integer enums, otherwise change GetTiledMultiResLevel +/// and SetTiledMultiResLevel to work without that assumption +typedef enum { + ovrpTiledMultiResLevel_Off = 0, + ovrpTiledMultiResLevel_LMSLow = 1, + ovrpTiledMultiResLevel_LMSMedium = 2, + ovrpTiledMultiResLevel_LMSHigh = 3, + ovrpTiledMultiResLevel_LMSHighTop = 4, + ovrpTiledMultiResLevel_EnumSize = 0x7fffffff +} ovrpTiledMultiResLevel; + +typedef enum { + ovrpFoveationFlag_EyeTracked = (1 << 0), + + + +} ovrpFoveationFlags; + +/// Control the activation of mixed reality capture +typedef enum { + ovrpMediaMrcActivationMode_Automatic = 0, + ovrpMediaMrcActivationMode_Disabled = 1, + ovrpMediaMrcActivationMode_EnumSize = 0x7fffffff +} ovrpMediaMrcActivationMode; + +/// Control the platform camera status +typedef enum { + ovrpPlatformCameraMode_Disabled = -1, + ovrpPlatformCameraMode_Initialized = 0, + ovrpPlatformCameraMode_UserControlled = 1, // Ex: Quest user grab and + ovrpPlatformCameraMode_SmartNavigated = 2, // Ex: Program to follow/zoom, avoid obstacle ...etc + ovrpPlatformCameraMode_StabilizedPoV = 3, // Ex: Stabilized 1st person view + ovrpPlatformCameraMode_RemoteDroneControlled = 4, // Ex: Control by remote clients + ovrpPlatformCameraMode_RemoteSpatialMapped = 5, // Ex: Control by anchor pose and SLAM tracking + ovrpPlatformCameraMode_EnumSize = 0x7fffffff +} ovrpPlatformCameraMode; + +/// Media encoder input buffer types +typedef enum { + /// raw memory. pixel format in RGBA + ovrpMediaInputVideoBufferType_Memory = 0, + /// texture handle (e.g. texId if GLES) + ovrpMediaInputVideoBufferType_TextureHandle = 1, + ovrpMediaInputVideoBufferType_EnumSize = 0x7fffffff +} ovrpMediaInputVideoBufferType; + + + + + + + + + + + + + + + + +/// Feature fidelity for XR Runtime Performance Manager +typedef enum { + ovrpFeatureType_HandTracking = 0, + ovrpFeatureType_KeyboardTracking = 1, + ovrpFeatureType_EyeTracking = 2, + ovrpFeatureType_FaceTracking = 3, + ovrpFeatureType_BodyTracking = 4, + ovrpFeatureType_Passthrough = 5, + ovrpFeatureType_GazeBasedFoveatedRendering = 6, + ovrpFeatureType_Count, + ovrpFeatureType_EnumSize = 0x7fffffff +} ovrpFeatureType; + +typedef enum { + ovrpFeatureFidelity_Default = -1, + ovrpFeatureFidelity_Low = 0, + ovrpFeatureFidelity_MediumLow = 1, + ovrpFeatureFidelity_Medium = 2, + ovrpFeatureFidelity_MediumHigh = 3, + ovrpFeatureFidelity_High = 4, + ovrpFeatureFidelity_EnumSize = 0x7fffffff +} ovrpFeatureFidelity; + +typedef enum { + ovrpFeatureEnableState_Default = -1, + ovrpFeatureEnableState_Off = 0, + ovrpFeatureEnableState_On = 1, + ovrpFeatureEnableState_EnumSize = 0x7fffffff +} ovrpFeatureEnableState; + +typedef struct { + ovrpFeatureEnableState enableState; + ovrpFeatureFidelity fidelity; +} ovrpFeatureState; + +#if defined(__arm__) +typedef void (*ovrpLogCallback)(ovrpLogLevel, const char*); +typedef void (*ovrpLogCallback2)(ovrpLogLevel, const char* /*msg*/, int /*length*/); +#else +typedef void(__cdecl* ovrpLogCallback)(ovrpLogLevel, const char*); +typedef void(__cdecl* ovrpLogCallback2)(ovrpLogLevel, const char* /*msg*/, int /*length*/); +#endif + +typedef struct { + int MajorVersion; + int MinorVersion; + int PatchVersion; +} ovrpVersion; + +typedef struct { + float LatencyRender; + float LatencyTimewarp; + float LatencyPostPresent; + float ErrorRender; + float ErrorTimewarp; +} ovrpAppLatencyTimings; + +enum { ovrpAppPerfFrameStatsMaxCount = 5 }; + +/// App Perf Frame Stats +typedef struct { + int HmdVsyncIndex; + + int AppFrameIndex; + int AppDroppedFrameCount; + float AppMotionToPhotonLatency; + float AppQueueAheadTime; + float AppCpuElapsedTime; + float AppGpuElapsedTime; + + int CompositorFrameIndex; + int CompositorDroppedFrameCount; + float CompositorLatency; + float CompositorCpuElapsedTime; + float CompositorGpuElapsedTime; + float CompositorCpuStartToGpuEndElapsedTime; + float CompositorGpuEndToVsyncElapsedTime; +} ovrpAppPerfFrameStats; + +/// App Perf Stats +typedef struct { + ovrpAppPerfFrameStats FrameStats[ovrpAppPerfFrameStatsMaxCount]; + int FrameStatsCount; + ovrpBool AnyFrameStatsDropped; + float AdaptiveGpuPerformanceScale; +} ovrpAppPerfStats; + +/// Cross-platform perf metrics +typedef enum { + ovrpPerfMetrics_App_CpuTime_Float = 0, + ovrpPerfMetrics_App_GpuTime_Float = 1, + ovrpPerfMetrics_App_MotionToPhotonLatencyTime_Float_DEPRECATED = 2, + + ovrpPerfMetrics_Compositor_CpuTime_Float = 3, + ovrpPerfMetrics_Compositor_GpuTime_Float = 4, + ovrpPerfMetrics_Compositor_DroppedFrameCount_Int = 5, + ovrpPerfMetrics_Compositor_LatencyTime_Float_DEPRECATED = 6, + + ovrpPerfMetrics_System_GpuUtilPercentage_Float = 7, + ovrpPerfMetrics_System_CpuUtilAveragePercentage_Float = 8, + ovrpPerfMetrics_System_CpuUtilWorstPercentage_Float = 9, + + // Added 1.32.0 + ovrpPerfMetrics_Device_CpuClockFrequencyInMHz_Float = 10, // Deprecated 1.68.0 + ovrpPerfMetrics_Device_GpuClockFrequencyInMHz_Float = 11, // Deprecated 1.68.0 + ovrpPerfMetrics_Device_CpuClockLevel_Int = 12, // Deprecated 1.68.0 + ovrpPerfMetrics_Device_GpuClockLevel_Int = 13, // Deprecated 1.68.0 + + ovrpPerfMetrics_Compositor_SpaceWarp_Mode_Int = 14, + + ovrpPerfMetrics_Device_CpuCore0UtilPercentage_Float = 32, + ovrpPerfMetrics_Device_CpuCore1UtilPercentage_Float = ovrpPerfMetrics_Device_CpuCore0UtilPercentage_Float + 1, + ovrpPerfMetrics_Device_CpuCore2UtilPercentage_Float = ovrpPerfMetrics_Device_CpuCore0UtilPercentage_Float + 2, + ovrpPerfMetrics_Device_CpuCore3UtilPercentage_Float = ovrpPerfMetrics_Device_CpuCore0UtilPercentage_Float + 3, + ovrpPerfMetrics_Device_CpuCore4UtilPercentage_Float = ovrpPerfMetrics_Device_CpuCore0UtilPercentage_Float + 4, + ovrpPerfMetrics_Device_CpuCore5UtilPercentage_Float = ovrpPerfMetrics_Device_CpuCore0UtilPercentage_Float + 5, + ovrpPerfMetrics_Device_CpuCore6UtilPercentage_Float = ovrpPerfMetrics_Device_CpuCore0UtilPercentage_Float + 6, + ovrpPerfMetrics_Device_CpuCore7UtilPercentage_Float = ovrpPerfMetrics_Device_CpuCore0UtilPercentage_Float + 7, + // Enum value 32~63 are reserved for CPU Cores' utilization (assuming at most 32 cores). + + ovrpPerfMetrics_Count, + ovrpPerfMetrics_Max = 0x7fffffff, +} ovrpPerfMetrics; + +/// A 2D size with integer components. +typedef struct { + int w, h; +} ovrpSizei; + +/// A 2D size with float components. +typedef struct { + float w, h; +} ovrpSizef; + +/// A 3D size (width, height, depth) with float components. +typedef struct { + float w, h, d; +} ovrpSize3f; + +/// A 2D vector with integer components. +typedef struct { + int x, y; +} ovrpVector2i; + +/// A 2D vector with float components. +typedef struct { + float x, y; +} ovrpVector2f; + +/// A 3D vector with float components. +typedef struct { + float x, y, z; +} ovrpVector3f; + +/// A 4D vector with float components. +typedef struct { + float x, y, z, w; +} ovrpVector4f; + +/// A 4D vector with Int16 components. +typedef struct { + ovrpInt16 x, y, z, w; +} ovrpVector4s; + +/// A quaternion rotation. +typedef struct { + float x, y, z, w; +} ovrpQuatf; + +/// Row-major 4x4 matrix. +typedef struct { + float M[4][4]; +} ovrpMatrix4f; + +/// Position and orientation together. +typedef struct { + ovrpQuatf Orientation; + ovrpVector3f Position; +} ovrpPosef; + +/// Equivalent to XrSpaceLocationFlags, see openxr.h for flag values +typedef ovrpUInt64 ovrpSpaceLocationFlags; + +typedef struct { + ovrpSpaceLocationFlags locationFlags; + ovrpPosef pose; +} ovrpSpaceLocationf; + +/// Position and orientation together. +typedef struct { + ovrpPosef Pose; + ovrpVector3f Velocity; + ovrpVector3f Acceleration; + ovrpVector3f AngularVelocity; + ovrpVector3f AngularAcceleration; + double Time; +} ovrpPoseStatef; + +/// Asymmetric fov port +typedef struct { + float UpTan; + float DownTan; + float LeftTan; + float RightTan; +} ovrpFovf; + +/// Asymmetric frustum for a camera. +typedef struct { + /// Near clip plane. + float zNear; + /// Far clip plane. + float zFar; + ovrpFovf Fov; +} ovrpFrustum2f; + +/// A 2D rectangle with a position and size as integers. +typedef struct { + ovrpVector2i Pos; + ovrpSizei Size; +} ovrpRecti; + +/// A 2D rectangle with a position and size as floats. +typedef struct { + ovrpVector2f Pos; + ovrpSizef Size; +} ovrpRectf; + +/// A 3D bounds with a position and size as floats. +/// \note: Bounds is defined in Unity with center & extent (half size) but ovrpBoundsf here is +/// defined consistent with ovrpRectf using Pos (min) & Size. +typedef struct { + ovrpVector3f Pos; + ovrpSize3f Size; +} ovrpBoundsf; + +typedef struct { + ovrpRectf LeftRect; + ovrpRectf RightRect; + ovrpVector4f LeftScaleBias; + ovrpVector4f RightScaleBias; +} ovrpTextureRectMatrixf; + +typedef struct { + float WarpLeft; + float WarpRight; + float WarpUp; + float WarpDown; + float SizeLeft; + float SizeRight; + float SizeUp; + float SizeDown; +} ovrpOctilinearLayout; + +typedef struct { + float r, g, b, a; +} ovrpColorf; + +/// Describes Input State for use with Gamepads and Oculus Controllers. +typedef struct { + unsigned int ConnectedControllerTypes; + unsigned int Buttons; + unsigned int Touches; + unsigned int NearTouches; + float IndexTrigger[2]; + float HandTrigger[2]; + ovrpVector2f Thumbstick[2]; + ovrpVector2f Touchpad[2]; + unsigned char BatteryPercentRemaining[2]; + unsigned char RecenterCount[2]; + unsigned char Reserved[28]; +} ovrpControllerState4; + +typedef struct { + unsigned int ConnectedControllerTypes; + unsigned int Buttons; + unsigned int Touches; + unsigned int NearTouches; + float IndexTrigger[2]; + float HandTrigger[2]; + ovrpVector2f Thumbstick[2]; + ovrpVector2f Touchpad[2]; + unsigned char BatteryPercentRemaining[2]; + unsigned char RecenterCount[2]; + float ThumbRestForce[2]; + float StylusForce[2]; + float IndexTriggerCurl[2]; + float IndexTriggerSlide[2]; +} ovrpControllerState5; + +typedef struct { + unsigned int ConnectedControllerTypes; + unsigned int Buttons; + unsigned int Touches; + unsigned int NearTouches; + float IndexTrigger[2]; + float HandTrigger[2]; + ovrpVector2f Thumbstick[2]; + ovrpVector2f Touchpad[2]; + unsigned char BatteryPercentRemaining[2]; + unsigned char RecenterCount[2]; + float ThumbRestForce[2]; + float StylusForce[2]; + float IndexTriggerCurl[2]; + float IndexTriggerSlide[2]; + float IndexTriggerForce[2]; +} ovrpControllerState6; + + + + + + + + + + +/// Describes Haptics Buffer for use with Oculus Controllers. +typedef struct { + const void* Samples; + int SamplesCount; +} ovrpHapticsBuffer; + +typedef struct { + int SamplesAvailable; + int SamplesQueued; +} ovrpHapticsState; + +typedef struct { + int SampleRateHz; + int SampleSizeInBytes; + int MinimumSafeSamplesQueued; + int MinimumBufferSamplesCount; + int OptimalBufferSamplesCount; + int MaximumBufferSamplesCount; +} ovrpHapticsDesc; + +typedef struct { + float Duration; + ovrpUInt32 AmplitudeCount; + const float* Amplitudes; +} ovrpHapticsAmplitudeEnvelopeVibration; + +typedef struct { + ovrpUInt32 BufferSize; + const float* Buffer; + float SampleRateHz; + ovrpBool Append; + ovrpUInt32* SamplesConsumed; +} ovrpHapticsPcmVibration; + +typedef enum ovrpHapticsConstants_ { + ovrpHapticsConstants_MaxSamples = 4000, + ovrpHapticsConstants_EnumSize = 0x7fffffff +} ovrpHapticsConstants; + +/// Boundary types that specify a surface in the boundary system +typedef enum { + /// Outer boundary - closely represents user setup walls, floor and ceiling + ovrpBoundary_Outer = 0x0001, + /// Play area - smaller convex area inside outer boundary where gameplay happens + ovrpBoundary_PlayArea = 0x0100, +} ovrpBoundaryType; + +/// Contains boundary test information +typedef struct { + /// Indicates if the boundary system is being triggered and visible + ovrpBool IsTriggering; + /// Distance to the closest play area or outer boundary surface + float ClosestDistance; + /// Closest point in the surface + ovrpVector3f ClosestPoint; + /// Normal of the closest point + ovrpVector3f ClosestPointNormal; +} ovrpBoundaryTestResult; + +/// Boundary system look and feel +typedef struct { + // Modulate color and alpha (color, brightness and opacity) + ovrpColorf Color; +} ovrpBoundaryLookAndFeel; + +/// Boundary system geometry +typedef struct { + /// The boundary type that the geometry represents. + ovrpBoundaryType BoundaryType; + /// A pointer to a clock-wise ordered array of points. Max count of 256. + ovrpVector3f Points[256]; + /// The number of points. Max count of 256. + int PointsCount; +} ovrpBoundaryGeometry; + +typedef struct { + /// Distance between eyes. + float InterpupillaryDistance; + /// Eye height relative to the ground. + float EyeHeight; + /// Eye offset forward from the head center at EyeHeight. + float HeadModelDepth; + /// Neck joint offset down from the head center at EyeHeight. + float HeadModelHeight; +} ovrpHeadModelParms; + +typedef enum { ovrpFunctionEndFrame = 0, ovrpFunctionCreateTexture } ovrpFunctionType; + +/// Camera status +typedef enum { + ovrpCameraStatus_None, + ovrpCameraStatus_Connected, + ovrpCameraStatus_Calibrating, + ovrpCameraStatus_CalibrationFailed, + ovrpCameraStatus_Calibrated, + ovrpCameraStatus_ThirdPerson, + ovrpCameraStatus_EnumSize = 0x7fffffff +} ovrpCameraStatus; + +// Camera anchor types +typedef enum { + ovrpCameraAnchorType_PreDefined = 0, + ovrpCameraAnchorType_Custom = 1, + ovrpCameraAnchorType_Count, + ovrpCameraAnchorType_EnumSize = 0x7fffffff +} ovrpCameraAnchorType; + +/// Camera intrinsics +typedef struct { + ovrpBool IsValid; + double LastChangedTimeSeconds; + ovrpFovf FOVPort; + float VirtualNearPlaneDistanceMeters; + float VirtualFarPlaneDistanceMeters; + ovrpSizei ImageSensorPixelResolution; +} ovrpCameraIntrinsics; + +/// Camera extrinsics +typedef struct { + ovrpBool IsValid; + double LastChangedTimeSeconds; + ovrpCameraStatus CameraStatus; + ovrpNode AttachedToNode; + ovrpPosef RelativePose; +} ovrpCameraExtrinsics; + +typedef void* ovrpCameraAnchorHandle; +#define OVRP_ANCHOR_INVALID_HANDLE nullptr + +#define OVRP_EXTERNAL_CAMERA_NAME_SIZE 32 +#define OVRP_ANCHOR_NAME_SIZE 32 + +#if !OVRP_MIXED_REALITY_PRIVATE +/// Unified camera device types +typedef enum { + ovrpCameraDevice_None = 0, + ovrpCameraDevice_WebCamera_First = 100, + ovrpCameraDevice_WebCamera0 = ovrpCameraDevice_WebCamera_First + 0, + ovrpCameraDevice_WebCamera1 = ovrpCameraDevice_WebCamera_First + 1, + ovrpCameraDevice_WebCamera_Last = ovrpCameraDevice_WebCamera1, + ovrpCameraDevice_DEPRECATED_DEVICE = 300, // ovrpCameraDevice_ZEDStereoCamera before deprecation + ovrpCameraDevice_EnumSize = 0x7fffffff +} ovrpCameraDevice; +#endif + +typedef enum { + ovrpCameraDeviceDepthSensingMode_Standard = 0, + ovrpCameraDeviceDepthSensingMode_Fill, + ovrpCameraDeviceDepthSensingMode_EnumSize = 0x7fffffff +} ovrpCameraDeviceDepthSensingMode; + +typedef enum { + ovrpCameraDeviceDepthQuality_Low = 0, + ovrpCameraDeviceDepthQuality_Medium, + ovrpCameraDeviceDepthQuality_High, + ovrpCameraDeviceDepthQuality_EnumSize = 0x7fffffff +} ovrpCameraDeviceDepthQuality; + +typedef struct { + float fx; /* Focal length in pixels along x axis. */ + float fy; /* Focal length in pixels along y axis. */ + float cx; /* Optical center along x axis, defined in pixels (usually close to width/2). */ + float cy; /* Optical center along y axis, defined in pixels (usually close to height/2). */ + double disto[5]; /* Distortion factor : [ k1, k2, p1, p2, k3 ]. Radial (k1,k2,k3) and Tangential (p1,p2) distortion.*/ + float v_fov; /* Vertical field of view after stereo rectification, in degrees. */ + float h_fov; /* Horizontal field of view after stereo rectification, in degrees.*/ + float d_fov; /* Diagonal field of view after stereo rectification, in degrees.*/ + int w; /* Resolution width */ + int h; /* Resolution height */ +} ovrpCameraDeviceIntrinsicsParameters; + +const static ovrpPosef s_identityPose = {{0, 0, 0, 1}, {0, 0, 0}}; +const static ovrpPoseStatef s_identityPoseState = + {{{0, 0, 0, 1}, {0, 0, 0}}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, 0}; +const static ovrpFrustum2f s_identityFrustum2 = {0, 0, {0, 0, 0, 0}}; +const static ovrpVector4f s_vec4Zero = {0, 0, 0, 0}; +const static ovrpVector3f s_vec3Zero = {0, 0, 0}; +const static ovrpVector2f s_vec2Zero = {0, 0}; +const static ovrpVector3f s_vec3One = {1, 1, 1}; +const static ovrpQuatf s_identityQuat = {0, 0, 0, 1}; +const static ovrpFovf s_identityFov = {1.0f, 1.0f, 1.0f, 1.0f}; +const static ovrpCameraIntrinsics s_invalidCameraIntrinsics = {ovrpBool_False, -1, {0, 0, 0, 0}, 0, 0, {0, 0}}; +const static ovrpCameraExtrinsics s_invalidCameraExtrinsics = + {ovrpBool_False, -1, ovrpCameraStatus_None, ovrpNode_None, {{0, 0, 0, 1}, {0, 0, 0}}}; + +/// Texture handle which can be cast to GLuint, VkImage, ID3D11Texture2D*, or ID3D12Resource* +typedef unsigned long long ovrpTextureHandle; + +/// Flags passed to ovrp_SetupDistortionWindow. +typedef enum { + ovrpDistortionWindowFlag_None = 0x00000000, + /// If true, the distortion window and eye buffers are set up to handle DRM-protected content. + ovrpDistortionWindowFlag_Protected = 0x00000001, + /// If true, the compositor's graphics device skips error checking to improve performance. + ovrpDistortionWindowFlag_NoErrorContext = 0x00000002, + /// Reserved 0x00000004 in ovrp_SetupDistortionWindow3 + + ovrpDistortionWindowFlag_PhaseSync = 0x00000008, + + ovrpDistortionWindowFlag_EnumSize = 0x7fffffff +} ovrpDistortionWindowFlag; + +/// A timestep type corresponding to a use case for tracking data. +typedef enum { + /// Updated from game thread at end of frame, to hand-off state to Render thread. + ovrpStep_Render = -1, + /// Updated from physics thread, once per simulation step. + ovrpStep_Physics = 0, + ovrpStep_EnumSize = 0x7fffffff +} ovrpStep; + +typedef enum { + ovrpShape_Quad = 0, + ovrpShape_Cylinder = 1, + ovrpShape_Cubemap = 2, + ovrpShape_EyeFov = 3, + ovrpShape_OffcenterCubemap = 4, + ovrpShape_Equirect = 5, + ovrpShape_ReconstructionPassthrough = 7, + ovrpShape_SurfaceProjectedPassthrough = 8, + ovrpShape_Fisheye = 9, + ovrpShape_KeyboardHandsPassthrough = 10, + ovrpShape_KeyboardMaskedHandsPassthrough = 11, + ovrpShape_EnumSize = 0xF +} ovrpShape; + +typedef enum { + ovrpLayout_Stereo = 0, + ovrpLayout_Mono = 1, + ovrpLayout_DoubleWide = 2, + ovrpLayout_Array = 3, + ovrpLayout_EnumSize = 0xF +} ovrpLayout; + +/// A texture format. +typedef enum { + ovrpTextureFormat_R8G8B8A8_sRGB = 0, + ovrpTextureFormat_R8G8B8A8 = 1, + ovrpTextureFormat_R16G16B16A16_FP = 2, + ovrpTextureFormat_R11G11B10_FP = 3, + ovrpTextureFormat_B8G8R8A8_sRGB = 4, + ovrpTextureFormat_B8G8R8A8 = 5, + ovrpTextureFormat_R5G6B5 = 11, + ovrpTextureFormat_R16G16_FP = 12, + ovrpTextureFormat_A2B10G10R10 = 13, + ovrpTextureFormat_R16 = 15, + ovrpTextureFormat_R16_FP = 16, + ovrpTextureFormat_R32_FP = 17, + + // depth texture formats + ovrpTextureFormat_D16 = 6, + ovrpTextureFormat_D24_S8 = 7, + ovrpTextureFormat_D32_FP = 8, + ovrpTextureFormat_D32_FP_S8 = 9, + + ovrpTextureFormat_None = 10, + + ovrpTextureFormat_EnumSize = 0x7fffffff +} ovrpTextureFormat; + +/// Flags used by ovrpLayerDesc +typedef enum { + /// Only create a single stage + ovrpLayerFlag_Static = (1 << 0), + /// Boost CPU priority while visible + ovrpLayerFlag_LoadingScreen = (1 << 1), + /// Force fov to be symmetric + ovrpLayerFlag_SymmetricFov = (1 << 2), + /// Texture origin is in bottom-left + ovrpLayerFlag_TextureOriginAtBottomLeft = (1 << 3), + /// Correct for chromatic aberration, deprecated + ovrpLayerFlag_ChromaticAberrationCorrection = (1 << 4), + /// Does not allocate texture space within the swapchain + ovrpLayerFlag_NoAllocation = (1 << 5), + /// Enable protected content, added in 1.23 + ovrpLayerFlag_ProtectedContent = (1 << 6), + /// Allocate AndroidSurfaceSwapChain, instead of regular TextureSwapChain + ovrpLayerFlag_AndroidSurfaceSwapChain = (1 << 7), + /// Allocate SpaceWarp data with m_textureSwapChain together + ovrpLayerFlag_SpaceWarpDataAllocation = (1 << 8), + ovrpLayerFlag_SpaceWarpDedicatedDepth = (1 << 9), + /// VrApi flag: VRAPI_ANDROID_SURFACE_SWAP_CHAIN_FLAG_SYNCHRONOUS + ovrpLayerFlag_Synchronous = (1 << 10), + /// VrApi flag:VRAPI_ANDROID_SURFACE_SWAP_CHAIN_FLAG_USE_TIMESTAMPS + ovrpLayerFlag_UseTimestamps = (1 << 11), + /// Allocate layer using subsampled layout + ovrpLayerFlag_Subsampled = (1 << 12), + /// if non-static, allocate 4 elements in a swapchain + ovrpLayerFlag_4DeepSwapchain = (1 << 13), + /// Bicubic Filtering + ovrpLayerFlag_BicubicFiltering = (1 << 14), + /// The layer is created through ovrp_EnqueueSetupLayer() + ovrpLayerFlag_LegacyOverlay = (1 << 15), + + + + +} ovrpLayerFlags; + +/// Layer description used by ovrp_SetupLayer to create the layer +#define OVRP_LAYER_DESC \ + struct { \ + ovrpShape Shape; \ + ovrpLayout Layout; \ + ovrpSizei TextureSize; \ + int MipLevels; \ + int SampleCount; \ + ovrpTextureFormat Format; \ + int LayerFlags; \ + } + +typedef OVRP_LAYER_DESC ovrpLayerDesc; + +#define OVRP_LAYER_DESC_TYPE \ + union { \ + ovrpLayerDesc Base; \ + OVRP_LAYER_DESC; \ + } + +typedef OVRP_LAYER_DESC_TYPE ovrpLayerDesc_Quad; +typedef OVRP_LAYER_DESC_TYPE ovrpLayerDesc_Cylinder; +typedef OVRP_LAYER_DESC_TYPE ovrpLayerDesc_Cubemap; +typedef OVRP_LAYER_DESC_TYPE ovrpLayerDesc_InsightPassthrough; + +typedef struct { + OVRP_LAYER_DESC_TYPE; + ovrpFovf Fov[ovrpEye_Count]; + ovrpRectf VisibleRect[ovrpEye_Count]; + ovrpSizei MaxViewportSize; + // added for 1.17 + ovrpTextureFormat DepthFormat; + + // added for 1.49 + ovrpTextureFormat MotionVectorFormat; + ovrpTextureFormat MotionVectorDepthFormat; + ovrpSizei MotionVectorTextureSize; +} ovrpLayerDesc_EyeFov; + +typedef OVRP_LAYER_DESC_TYPE ovrpLayerDesc_OffcenterCubemap; +typedef OVRP_LAYER_DESC_TYPE ovrpLayerDesc_Equirect; +typedef OVRP_LAYER_DESC_TYPE ovrpLayerDesc_Fisheye; + +typedef union { + OVRP_LAYER_DESC_TYPE; + ovrpLayerDesc_Quad Quad; + ovrpLayerDesc_Cylinder Cylinder; + ovrpLayerDesc_Cubemap Cubemap; + ovrpLayerDesc_EyeFov EyeFov; + ovrpLayerDesc_OffcenterCubemap OffcenterCubemap; + ovrpLayerDesc_Equirect Equirect; + ovrpLayerDesc_Fisheye Fisheye; + ovrpLayerDesc_InsightPassthrough InsightPassthrough; +} ovrpLayerDescUnion; + +#undef OVRP_LAYER_DESC +#undef OVRP_LAYER_DESC_TYPE + +/// Flags used by ovrpLayerSubmit +typedef enum { + /// Pose relative to head + ovrpLayerSubmitFlag_HeadLocked = (1 << 0), + /// Layer is octilinear (LMS) + ovrpLayerSubmitFlag_Octilinear = (1 << 1), + /// Use reverse Z + ovrpLayerSubmitFlag_ReverseZ = (1 << 2), + /// Disable layer depth compositing on Rift + ovrpLayerSubmitFlag_NoDepth = (1 << 3), + /// Use inverse alpha for timewarp blending + ovrpLayerSubmitFlag_InverseAlpha = (1 << 4), + /// Combine the submitted layer with the layers generated from OVROverlay commands + ovrpLayerSubmitFlag_CombineLayerSubmits = (1 << 5), + /// Enable VrApi "Expensive" SuperSample Flag. + ovrpLayerSubmitFlag_ExpensiveSuperSample = (1 << 8), + /// Enable per-overlay show/hide functionality. + ovrpLayerSubmitFlag_Hidden = (1 << 9), + /// Force the texture's alpha to 1.0 on Rift + ovrpLayerSubmitFlag_IgnoreSourceAlpha = (1 << 10), + /// Enable Space warp on Fov layer + ovrpLayerSubmitFlag_SpaceWarp = (1 << 11), + /// An efficient version of ovrpLayerSubmitFlag_ExpensiveSuperSample + ovrpLayerSubmitFlag_EfficientSuperSample = (1 << 12), + /// Applies a post-distortion space sharpening filtering + ovrpLayerSubmitFlag_EfficientSharpen = (1 << 13), + /// Be used as a placeholder in combining native layers which was created outside OVRPlugin + ovrpLayerSubmitFlag_ExternalNativeLayer = (1 << 14), + /// Layer submit flag version of bicubic filtering + ovrpLayerSubmitFlag_BicubicFiltering = (1 << 15), + // Higher quality but more costly version of ovrpLayerSubmitFlag_Sharpen + ovrpLayerSubmitFlag_QualitySharpen = (1 << 16), + // Layer submit flag version of secure content + ovrpLayerSubmitFlag_SecureContent = (1 << 17), + // Layer flag to automatically apply sharpening or supersamping filter + ovrpLayerSubmitFlag_AutoLayerFilter = (1 << 18), + +} ovrpLayerSubmitFlags; + +/// Factors used for source and dest alpha to make up the blend function. +typedef enum { + ovrpBlendFactorZero = 0, + ovrpBlendFactorOne = 1, + ovrpBlendFactorSrcAlpha = 2, + ovrpBlendFactorOneMinusSrcAlpha = 3, + ovrpBlendFactorDstAlpha = 4, + ovrpBlendFactorOneMinusDstAlpha = 5 +} ovrpBlendFactor; + +/// Layer state to submit to ovrp_EndFrame +#define OVRP_LAYER_SUBMIT \ + struct { \ + int LayerId; \ + int TextureStage; \ + ovrpRecti ViewportRect[ovrpEye_Count]; \ + ovrpPosef Pose; \ + int LayerSubmitFlags; \ + /* Added in 1.31 */ \ + ovrpVector4f ColorScale; \ + ovrpVector4f ColorOffset; \ + /* Added in 1.34 */ \ + ovrpBool OverrideTextureRectMatrix; \ + ovrpTextureRectMatrixf TextureRectMatrix; \ + ovrpBool OverridePerLayerColorScaleAndOffset; \ + /* Added in 1.60 */ \ + /* If blend factors are present (signaled by `HasBlendFactors == true`),*/ \ + /* they override the default blend function and all other influences */ \ + /* like the layer submit flags `ovrpLayerSubmitFlag_InverseAlpha` and */ \ + /* `ovrpLayerSubmitFlag_IgnoreSourceAlpha`. */ \ + /* Blend factors are not supported by CAPI and are ignored in the CAPI */ \ + /* implementation. */ \ + ovrpBool HasBlendFactors; \ + ovrpBlendFactor SrcBlendFactor; \ + ovrpBlendFactor DstBlendFactor; \ + } + +typedef OVRP_LAYER_SUBMIT ovrpLayerSubmit; + +#define OVRP_LAYER_SUBMIT_TYPE \ + union { \ + ovrpLayerSubmit Base; \ + OVRP_LAYER_SUBMIT; \ + } + +typedef struct { + OVRP_LAYER_SUBMIT_TYPE; + ovrpSizef Size; +} ovrpLayerSubmit_Quad; + +typedef struct { + OVRP_LAYER_SUBMIT_TYPE; + float ArcWidth; + float Height; + float Radius; +} ovrpLayerSubmit_Cylinder; + +typedef OVRP_LAYER_SUBMIT_TYPE ovrpLayerSubmit_Cubemap; + +typedef struct { + OVRP_LAYER_SUBMIT_TYPE; + // added in 1.18 + ovrpOctilinearLayout OctilinearLayout[ovrpEye_Count]; + float DepthNear; + float DepthFar; + // added in 1.44 + ovrpFovf Fov[ovrpEye_Count]; + // added in 1.49 + float MotionVectorDepthNear; + float MotionVectorDepthFar; + ovrpVector4f MotionVectorScale; + ovrpVector4f MotionVectorOffset; + ovrpPosef AppSpaceDeltaPose; +} ovrpLayerSubmit_EyeFov; + +typedef OVRP_LAYER_SUBMIT_TYPE ovrpLayerSubmit_OffcenterCubemap; +typedef OVRP_LAYER_SUBMIT_TYPE ovrpLayerSubmit_Equirect; + +typedef struct { + OVRP_LAYER_SUBMIT_TYPE; + float FovX; + float FovY; + float Horizon; + float Meridian; +} ovrpLayerSubmit_Fisheye; + +typedef union { + OVRP_LAYER_SUBMIT_TYPE; + ovrpLayerSubmit_Quad Quad; + ovrpLayerSubmit_Cylinder Cylinder; + ovrpLayerSubmit_Cubemap Cubemap; + ovrpLayerSubmit_EyeFov EyeFov; + ovrpLayerSubmit_OffcenterCubemap OffcenterCubemap; + ovrpLayerSubmit_Equirect Equirect; + ovrpLayerSubmit_Fisheye Fisheye; +} ovrpLayerSubmitUnion; + +typedef enum { + ovrpViewportStencilType_HiddenArea = 0, + ovrpViewportStencilType_VisibleArea = 1, + ovrpViewportStencilType_BorderLine = 2, + ovrpViewportStencilType_VisibleRectangle = 3, +} ovrpViewportStencilType; + +#undef OVRP_LAYER_SUBMIT +#undef OVRP_LAYER_SUBMIT_TYPE + +//----------------------------------------------------------------- +// Hand tracking +//----------------------------------------------------------------- + +typedef enum ovrpHandStatus_ { + ovrpHandStatus_HandTracked = (1 << 0), // hand is currently tracked by hand tracking + ovrpHandStatus_InputValid = (1 << 1), // if this is set the pointer pose and pinch data is usable + ovrpHandStatus_SystemGestureInProgress = (1 << 6), // if this is set the user is performing the system gesture + ovrpHandStatus_DominantHand = (1 << 7), // if this is set the hand is considered the dominant hand + ovrpHandStatus_MenuPressed = + (1 << 8), // if this is set the hand performed the system gesture as the non-dominant hand + ovrpHandStatus_EnumSize = 0x7fffffff +} ovrpHandStatus; + +typedef enum ovrpHandFinger_ { + ovrpHandFinger_Thumb = 0, + ovrpHandFinger_Index = 1, + ovrpHandFinger_Middle = 2, + ovrpHandFinger_Ring = 3, + ovrpHandFinger_Pinky = 4, + ovrpHandFinger_Max, + ovrpHandFinger_EnumSize = 0x7fffffff +} ovrpHandFinger; + +// clang-format off +typedef enum ovrpHandFingerPinch_ { + ovrpHandFingerPinch_Thumb = (1 << ovrpHandFinger_Thumb), + ovrpHandFingerPinch_Index = (1 << ovrpHandFinger_Index), + ovrpHandFingerPinch_Middle = (1 << ovrpHandFinger_Middle), + ovrpHandFingerPinch_Ring = (1 << ovrpHandFinger_Ring), + ovrpHandFingerPinch_Pinky = (1 << ovrpHandFinger_Pinky), + ovrpHandFingerPinch_Max, + ovrpHandFingerPinch_EnumSize = 0x7fffffff +} ovrpHandFingerPinch; +// clang-format on + +// clang-format off +typedef enum ovrpBoneId_ { + ovrpBoneId_Invalid = -1, + + // hand bones + ovrpBoneId_Hand_Start = 0, + ovrpBoneId_Hand_WristRoot = ovrpBoneId_Hand_Start + 0, // root frame of the hand, where the wrist is located + ovrpBoneId_Hand_ForearmStub = ovrpBoneId_Hand_Start + 1, // frame for user's forearm + ovrpBoneId_Hand_Thumb0 = ovrpBoneId_Hand_Start + 2, // thumb trapezium bone + ovrpBoneId_Hand_Thumb1 = ovrpBoneId_Hand_Start + 3, // thumb metacarpal bone + ovrpBoneId_Hand_Thumb2 = ovrpBoneId_Hand_Start + 4, // thumb proximal phalange bone + ovrpBoneId_Hand_Thumb3 = ovrpBoneId_Hand_Start + 5, // thumb distal phalange bone + ovrpBoneId_Hand_Index1 = ovrpBoneId_Hand_Start + 6, // index proximal phalange bone + ovrpBoneId_Hand_Index2 = ovrpBoneId_Hand_Start + 7, // index intermediate phalange bone + ovrpBoneId_Hand_Index3 = ovrpBoneId_Hand_Start + 8, // index distal phalange bone + ovrpBoneId_Hand_Middle1 = ovrpBoneId_Hand_Start + 9, // middle proximal phalange bone + ovrpBoneId_Hand_Middle2 = ovrpBoneId_Hand_Start + 10, // middle intermediate phalange bone + ovrpBoneId_Hand_Middle3 = ovrpBoneId_Hand_Start + 11, // middle distal phalange bone + ovrpBoneId_Hand_Ring1 = ovrpBoneId_Hand_Start + 12, // ring proximal phalange bone + ovrpBoneId_Hand_Ring2 = ovrpBoneId_Hand_Start + 13, // ring intermediate phalange bone + ovrpBoneId_Hand_Ring3 = ovrpBoneId_Hand_Start + 14, // ring distal phalange bone + ovrpBoneId_Hand_Pinky0 = ovrpBoneId_Hand_Start + 15, // pinky metacarpal bone + ovrpBoneId_Hand_Pinky1 = ovrpBoneId_Hand_Start + 16, // pinky proximal phalange bone + ovrpBoneId_Hand_Pinky2 = ovrpBoneId_Hand_Start + 17, // pinky intermediate phalange bone + ovrpBoneId_Hand_Pinky3 = ovrpBoneId_Hand_Start + 18, // pinky distal phalange bone + ovrpBoneId_Hand_MaxSkinnable = ovrpBoneId_Hand_Start + 19, + // Bone tips are position only. They are not used for skinning but useful for hit-testing. + // NOTE: ovrBoneId_Hand_ThumbTip == ovrBoneId_Hand_MaxSkinnable since the extended tips need to be contiguous + ovrpBoneId_Hand_ThumbTip = ovrpBoneId_Hand_MaxSkinnable + 0, // tip of the thumb + ovrpBoneId_Hand_IndexTip = ovrpBoneId_Hand_MaxSkinnable + 1, // tip of the index finger + ovrpBoneId_Hand_MiddleTip = ovrpBoneId_Hand_MaxSkinnable + 2, // tip of the middle finger + ovrpBoneId_Hand_RingTip = ovrpBoneId_Hand_MaxSkinnable + 3, // tip of the ring finger + ovrpBoneId_Hand_PinkyTip = ovrpBoneId_Hand_MaxSkinnable + 4, // tip of the pinky + ovrpBoneId_Hand_End = ovrpBoneId_Hand_MaxSkinnable + 5, + + // body bones (upper body) + ovrpBoneId_Body_Start = 0, + ovrpBoneId_Body_Root = ovrpBoneId_Body_Start + 0, + ovrpBoneId_Body_Hips = ovrpBoneId_Body_Start + 1, + ovrpBoneId_Body_SpineLower = ovrpBoneId_Body_Start + 2, + ovrpBoneId_Body_SpineMiddle = ovrpBoneId_Body_Start + 3, + ovrpBoneId_Body_SpineUpper = ovrpBoneId_Body_Start + 4, + ovrpBoneId_Body_Chest = ovrpBoneId_Body_Start + 5, + ovrpBoneId_Body_Neck = ovrpBoneId_Body_Start + 6, + ovrpBoneId_Body_Head = ovrpBoneId_Body_Start + 7, + ovrpBoneId_Body_LeftShoulder = ovrpBoneId_Body_Start + 8, + ovrpBoneId_Body_LeftScapula = ovrpBoneId_Body_Start + 9, + ovrpBoneId_Body_LeftArmUpper = ovrpBoneId_Body_Start + 10, + ovrpBoneId_Body_LeftArmLower = ovrpBoneId_Body_Start + 11, + ovrpBoneId_Body_LeftHandWristTwist = ovrpBoneId_Body_Start + 12, + ovrpBoneId_Body_RightShoulder = ovrpBoneId_Body_Start + 13, + ovrpBoneId_Body_RightScapula = ovrpBoneId_Body_Start + 14, + ovrpBoneId_Body_RightArmUpper = ovrpBoneId_Body_Start + 15, + ovrpBoneId_Body_RightArmLower = ovrpBoneId_Body_Start + 16, + ovrpBoneId_Body_RightHandWristTwist = ovrpBoneId_Body_Start + 17, + ovrpBoneId_Body_LeftHandPalm = ovrpBoneId_Body_Start + 18, + ovrpBoneId_Body_LeftHandWrist = ovrpBoneId_Body_Start + 19, + ovrpBoneId_Body_LeftHandThumbMetacarpal = ovrpBoneId_Body_Start + 20, + ovrpBoneId_Body_LeftHandThumbProximal = ovrpBoneId_Body_Start + 21, + ovrpBoneId_Body_LeftHandThumbDistal = ovrpBoneId_Body_Start + 22, + ovrpBoneId_Body_LeftHandThumbTip = ovrpBoneId_Body_Start + 23, + ovrpBoneId_Body_LeftHandIndexMetacarpal = ovrpBoneId_Body_Start + 24, + ovrpBoneId_Body_LeftHandIndexProximal = ovrpBoneId_Body_Start + 25, + ovrpBoneId_Body_LeftHandIndexIntermediate = ovrpBoneId_Body_Start + 26, + ovrpBoneId_Body_LeftHandIndexDistal = ovrpBoneId_Body_Start + 27, + ovrpBoneId_Body_LeftHandIndexTip = ovrpBoneId_Body_Start + 28, + ovrpBoneId_Body_LeftHandMiddleMetacarpal = ovrpBoneId_Body_Start + 29, + ovrpBoneId_Body_LeftHandMiddleProximal = ovrpBoneId_Body_Start + 30, + ovrpBoneId_Body_LeftHandMiddleIntermediate = ovrpBoneId_Body_Start + 31, + ovrpBoneId_Body_LeftHandMiddleDistal = ovrpBoneId_Body_Start + 32, + ovrpBoneId_Body_LeftHandMiddleTip = ovrpBoneId_Body_Start + 33, + ovrpBoneId_Body_LeftHandRingMetacarpal = ovrpBoneId_Body_Start + 34, + ovrpBoneId_Body_LeftHandRingProximal = ovrpBoneId_Body_Start + 35, + ovrpBoneId_Body_LeftHandRingIntermediate = ovrpBoneId_Body_Start + 36, + ovrpBoneId_Body_LeftHandRingDistal = ovrpBoneId_Body_Start + 37, + ovrpBoneId_Body_LeftHandRingTip = ovrpBoneId_Body_Start + 38, + ovrpBoneId_Body_LeftHandLittleMetacarpal = ovrpBoneId_Body_Start + 39, + ovrpBoneId_Body_LeftHandLittleProximal = ovrpBoneId_Body_Start + 40, + ovrpBoneId_Body_LeftHandLittleIntermediate = ovrpBoneId_Body_Start + 41, + ovrpBoneId_Body_LeftHandLittleDistal = ovrpBoneId_Body_Start + 42, + ovrpBoneId_Body_LeftHandLittleTip = ovrpBoneId_Body_Start + 43, + ovrpBoneId_Body_RightHandPalm = ovrpBoneId_Body_Start + 44, + ovrpBoneId_Body_RightHandWrist = ovrpBoneId_Body_Start + 45, + ovrpBoneId_Body_RightHandThumbMetacarpal = ovrpBoneId_Body_Start + 46, + ovrpBoneId_Body_RightHandThumbProximal = ovrpBoneId_Body_Start + 47, + ovrpBoneId_Body_RightHandThumbDistal = ovrpBoneId_Body_Start + 48, + ovrpBoneId_Body_RightHandThumbTip = ovrpBoneId_Body_Start + 49, + ovrpBoneId_Body_RightHandIndexMetacarpal = ovrpBoneId_Body_Start + 50, + ovrpBoneId_Body_RightHandIndexProximal = ovrpBoneId_Body_Start + 51, + ovrpBoneId_Body_RightHandIndexIntermediate = ovrpBoneId_Body_Start + 52, + ovrpBoneId_Body_RightHandIndexDistal = ovrpBoneId_Body_Start + 53, + ovrpBoneId_Body_RightHandIndexTip = ovrpBoneId_Body_Start + 54, + ovrpBoneId_Body_RightHandMiddleMetacarpal = ovrpBoneId_Body_Start + 55, + ovrpBoneId_Body_RightHandMiddleProximal = ovrpBoneId_Body_Start + 56, + ovrpBoneId_Body_RightHandMiddleIntermediate = ovrpBoneId_Body_Start + 57, + ovrpBoneId_Body_RightHandMiddleDistal = ovrpBoneId_Body_Start + 58, + ovrpBoneId_Body_RightHandMiddleTip = ovrpBoneId_Body_Start + 59, + ovrpBoneId_Body_RightHandRingMetacarpal = ovrpBoneId_Body_Start + 60, + ovrpBoneId_Body_RightHandRingProximal = ovrpBoneId_Body_Start + 61, + ovrpBoneId_Body_RightHandRingIntermediate = ovrpBoneId_Body_Start + 62, + ovrpBoneId_Body_RightHandRingDistal = ovrpBoneId_Body_Start + 63, + ovrpBoneId_Body_RightHandRingTip = ovrpBoneId_Body_Start + 64, + ovrpBoneId_Body_RightHandLittleMetacarpal = ovrpBoneId_Body_Start + 65, + ovrpBoneId_Body_RightHandLittleProximal = ovrpBoneId_Body_Start + 66, + ovrpBoneId_Body_RightHandLittleIntermediate = ovrpBoneId_Body_Start + 67, + ovrpBoneId_Body_RightHandLittleDistal = ovrpBoneId_Body_Start + 68, + ovrpBoneId_Body_RightHandLittleTip = ovrpBoneId_Body_Start + 69, + ovrpBoneId_Body_End = ovrpBoneId_Body_Start + 70, + + // full body bones + ovrpBoneId_FullBody_Start = 0, + ovrpBoneId_FullBody_Root = ovrpBoneId_FullBody_Start + 0, + ovrpBoneId_FullBody_Hips = ovrpBoneId_FullBody_Start + 1, + ovrpBoneId_FullBody_SpineLower = ovrpBoneId_FullBody_Start + 2, + ovrpBoneId_FullBody_SpineMiddle = ovrpBoneId_FullBody_Start + 3, + ovrpBoneId_FullBody_SpineUpper = ovrpBoneId_FullBody_Start + 4, + ovrpBoneId_FullBody_Chest = ovrpBoneId_FullBody_Start + 5, + ovrpBoneId_FullBody_Neck = ovrpBoneId_FullBody_Start + 6, + ovrpBoneId_FullBody_Head = ovrpBoneId_FullBody_Start + 7, + ovrpBoneId_FullBody_LeftShoulder = ovrpBoneId_FullBody_Start + 8, + ovrpBoneId_FullBody_LeftScapula = ovrpBoneId_FullBody_Start + 9, + ovrpBoneId_FullBody_LeftArmUpper = ovrpBoneId_FullBody_Start + 10, + ovrpBoneId_FullBody_LeftArmLower = ovrpBoneId_FullBody_Start + 11, + ovrpBoneId_FullBody_LeftHandWristTwist = ovrpBoneId_FullBody_Start + 12, + ovrpBoneId_FullBody_RightShoulder = ovrpBoneId_FullBody_Start + 13, + ovrpBoneId_FullBody_RightScapula = ovrpBoneId_FullBody_Start + 14, + ovrpBoneId_FullBody_RightArmUpper = ovrpBoneId_FullBody_Start + 15, + ovrpBoneId_FullBody_RightArmLower = ovrpBoneId_FullBody_Start + 16, + ovrpBoneId_FullBody_RightHandWristTwist = ovrpBoneId_FullBody_Start + 17, + ovrpBoneId_FullBody_LeftHandPalm = ovrpBoneId_FullBody_Start + 18, + ovrpBoneId_FullBody_LeftHandWrist = ovrpBoneId_FullBody_Start + 19, + ovrpBoneId_FullBody_LeftHandThumbMetacarpal = ovrpBoneId_FullBody_Start + 20, + ovrpBoneId_FullBody_LeftHandThumbProximal = ovrpBoneId_FullBody_Start + 21, + ovrpBoneId_FullBody_LeftHandThumbDistal = ovrpBoneId_FullBody_Start + 22, + ovrpBoneId_FullBody_LeftHandThumbTip = ovrpBoneId_FullBody_Start + 23, + ovrpBoneId_FullBody_LeftHandIndexMetacarpal = ovrpBoneId_FullBody_Start + 24, + ovrpBoneId_FullBody_LeftHandIndexProximal = ovrpBoneId_FullBody_Start + 25, + ovrpBoneId_FullBody_LeftHandIndexIntermediate = ovrpBoneId_FullBody_Start + 26, + ovrpBoneId_FullBody_LeftHandIndexDistal = ovrpBoneId_FullBody_Start + 27, + ovrpBoneId_FullBody_LeftHandIndexTip = ovrpBoneId_FullBody_Start + 28, + ovrpBoneId_FullBody_LeftHandMiddleMetacarpal = ovrpBoneId_FullBody_Start + 29, + ovrpBoneId_FullBody_LeftHandMiddleProximal = ovrpBoneId_FullBody_Start + 30, + ovrpBoneId_FullBody_LeftHandMiddleIntermediate = ovrpBoneId_FullBody_Start + 31, + ovrpBoneId_FullBody_LeftHandMiddleDistal = ovrpBoneId_FullBody_Start + 32, + ovrpBoneId_FullBody_LeftHandMiddleTip = ovrpBoneId_FullBody_Start + 33, + ovrpBoneId_FullBody_LeftHandRingMetacarpal = ovrpBoneId_FullBody_Start + 34, + ovrpBoneId_FullBody_LeftHandRingProximal = ovrpBoneId_FullBody_Start + 35, + ovrpBoneId_FullBody_LeftHandRingIntermediate = ovrpBoneId_FullBody_Start + 36, + ovrpBoneId_FullBody_LeftHandRingDistal = ovrpBoneId_FullBody_Start + 37, + ovrpBoneId_FullBody_LeftHandRingTip = ovrpBoneId_FullBody_Start + 38, + ovrpBoneId_FullBody_LeftHandLittleMetacarpal = ovrpBoneId_FullBody_Start + 39, + ovrpBoneId_FullBody_LeftHandLittleProximal = ovrpBoneId_FullBody_Start + 40, + ovrpBoneId_FullBody_LeftHandLittleIntermediate = ovrpBoneId_FullBody_Start + 41, + ovrpBoneId_FullBody_LeftHandLittleDistal = ovrpBoneId_FullBody_Start + 42, + ovrpBoneId_FullBody_LeftHandLittleTip = ovrpBoneId_FullBody_Start + 43, + ovrpBoneId_FullBody_RightHandPalm = ovrpBoneId_FullBody_Start + 44, + ovrpBoneId_FullBody_RightHandWrist = ovrpBoneId_FullBody_Start + 45, + ovrpBoneId_FullBody_RightHandThumbMetacarpal = ovrpBoneId_FullBody_Start + 46, + ovrpBoneId_FullBody_RightHandThumbProximal = ovrpBoneId_FullBody_Start + 47, + ovrpBoneId_FullBody_RightHandThumbDistal = ovrpBoneId_FullBody_Start + 48, + ovrpBoneId_FullBody_RightHandThumbTip = ovrpBoneId_FullBody_Start + 49, + ovrpBoneId_FullBody_RightHandIndexMetacarpal = ovrpBoneId_FullBody_Start + 50, + ovrpBoneId_FullBody_RightHandIndexProximal = ovrpBoneId_FullBody_Start + 51, + ovrpBoneId_FullBody_RightHandIndexIntermediate = ovrpBoneId_FullBody_Start + 52, + ovrpBoneId_FullBody_RightHandIndexDistal = ovrpBoneId_FullBody_Start + 53, + ovrpBoneId_FullBody_RightHandIndexTip = ovrpBoneId_FullBody_Start + 54, + ovrpBoneId_FullBody_RightHandMiddleMetacarpal = ovrpBoneId_FullBody_Start + 55, + ovrpBoneId_FullBody_RightHandMiddleProximal = ovrpBoneId_FullBody_Start + 56, + ovrpBoneId_FullBody_RightHandMiddleIntermediate = ovrpBoneId_FullBody_Start + 57, + ovrpBoneId_FullBody_RightHandMiddleDistal = ovrpBoneId_FullBody_Start + 58, + ovrpBoneId_FullBody_RightHandMiddleTip = ovrpBoneId_FullBody_Start + 59, + ovrpBoneId_FullBody_RightHandRingMetacarpal = ovrpBoneId_FullBody_Start + 60, + ovrpBoneId_FullBody_RightHandRingProximal = ovrpBoneId_FullBody_Start + 61, + ovrpBoneId_FullBody_RightHandRingIntermediate = ovrpBoneId_FullBody_Start + 62, + ovrpBoneId_FullBody_RightHandRingDistal = ovrpBoneId_FullBody_Start + 63, + ovrpBoneId_FullBody_RightHandRingTip = ovrpBoneId_FullBody_Start + 64, + ovrpBoneId_FullBody_RightHandLittleMetacarpal = ovrpBoneId_FullBody_Start + 65, + ovrpBoneId_FullBody_RightHandLittleProximal = ovrpBoneId_FullBody_Start + 66, + ovrpBoneId_FullBody_RightHandLittleIntermediate = ovrpBoneId_FullBody_Start + 67, + ovrpBoneId_FullBody_RightHandLittleDistal = ovrpBoneId_FullBody_Start + 68, + ovrpBoneId_FullBody_RightHandLittleTip = ovrpBoneId_FullBody_Start + 69, + ovrpBoneId_FullBody_LeftUpperLeg = ovrpBoneId_FullBody_Start + 70, + ovrpBoneId_FullBody_LeftLowerLeg = ovrpBoneId_FullBody_Start + 71, + ovrpBoneId_FullBody_LeftFootAnkleTwist = ovrpBoneId_FullBody_Start + 72, + ovrpBoneId_FullBody_LeftFootAnkle = ovrpBoneId_FullBody_Start + 73, + ovrpBoneId_FullBody_LeftFootSubtalar = ovrpBoneId_FullBody_Start + 74, + ovrpBoneId_FullBody_LeftFootTransverse = ovrpBoneId_FullBody_Start + 75, + ovrpBoneId_FullBody_LeftFootBall = ovrpBoneId_FullBody_Start + 76, + ovrpBoneId_FullBody_RightUpperLeg = ovrpBoneId_FullBody_Start + 77, + ovrpBoneId_FullBody_RightLowerLeg = ovrpBoneId_FullBody_Start + 78, + ovrpBoneId_FullBody_RightFootAnkleTwist = ovrpBoneId_FullBody_Start + 79, + ovrpBoneId_FullBody_RightFootAnkle = ovrpBoneId_FullBody_Start + 80, + ovrpBoneId_FullBody_RightFootSubtalar = ovrpBoneId_FullBody_Start + 81, + ovrpBoneId_FullBody_RightFootTransverse = ovrpBoneId_FullBody_Start + 82, + ovrpBoneId_FullBody_RightFootBall = ovrpBoneId_FullBody_Start + 83, + ovrpBoneId_FullBody_End = ovrpBoneId_FullBody_Start + 84, + + // The new OpenXR extension has invalid mapped to FullBody_End + 1 to avoid using negative values + ovrpBoneId_FullBody_Invalid = ovrpBoneId_FullBody_Start + 85, + + // add other skeleton bone definitions here... + ovrpBoneId_Max = ovrpBoneId_FullBody_End, + + ovrpBoneId_EnumSize = 0x7fff +} ovrpBoneId; +// clang-format on + +//----------------------------------------------------------------- +// Hand skeleton + +// ovrBoneCapsule +// _---_ +// -" "- +// / \ +// |----A----| +// | | | +// | | | +// | |-r->| +// | | | +// | | | +// |----B----| +// \ / +// -. .- +// '---' +typedef struct ovrpBoneCapsule_ { + short BoneIndex; + // Points at either end of the cylinder inscribed in the capsule. Also the center points for + // spheres at either end of the capsule. Points A and B in the diagram above. + ovrpVector3f Points[2]; + // The radius of the capsule cylinder and of the half-sphere caps on the ends of the capsule. + float Radius; +} ovrpBoneCapsule; + +typedef struct ovrpBone_ { + ovrpBoneId BoneId; + // index of this bone's parent bone (-1 if no parent) + short ParentBoneIndex; + ovrpPosef Pose; +} ovrpBone; + + + + + + + + + + + +typedef enum ovrpBodyTrackingCalibrationState_ { + orvpBodyTrackingCalibrationState_Valid = 1, + orvpBodyTrackingCalibrationState_Calibrating = 2, + orvpBodyTrackingCalibrationState_Invalid = 3, + + orvpBodyTrackingCalibrationState_EnumSize = 0x7fffffff +} ovrpBodyTrackingCalibrationState; + +typedef struct ovrpBodyTrackingCalibrationInfo_ { + float bodyHeight; +} ovrpBodyTrackingCalibrationInfo; + +typedef enum ovrpSkeletonConstants_ { + ovrpSkeletonConstants_MaxHandBones = ovrpBoneId_Hand_End, + ovrpSkeletonConstants_MaxBodyBones = ovrpBoneId_Body_End, + ovrpSkeletonConstants_MaxFullBodyBones = ovrpBoneId_FullBody_End, + ovrpSkeletonConstants_MaxUpperBodyBones = ovrpBoneId_Body_End, + ovrpSkeletonConstants_MaxBones = ovrpBoneId_Max, + ovrpSkeletonConstants_MaxBoneCapsules = 19, + ovrpSkeletonConstants_EnumSize = 0x7fffffff +} ovrpSkeletonConstants; + +/// Identifies a skeleton type. +typedef enum ovrpSkeletonType_ { + ovrpSkeletonType_None = -1, + ovrpSkeletonType_HandLeft = 0, + ovrpSkeletonType_HandRight = 1, + ovrpSkeletonType_Body = 2, + ovrpSkeletonType_FullBody = 3, + ovrpSkeletonType_Count, + ovrpSkeletonType_EnumSize = 0x7fffffff +} ovrpSkeletonType; + +typedef struct ovrpSkeleton3_ { + ovrpSkeletonType SkeletonType; + unsigned int NumBones; + unsigned int NumBoneCapsules; + ovrpBone Bones[ovrpSkeletonConstants_MaxBones]; + ovrpBoneCapsule BoneCapsules[ovrpSkeletonConstants_MaxBoneCapsules]; +} ovrpSkeleton3; +typedef struct ovrpSkeleton2_ { + ovrpSkeletonType SkeletonType; + unsigned int NumBones; + unsigned int NumBoneCapsules; + ovrpBone Bones[ovrpSkeletonConstants_MaxUpperBodyBones]; + ovrpBoneCapsule BoneCapsules[ovrpSkeletonConstants_MaxBoneCapsules]; +} ovrpSkeleton2; + +//----------------------------------------------------------------- +// Hand mesh + +typedef enum ovrpMeshConstants_ { + ovrpMesh_MaxVertices = 3000, + ovrpMesh_MaxIndices = ovrpMesh_MaxVertices * 6, + ovrpMesh_EnumSize = 0x7fffffff +} ovrpMeshConstants; + +/// Identifies a mesh type. +typedef enum ovrpMeshType_ { + ovrpMeshType_None = -1, + ovrpMeshType_HandLeft = 0, + ovrpMeshType_HandRight = 1, + ovrpMeshType_Count, + ovrpMeshType_EnumSize = 0x7fffffff +} ovrpMeshType; + + +typedef struct ovrpMesh_ { + // Type of mesh this data describes. + ovrpMeshType MeshType; + // Number of unique vertices in the mesh. + unsigned int NumVertices; + // Number of unique indices in the mesh. + unsigned int NumIndices; + // An array of count NumVertices positions for each vertex. Always valid. + ovrpVector3f VertexPositions[ovrpMesh_MaxVertices]; + // An array of count NumIndices of vertex indices specifying triangles that make up the mesh. Always valid. + ovrpInt16 Indices[ovrpMesh_MaxIndices]; + // An array of count NumVertices of normals for each vertex. + // If null, this attribute is not used. + ovrpVector3f VertexNormals[ovrpMesh_MaxVertices]; + // An array of count NumVertices of texture coordinates for each vertex. + // If null, this attribute is not used. + ovrpVector2f VertexUV0[ovrpMesh_MaxVertices]; + // An array of count NumVertices of blend indices for each of the bones that each vertex is weighted to. + // Always valid. An index of < 0 means no blend weight. + ovrpVector4s BlendIndices[ovrpMesh_MaxVertices]; + // An array of count NumVertices of weights for each of the bones affecting each vertex. Always valid. + ovrpVector4f BlendWeights[ovrpMesh_MaxVertices]; +} ovrpMesh; + +//----------------------------------------------------------------- +// Hand pose +typedef enum ovrpTrackingConfidence_ { + ovrpTrackingConfidence_Low = 0, + ovrpTrackingConfidence_High = 0x3f800000, + ovrpTrackingConfidence_EnumSize = 0x7fffffff +} ovrpTrackingConfidence; + +typedef struct ovrpHandState_ { + // Hand Status bitfield described by ovrpHandStatus flags. + unsigned int Status; + + // Root pose of the hand in world space. Not to be confused with the root bone's transform. + // The root bone can still be offset from this by the skeleton's rest pose. + ovrpPosef RootPose; + + // Current rotation of each bone. + ovrpQuatf BoneRotations[ovrpSkeletonConstants_MaxHandBones]; + + // Provides a bitmask indicating if each finger is "pinched" or not. Indexable via bitshifting with the ovrpHandFinger + // enum i.e. (1 << ovrpHandFinger_Index) + unsigned int Pinches; + + // Provides a 0.0f to 1.0f value of how "pinched" each finger is. Indexable via the ovrpHandFinger enum. + float PinchStrength[ovrpHandFinger_Max]; + + // World space position and translation of the pointer attached to the hand. + ovrpPosef PointerPose; + + float HandScale; + + // Tracking confidence. Range [0,1], 0.0 = lowest confidence, 1.0 = highest confidence. + // This is useful for smoothly de-emphasizing hands as confidence decreases. + // This is the amount of confidence that the system has that the entire hand pose is correct. + ovrpTrackingConfidence HandConfidence; + + // Per-finger tracking confidence. Range [0,1], 0.0 = lowest confidence, 1.0 = highest confidence. + // This is the amount of confidence the system has that the individual finger poses are correct. + ovrpTrackingConfidence FingerConfidences[ovrpHandFinger_Max]; + + // Time stamp for the pose that was requested in global system time. + double RequestedTimeStamp; + + // Time stamp of the captured sample that the pose was extrapolated from. + double SampleTimeStamp; +} ovrpHandState; + +typedef struct ovrpBodyJointLocation_ { + ovrpUInt64 LocationFlags; + ovrpPosef Pose; +} ovrpBodyJointLocation; + +typedef struct ovrpBodyState_ { + ovrpBool IsActive; + float Confidence; + ovrpUInt32 SkeletonChangedCount; + double Time; + ovrpBodyJointLocation JointLocations[ovrpBoneId_Body_End]; +} ovrpBodyState; + +typedef enum ovrpBodyJointSet_ { + ovrpBodyJointSet_None = -1, + ovrpBodyJointSet_UpperBody = 0, + ovrpBodyJointSet_FullBody = 1, + ovrpBodyJointSet_Count = 2 +} ovrpBodyJointSet; + + + + + + + + + + + + + + + + +// Must match XrBodyTrackingFidelityMETA +typedef enum ovrpBodyTrackingFidelity2_ { + ovrpBodyTrackingFidelity2_Low = 1, + ovrpBodyTrackingFidelity2_High = 2, + ovrpBodyTrackingFidelity2_EnumSize = 0x7fffffff, +} ovrpBodyTrackingFidelity2; + + + + + + + + + + + + +typedef struct ovrpBodyState4_ { + ovrpBool IsActive; + float Confidence; + ovrpUInt32 SkeletonChangedCount; + double Time; + ovrpBodyJointLocation JointLocations[ovrpBoneId_Max]; + ovrpBodyTrackingCalibrationState calibrationStatus; + ovrpBodyTrackingFidelity2 fidelity; +} ovrpBodyState4; + +typedef enum ovrpFaceExpression_ { + ovrpFaceExpression_Invalid = -1, + ovrpFaceExpression_Brow_Lowerer_L = 0, + ovrpFaceExpression_Brow_Lowerer_R = 1, + ovrpFaceExpression_Cheek_Puff_L = 2, + ovrpFaceExpression_Cheek_Puff_R = 3, + ovrpFaceExpression_Cheek_Raiser_L = 4, + ovrpFaceExpression_Cheek_Raiser_R = 5, + ovrpFaceExpression_Cheek_Suck_L = 6, + ovrpFaceExpression_Cheek_Suck_R = 7, + ovrpFaceExpression_Chin_Raiser_B = 8, + ovrpFaceExpression_Chin_Raiser_T = 9, + ovrpFaceExpression_Dimpler_L = 10, + ovrpFaceExpression_Dimpler_R = 11, + ovrpFaceExpression_Eyes_Closed_L = 12, + ovrpFaceExpression_Eyes_Closed_R = 13, + ovrpFaceExpression_Eyes_Look_Down_L = 14, + ovrpFaceExpression_Eyes_Look_Down_R = 15, + ovrpFaceExpression_Eyes_Look_Left_L = 16, + ovrpFaceExpression_Eyes_Look_Left_R = 17, + ovrpFaceExpression_Eyes_Look_Right_L = 18, + ovrpFaceExpression_Eyes_Look_Right_R = 19, + ovrpFaceExpression_Eyes_Look_Up_L = 20, + ovrpFaceExpression_Eyes_Look_Up_R = 21, + ovrpFaceExpression_Inner_Brow_Raiser_L = 22, + ovrpFaceExpression_Inner_Brow_Raiser_R = 23, + ovrpFaceExpression_Jaw_Drop = 24, + ovrpFaceExpression_Jaw_Sideways_Left = 25, + ovrpFaceExpression_Jaw_Sideways_Right = 26, + ovrpFaceExpression_Jaw_Thrust = 27, + ovrpFaceExpression_Lid_Tightener_L = 28, + ovrpFaceExpression_Lid_Tightener_R = 29, + ovrpFaceExpression_Lip_Corner_Depressor_L = 30, + ovrpFaceExpression_Lip_Corner_Depressor_R = 31, + ovrpFaceExpression_Lip_Corner_Puller_L = 32, + ovrpFaceExpression_Lip_Corner_Puller_R = 33, + ovrpFaceExpression_Lip_Funneler_LB = 34, + ovrpFaceExpression_Lip_Funneler_LT = 35, + ovrpFaceExpression_Lip_Funneler_RB = 36, + ovrpFaceExpression_Lip_Funneler_RT = 37, + ovrpFaceExpression_Lip_Pressor_L = 38, + ovrpFaceExpression_Lip_Pressor_R = 39, + ovrpFaceExpression_Lip_Pucker_L = 40, + ovrpFaceExpression_Lip_Pucker_R = 41, + ovrpFaceExpression_Lip_Stretcher_L = 42, + ovrpFaceExpression_Lip_Stretcher_R = 43, + ovrpFaceExpression_Lip_Suck_LB = 44, + ovrpFaceExpression_Lip_Suck_LT = 45, + ovrpFaceExpression_Lip_Suck_RB = 46, + ovrpFaceExpression_Lip_Suck_RT = 47, + ovrpFaceExpression_Lip_Tightener_L = 48, + ovrpFaceExpression_Lip_Tightener_R = 49, + ovrpFaceExpression_Lips_Toward = 50, + ovrpFaceExpression_Lower_Lip_Depressor_L = 51, + ovrpFaceExpression_Lower_Lip_Depressor_R = 52, + ovrpFaceExpression_Mouth_Left = 53, + ovrpFaceExpression_Mouth_Right = 54, + ovrpFaceExpression_Nose_Wrinkler_L = 55, + ovrpFaceExpression_Nose_Wrinkler_R = 56, + ovrpFaceExpression_Outer_Brow_Raiser_L = 57, + ovrpFaceExpression_Outer_Brow_Raiser_R = 58, + ovrpFaceExpression_Upper_Lid_Raiser_L = 59, + ovrpFaceExpression_Upper_Lid_Raiser_R = 60, + ovrpFaceExpression_Upper_Lip_Raiser_L = 61, + ovrpFaceExpression_Upper_Lip_Raiser_R = 62, + ovrpFaceExpression_Max = 63, + + + + + + + + + + + ovrpFaceExpression_EnumSize = 0x7FFFFFFF +} ovrpFaceExpression; + +typedef enum ovrpFaceExpression2_ { + ovrpFaceExpression2_Invalid = -1, + ovrpFaceExpression2_Brow_Lowerer_L = 0, + ovrpFaceExpression2_Brow_Lowerer_R = 1, + ovrpFaceExpression2_Cheek_Puff_L = 2, + ovrpFaceExpression2_Cheek_Puff_R = 3, + ovrpFaceExpression2_Cheek_Raiser_L = 4, + ovrpFaceExpression2_Cheek_Raiser_R = 5, + ovrpFaceExpression2_Cheek_Suck_L = 6, + ovrpFaceExpression2_Cheek_Suck_R = 7, + ovrpFaceExpression2_Chin_Raiser_B = 8, + ovrpFaceExpression2_Chin_Raiser_T = 9, + ovrpFaceExpression2_Dimpler_L = 10, + ovrpFaceExpression2_Dimpler_R = 11, + ovrpFaceExpression2_Eyes_Closed_L = 12, + ovrpFaceExpression2_Eyes_Closed_R = 13, + ovrpFaceExpression2_Eyes_Look_Down_L = 14, + ovrpFaceExpression2_Eyes_Look_Down_R = 15, + ovrpFaceExpression2_Eyes_Look_Left_L = 16, + ovrpFaceExpression2_Eyes_Look_Left_R = 17, + ovrpFaceExpression2_Eyes_Look_Right_L = 18, + ovrpFaceExpression2_Eyes_Look_Right_R = 19, + ovrpFaceExpression2_Eyes_Look_Up_L = 20, + ovrpFaceExpression2_Eyes_Look_Up_R = 21, + ovrpFaceExpression2_Inner_Brow_Raiser_L = 22, + ovrpFaceExpression2_Inner_Brow_Raiser_R = 23, + ovrpFaceExpression2_Jaw_Drop = 24, + ovrpFaceExpression2_Jaw_Sideways_Left = 25, + ovrpFaceExpression2_Jaw_Sideways_Right = 26, + ovrpFaceExpression2_Jaw_Thrust = 27, + ovrpFaceExpression2_Lid_Tightener_L = 28, + ovrpFaceExpression2_Lid_Tightener_R = 29, + ovrpFaceExpression2_Lip_Corner_Depressor_L = 30, + ovrpFaceExpression2_Lip_Corner_Depressor_R = 31, + ovrpFaceExpression2_Lip_Corner_Puller_L = 32, + ovrpFaceExpression2_Lip_Corner_Puller_R = 33, + ovrpFaceExpression2_Lip_Funneler_LB = 34, + ovrpFaceExpression2_Lip_Funneler_LT = 35, + ovrpFaceExpression2_Lip_Funneler_RB = 36, + ovrpFaceExpression2_Lip_Funneler_RT = 37, + ovrpFaceExpression2_Lip_Pressor_L = 38, + ovrpFaceExpression2_Lip_Pressor_R = 39, + ovrpFaceExpression2_Lip_Pucker_L = 40, + ovrpFaceExpression2_Lip_Pucker_R = 41, + ovrpFaceExpression2_Lip_Stretcher_L = 42, + ovrpFaceExpression2_Lip_Stretcher_R = 43, + ovrpFaceExpression2_Lip_Suck_LB = 44, + ovrpFaceExpression2_Lip_Suck_LT = 45, + ovrpFaceExpression2_Lip_Suck_RB = 46, + ovrpFaceExpression2_Lip_Suck_RT = 47, + ovrpFaceExpression2_Lip_Tightener_L = 48, + ovrpFaceExpression2_Lip_Tightener_R = 49, + ovrpFaceExpression2_Lips_Toward = 50, + ovrpFaceExpression2_Lower_Lip_Depressor_L = 51, + ovrpFaceExpression2_Lower_Lip_Depressor_R = 52, + ovrpFaceExpression2_Mouth_Left = 53, + ovrpFaceExpression2_Mouth_Right = 54, + ovrpFaceExpression2_Nose_Wrinkler_L = 55, + ovrpFaceExpression2_Nose_Wrinkler_R = 56, + ovrpFaceExpression2_Outer_Brow_Raiser_L = 57, + ovrpFaceExpression2_Outer_Brow_Raiser_R = 58, + ovrpFaceExpression2_Upper_Lid_Raiser_L = 59, + ovrpFaceExpression2_Upper_Lid_Raiser_R = 60, + ovrpFaceExpression2_Upper_Lip_Raiser_L = 61, + ovrpFaceExpression2_Upper_Lip_Raiser_R = 62, + ovrpFaceExpression2_Tongue_Tip_Interdental = 63, + ovrpFaceExpression2_Tongue_Tip_Alveolar = 64, + ovrpFaceExpression2_Tongue_Front_Dorsal_Palate = 65, + ovrpFaceExpression2_Tongue_Mid_Dorsal_Palate = 66, + ovrpFaceExpression2_Tongue_Back_Dorsal_Velar = 67, + ovrpFaceExpression2_Tongue_Out = 68, + ovrpFaceExpression2_Tongue_Retreat = 69, + ovrpFaceExpression2_Max = 70, + ovrpFaceExpression2_EnumSize = 0x7FFFFFFF +} ovrpFaceExpression2; + +typedef enum ovrpFaceTrackingDataSource2_ { + ovrpFaceTrackingDataSource2_Visual = 0, + ovrpFaceTrackingDataSource2_Audio = 1, + ovrpFaceTrackingDataSource2_EnumSize = 0x7FFFFFFF +} ovrpFaceTrackingDataSource2; + +typedef enum ovrpFaceConfidence_ { + ovrpFaceConfidence_Lower = 0, + ovrpFaceConfidence_Upper = 1, + ovrpFaceConfidence_Max = 2, + ovrpFaceConfidence_None = -1, + ovrpFaceConfidence_EnumSize = 0x7FFFFFFF +} ovrpFaceConfidence; + +typedef enum ovrpFaceConstants_ { + + + + + ovrpFaceConstants_FaceTrackingDataSourcesCount = 2, + ovrpFaceConstants_MaxFaceExpressionsWithoutTongue = ovrpFaceExpression_Max, + ovrpFaceConstants_MaxFaceConfidenceWeights = ovrpFaceConfidence_Max, + ovrpFaceConstants_EnumSize = 0x7fffffff +} ovrpFaceConstants; + +typedef struct ovrpFaceExpressionStatus_ { + ovrpBool IsValid; + ovrpBool IsEyeFollowingBlendshapesValid; +} ovrpFaceExpressionStatus; + +typedef struct ovrpFaceState_ { + float ExpressionWeights[ovrpFaceConstants_MaxFaceExpressionsWithoutTongue]; + float ExpressionWeightConfidences[ovrpFaceConstants_MaxFaceConfidenceWeights]; + ovrpFaceExpressionStatus Status; + double Time; +} ovrpFaceState; + +typedef struct ovrpFaceState2_ { + float ExpressionWeights[ovrpFaceExpression2_Max]; + float ExpressionWeightConfidences[ovrpFaceConstants_MaxFaceConfidenceWeights]; + ovrpFaceExpressionStatus Status; + ovrpFaceTrackingDataSource2 DataSource; + double Time; +} ovrpFaceState2; + +typedef struct ovrpEyeGazeState_ { + ovrpPosef Pose; + float Confidence; + ovrpBool IsValid; +} ovrpEyeGazeState; + +typedef struct ovrpEyeGazesState_ { + ovrpEyeGazeState EyeGazes[ovrpEye_Count]; + double Time; +} ovrpEyeGazesState; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +//----------------------------------------------------------------- +// Color Space Management +//----------------------------------------------------------------- +/// Color space types for HMDs +/// +/// Until vrapi_SetClientColorDesc is called, the client will default to Rec2020 for Quest and +/// Rec709 for Go HMDs. +/// +/// This API only handles color-space remapping. Unless specified, all color spaces use D65 white +/// point. It will not affect brightness, contrast or gamma curves. Some of these aspects such as +/// gamma, is handled by the texture format being used. From the GPU samplers' point-of-view, each +/// texture will continue to be treated as linear luminance including sRGB which is converted to +/// linear by the texture sampler. +/// +/// 'VRAPI_COLORSPACE_UNMANAGED' will force the runtime to skip color correction for the provided +/// content. This is *not* recommended unless the app developer is sure about what they're doing. +/// 'VRAPI_COLORSPACE_UNMANAGED' is mostly useful for research & experimentation, but not for +/// software distribution. This is because unless the client is applying the necessary corrections +/// for each HMD type, the results seen in the HMD will be uncalibrated. This is especially true for +/// future HMDs where the color space is not yet known or defined, which could lead to colors that +/// look too dull, too saturated, or hue shifted. +/// +/// Although native Quest and Rift CV1 color spaces are provided as options, they are not +/// standardized color spaces. While we provide the exact color space primary coordinates, for +/// better standardized visualized of authored content, it's recommended that the developers master +/// using a well-defined color space in the provided in the options such as Rec.2020. +/// +/// It is also recommended that content be authored for the wider color spaces instead of Rec.709 to +/// prevent visuals from looking "washed out", "dull" or "desaturated" on wider gamut devices like +/// the Quest. +/// +/// Unique Color Space Details with Chromaticity Primaries in CIE 1931 xy: +/// +/// Color Space: P3, similar to DCI-P3, but using D65 white point instead. +/// Red : (0.680, 0.320) +/// Green: (0.265, 0.690) +/// Blue : (0.150, 0.060) +/// White: (0.313, 0.329) +/// +/// Color Space: Rift CV1 between P3 & Adobe RGB using D75 white point +/// Red : (0.666, 0.334) +/// Green: (0.238, 0.714) +/// Blue : (0.139, 0.053) +/// White: (0.298, 0.318) +/// +/// Color Space: Quest similar to Rift CV1 using D75 white point +/// Red : (0.661, 0.338) +/// Green: (0.228, 0.718) +/// Blue : (0.142, 0.042) +/// White: (0.298, 0.318) +/// +/// Color Space: Rift S similar to Rec 709 using D75 +/// Red : (0.640, 0.330) +/// Green: (0.292, 0.586) +/// Blue : (0.156, 0.058) +/// White: (0.298, 0.318) +/// +/// Note: Due to LCD limitations, the Go display will not be able to meaningfully differentiate +/// brightness levels below 13 out of 255 for 8-bit sRGB or 0.0015 out of 1.0 max for linear-RGB +/// shader output values. To that end, it is recommended that reliance on a dark and narrow gamut is +/// avoided, and the content is instead spread across a larger brightness range when possible. +/// +typedef enum ovrpColorSpace_ { + /// Default value until client sets calls SetClientColorDesc + ovrpColorSpace_Unknown = 0, + /// No color correction, not recommended for production use. See notes above for more info + ovrpColorSpace_Unmanaged = 1, + /// Preferred color space for standardized color across all Oculus HMDs with D65 white point + ovrpColorSpace_Rec_2020 = 2, + /// Rec. 709 is used on Oculus Go and shares the same primary color coordinates as sRGB + ovrpColorSpace_Rec_709 = 3, + /// Oculus Rift CV1 uses a unique color space, see enum description for more info + ovrpColorSpace_Rift_CV1 = 4, + /// Oculus Rift S uses a unique color space, see enum description for more info + ovrpColorSpace_Rift_S = 5, + /// Oculus Quest's native color space is slightly different than Rift CV1 + ovrpColorSpace_Quest = 6, + /// Similar to DCI-P3. See notes above for more details on P3 + ovrpColorSpace_P3 = 7, + /// Similar to sRGB but with deeper greens using D65 white point + ovrpColorSpace_Adobe_RGB = 8, + ovrpColorSpace_Count +} ovrpColorSpace; + +//----------------------------------------------------------------- +// Event Management +//----------------------------------------------------------------- +// Enum defining the type of the underlying event, required first element in every event struct +typedef enum ovrpEventType_ { + ovrpEventType_None = 0, + /// Refresh rate changed event + ovrpEventType_DisplayRefreshRateChange = 1, + + ovrpEventType_SpatialEntityCreateSpatialAnchorComplete = 49, // Deprecated + ovrpEventType_SpatialAnchorCreateComplete = 49, + + ovrpEventType_SpatialEntitySetComponentEnabledComplete = 50, // Deprecated + ovrpEventType_SpaceSetComponentStatusComplete = 50, + + ovrpEventType_SpatialEntityQueryResults = 51, // Deprecated + ovrpEventType_SpaceQueryResults = 51, + + ovrpEventType_SpatialEntityQueryComplete = 52, // Deprecated + ovrpEventType_SpaceQueryComplete = 52, + + ovrpEventType_SpatialEntityStorageSaveResult = 53, // Deprecated + ovrpEventType_SpaceSaveComplete = 53, + + ovrpEventType_SpatialEntityStorageEraseResult = 54, // Deprecated + ovrpEventType_SpaceEraseComplete = 54, + ovrpEventType_SpaceShareResult = 56, + ovrpEventType_SpaceListSaveResult = 57, + ovrpEventType_SceneCaptureComplete = 100, + + + + + + + + + + + + + + + ovrpEventType_VirtualKeyboardCommitText = 201, + ovrpEventType_VirtualKeyboardBackspace = 202, + ovrpEventType_VirtualKeyboardEnter = 203, + ovrpEventType_VirtualKeyboardShown = 204, + ovrpEventType_VirtualKeyboardHidden = 205, + + + + + + + + + + ovrpEventType_PerfSettings = 304, + + + + + + + + + + + + + + + + + + + + + + + ovrpEventType_PassthroughLayerResumed = 500, + + + + + + + + + + + + + +} ovrpEventType; + +// biggest event that OVRPlugin can use +typedef struct ovrpEventDataBuffer_ { + ovrpEventType EventType; + unsigned char EventData[4000]; +} ovrpEventDataBuffer; + +typedef struct ovrpEventDisplayRefreshRateChange_ { + ovrpEventType EventType; + float FromRefreshRate; + float ToRefreshRate; +} ovrpEventDisplayRefreshRateChange; + +//----------------------------------------------------------------- +// CPU/GPU Performance Levels and associated events +typedef enum { + ovrpProcessorPerformanceLevel_PowerSavings = 0, + ovrpProcessorPerformanceLevel_SustainedLow = 1, + ovrpProcessorPerformanceLevel_SustainedHigh = 2, + ovrpProcessorPerformanceLevel_Boost = 3, + ovrpProcessorPerformanceLevel_EnumSize = 0x7fffffff +} ovrpProcessorPerformanceLevel; + +typedef enum ovrpProcessorDomain { + ovrpProcessorDomain_CPU = 0, + ovrpProcessorDomain_GPU = 1, + ovrpProcessorDomain_EnumSize = 0x7fffffff +} ovrpProcessorDomain; + +typedef enum ovrpProcessorSubDomain { + ovrpProcessorSubDomain_Compositing = 0, + ovrpProcessorSubDomain_Rendering = 1, + ovrpProcessorSubDomain_Thermal = 2, + ovrpProcessorSubDomain_EnumSize = 0x7fffffff +} ovrpProcessorSubDomain; + +typedef enum ovrpProcessorNotificationLevel { + ovrpProcessorNotificationLevel_Normal = 0, + ovrpProcessorNotificationLevel_Warning = 1, + ovrpProcessorNotificationLevel_Impaired = 2, + ovrpProcessorNotificationLevel_EnumSize = 0x7fffffff +} ovrpProcessorNotificationLevel; + +typedef struct ovrpEventDataPerfSettings_ { + ovrpEventType EventType; + ovrpProcessorDomain Domain; + ovrpProcessorSubDomain SubDomain; + ovrpProcessorNotificationLevel FromLevel; + ovrpProcessorNotificationLevel ToLevel; +} ovrpEventDataPerfSettings; + +//----------------------------------------------------------------- +// Keyboard Tracking + + + + + + + + + + + + + + + + +#define OVRP_KEYBOARD_DESCRIPTION_NAME_LENGTH 128 + +// Enum defining the type of the keyboard model, effect render parameters and passthrough configuration. +typedef enum ovrpKeyboardPresentationStyles_ { + ovrpKeyboardPresentationStyles_Unknown = 0, + ovrpKeyboardPresentationStyles_Opaque = 1, + ovrpKeyboardPresentationStyles_KeyLabel = 2, +} ovrpKeyboardPresentationStyles; + +// Enum defining the type of the keyboard returned +typedef enum ovrpTrackedKeyboardFlags_ { + ovrpTrackedKeyboardFlags_Exists = 1, + ovrpTrackedKeyboardFlags_Local = 2, + ovrpTrackedKeyboardFlags_Remote = 4, + ovrpTrackedKeyboardFlags_Connected = 8, +} ovrpTrackedKeyboardFlags; + +// Enum defining the type of the keyboard requested +typedef enum ovrpTrackedKeyboardTrackingQueryFlags_ { + ovrpTrackedKeyboardQueryFlags_Local = 2, + ovrpTrackedKeyboardQueryFlags_Remote = 4, +} ovrpTrackedKeyboardQueryFlags; + +typedef struct ovrpKeyboardDescription_ { + // Tracked Object Name + char Name[OVRP_KEYBOARD_DESCRIPTION_NAME_LENGTH]; + + // Unique Object Identifier + ovrpUInt64 TrackedKeyboardId; + + // Keyboard Locale + ovrpVector3f Dimensions; + + // State of this keyboard + ovrpTrackedKeyboardFlags KeyboardFlags; + + // What type of rendering can be done for the model. + ovrpKeyboardPresentationStyles SupportedPresentationStyles; +} ovrpKeyboardDescription; + +typedef struct ovrpKeyboardState_ { + // Set to false if keyboard tracking is in an error state + ovrpBool IsActive; + + ovrpBool OrientationValid; + ovrpBool PositionValid; + ovrpBool OrientationTracked; + ovrpBool PositionTracked; + + // Position and orientation of keyboard + ovrpPoseStatef PoseState; + + // Contrast parameters, provided to Mixed Reality SDK for passthrough visualization + // when hands are over keyboard. (Will be deprecated in future.) + ovrpVector4f ContrastParameters; +} ovrpKeyboardState; + +// Keyboard Tracking Internal + + + + + + + + + + + + + + +#define OVRP_RENDER_MODEL_NAME_MAX_LENGTH 64 + +typedef struct ovrpRenderModelProperies_ { + char modelName[OVRP_RENDER_MODEL_NAME_MAX_LENGTH]; + ovrpUInt64 modelKey; + ovrpUInt32 vendorId; + ovrpUInt32 modelVersion; +} ovrpRenderModelProperties; + +// Enum defining the level of GLTF model supported by the application. +// Must match flags defined in openxr/openxr.h +typedef enum { + ovrpRenderModelFlags_SupportsGltf20Subset1 = 1, + ovrpRenderModelFlags_SupportsGltf20Subset2 = 2, + ovrpRenderModelFlags_EnumSize = 0x7fffffff +} ovrpRenderModelFlags; + +typedef enum ovrpVirtualKeyboardLocationType_ { + ovrpVirtualKeyboardLocationType_Custom = 0, + ovrpVirtualKeyboardLocationType_Far = 1, + ovrpVirtualKeyboardLocationType_Direct = 2 +} ovrpVirtualKeyboardLocationType; + +// Info necessary to help build a virtual keyboard +typedef struct ovrpVirtualKeyboardCreateInfo_ { + float placeholder; +} ovrpVirtualKeyboardCreateInfo; + +typedef struct ovrpVirtualKeyboardSpaceCreateInfo_ { + ovrpVirtualKeyboardLocationType locationType; + ovrpPosef pose; + ovrpTrackingOrigin trackingOrigin; +} ovrpVirtualKeyboardSpaceCreateInfo; + +typedef struct ovrpVirtualKeyboardLocationInfo_ { + ovrpVirtualKeyboardLocationType locationType; + ovrpPosef pose; + float scale; + ovrpTrackingOrigin trackingOrigin; +} ovrpVirtualKeyboardLocationInfo; + +// When supplying input info, specifies which input device was used. +// Must match XrVirtualKeyboardInputSourceMETA defined in +// arvr/libraries/openxr/include/openxr/meta_virtual_keyboard.h +typedef enum { + ovrpVirtualKeyboardInputSource_Invalid = 0, + ovrpVirtualKeyboardInputSource_ControllerRayLeft = 1, + ovrpVirtualKeyboardInputSource_ControllerRayRight = 2, + ovrpVirtualKeyboardInputSource_HandRayLeft = 3, + ovrpVirtualKeyboardInputSource_HandRayRight = 4, + ovrpVirtualKeyboardInputSource_ControllerDirectLeft = 5, + ovrpVirtualKeyboardInputSource_ControllerDirectRight = 6, + ovrpVirtualKeyboardInputSource_HandDirectIndexTipLeft = 7, + ovrpVirtualKeyboardInputSource_HandDirectIndexTipRight = 8, + ovrpVirtualKeyboardInputSource_EnumSize = 0x7FFFFFFF +} ovrpVirtualKeyboardInputSource; + +// Indicates an interaction with a location on the virtual keyboard +typedef struct ovrpVirtualKeyboardInputInfo_ { + ovrpVirtualKeyboardInputSource inputSource; + ovrpPosef inputPose; + ovrpUInt64 inputState; + ovrpTrackingOrigin trackingOrigin; +} ovrpVirtualKeyboardInputInfo; + +// Should remain synced with XR_MAX_VIRTUAL_KEYBOARD_COMMIT_TEXT_SIZE_META in meta_virtual_keyboard.h +#define OVRP_MAX_VIRTUAL_KEYBOARD_COMMIT_TEXT_SIZE 3992 + +typedef struct ovrpVirtualKeyboardAnimationState_ { + int animationIndex; + float fraction; +} ovrpVirtualKeyboardAnimationState; + +typedef struct ovrpVirtualKeyboardModelAnimationStates_ { + unsigned int stateCapacityInput; + unsigned int stateCountOutput; + ovrpVirtualKeyboardAnimationState* states; +} ovrpVirtualKeyboardModelAnimationStates; + +typedef struct ovrpVirtualKeyboardTextureIds_ { + unsigned int textureIdCapacityInput; + unsigned int textureIdCountOutput; + ovrpUInt64* textureIds; +} ovrpVirtualKeyboardTextureIds; + +typedef struct ovrpVirtualKeyboardTextureData_ { + unsigned int textureWidth; + unsigned int textureHeight; + unsigned int bufferCapacityInput; + unsigned int bufferCountOutput; + unsigned char* buffer; +} ovrpVirtualKeyboardTextureData; + +typedef struct ovrpVirtualKeyboardModelVisibility_ { + ovrpBool visible; +} ovrpVirtualKeyboardModelVisibility; + +// Events +typedef struct ovrpEventVirtualKeyboardCommitText_ { + ovrpEventType EventType; + char Text[OVRP_MAX_VIRTUAL_KEYBOARD_COMMIT_TEXT_SIZE]; +} ovrpEventVirtualKeyboardCommitText; + +typedef struct ovrpEventVirtualKeyboardBackspace_ { + ovrpEventType EventType; +} ovrpEventVirtualKeyboardBackspace; + +typedef struct ovrpEventVirtualKeyboardEnter_ { + ovrpEventType EventType; +} ovrpEventVirtualKeyboardEnter; + +typedef struct ovrpEventVirtualKeyboardShown_ { + ovrpEventType EventType; +} ovrpEventVirtualKeyboardShown; + +typedef struct ovrpEventVirtualKeyboardHidden_ { + ovrpEventType EventType; +} ovrpEventVirtualKeyboardHidden; + +//----------------------------------------------------------------- +// Insight Passthrough +//----------------------------------------------------------------- +typedef enum { + ovrpInsightPassthroughColorMapType_None = 0, + ovrpInsightPassthroughColorMapType_MonoToRgba = 1, + ovrpInsightPassthroughColorMapType_MonoToMono = 2, + ovrpInsightPassthroughColorMapType_HandsContrast = 3, + ovrpInsightPassthroughColorMapType_BrightnessContrastSaturation = 4, + ovrpInsightPassthroughColorMapType_ColorLut = 6, + ovrpInsightPassthroughColorMapType_InterpolatedColorLut = 7, + ovrpInsightPassthroughColorMapType_EnumSize = 0x7fffffff +} ovrpInsightPassthroughColorMapType; + +typedef enum { + ovrpInsightPassthroughStyleFlags_HasTextureOpacityFactor = 1 << 0, + ovrpInsightPassthroughStyleFlags_HasEdgeColor = 1 << 1, + ovrpInsightPassthroughStyleFlags_HasTextureColorMap = 1 << 2, + ovrpInsightPassthroughStyleFlags_EnumSize = 0x7fffffff +} ovrpInsightPassthroughStyleFlags; + +typedef ovrpUInt64 ovrpPassthroughColorLut; + +typedef struct { + /// The flags determine which fields of the struct have been initialize and + /// should be read. The values of fields which are not indicated to be + /// present by the flags should not be accessed. This is used to establish + /// backward: When new fields are added to the struct, callers of an older + /// version will only initialize the memory of previously known fields and + // indicate which ones those are in the flags. + ovrpInsightPassthroughStyleFlags Flags; + + /// Opacity of the (main) passthrough texture. + float TextureOpacityFactor; + + /// Color of the edge rendering effect. The effect is disabled if the alpha + /// value is set to 0. + ovrpColorf EdgeColor; + + /// The texture color map assigns a new color for each input (image) color. + /// The contents of `TextureColorMapData` is determined by + /// `TextureColorMapType`: + /// - For `MonoToRgba`, it is an array of 256 MrColorf values, i.e. one + /// float color tuple for each 8 bit grayscale input value. + /// - For `MonoToMono`, it is an array of 256 uint8 values, i.e. one + /// 8 bit grayscale output value for each input value. + /// - For `HandsContrast`, it is an array of 4 float values. + /// - For `BrightnessContrastSaturation`, it is an array of 3 float + /// values: [brightness, contrast, saturation]. + ovrpInsightPassthroughColorMapType TextureColorMapType; + unsigned int TextureColorMapDataSize; + unsigned char* TextureColorMapData; + + // Added in v1.84: + + /// Color LUTs are specified as part of the color mapping system. Clients must + /// set `TextureColorMapType` to `ovrpInsightPassthroughColorMapType_ColorLut` + /// or `ovrpInsightPassthroughColorMapType_InterpolatedColorLut` in order + /// to apply a color LUT. If that's the case, `TextureColorMapData` will be + /// ignored. Instead, `LutSource` and optionally `LutTarget` (for + /// `InterpolatedColorLut`) are applied, which must be created using + /// `ovrp_CreatePassthroughColorLut` previously. + /// There is no specific `ovrpInsightPassthroughStyleFlags` for color LUTs, + /// their validity is a consequence of the supplied `TextureColorMapType`. + ovrpPassthroughColorLut LutSource; + ovrpPassthroughColorLut LutTarget; + float LutWeight; +} ovrpInsightPassthroughStyle; + +typedef enum { + ovrpInsightPassthroughCapabilityFlags_Passthrough = 1 << 0, + ovrpInsightPassthroughCapabilityFlags_Color = 1 << 1, + ovrpInsightPassthroughCapabilityFlags_Depth = 1 << 2, + ovrpInsightPassthroughCapabilityFlags_ColorLut = 1 << 3, + ovrpInsightPassthroughCapabilityFlags_EnumSize = 0x7fffffff +} ovrpInsightPassthroughCapabilityFlags; + +typedef enum { + ovrpInsightPassthroughCapabilityFields_Flags = 1 << 0, + ovrpInsightPassthroughCapabilityFields_MaxColorLutResolution = 1 << 1, + ovrpInsightPassthroughCapabilityFields_EnumSize = 0x7fffffff +} ovrpInsightPassthroughCapabilityFields; + +typedef struct { + /// This field determines which other fields of the struct the caller expects to be filled (and has allocated memory + /// for). This is used to establish backward compatibility: when new fields are added to the struct, callers of + /// `ovrp_GetPassthroughCapabilities` may be built based on an older version and thus only provide enough memory for + /// part of the struct. The callee must thus check which fields it is expected to fill. Note that we should only ever + /// add new fields using this mechanism, not change or remove existing ones. + ovrpInsightPassthroughCapabilityFields Fields; + + /// General capability flags ("supports X"). + ovrpInsightPassthroughCapabilityFlags Flags; + + /// Maximum color LUT resolution supported by the system. + ovrpUInt32 MaxColorLutResolution; +} ovrpInsightPassthroughCapabilities; + +typedef enum { + ovrpPassthroughColorLutChannels_Invalid = 0, + ovrpPassthroughColorLutChannels_Rgb = 1, + ovrpPassthroughColorLutChannels_Rgba = 2, + ovrpPassthroughColorLutChannels_Max = 0x7fffffff, +} ovrpPassthroughColorLutChannels; + +typedef struct ovrpPassthroughColorLutData_ { + ovrpUInt32 BufferSize; + const ovrpByte* Buffer; +} ovrpPassthroughColorLutData; + +//----------------------------------------------------------------- +// Insight Passthrough Keyboard Hands +//----------------------------------------------------------------- +typedef struct { + /// An intensity for left tracked hand. + /// An intensity value can be in the range [0.0, 1.0] where 0.0 is the lowest intensity. + float LeftHandIntensity; + + /// An intensity for right tracked hand. + /// An intensity value can be in the range [0.0, 1.0] where 0.0 is the lowest intensity. + float RightHandIntensity; +} ovrpInsightPassthroughKeyboardHandsIntensity; + +//----------------------------------------------------------------- +// Spatial Anchors + +typedef ovrpUInt64 ovrpSpace; +typedef ovrpUInt64 ovrpUser; +#define OVRP_SPACE_INVALID_HANDLE nullptr +#define OVRP_SPATIAL_ENTITY_UUID_SIZE 2 +#define OVRP_UUID_SIZE 16 +#define OVRP_SPACE_MAX_QUERY_RESULTS_PER_EVENT 128 + +// Components used by XrSpaces to determine what functionality they support +// - Locatable, enables location functionality for pose and orientation +// - Storable, enables save and erase functionality +// - Sharable, enables sharing off-device +// - Bounded2D, used in fb_scene extension +// - Bounded3D, used in fb_scene extension +// - SemanticLabels, used in fb_scene extension +// - RoomLayout, used in fb_scene extension +// - SpaceContainer, used in fb_spatial_entity_container extension +typedef enum { + ovrpSpatialEntityComponentType_Locatable = 0, // Deprecated + ovrpSpaceComponentType_Locatable = 0, + + ovrpSpatialEntityComponentType_Storable = 1, // Deprecated + ovrpSpaceComponentType_Storable = 1, + ovrpSpaceComponentType_Sharable = 2, + + ovrpSpaceComponentType_Bounded2D = 3, + ovrpSpaceComponentType_Bounded3D = 4, + ovrpSpaceComponentType_SemanticLabels = 5, + ovrpSpaceComponentType_RoomLayout = 6, + ovrpSpaceComponentType_SpaceContainer = 7, + ovrpSpaceComponentType_TriangleMesh = 1000269000, + + + + + ovrpSpatialEntityComponentType_Max = 0x7ffffff, // Deprecated + ovrpSpaceComponentType_Max = 0x7ffffff, +} ovrpSpaceComponentType; + +// ovrpSpatialEntityComponentType is deprecated and replaced by ovrpSpaceComponentType +typedef ovrpSpaceComponentType ovrpSpatialEntityComponentType; + +// The storage location for the spatial entity +typedef enum { + ovrpSpaceStorageLocation_Invalid = 0, + ovrpSpaceStorageLocation_Local = 1, + ovrpSpaceStorageLocation_Cloud = 2, + ovrpSpaceStorageLocation_Max = 0x7ffffff, +} ovrpSpaceStorageLocation; + +typedef enum { + ovrpSpaceStoragePersistenceMode_Invalid = 0, + ovrpSpaceStoragePersistenceMode_Indefinite = 1, + ovrpSpaceStoragePersistenceMode_Max = 0x7ffffff, +} ovrpSpaceStoragePersistenceMode; + +// Action to be performed on queried items. +// - Load, Query for spaces and attempt a load on the spaces found. +// Successfully loaded spaces are returned. +typedef enum { + ovrpSpaceQueryActionType_Load = 0, +} ovrpSpaceQueryActionType; + +// Type of query to be performed +// - Action, Query for spaces using an ovrpSpaceQueryActionType +typedef enum { + ovrpSpaceQueryType_Action = 0, + ovrpSpaceQueryType_Max = 0x7ffffff, +} ovrpSpaceQueryType; + +// Filter to be used to narrow the queried spatial entities +// - None, Query for all spatial entities +// - Ids, Query for a single or a list of specific uuids +typedef enum { + ovrpSpaceQueryFilterType_None = 0, + ovrpSpaceQueryFilterType_Ids = 1, + ovrpSpaceQueryFilterType_Components = 2, + + + + ovrpSpaceQueryFilterType_Max = 0x7ffffff, +} ovrpSpaceQueryFilterType; + +typedef struct { + ovrpTrackingOrigin trackingSpace; + ovrpPosef poseInSpace; + double time; +} ovrpSpatialAnchorCreateInfo; + +// New UUID type, uses ovrpByte for uint8_t +typedef struct ovrpUuid { + ovrpByte data[OVRP_UUID_SIZE]; +} ovrpUuid; + +typedef struct { + // list of uuids used for querying + ovrpUuid ids[1024]; + // size of the list + int numIds; +} ovrpSpaceFilterIdInfo; + +typedef struct { + // list of components used for querying + ovrpSpaceComponentType components[16]; + // size of the list + int numComponents; +} ovrpSpaceFilterComponentsInfo; + +typedef struct { + // type of query to be performed + ovrpSpaceQueryType queryType; + // maximum number of spaces to be returned + int maxQuerySpaces; + // timeout wait on query + double timeout; + // location we are querying for the spaces from + ovrpSpaceStorageLocation location; + // action to be performed on queried items if query type is + // of type ovrpSpaceQueryType_Action + ovrpSpaceQueryActionType actionType; + // type of filtering we wish to use on the spaces we've queried + ovrpSpaceQueryFilterType filterType; + // use only when filter type is ovrpSpaceQueryFilterType_Ids + ovrpSpaceFilterIdInfo IdInfo; + // use only when filter type is ovrpSpaceQueryFilterType_Components + ovrpSpaceFilterComponentsInfo componentsInfo; +} ovrpSpaceQueryInfo; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +typedef struct ovrpSpaceQueryResult { + ovrpSpace space; + ovrpUuid uuid; +} ovrpSpaceQueryResult; + +typedef struct ovrpEventDataSpatialAnchorCreateComplete_ { + ovrpEventType EventType; + ovrpUInt64 requestId; + ovrpResult result; + ovrpSpace space; + ovrpUuid uuid; +} ovrpEventDataSpatialAnchorCreateComplete; + +typedef struct ovrpEventDataSpaceSetStatusComplete_ { + ovrpEventType EventType; + ovrpUInt64 requestId; + ovrpResult result; + ovrpSpace space; + ovrpUuid uuid; + ovrpSpaceComponentType componentType; + ovrpBool enabled; +} ovrpEventDataSpaceSetStatusComplete; + +typedef struct ovrpEventSpaceQueryResults_ { + ovrpEventType EventType; + ovrpUInt64 requestId; +} ovrpEventSpaceQueryResults; + +typedef struct ovrpEventSpaceQueryComplete_ { + ovrpEventType EventType; + ovrpUInt64 requestId; + ovrpResult result; +} ovrpEventSpaceQueryComplete; + +typedef struct ovrpEventSpaceStorageSaveResult_ { + ovrpEventType EventType; + ovrpUInt64 requestId; + ovrpSpace space; + ovrpResult result; + ovrpUuid uuid; +} ovrpEventSpaceStorageSaveResult; + +typedef struct ovrpEventSpaceStorageEraseResult_ { + ovrpEventType EventType; + ovrpUInt64 requestId; + ovrpResult result; + ovrpUuid uuid; + ovrpSpaceStorageLocation location; +} ovrpEventSpaceStorageEraseResult; + +typedef struct ovrpEventSpaceShareResult_ { + ovrpEventType EventType; + ovrpUInt64 requestId; + ovrpResult result; +} ovrpEventSpaceShareResult; + +typedef struct ovrpEventSpaceListSaveResult_ { + ovrpEventType EventType; + ovrpUInt64 requestId; + ovrpResult result; +} ovrpEventSpaceListSaveResult; + +typedef struct ovrpSpaceContainer_ { + // Input, capacity of UUID list. + int uuidCapacityInput; + // Output, number of spatial entities included in the list. + int uuidCountOutput; + // List of spatial entities contained in the entity to which this component is attached. + ovrpUuid* uuids; +} ovrpSpaceContainer; + +typedef struct ovrpSemanticLabels_ { + // Input, capacity of the label buffer in byte. + int byteCapacityInput; + // Output, size of the label buffer in byte. + int byteCountOutput; + // Multiple labels represented by raw string, separated by comma (,). + char* labels; +} ovrpSemanticLabels; + +typedef struct ovrpRoomLayout_ { + // UUID, floor of the room layout. + ovrpUuid floorUuid; + // UUID, ceiling of the room layout. + ovrpUuid ceilingUuid; + // Input, indicating the capacity of pointer `wallUuids`. + int wallUuidCapacityInput; + // Output, number of walls included in the list. + int wallUuidCountOutput; + // Ordered list of walls of the room layout. + ovrpUuid* wallUuids; +} ovrpRoomLayout; + +typedef struct ovrpBoundary2D_ { + // Input, capacity of the vertex buffer. + int vertexCapacityInput; + // Output, size of the vertex buffer. + int vertexCountOutput; + // Vertices of the polygonal boundary in the coordinate frame of the associated space. + // Currently only support outer bounds. + ovrpVector2f* vertices; +} ovrpBoundary2D; + +typedef struct ovrpEventSceneCaptureComplete_ { + ovrpEventType EventType; + ovrpUInt64 requestId; + ovrpResult result; +} ovrpEventSceneCaptureComplete; + +#define OVRP_SCENE_CAPTURE_MAX_REQUEST_TYPE_COUNT 30 + +typedef struct ovrpSceneCaptureRequest_ { + int requestByteCount; + char* request; +} ovrpSceneCaptureRequest; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +typedef struct ovrpTriangleMesh_ { + // Input, capacity of the vertex buffer. + int vertexCapacityInput; + // Output, size of the vertex buffer. + int vertexCountOutput; + // Vertices of the triangle mesh in the coordinate frame of the associated space. + ovrpVector3f* vertices; + // Input, capacity of the index buffer. + int indexCapacityInput; + // Output, size of the index buffer. + int indexCountOutput; + // Indices of the triangle mesh. + int* indices; +} ovrpTriangleMesh; + + + + + + + + + + + + + + + + + + + + + + + + + + +typedef enum { + ovrpInteractionProfile_None = 0, + ovrpInteractionProfile_Touch = 1, + ovrpInteractionProfile_TouchPro = 2, + + + + ovrpInteractionProfile_TouchPlus = 4, + ovrpInteractionProfile_EnumSize = 0x7fffffff +} ovrpInteractionProfile; + +typedef enum { + ovrpPassthroughPreferenceFields_Flags = 1 << 0, + ovrpPassthroughPreferenceFields_EnumSize = 0x7fffffff +} ovrpPassthroughPreferenceFields; + +typedef enum { + ovrpPassthroughPreferenceFlags_DefaultToActive = 1 << 0, + // OpenXR flag words are 64 bit, use the same size to make them binary-compatible + ovrpPassthroughPreferenceFlags_EnumSize = 0xffffffffffffffff +} ovrpPassthroughPreferenceFlags; + +typedef struct ovrpPassthroughPreferences_ { + ovrpPassthroughPreferenceFields Fields; + ovrpPassthroughPreferenceFlags Flags; +} ovrpPassthroughPreferences; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +typedef struct ovrpEventDataPassthroughLayerResumed_ { + ovrpEventType EventType; + int LayerId; +} ovrpEventDataPassthroughLayerResumed; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +typedef struct ovrpEnvironmentDepthTextureDesc_ { + ovrpSizei TextureSize; + int MipLevels; + int SampleCount; + ovrpLayout Layout; + ovrpTextureFormat Format; +} ovrpEnvironmentDepthTextureDesc; + +typedef struct ovrpEnvironmentDepthFrameDesc_ { + ovrpBool IsValid; + double CreateTime; + double PredictedDisplayTime; + int SwapchainIndex; + ovrpPosef CreatePose; + ovrpFovf Fov; + float NearZ; + float FarZ; + float MinDepth; + float MaxDepth; +} ovrpEnvironmentDepthFrameDesc; + +typedef enum { + ovrpEnvironmentDepthCreateFlag_None = 0, + ovrpEnvironmentDepthCreateFlag_RemoveHands = 1 << 0, +} ovrpEnvironmentDepthCreateFlag; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +typedef enum { + ovrpQplVariantType_None = 0, + ovrpQplVariantType_String = 1, + ovrpQplVariantType_Int = 2, + ovrpQplVariantType_Double = 3, + ovrpQplVariantType_Bool = 4, + ovrpQplVariantType_StringArray = 5, + ovrpQplVariantType_IntArray = 6, + ovrpQplVariantType_DoubleArray = 7, + ovrpQplVariantType_BoolArray = 8, + ovrpQplVariantType_Max = 0x7fffffff, +} ovrpQplVariantType; + +typedef struct ovrpQplVariant_ { + ovrpQplVariantType Type; + int ValueCount; + union { + const char* StringValue; + ovrpInt64 IntValue; + double DoubleValue; + ovrpBool BoolValue; + const char** StringValues; + ovrpInt64* IntValues; + double* DoubleValues; + ovrpBool* BoolValues; + }; +} ovrpQplVariant; + +typedef struct ovrpQplAnnotation_ { + const char* Key; + ovrpQplVariant Value; +} ovrpQplAnnotation; + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif // __clang__ + +#endif diff --git a/Plugins/MetaXR/Source/Thirdparty/OVRPlugin/OVRPlugin/Include/OVR_Plugin_Types_Deprecated.h b/Plugins/MetaXR/Source/Thirdparty/OVRPlugin/OVRPlugin/Include/OVR_Plugin_Types_Deprecated.h new file mode 100644 index 0000000..510d7c8 --- /dev/null +++ b/Plugins/MetaXR/Source/Thirdparty/OVRPlugin/OVRPlugin/Include/OVR_Plugin_Types_Deprecated.h @@ -0,0 +1,237 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * All rights reserved. + * + * Licensed under the Oculus SDK License Agreement (the "License"); + * you may not use the Oculus SDK except in compliance with the License, + * which is provided at the time of installation or download, or which + * otherwise accompanies this software in either electronic or hard copy form. + * + * You may obtain a copy of the License at + * + * https://developer.oculus.com/licenses/oculussdk/ + * + * Unless required by applicable law or agreed to in writing, the Oculus SDK + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OVR_Plugin_Types_Deprecated_h +#define OVR_Plugin_Types_Deprecated_h + +#include "OVR_Plugin_Types.h" + +#if defined ANDROID || defined __linux__ +#define __cdecl +#endif + +/// Symmetric frustum for a camera. +typedef struct { + /// Near clip plane. + float zNear; + /// Far clip plane. + float zFar; + /// Horizontal field of view. + float fovX; + /// Vertical field of view. + float fovY; +} ovrpFrustumf; + +const static ovrpFrustumf s_identityFrustum = {0, 0, 0, 0}; + +/// Describes Input State for use with Gamepads and Oculus Controllers. +typedef struct { + unsigned int ConnectedControllerTypes; + unsigned int Buttons; + unsigned int Touches; + unsigned int NearTouches; + float IndexTrigger[2]; + float HandTrigger[2]; + ovrpVector2f Thumbstick[2]; + ovrpVector2f Touchpad[2]; +} ovrpControllerState2; + +/// Describes Input State for use with Gamepads and Oculus Controllers. +typedef struct { + unsigned int ConnectedControllerTypes; + unsigned int Buttons; + unsigned int Touches; + unsigned int NearTouches; + float IndexTrigger[2]; + float HandTrigger[2]; + ovrpVector2f Thumbstick[2]; +} ovrpControllerState; + +typedef ovrpControllerState ovrpInputState; + +typedef struct ovrpSkeleton_ { + ovrpSkeletonType SkeletonType; + unsigned int NumBones; + unsigned int NumBoneCapsules; + ovrpBone Bones[ovrpSkeletonConstants_MaxHandBones]; + ovrpBoneCapsule BoneCapsules[ovrpSkeletonConstants_MaxBoneCapsules]; +} ovrpSkeleton; + +// Old UUID type +typedef struct ovrpSpatialEntityUuid { + // unique id value + ovrpUInt64 value[OVRP_SPATIAL_ENTITY_UUID_SIZE]; +} ovrpSpatialEntityUuid; + +// Backward compatibility for Unreal integration +typedef ovrpSpatialAnchorCreateInfo ovrpSpaceAnchorCreateInfo; + +// Single Space Load is no longer supported +typedef struct ovrpEventSpaceStorageLoadResult_ { + ovrpEventType EventType; + ovrpUInt64 requestId; + ovrpSpace space; + ovrpResult result; + ovrpSpatialEntityUuid uuid; +} ovrpEventSpaceStorageLoadResult; + +/// Capability bits that control the plugin's configuration. +/// Each value corresponds to a left-shift offset in the bitfield. +typedef enum { + /// If true, sRGB read-write occurs, reducing eye texture aliasing. + ovrpCap_SRGB = 0, + /// If true, the image will be corrected for chromatic aberration. + ovrpCap_Chromatic, + /// If true, eye textures are flipped on the Y axis before display. + ovrpCap_FlipInput, + /// If true, head tracking affects the rotation reported by ovrp_GetEyePose. + ovrpCap_Rotation, + /// (Deprecated) If true, head rotation affects the position reported by ovrp_GetEyePose. + ovrpCap_HeadModel, + /// If true, head position tracking affects the poses returned by ovrp_GetEyePose. + ovrpCap_Position, + /// If true, the runtime collects performance statistics for debugging. + ovrpCap_CollectPerf, + /// If true, a debugging heads-up display appears in the scene. + ovrpCap_DebugDisplay, + /// If true, the left eye image is shown to both eyes. Right is ignored. + ovrpCap_Monoscopic, + /// If true, both eyes share texture 0, with the left eye on the left side. + ovrpCap_ShareTexture, + /// If true, a clip mesh will be provided for both eyes + ovrpCap_OcclusionMesh, + ovrpCap_EnumSize = 0x7fffffff +} ovrpCaps; + +/// Read-only bits that reflect the plugins' current status. +/// Each value corresponds to a left-shift offset in the bitfield. +typedef enum { + /// If true, the VR display is virtual and no physical device is attached. + ovrpStatus_Debug = 0, + /// (Deprecated) If true, the health & safety warning is currently visible. + ovrpStatus_HSWVisible, + /// If true, the HMD supports position tracking (e.g. a camera is attached). + ovrpStatus_PositionSupported, + /// If true, position tracking is active and not obstructed. + ovrpStatus_PositionTracked, + /// If true, the system has reduced performance to save power. + ovrpStatus_PowerSaving, + /// If true, the plugin is initialized and ready for use. + ovrpStatus_Initialized, + /// If true, a working VR display is present, but it may be a "debug" display. + ovrpStatus_HMDPresent, + /// If true, the user is currently wearing the VR display and it is not idle. + ovrpStatus_UserPresent, + /// If true, the app has VR focus. + ovrpStatus_HasVrFocus, + /// If true, the app should quit as soon as possible. + ovrpStatus_ShouldQuit, + /// If true, the app should call ovrp_RecenterPose as soon as possible. + ovrpStatus_ShouldRecenter, + /// If true, we need to recreate the session + ovrpStatus_ShouldRecreateDistortionWindow, + ovrpStatus_EnumSize = 0x7fffffff +} ovrpStatus; + +typedef enum { + /// (String) Identifies the version of OVRPlugin you are using. Format: "major.minor.release" + ovrpKey_Version, + /// (String) Identifies the type of VR display device in use, if any. + ovrpKey_ProductName, + /// (String) The latest measured latency. + ovrpKey_Latency, + /// (Float) The physical distance from the front of the player's eye to the back of their neck + /// in meters. + ovrpKey_EyeDepth, + /// (Float) The physical height of the player's eyes from the ground in meters. + ovrpKey_EyeHeight, + /// (Float, read-only) The current available battery charge, ranging from 0 (empty) to 1 (full). + ovrpKey_BatteryLevel, + /// (Float, read-only) The current battery temperature in degrees Celsius. + ovrpKey_BatteryTemperature, + /// (Float) The current CPU performance level, rounded down to nearest integer in the range 0-2. + ovrpKey_CpuLevel, + /// (Float) The current GPU performance level, rounded down to nearest integer in the range 0-2. + ovrpKey_GpuLevel, + /// (Float, read-only) The current system volume level. + ovrpKey_SystemVolume, + /// (Float) The fraction of a frame ahead to predict poses and allow GPU-CPU parallelism. + /// Trades latency for performance. + ovrpKey_QueueAheadFraction, + /// (Float) The physical inter-pupillary distance (IPD) separating the user's eyes in meters. + ovrpKey_IPD, + /// (Float) The number of allocated eye texture texels per screen pixel in each direction + /// (horizontal and vertical). + ovrpKey_NativeTextureScale, + /// (Float) The number of rendered eye texture texels per screen pixel based on viewport scaling. + ovrpKey_VirtualTextureScale, + /// (Float) The native refresh rate of the HMD. + ovrpKey_Frequency, + /// (String) The version of the underlying SDK in use. + ovrpKey_SDKVersion, + ovrpKey_EnumSize = 0x7fffffff +} ovrpKey; + +typedef ovrpShape ovrpOverlayShape; + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wpedantic" +#endif // __clang__ + +typedef enum { + ovrpOverlayFlag_None = 0x00000000, + /// If true, the overlay appears on top of all lower-indexed layers and the eye buffers. + ovrpOverlayFlag_OnTop = 0x00000001, + /// If true, the overlay bypasses TimeWarp and directly follows head motion. + ovrpOverlayFlag_HeadLocked = 0x00000002, + /// If true, the overlay will not allow depth compositing on Rift. + ovrpOverlayFlag_NoDepth = 0x00000004, + // If true, the overlay will use the VrApi supersample flag, which can be helpful but is extremely expensive. + ovrpOverlayFlag_ExpensiveSuperSample = 0x00000008, + // if true, the overlay will use the Vrapi efficient supersample flag + ovrpOverlayFlag_EfficientSuperSample = 0x00000010, + // If true, the overlay will use the Vrapi sharpen flag + ovrpOverlayFlag_EfficientSharpen = 0x00000020, + // If true, the overlay will use bicubic filtering flag + ovrpOverlayFlag_BicubicFiltering = 0x00000040, + // If true, the overlay will use the Vrapi sharpen flag + ovrpOverlayFlag_QualitySharpen = 0x00000080, + // If true, the overlay will be "secure content"; the contents cannot be recorded by users + ovrpOverlayFlag_SecureContent = 0x00000100, + + ovrpOverlayFlag_Hidden = 0x00000200, + + ovrpOverlayFlag_AutoFilter = 0x00000400, + + // Internal flags + /// If true, the overlay is a loading screen. + ovrpOverlayFlag_LoadingScreen = 0x40000000, + /// If true, the overlay bypasses distortion and is copied directly to the display + /// (possibly with scaling). + ovrpOverlayFlag_Undistorted = 0x80000000, + ovrpOverlayFlag_EnumSize = 0x7fffffff +} ovrpOverlayFlag; + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif // __clang__ + +#endif diff --git a/Plugins/MetaXR/Source/Thirdparty/OVRPlugin/OVRPlugin/LICENSE.txt b/Plugins/MetaXR/Source/Thirdparty/OVRPlugin/OVRPlugin/LICENSE.txt new file mode 100644 index 0000000..3c024a8 --- /dev/null +++ b/Plugins/MetaXR/Source/Thirdparty/OVRPlugin/OVRPlugin/LICENSE.txt @@ -0,0 +1,17 @@ +Copyright (c) Meta Platforms, Inc. and affiliates. +All rights reserved. + +Licensed under the Oculus SDK License Agreement (the "License"); +you may not use the Oculus SDK except in compliance with the License, +which is provided at the time of installation or download, or which +otherwise accompanies this software in either electronic or hard copy form. + +You may obtain a copy of the License at + +https://developer.oculus.com/licenses/oculussdk/ + +Unless required by applicable law or agreed to in writing, the Oculus SDK +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/Plugins/MetaXR/Source/Thirdparty/OVRPlugin/OVRPluginXR.build.cs b/Plugins/MetaXR/Source/Thirdparty/OVRPlugin/OVRPluginXR.build.cs new file mode 100644 index 0000000..76f0826 --- /dev/null +++ b/Plugins/MetaXR/Source/Thirdparty/OVRPlugin/OVRPluginXR.build.cs @@ -0,0 +1,23 @@ +// @lint-ignore-every LICENSELINT +// Copyright Epic Games, Inc. All Rights Reserved. + +using UnrealBuildTool; + +public class OVRPluginXR : ModuleRules +{ + public OVRPluginXR(ReadOnlyTargetRules Target) : base(Target) + { + + + Type = ModuleType.External; + + string SourceDirectory = "$(PluginDir)/Source/ThirdParty/OVRPlugin/OVRPlugin/"; + + PublicIncludePaths.Add(SourceDirectory + "Include"); + + if (Target.Platform == UnrealTargetPlatform.Android) + { + RuntimeDependencies.Add(SourceDirectory + "Lib/arm64-v8a/OpenXR/libOVRPlugin.so"); + } + } +} diff --git a/Plugins/MetaXR/Source/Thirdparty/OpenXR/LICENSE b/Plugins/MetaXR/Source/Thirdparty/OpenXR/LICENSE new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/Plugins/MetaXR/Source/Thirdparty/OpenXR/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/Plugins/MetaXR/Source/Thirdparty/OpenXR/LICENSES/Apache-2.0.txt b/Plugins/MetaXR/Source/Thirdparty/OpenXR/LICENSES/Apache-2.0.txt new file mode 100644 index 0000000..527a83a --- /dev/null +++ b/Plugins/MetaXR/Source/Thirdparty/OpenXR/LICENSES/Apache-2.0.txt @@ -0,0 +1,208 @@ +Apache License + +Version 2.0, January 2004 + +http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, +AND DISTRIBUTION + + 1. Definitions. + + + +"License" shall mean the terms and conditions for use, reproduction, and distribution +as defined by Sections 1 through 9 of this document. + + + +"Licensor" shall mean the copyright owner or entity authorized by the copyright +owner that is granting the License. + + + +"Legal Entity" shall mean the union of the acting entity and all other entities +that control, are controlled by, or are under common control with that entity. +For the purposes of this definition, "control" means (i) the power, direct +or indirect, to cause the direction or management of such entity, whether +by contract or otherwise, or (ii) ownership of fifty percent (50%) or more +of the outstanding shares, or (iii) beneficial ownership of such entity. + + + +"You" (or "Your") shall mean an individual or Legal Entity exercising permissions +granted by this License. + + + +"Source" form shall mean the preferred form for making modifications, including +but not limited to software source code, documentation source, and configuration +files. + + + +"Object" form shall mean any form resulting from mechanical transformation +or translation of a Source form, including but not limited to compiled object +code, generated documentation, and conversions to other media types. + + + +"Work" shall mean the work of authorship, whether in Source or Object form, +made available under the License, as indicated by a copyright notice that +is included in or attached to the work (an example is provided in the Appendix +below). + + + +"Derivative Works" shall mean any work, whether in Source or Object form, +that is based on (or derived from) the Work and for which the editorial revisions, +annotations, elaborations, or other modifications represent, as a whole, an +original work of authorship. For the purposes of this License, Derivative +Works shall not include works that remain separable from, or merely link (or +bind by name) to the interfaces of, the Work and Derivative Works thereof. + + + +"Contribution" shall mean any work of authorship, including the original version +of the Work and any modifications or additions to that Work or Derivative +Works thereof, that is intentionally submitted to Licensor for inclusion in +the Work by the copyright owner or by an individual or Legal Entity authorized +to submit on behalf of the copyright owner. For the purposes of this definition, +"submitted" means any form of electronic, verbal, or written communication +sent to the Licensor or its representatives, including but not limited to +communication on electronic mailing lists, source code control systems, and +issue tracking systems that are managed by, or on behalf of, the Licensor +for the purpose of discussing and improving the Work, but excluding communication +that is conspicuously marked or otherwise designated in writing by the copyright +owner as "Not a Contribution." + + + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf +of whom a Contribution has been received by Licensor and subsequently incorporated +within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of this +License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, +no-charge, royalty-free, irrevocable copyright license to reproduce, prepare +Derivative Works of, publicly display, publicly perform, sublicense, and distribute +the Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of this License, +each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, +no-charge, royalty-free, irrevocable (except as stated in this section) patent +license to make, have made, use, offer to sell, sell, import, and otherwise +transfer the Work, where such license applies only to those patent claims +licensable by such Contributor that are necessarily infringed by their Contribution(s) +alone or by combination of their Contribution(s) with the Work to which such +Contribution(s) was submitted. If You institute patent litigation against +any entity (including a cross-claim or counterclaim in a lawsuit) alleging +that the Work or a Contribution incorporated within the Work constitutes direct +or contributory patent infringement, then any patent licenses granted to You +under this License for that Work shall terminate as of the date such litigation +is filed. + +4. Redistribution. You may reproduce and distribute copies of the Work or +Derivative Works thereof in any medium, with or without modifications, and +in Source or Object form, provided that You meet the following conditions: + +(a) You must give any other recipients of the Work or Derivative Works a copy +of this License; and + +(b) You must cause any modified files to carry prominent notices stating that +You changed the files; and + +(c) You must retain, in the Source form of any Derivative Works that You distribute, +all copyright, patent, trademark, and attribution notices from the Source +form of the Work, excluding those notices that do not pertain to any part +of the Derivative Works; and + +(d) If the Work includes a "NOTICE" text file as part of its distribution, +then any Derivative Works that You distribute must include a readable copy +of the attribution notices contained within such NOTICE file, excluding those +notices that do not pertain to any part of the Derivative Works, in at least +one of the following places: within a NOTICE text file distributed as part +of the Derivative Works; within the Source form or documentation, if provided +along with the Derivative Works; or, within a display generated by the Derivative +Works, if and wherever such third-party notices normally appear. The contents +of the NOTICE file are for informational purposes only and do not modify the +License. You may add Your own attribution notices within Derivative Works +that You distribute, alongside or as an addendum to the NOTICE text from the +Work, provided that such additional attribution notices cannot be construed +as modifying the License. + +You may add Your own copyright statement to Your modifications and may provide +additional or different license terms and conditions for use, reproduction, +or distribution of Your modifications, or for any such Derivative Works as +a whole, provided Your use, reproduction, and distribution of the Work otherwise +complies with the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, any +Contribution intentionally submitted for inclusion in the Work by You to the +Licensor shall be under the terms and conditions of this License, without +any additional terms or conditions. Notwithstanding the above, nothing herein +shall supersede or modify the terms of any separate license agreement you +may have executed with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade names, +trademarks, service marks, or product names of the Licensor, except as required +for reasonable and customary use in describing the origin of the Work and +reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or agreed to +in writing, Licensor provides the Work (and each Contributor provides its +Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied, including, without limitation, any warranties +or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR +A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness +of using or redistributing the Work and assume any risks associated with Your +exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, whether +in tort (including negligence), contract, or otherwise, unless required by +applicable law (such as deliberate and grossly negligent acts) or agreed to +in writing, shall any Contributor be liable to You for damages, including +any direct, indirect, special, incidental, or consequential damages of any +character arising as a result of this License or out of the use or inability +to use the Work (including but not limited to damages for loss of goodwill, +work stoppage, computer failure or malfunction, or any and all other commercial +damages or losses), even if such Contributor has been advised of the possibility +of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing the Work +or Derivative Works thereof, You may choose to offer, and charge a fee for, +acceptance of support, warranty, indemnity, or other liability obligations +and/or rights consistent with this License. However, in accepting such obligations, +You may act only on Your own behalf and on Your sole responsibility, not on +behalf of any other Contributor, and only if You agree to indemnify, defend, +and hold each Contributor harmless for any liability incurred by, or claims +asserted against, such Contributor by reason of your accepting any such warranty +or additional liability. END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + +To apply the Apache License to your work, attach the following boilerplate +notice, with the fields enclosed by brackets "[]" replaced with your own identifying +information. (Don't include the brackets!) The text should be enclosed in +the appropriate comment syntax for the file format. We also recommend that +a file or class name and description of purpose be included on the same "printed +page" as the copyright notice for easier identification within third-party +archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); + +you may not use this file except in compliance with the License. + +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software + +distributed under the License is distributed on an "AS IS" BASIS, + +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + +See the License for the specific language governing permissions and + +limitations under the License. diff --git a/Plugins/MetaXR/Source/Thirdparty/OpenXR/LICENSES/MIT.txt b/Plugins/MetaXR/Source/Thirdparty/OpenXR/LICENSES/MIT.txt new file mode 100644 index 0000000..204b93d --- /dev/null +++ b/Plugins/MetaXR/Source/Thirdparty/OpenXR/LICENSES/MIT.txt @@ -0,0 +1,19 @@ +MIT License Copyright (c) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice (including the next +paragraph) shall be included in all copies or substantial portions of the +Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS +OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/Plugins/MetaXR/Source/Thirdparty/OpenXR/OpenXRHeaders.build.cs b/Plugins/MetaXR/Source/Thirdparty/OpenXR/OpenXRHeaders.build.cs new file mode 100644 index 0000000..c3d2aa9 --- /dev/null +++ b/Plugins/MetaXR/Source/Thirdparty/OpenXR/OpenXRHeaders.build.cs @@ -0,0 +1,15 @@ +// Copyright Epic Games, Inc. All Rights Reserved. + +using UnrealBuildTool; + +public class OpenXRHeaders : ModuleRules +{ + public OpenXRHeaders(ReadOnlyTargetRules Target) : base(Target) + { + Type = ModuleType.External; + + string SourceDirectory = "$(PluginDir)/Source/ThirdParty/OpenXR/"; + + PublicIncludePaths.Add(SourceDirectory + "include"); + } +} diff --git a/Plugins/MetaXR/Source/Thirdparty/OpenXR/include/khronos/openxr/openxr.h b/Plugins/MetaXR/Source/Thirdparty/OpenXR/include/khronos/openxr/openxr.h new file mode 100644 index 0000000..6f9b71a --- /dev/null +++ b/Plugins/MetaXR/Source/Thirdparty/OpenXR/include/khronos/openxr/openxr.h @@ -0,0 +1,4581 @@ +#ifndef OPENXR_H_ +#define OPENXR_H_ 1 + +/* +** Copyright 2017-2022 The Khronos Group Inc. +** +** SPDX-License-Identifier: Apache-2.0 OR MIT +*/ + +/* +** This header is generated from the Khronos OpenXR XML API Registry. +** +*/ + + +#ifdef __cplusplus +extern "C" { +#endif + + + +#define XR_VERSION_1_0 1 +#include "openxr_platform_defines.h" +#define XR_MAKE_VERSION(major, minor, patch) \ + ((((major) & 0xffffULL) << 48) | (((minor) & 0xffffULL) << 32) | ((patch) & 0xffffffffULL)) + +// OpenXR current version number. +#define XR_CURRENT_API_VERSION XR_MAKE_VERSION(1, 0, 25) + +#define XR_VERSION_MAJOR(version) (uint16_t)(((uint64_t)(version) >> 48)& 0xffffULL) +#define XR_VERSION_MINOR(version) (uint16_t)(((uint64_t)(version) >> 32) & 0xffffULL) +#define XR_VERSION_PATCH(version) (uint32_t)((uint64_t)(version) & 0xffffffffULL) + +#define XR_MIN_COMPOSITION_LAYERS_SUPPORTED 16 + + +#if !defined(XR_NULL_HANDLE) +#if (XR_PTR_SIZE == 8) && XR_CPP_NULLPTR_SUPPORTED + #define XR_NULL_HANDLE nullptr +#else + #define XR_NULL_HANDLE 0 +#endif +#endif + + + +#define XR_NULL_SYSTEM_ID 0 + + +#define XR_NULL_PATH 0 + + +#define XR_SUCCEEDED(result) ((result) >= 0) + + +#define XR_FAILED(result) ((result) < 0) + + +#define XR_UNQUALIFIED_SUCCESS(result) ((result) == 0) + + +#define XR_NO_DURATION 0 + + +#define XR_INFINITE_DURATION 0x7fffffffffffffffLL + + +#define XR_MIN_HAPTIC_DURATION -1 + + +#define XR_FREQUENCY_UNSPECIFIED 0 + + +#define XR_MAX_EVENT_DATA_SIZE sizeof(XrEventDataBuffer) + + +#if !defined(XR_MAY_ALIAS) +#if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4)) +#define XR_MAY_ALIAS __attribute__((__may_alias__)) +#else +#define XR_MAY_ALIAS +#endif +#endif + + +#if !defined(XR_DEFINE_HANDLE) +#if (XR_PTR_SIZE == 8) + #define XR_DEFINE_HANDLE(object) typedef struct object##_T* object; +#else + #define XR_DEFINE_HANDLE(object) typedef uint64_t object; +#endif +#endif + + + +#if !defined(XR_DEFINE_ATOM) + #define XR_DEFINE_ATOM(object) typedef uint64_t object; +#endif + + +typedef uint64_t XrVersion; +typedef uint64_t XrFlags64; +XR_DEFINE_ATOM(XrSystemId) +typedef uint32_t XrBool32; +XR_DEFINE_ATOM(XrPath) +typedef int64_t XrTime; +typedef int64_t XrDuration; +XR_DEFINE_HANDLE(XrInstance) +XR_DEFINE_HANDLE(XrSession) +XR_DEFINE_HANDLE(XrSpace) +XR_DEFINE_HANDLE(XrAction) +XR_DEFINE_HANDLE(XrSwapchain) +XR_DEFINE_HANDLE(XrActionSet) +#define XR_TRUE 1 +#define XR_FALSE 0 +#define XR_MAX_EXTENSION_NAME_SIZE 128 +#define XR_MAX_API_LAYER_NAME_SIZE 256 +#define XR_MAX_API_LAYER_DESCRIPTION_SIZE 256 +#define XR_MAX_SYSTEM_NAME_SIZE 256 +#define XR_MAX_APPLICATION_NAME_SIZE 128 +#define XR_MAX_ENGINE_NAME_SIZE 128 +#define XR_MAX_RUNTIME_NAME_SIZE 128 +#define XR_MAX_PATH_LENGTH 256 +#define XR_MAX_STRUCTURE_NAME_SIZE 64 +#define XR_MAX_RESULT_STRING_SIZE 64 +#define XR_MAX_ACTION_SET_NAME_SIZE 64 +#define XR_MAX_LOCALIZED_ACTION_SET_NAME_SIZE 128 +#define XR_MAX_ACTION_NAME_SIZE 64 +#define XR_MAX_LOCALIZED_ACTION_NAME_SIZE 128 + +typedef enum XrResult { + XR_SUCCESS = 0, + XR_TIMEOUT_EXPIRED = 1, + XR_SESSION_LOSS_PENDING = 3, + XR_EVENT_UNAVAILABLE = 4, + XR_SPACE_BOUNDS_UNAVAILABLE = 7, + XR_SESSION_NOT_FOCUSED = 8, + XR_FRAME_DISCARDED = 9, + XR_ERROR_VALIDATION_FAILURE = -1, + XR_ERROR_RUNTIME_FAILURE = -2, + XR_ERROR_OUT_OF_MEMORY = -3, + XR_ERROR_API_VERSION_UNSUPPORTED = -4, + XR_ERROR_INITIALIZATION_FAILED = -6, + XR_ERROR_FUNCTION_UNSUPPORTED = -7, + XR_ERROR_FEATURE_UNSUPPORTED = -8, + XR_ERROR_EXTENSION_NOT_PRESENT = -9, + XR_ERROR_LIMIT_REACHED = -10, + XR_ERROR_SIZE_INSUFFICIENT = -11, + XR_ERROR_HANDLE_INVALID = -12, + XR_ERROR_INSTANCE_LOST = -13, + XR_ERROR_SESSION_RUNNING = -14, + XR_ERROR_SESSION_NOT_RUNNING = -16, + XR_ERROR_SESSION_LOST = -17, + XR_ERROR_SYSTEM_INVALID = -18, + XR_ERROR_PATH_INVALID = -19, + XR_ERROR_PATH_COUNT_EXCEEDED = -20, + XR_ERROR_PATH_FORMAT_INVALID = -21, + XR_ERROR_PATH_UNSUPPORTED = -22, + XR_ERROR_LAYER_INVALID = -23, + XR_ERROR_LAYER_LIMIT_EXCEEDED = -24, + XR_ERROR_SWAPCHAIN_RECT_INVALID = -25, + XR_ERROR_SWAPCHAIN_FORMAT_UNSUPPORTED = -26, + XR_ERROR_ACTION_TYPE_MISMATCH = -27, + XR_ERROR_SESSION_NOT_READY = -28, + XR_ERROR_SESSION_NOT_STOPPING = -29, + XR_ERROR_TIME_INVALID = -30, + XR_ERROR_REFERENCE_SPACE_UNSUPPORTED = -31, + XR_ERROR_FILE_ACCESS_ERROR = -32, + XR_ERROR_FILE_CONTENTS_INVALID = -33, + XR_ERROR_FORM_FACTOR_UNSUPPORTED = -34, + XR_ERROR_FORM_FACTOR_UNAVAILABLE = -35, + XR_ERROR_API_LAYER_NOT_PRESENT = -36, + XR_ERROR_CALL_ORDER_INVALID = -37, + XR_ERROR_GRAPHICS_DEVICE_INVALID = -38, + XR_ERROR_POSE_INVALID = -39, + XR_ERROR_INDEX_OUT_OF_RANGE = -40, + XR_ERROR_VIEW_CONFIGURATION_TYPE_UNSUPPORTED = -41, + XR_ERROR_ENVIRONMENT_BLEND_MODE_UNSUPPORTED = -42, + XR_ERROR_NAME_DUPLICATED = -44, + XR_ERROR_NAME_INVALID = -45, + XR_ERROR_ACTIONSET_NOT_ATTACHED = -46, + XR_ERROR_ACTIONSETS_ALREADY_ATTACHED = -47, + XR_ERROR_LOCALIZED_NAME_DUPLICATED = -48, + XR_ERROR_LOCALIZED_NAME_INVALID = -49, + XR_ERROR_GRAPHICS_REQUIREMENTS_CALL_MISSING = -50, + XR_ERROR_RUNTIME_UNAVAILABLE = -51, + XR_ERROR_ANDROID_THREAD_SETTINGS_ID_INVALID_KHR = -1000003000, + XR_ERROR_ANDROID_THREAD_SETTINGS_FAILURE_KHR = -1000003001, + XR_ERROR_CREATE_SPATIAL_ANCHOR_FAILED_MSFT = -1000039001, + XR_ERROR_SECONDARY_VIEW_CONFIGURATION_TYPE_NOT_ENABLED_MSFT = -1000053000, + XR_ERROR_CONTROLLER_MODEL_KEY_INVALID_MSFT = -1000055000, + XR_ERROR_REPROJECTION_MODE_UNSUPPORTED_MSFT = -1000066000, + XR_ERROR_COMPUTE_NEW_SCENE_NOT_COMPLETED_MSFT = -1000097000, + XR_ERROR_SCENE_COMPONENT_ID_INVALID_MSFT = -1000097001, + XR_ERROR_SCENE_COMPONENT_TYPE_MISMATCH_MSFT = -1000097002, + XR_ERROR_SCENE_MESH_BUFFER_ID_INVALID_MSFT = -1000097003, + XR_ERROR_SCENE_COMPUTE_FEATURE_INCOMPATIBLE_MSFT = -1000097004, + XR_ERROR_SCENE_COMPUTE_CONSISTENCY_MISMATCH_MSFT = -1000097005, + XR_ERROR_DISPLAY_REFRESH_RATE_UNSUPPORTED_FB = -1000101000, + XR_ERROR_COLOR_SPACE_UNSUPPORTED_FB = -1000108000, + XR_ERROR_SPACE_COMPONENT_NOT_SUPPORTED_FB = -1000113000, + XR_ERROR_SPACE_COMPONENT_NOT_ENABLED_FB = -1000113001, + XR_ERROR_SPACE_COMPONENT_STATUS_PENDING_FB = -1000113002, + XR_ERROR_SPACE_COMPONENT_STATUS_ALREADY_SET_FB = -1000113003, + XR_ERROR_UNEXPECTED_STATE_PASSTHROUGH_FB = -1000118000, + XR_ERROR_FEATURE_ALREADY_CREATED_PASSTHROUGH_FB = -1000118001, + XR_ERROR_FEATURE_REQUIRED_PASSTHROUGH_FB = -1000118002, + XR_ERROR_NOT_PERMITTED_PASSTHROUGH_FB = -1000118003, + XR_ERROR_INSUFFICIENT_RESOURCES_PASSTHROUGH_FB = -1000118004, + XR_ERROR_UNKNOWN_PASSTHROUGH_FB = -1000118050, + XR_ERROR_RENDER_MODEL_KEY_INVALID_FB = -1000119000, + XR_RENDER_MODEL_UNAVAILABLE_FB = 1000119020, + XR_ERROR_MARKER_NOT_TRACKED_VARJO = -1000124000, + XR_ERROR_MARKER_ID_INVALID_VARJO = -1000124001, + XR_ERROR_SPATIAL_ANCHOR_NAME_NOT_FOUND_MSFT = -1000142001, + XR_ERROR_SPATIAL_ANCHOR_NAME_INVALID_MSFT = -1000142002, + XR_RESULT_MAX_ENUM = 0x7FFFFFFF +} XrResult; + +typedef enum XrStructureType { + XR_TYPE_UNKNOWN = 0, + XR_TYPE_API_LAYER_PROPERTIES = 1, + XR_TYPE_EXTENSION_PROPERTIES = 2, + XR_TYPE_INSTANCE_CREATE_INFO = 3, + XR_TYPE_SYSTEM_GET_INFO = 4, + XR_TYPE_SYSTEM_PROPERTIES = 5, + XR_TYPE_VIEW_LOCATE_INFO = 6, + XR_TYPE_VIEW = 7, + XR_TYPE_SESSION_CREATE_INFO = 8, + XR_TYPE_SWAPCHAIN_CREATE_INFO = 9, + XR_TYPE_SESSION_BEGIN_INFO = 10, + XR_TYPE_VIEW_STATE = 11, + XR_TYPE_FRAME_END_INFO = 12, + XR_TYPE_HAPTIC_VIBRATION = 13, + XR_TYPE_EVENT_DATA_BUFFER = 16, + XR_TYPE_EVENT_DATA_INSTANCE_LOSS_PENDING = 17, + XR_TYPE_EVENT_DATA_SESSION_STATE_CHANGED = 18, + XR_TYPE_ACTION_STATE_BOOLEAN = 23, + XR_TYPE_ACTION_STATE_FLOAT = 24, + XR_TYPE_ACTION_STATE_VECTOR2F = 25, + XR_TYPE_ACTION_STATE_POSE = 27, + XR_TYPE_ACTION_SET_CREATE_INFO = 28, + XR_TYPE_ACTION_CREATE_INFO = 29, + XR_TYPE_INSTANCE_PROPERTIES = 32, + XR_TYPE_FRAME_WAIT_INFO = 33, + XR_TYPE_COMPOSITION_LAYER_PROJECTION = 35, + XR_TYPE_COMPOSITION_LAYER_QUAD = 36, + XR_TYPE_REFERENCE_SPACE_CREATE_INFO = 37, + XR_TYPE_ACTION_SPACE_CREATE_INFO = 38, + XR_TYPE_EVENT_DATA_REFERENCE_SPACE_CHANGE_PENDING = 40, + XR_TYPE_VIEW_CONFIGURATION_VIEW = 41, + XR_TYPE_SPACE_LOCATION = 42, + XR_TYPE_SPACE_VELOCITY = 43, + XR_TYPE_FRAME_STATE = 44, + XR_TYPE_VIEW_CONFIGURATION_PROPERTIES = 45, + XR_TYPE_FRAME_BEGIN_INFO = 46, + XR_TYPE_COMPOSITION_LAYER_PROJECTION_VIEW = 48, + XR_TYPE_EVENT_DATA_EVENTS_LOST = 49, + XR_TYPE_INTERACTION_PROFILE_SUGGESTED_BINDING = 51, + XR_TYPE_EVENT_DATA_INTERACTION_PROFILE_CHANGED = 52, + XR_TYPE_INTERACTION_PROFILE_STATE = 53, + XR_TYPE_SWAPCHAIN_IMAGE_ACQUIRE_INFO = 55, + XR_TYPE_SWAPCHAIN_IMAGE_WAIT_INFO = 56, + XR_TYPE_SWAPCHAIN_IMAGE_RELEASE_INFO = 57, + XR_TYPE_ACTION_STATE_GET_INFO = 58, + XR_TYPE_HAPTIC_ACTION_INFO = 59, + XR_TYPE_SESSION_ACTION_SETS_ATTACH_INFO = 60, + XR_TYPE_ACTIONS_SYNC_INFO = 61, + XR_TYPE_BOUND_SOURCES_FOR_ACTION_ENUMERATE_INFO = 62, + XR_TYPE_INPUT_SOURCE_LOCALIZED_NAME_GET_INFO = 63, + XR_TYPE_COMPOSITION_LAYER_CUBE_KHR = 1000006000, + XR_TYPE_INSTANCE_CREATE_INFO_ANDROID_KHR = 1000008000, + XR_TYPE_COMPOSITION_LAYER_DEPTH_INFO_KHR = 1000010000, + XR_TYPE_VULKAN_SWAPCHAIN_FORMAT_LIST_CREATE_INFO_KHR = 1000014000, + XR_TYPE_EVENT_DATA_PERF_SETTINGS_EXT = 1000015000, + XR_TYPE_COMPOSITION_LAYER_CYLINDER_KHR = 1000017000, + XR_TYPE_COMPOSITION_LAYER_EQUIRECT_KHR = 1000018000, + XR_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT = 1000019000, + XR_TYPE_DEBUG_UTILS_MESSENGER_CALLBACK_DATA_EXT = 1000019001, + XR_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT = 1000019002, + XR_TYPE_DEBUG_UTILS_LABEL_EXT = 1000019003, + XR_TYPE_GRAPHICS_BINDING_OPENGL_WIN32_KHR = 1000023000, + XR_TYPE_GRAPHICS_BINDING_OPENGL_XLIB_KHR = 1000023001, + XR_TYPE_GRAPHICS_BINDING_OPENGL_XCB_KHR = 1000023002, + XR_TYPE_GRAPHICS_BINDING_OPENGL_WAYLAND_KHR = 1000023003, + XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_KHR = 1000023004, + XR_TYPE_GRAPHICS_REQUIREMENTS_OPENGL_KHR = 1000023005, + XR_TYPE_GRAPHICS_BINDING_OPENGL_ES_ANDROID_KHR = 1000024001, + XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_ES_KHR = 1000024002, + XR_TYPE_GRAPHICS_REQUIREMENTS_OPENGL_ES_KHR = 1000024003, + XR_TYPE_GRAPHICS_BINDING_VULKAN_KHR = 1000025000, + XR_TYPE_SWAPCHAIN_IMAGE_VULKAN_KHR = 1000025001, + XR_TYPE_GRAPHICS_REQUIREMENTS_VULKAN_KHR = 1000025002, + XR_TYPE_GRAPHICS_BINDING_D3D11_KHR = 1000027000, + XR_TYPE_SWAPCHAIN_IMAGE_D3D11_KHR = 1000027001, + XR_TYPE_GRAPHICS_REQUIREMENTS_D3D11_KHR = 1000027002, + XR_TYPE_GRAPHICS_BINDING_D3D12_KHR = 1000028000, + XR_TYPE_SWAPCHAIN_IMAGE_D3D12_KHR = 1000028001, + XR_TYPE_GRAPHICS_REQUIREMENTS_D3D12_KHR = 1000028002, + XR_TYPE_SYSTEM_EYE_GAZE_INTERACTION_PROPERTIES_EXT = 1000030000, + XR_TYPE_EYE_GAZE_SAMPLE_TIME_EXT = 1000030001, + XR_TYPE_VISIBILITY_MASK_KHR = 1000031000, + XR_TYPE_EVENT_DATA_VISIBILITY_MASK_CHANGED_KHR = 1000031001, + XR_TYPE_SESSION_CREATE_INFO_OVERLAY_EXTX = 1000033000, + XR_TYPE_EVENT_DATA_MAIN_SESSION_VISIBILITY_CHANGED_EXTX = 1000033003, + XR_TYPE_COMPOSITION_LAYER_COLOR_SCALE_BIAS_KHR = 1000034000, + XR_TYPE_SPATIAL_ANCHOR_CREATE_INFO_MSFT = 1000039000, + XR_TYPE_SPATIAL_ANCHOR_SPACE_CREATE_INFO_MSFT = 1000039001, + XR_TYPE_COMPOSITION_LAYER_IMAGE_LAYOUT_FB = 1000040000, + XR_TYPE_COMPOSITION_LAYER_ALPHA_BLEND_FB = 1000041001, + XR_TYPE_VIEW_CONFIGURATION_DEPTH_RANGE_EXT = 1000046000, + XR_TYPE_GRAPHICS_BINDING_EGL_MNDX = 1000048004, + XR_TYPE_SPATIAL_GRAPH_NODE_SPACE_CREATE_INFO_MSFT = 1000049000, + XR_TYPE_SPATIAL_GRAPH_STATIC_NODE_BINDING_CREATE_INFO_MSFT = 1000049001, + XR_TYPE_SPATIAL_GRAPH_NODE_BINDING_PROPERTIES_GET_INFO_MSFT = 1000049002, + XR_TYPE_SPATIAL_GRAPH_NODE_BINDING_PROPERTIES_MSFT = 1000049003, + XR_TYPE_SYSTEM_HAND_TRACKING_PROPERTIES_EXT = 1000051000, + XR_TYPE_HAND_TRACKER_CREATE_INFO_EXT = 1000051001, + XR_TYPE_HAND_JOINTS_LOCATE_INFO_EXT = 1000051002, + XR_TYPE_HAND_JOINT_LOCATIONS_EXT = 1000051003, + XR_TYPE_HAND_JOINT_VELOCITIES_EXT = 1000051004, + XR_TYPE_SYSTEM_HAND_TRACKING_MESH_PROPERTIES_MSFT = 1000052000, + XR_TYPE_HAND_MESH_SPACE_CREATE_INFO_MSFT = 1000052001, + XR_TYPE_HAND_MESH_UPDATE_INFO_MSFT = 1000052002, + XR_TYPE_HAND_MESH_MSFT = 1000052003, + XR_TYPE_HAND_POSE_TYPE_INFO_MSFT = 1000052004, + XR_TYPE_SECONDARY_VIEW_CONFIGURATION_SESSION_BEGIN_INFO_MSFT = 1000053000, + XR_TYPE_SECONDARY_VIEW_CONFIGURATION_STATE_MSFT = 1000053001, + XR_TYPE_SECONDARY_VIEW_CONFIGURATION_FRAME_STATE_MSFT = 1000053002, + XR_TYPE_SECONDARY_VIEW_CONFIGURATION_FRAME_END_INFO_MSFT = 1000053003, + XR_TYPE_SECONDARY_VIEW_CONFIGURATION_LAYER_INFO_MSFT = 1000053004, + XR_TYPE_SECONDARY_VIEW_CONFIGURATION_SWAPCHAIN_CREATE_INFO_MSFT = 1000053005, + XR_TYPE_CONTROLLER_MODEL_KEY_STATE_MSFT = 1000055000, + XR_TYPE_CONTROLLER_MODEL_NODE_PROPERTIES_MSFT = 1000055001, + XR_TYPE_CONTROLLER_MODEL_PROPERTIES_MSFT = 1000055002, + XR_TYPE_CONTROLLER_MODEL_NODE_STATE_MSFT = 1000055003, + XR_TYPE_CONTROLLER_MODEL_STATE_MSFT = 1000055004, + XR_TYPE_VIEW_CONFIGURATION_VIEW_FOV_EPIC = 1000059000, + XR_TYPE_HOLOGRAPHIC_WINDOW_ATTACHMENT_MSFT = 1000063000, + XR_TYPE_COMPOSITION_LAYER_REPROJECTION_INFO_MSFT = 1000066000, + XR_TYPE_COMPOSITION_LAYER_REPROJECTION_PLANE_OVERRIDE_MSFT = 1000066001, + XR_TYPE_ANDROID_SURFACE_SWAPCHAIN_CREATE_INFO_FB = 1000070000, + XR_TYPE_COMPOSITION_LAYER_SECURE_CONTENT_FB = 1000072000, + XR_TYPE_INTERACTION_PROFILE_DPAD_BINDING_EXT = 1000078000, + XR_TYPE_INTERACTION_PROFILE_ANALOG_THRESHOLD_VALVE = 1000079000, + XR_TYPE_HAND_JOINTS_MOTION_RANGE_INFO_EXT = 1000080000, + XR_TYPE_LOADER_INIT_INFO_ANDROID_KHR = 1000089000, + XR_TYPE_VULKAN_INSTANCE_CREATE_INFO_KHR = 1000090000, + XR_TYPE_VULKAN_DEVICE_CREATE_INFO_KHR = 1000090001, + XR_TYPE_VULKAN_GRAPHICS_DEVICE_GET_INFO_KHR = 1000090003, + XR_TYPE_COMPOSITION_LAYER_EQUIRECT2_KHR = 1000091000, + XR_TYPE_SCENE_OBSERVER_CREATE_INFO_MSFT = 1000097000, + XR_TYPE_SCENE_CREATE_INFO_MSFT = 1000097001, + XR_TYPE_NEW_SCENE_COMPUTE_INFO_MSFT = 1000097002, + XR_TYPE_VISUAL_MESH_COMPUTE_LOD_INFO_MSFT = 1000097003, + XR_TYPE_SCENE_COMPONENTS_MSFT = 1000097004, + XR_TYPE_SCENE_COMPONENTS_GET_INFO_MSFT = 1000097005, + XR_TYPE_SCENE_COMPONENT_LOCATIONS_MSFT = 1000097006, + XR_TYPE_SCENE_COMPONENTS_LOCATE_INFO_MSFT = 1000097007, + XR_TYPE_SCENE_OBJECTS_MSFT = 1000097008, + XR_TYPE_SCENE_COMPONENT_PARENT_FILTER_INFO_MSFT = 1000097009, + XR_TYPE_SCENE_OBJECT_TYPES_FILTER_INFO_MSFT = 1000097010, + XR_TYPE_SCENE_PLANES_MSFT = 1000097011, + XR_TYPE_SCENE_PLANE_ALIGNMENT_FILTER_INFO_MSFT = 1000097012, + XR_TYPE_SCENE_MESHES_MSFT = 1000097013, + XR_TYPE_SCENE_MESH_BUFFERS_GET_INFO_MSFT = 1000097014, + XR_TYPE_SCENE_MESH_BUFFERS_MSFT = 1000097015, + XR_TYPE_SCENE_MESH_VERTEX_BUFFER_MSFT = 1000097016, + XR_TYPE_SCENE_MESH_INDICES_UINT32_MSFT = 1000097017, + XR_TYPE_SCENE_MESH_INDICES_UINT16_MSFT = 1000097018, + XR_TYPE_SERIALIZED_SCENE_FRAGMENT_DATA_GET_INFO_MSFT = 1000098000, + XR_TYPE_SCENE_DESERIALIZE_INFO_MSFT = 1000098001, + XR_TYPE_EVENT_DATA_DISPLAY_REFRESH_RATE_CHANGED_FB = 1000101000, + XR_TYPE_VIVE_TRACKER_PATHS_HTCX = 1000103000, + XR_TYPE_EVENT_DATA_VIVE_TRACKER_CONNECTED_HTCX = 1000103001, + XR_TYPE_SYSTEM_FACIAL_TRACKING_PROPERTIES_HTC = 1000104000, + XR_TYPE_FACIAL_TRACKER_CREATE_INFO_HTC = 1000104001, + XR_TYPE_FACIAL_EXPRESSIONS_HTC = 1000104002, + XR_TYPE_SYSTEM_COLOR_SPACE_PROPERTIES_FB = 1000108000, + XR_TYPE_HAND_TRACKING_MESH_FB = 1000110001, + XR_TYPE_HAND_TRACKING_SCALE_FB = 1000110003, + XR_TYPE_HAND_TRACKING_AIM_STATE_FB = 1000111001, + XR_TYPE_HAND_TRACKING_CAPSULES_STATE_FB = 1000112000, + XR_TYPE_SYSTEM_SPATIAL_ENTITY_PROPERTIES_FB = 1000113004, + XR_TYPE_SPATIAL_ANCHOR_CREATE_INFO_FB = 1000113003, + XR_TYPE_SPACE_COMPONENT_STATUS_SET_INFO_FB = 1000113007, + XR_TYPE_SPACE_COMPONENT_STATUS_FB = 1000113001, + XR_TYPE_EVENT_DATA_SPATIAL_ANCHOR_CREATE_COMPLETE_FB = 1000113005, + XR_TYPE_EVENT_DATA_SPACE_SET_STATUS_COMPLETE_FB = 1000113006, + XR_TYPE_FOVEATION_PROFILE_CREATE_INFO_FB = 1000114000, + XR_TYPE_SWAPCHAIN_CREATE_INFO_FOVEATION_FB = 1000114001, + XR_TYPE_SWAPCHAIN_STATE_FOVEATION_FB = 1000114002, + XR_TYPE_FOVEATION_LEVEL_PROFILE_CREATE_INFO_FB = 1000115000, + XR_TYPE_KEYBOARD_SPACE_CREATE_INFO_FB = 1000116009, + XR_TYPE_KEYBOARD_TRACKING_QUERY_FB = 1000116004, + XR_TYPE_SYSTEM_KEYBOARD_TRACKING_PROPERTIES_FB = 1000116002, + XR_TYPE_TRIANGLE_MESH_CREATE_INFO_FB = 1000117001, + XR_TYPE_SYSTEM_PASSTHROUGH_PROPERTIES_FB = 1000118000, + XR_TYPE_PASSTHROUGH_CREATE_INFO_FB = 1000118001, + XR_TYPE_PASSTHROUGH_LAYER_CREATE_INFO_FB = 1000118002, + XR_TYPE_COMPOSITION_LAYER_PASSTHROUGH_FB = 1000118003, + XR_TYPE_GEOMETRY_INSTANCE_CREATE_INFO_FB = 1000118004, + XR_TYPE_GEOMETRY_INSTANCE_TRANSFORM_FB = 1000118005, + XR_TYPE_SYSTEM_PASSTHROUGH_PROPERTIES2_FB = 1000118006, + XR_TYPE_PASSTHROUGH_STYLE_FB = 1000118020, + XR_TYPE_PASSTHROUGH_COLOR_MAP_MONO_TO_RGBA_FB = 1000118021, + XR_TYPE_PASSTHROUGH_COLOR_MAP_MONO_TO_MONO_FB = 1000118022, + XR_TYPE_PASSTHROUGH_BRIGHTNESS_CONTRAST_SATURATION_FB = 1000118023, + XR_TYPE_EVENT_DATA_PASSTHROUGH_STATE_CHANGED_FB = 1000118030, + XR_TYPE_RENDER_MODEL_PATH_INFO_FB = 1000119000, + XR_TYPE_RENDER_MODEL_PROPERTIES_FB = 1000119001, + XR_TYPE_RENDER_MODEL_BUFFER_FB = 1000119002, + XR_TYPE_RENDER_MODEL_LOAD_INFO_FB = 1000119003, + XR_TYPE_SYSTEM_RENDER_MODEL_PROPERTIES_FB = 1000119004, + XR_TYPE_RENDER_MODEL_CAPABILITIES_REQUEST_FB = 1000119005, + XR_TYPE_BINDING_MODIFICATIONS_KHR = 1000120000, + XR_TYPE_VIEW_LOCATE_FOVEATED_RENDERING_VARJO = 1000121000, + XR_TYPE_FOVEATED_VIEW_CONFIGURATION_VIEW_VARJO = 1000121001, + XR_TYPE_SYSTEM_FOVEATED_RENDERING_PROPERTIES_VARJO = 1000121002, + XR_TYPE_COMPOSITION_LAYER_DEPTH_TEST_VARJO = 1000122000, + XR_TYPE_SYSTEM_MARKER_TRACKING_PROPERTIES_VARJO = 1000124000, + XR_TYPE_EVENT_DATA_MARKER_TRACKING_UPDATE_VARJO = 1000124001, + XR_TYPE_MARKER_SPACE_CREATE_INFO_VARJO = 1000124002, + XR_TYPE_SPATIAL_ANCHOR_PERSISTENCE_INFO_MSFT = 1000142000, + XR_TYPE_SPATIAL_ANCHOR_FROM_PERSISTED_ANCHOR_CREATE_INFO_MSFT = 1000142001, + XR_TYPE_SPACE_QUERY_INFO_FB = 1000156001, + XR_TYPE_SPACE_QUERY_RESULTS_FB = 1000156002, + XR_TYPE_SPACE_STORAGE_LOCATION_FILTER_INFO_FB = 1000156003, + XR_TYPE_SPACE_UUID_FILTER_INFO_FB = 1000156054, + XR_TYPE_SPACE_COMPONENT_FILTER_INFO_FB = 1000156052, + XR_TYPE_EVENT_DATA_SPACE_QUERY_RESULTS_AVAILABLE_FB = 1000156103, + XR_TYPE_EVENT_DATA_SPACE_QUERY_COMPLETE_FB = 1000156104, + XR_TYPE_SPACE_SAVE_INFO_FB = 1000158000, + XR_TYPE_SPACE_ERASE_INFO_FB = 1000158001, + XR_TYPE_EVENT_DATA_SPACE_SAVE_COMPLETE_FB = 1000158106, + XR_TYPE_EVENT_DATA_SPACE_ERASE_COMPLETE_FB = 1000158107, + XR_TYPE_SWAPCHAIN_IMAGE_FOVEATION_VULKAN_FB = 1000160000, + XR_TYPE_SWAPCHAIN_STATE_ANDROID_SURFACE_DIMENSIONS_FB = 1000161000, + XR_TYPE_SWAPCHAIN_STATE_SAMPLER_OPENGL_ES_FB = 1000162000, + XR_TYPE_SWAPCHAIN_STATE_SAMPLER_VULKAN_FB = 1000163000, + XR_TYPE_COMPOSITION_LAYER_SPACE_WARP_INFO_FB = 1000171000, + XR_TYPE_SYSTEM_SPACE_WARP_PROPERTIES_FB = 1000171001, + XR_TYPE_SEMANTIC_LABELS_FB = 1000175000, + XR_TYPE_ROOM_LAYOUT_FB = 1000175001, + XR_TYPE_BOUNDARY_2D_FB = 1000175002, + XR_TYPE_DIGITAL_LENS_CONTROL_ALMALENCE = 1000196000, + XR_TYPE_SPACE_CONTAINER_FB = 1000199000, + XR_TYPE_PASSTHROUGH_KEYBOARD_HANDS_INTENSITY_FB = 1000203002, + XR_TYPE_COMPOSITION_LAYER_SETTINGS_FB = 1000204000, + XR_TYPE_VULKAN_SWAPCHAIN_CREATE_INFO_META = 1000227000, + XR_TYPE_PERFORMANCE_METRICS_STATE_META = 1000232001, + XR_TYPE_PERFORMANCE_METRICS_COUNTER_META = 1000232002, + XR_TYPE_GRAPHICS_BINDING_VULKAN2_KHR = XR_TYPE_GRAPHICS_BINDING_VULKAN_KHR, + XR_TYPE_SWAPCHAIN_IMAGE_VULKAN2_KHR = XR_TYPE_SWAPCHAIN_IMAGE_VULKAN_KHR, + XR_TYPE_GRAPHICS_REQUIREMENTS_VULKAN2_KHR = XR_TYPE_GRAPHICS_REQUIREMENTS_VULKAN_KHR, + XR_STRUCTURE_TYPE_MAX_ENUM = 0x7FFFFFFF +} XrStructureType; + +typedef enum XrFormFactor { + XR_FORM_FACTOR_HEAD_MOUNTED_DISPLAY = 1, + XR_FORM_FACTOR_HANDHELD_DISPLAY = 2, + XR_FORM_FACTOR_MAX_ENUM = 0x7FFFFFFF +} XrFormFactor; + +typedef enum XrViewConfigurationType { + XR_VIEW_CONFIGURATION_TYPE_PRIMARY_MONO = 1, + XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO = 2, + XR_VIEW_CONFIGURATION_TYPE_PRIMARY_QUAD_VARJO = 1000037000, + XR_VIEW_CONFIGURATION_TYPE_SECONDARY_MONO_FIRST_PERSON_OBSERVER_MSFT = 1000054000, + XR_VIEW_CONFIGURATION_TYPE_MAX_ENUM = 0x7FFFFFFF +} XrViewConfigurationType; + +typedef enum XrEnvironmentBlendMode { + XR_ENVIRONMENT_BLEND_MODE_OPAQUE = 1, + XR_ENVIRONMENT_BLEND_MODE_ADDITIVE = 2, + XR_ENVIRONMENT_BLEND_MODE_ALPHA_BLEND = 3, + XR_ENVIRONMENT_BLEND_MODE_MAX_ENUM = 0x7FFFFFFF +} XrEnvironmentBlendMode; + +typedef enum XrReferenceSpaceType { + XR_REFERENCE_SPACE_TYPE_VIEW = 1, + XR_REFERENCE_SPACE_TYPE_LOCAL = 2, + XR_REFERENCE_SPACE_TYPE_STAGE = 3, + XR_REFERENCE_SPACE_TYPE_UNBOUNDED_MSFT = 1000038000, + XR_REFERENCE_SPACE_TYPE_COMBINED_EYE_VARJO = 1000121000, + XR_REFERENCE_SPACE_TYPE_MAX_ENUM = 0x7FFFFFFF +} XrReferenceSpaceType; + +typedef enum XrActionType { + XR_ACTION_TYPE_BOOLEAN_INPUT = 1, + XR_ACTION_TYPE_FLOAT_INPUT = 2, + XR_ACTION_TYPE_VECTOR2F_INPUT = 3, + XR_ACTION_TYPE_POSE_INPUT = 4, + XR_ACTION_TYPE_VIBRATION_OUTPUT = 100, + XR_ACTION_TYPE_MAX_ENUM = 0x7FFFFFFF +} XrActionType; + +typedef enum XrEyeVisibility { + XR_EYE_VISIBILITY_BOTH = 0, + XR_EYE_VISIBILITY_LEFT = 1, + XR_EYE_VISIBILITY_RIGHT = 2, + XR_EYE_VISIBILITY_MAX_ENUM = 0x7FFFFFFF +} XrEyeVisibility; + +typedef enum XrSessionState { + XR_SESSION_STATE_UNKNOWN = 0, + XR_SESSION_STATE_IDLE = 1, + XR_SESSION_STATE_READY = 2, + XR_SESSION_STATE_SYNCHRONIZED = 3, + XR_SESSION_STATE_VISIBLE = 4, + XR_SESSION_STATE_FOCUSED = 5, + XR_SESSION_STATE_STOPPING = 6, + XR_SESSION_STATE_LOSS_PENDING = 7, + XR_SESSION_STATE_EXITING = 8, + XR_SESSION_STATE_MAX_ENUM = 0x7FFFFFFF +} XrSessionState; + +typedef enum XrObjectType { + XR_OBJECT_TYPE_UNKNOWN = 0, + XR_OBJECT_TYPE_INSTANCE = 1, + XR_OBJECT_TYPE_SESSION = 2, + XR_OBJECT_TYPE_SWAPCHAIN = 3, + XR_OBJECT_TYPE_SPACE = 4, + XR_OBJECT_TYPE_ACTION_SET = 5, + XR_OBJECT_TYPE_ACTION = 6, + XR_OBJECT_TYPE_DEBUG_UTILS_MESSENGER_EXT = 1000019000, + XR_OBJECT_TYPE_SPATIAL_ANCHOR_MSFT = 1000039000, + XR_OBJECT_TYPE_SPATIAL_GRAPH_NODE_BINDING_MSFT = 1000049000, + XR_OBJECT_TYPE_HAND_TRACKER_EXT = 1000051000, + XR_OBJECT_TYPE_SCENE_OBSERVER_MSFT = 1000097000, + XR_OBJECT_TYPE_SCENE_MSFT = 1000097001, + XR_OBJECT_TYPE_FACIAL_TRACKER_HTC = 1000104000, + XR_OBJECT_TYPE_FOVEATION_PROFILE_FB = 1000114000, + XR_OBJECT_TYPE_TRIANGLE_MESH_FB = 1000117000, + XR_OBJECT_TYPE_PASSTHROUGH_FB = 1000118000, + XR_OBJECT_TYPE_PASSTHROUGH_LAYER_FB = 1000118002, + XR_OBJECT_TYPE_GEOMETRY_INSTANCE_FB = 1000118004, + XR_OBJECT_TYPE_SPATIAL_ANCHOR_STORE_CONNECTION_MSFT = 1000142000, + XR_OBJECT_TYPE_MAX_ENUM = 0x7FFFFFFF +} XrObjectType; +typedef XrFlags64 XrInstanceCreateFlags; + +// Flag bits for XrInstanceCreateFlags + +typedef XrFlags64 XrSessionCreateFlags; + +// Flag bits for XrSessionCreateFlags + +typedef XrFlags64 XrSpaceVelocityFlags; + +// Flag bits for XrSpaceVelocityFlags +static const XrSpaceVelocityFlags XR_SPACE_VELOCITY_LINEAR_VALID_BIT = 0x00000001; +static const XrSpaceVelocityFlags XR_SPACE_VELOCITY_ANGULAR_VALID_BIT = 0x00000002; + +typedef XrFlags64 XrSpaceLocationFlags; + +// Flag bits for XrSpaceLocationFlags +static const XrSpaceLocationFlags XR_SPACE_LOCATION_ORIENTATION_VALID_BIT = 0x00000001; +static const XrSpaceLocationFlags XR_SPACE_LOCATION_POSITION_VALID_BIT = 0x00000002; +static const XrSpaceLocationFlags XR_SPACE_LOCATION_ORIENTATION_TRACKED_BIT = 0x00000004; +static const XrSpaceLocationFlags XR_SPACE_LOCATION_POSITION_TRACKED_BIT = 0x00000008; + +typedef XrFlags64 XrSwapchainCreateFlags; + +// Flag bits for XrSwapchainCreateFlags +static const XrSwapchainCreateFlags XR_SWAPCHAIN_CREATE_PROTECTED_CONTENT_BIT = 0x00000001; +static const XrSwapchainCreateFlags XR_SWAPCHAIN_CREATE_STATIC_IMAGE_BIT = 0x00000002; + +typedef XrFlags64 XrSwapchainUsageFlags; + +// Flag bits for XrSwapchainUsageFlags +static const XrSwapchainUsageFlags XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT = 0x00000001; +static const XrSwapchainUsageFlags XR_SWAPCHAIN_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT = 0x00000002; +static const XrSwapchainUsageFlags XR_SWAPCHAIN_USAGE_UNORDERED_ACCESS_BIT = 0x00000004; +static const XrSwapchainUsageFlags XR_SWAPCHAIN_USAGE_TRANSFER_SRC_BIT = 0x00000008; +static const XrSwapchainUsageFlags XR_SWAPCHAIN_USAGE_TRANSFER_DST_BIT = 0x00000010; +static const XrSwapchainUsageFlags XR_SWAPCHAIN_USAGE_SAMPLED_BIT = 0x00000020; +static const XrSwapchainUsageFlags XR_SWAPCHAIN_USAGE_MUTABLE_FORMAT_BIT = 0x00000040; +static const XrSwapchainUsageFlags XR_SWAPCHAIN_USAGE_INPUT_ATTACHMENT_BIT_MND = 0x00000080; +static const XrSwapchainUsageFlags XR_SWAPCHAIN_USAGE_INPUT_ATTACHMENT_BIT_KHR = 0x00000080; // alias of XR_SWAPCHAIN_USAGE_INPUT_ATTACHMENT_BIT_MND + +typedef XrFlags64 XrCompositionLayerFlags; + +// Flag bits for XrCompositionLayerFlags +static const XrCompositionLayerFlags XR_COMPOSITION_LAYER_CORRECT_CHROMATIC_ABERRATION_BIT = 0x00000001; +static const XrCompositionLayerFlags XR_COMPOSITION_LAYER_BLEND_TEXTURE_SOURCE_ALPHA_BIT = 0x00000002; +static const XrCompositionLayerFlags XR_COMPOSITION_LAYER_UNPREMULTIPLIED_ALPHA_BIT = 0x00000004; + +typedef XrFlags64 XrViewStateFlags; + +// Flag bits for XrViewStateFlags +static const XrViewStateFlags XR_VIEW_STATE_ORIENTATION_VALID_BIT = 0x00000001; +static const XrViewStateFlags XR_VIEW_STATE_POSITION_VALID_BIT = 0x00000002; +static const XrViewStateFlags XR_VIEW_STATE_ORIENTATION_TRACKED_BIT = 0x00000004; +static const XrViewStateFlags XR_VIEW_STATE_POSITION_TRACKED_BIT = 0x00000008; + +typedef XrFlags64 XrInputSourceLocalizedNameFlags; + +// Flag bits for XrInputSourceLocalizedNameFlags +static const XrInputSourceLocalizedNameFlags XR_INPUT_SOURCE_LOCALIZED_NAME_USER_PATH_BIT = 0x00000001; +static const XrInputSourceLocalizedNameFlags XR_INPUT_SOURCE_LOCALIZED_NAME_INTERACTION_PROFILE_BIT = 0x00000002; +static const XrInputSourceLocalizedNameFlags XR_INPUT_SOURCE_LOCALIZED_NAME_COMPONENT_BIT = 0x00000004; + +typedef void (XRAPI_PTR *PFN_xrVoidFunction)(void); +typedef struct XrApiLayerProperties { + XrStructureType type; + void* XR_MAY_ALIAS next; + char layerName[XR_MAX_API_LAYER_NAME_SIZE]; + XrVersion specVersion; + uint32_t layerVersion; + char description[XR_MAX_API_LAYER_DESCRIPTION_SIZE]; +} XrApiLayerProperties; + +typedef struct XrExtensionProperties { + XrStructureType type; + void* XR_MAY_ALIAS next; + char extensionName[XR_MAX_EXTENSION_NAME_SIZE]; + uint32_t extensionVersion; +} XrExtensionProperties; + +typedef struct XrApplicationInfo { + char applicationName[XR_MAX_APPLICATION_NAME_SIZE]; + uint32_t applicationVersion; + char engineName[XR_MAX_ENGINE_NAME_SIZE]; + uint32_t engineVersion; + XrVersion apiVersion; +} XrApplicationInfo; + +typedef struct XrInstanceCreateInfo { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrInstanceCreateFlags createFlags; + XrApplicationInfo applicationInfo; + uint32_t enabledApiLayerCount; + const char* const* enabledApiLayerNames; + uint32_t enabledExtensionCount; + const char* const* enabledExtensionNames; +} XrInstanceCreateInfo; + +typedef struct XrInstanceProperties { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrVersion runtimeVersion; + char runtimeName[XR_MAX_RUNTIME_NAME_SIZE]; +} XrInstanceProperties; + +typedef struct XrEventDataBuffer { + XrStructureType type; + const void* XR_MAY_ALIAS next; + uint8_t varying[4000]; +} XrEventDataBuffer; + +typedef struct XrSystemGetInfo { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrFormFactor formFactor; +} XrSystemGetInfo; + +typedef struct XrSystemGraphicsProperties { + uint32_t maxSwapchainImageHeight; + uint32_t maxSwapchainImageWidth; + uint32_t maxLayerCount; +} XrSystemGraphicsProperties; + +typedef struct XrSystemTrackingProperties { + XrBool32 orientationTracking; + XrBool32 positionTracking; +} XrSystemTrackingProperties; + +typedef struct XrSystemProperties { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrSystemId systemId; + uint32_t vendorId; + char systemName[XR_MAX_SYSTEM_NAME_SIZE]; + XrSystemGraphicsProperties graphicsProperties; + XrSystemTrackingProperties trackingProperties; +} XrSystemProperties; + +typedef struct XrSessionCreateInfo { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSessionCreateFlags createFlags; + XrSystemId systemId; +} XrSessionCreateInfo; + +typedef struct XrVector3f { + float x; + float y; + float z; +} XrVector3f; + +// XrSpaceVelocity extends XrSpaceLocation +typedef struct XrSpaceVelocity { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrSpaceVelocityFlags velocityFlags; + XrVector3f linearVelocity; + XrVector3f angularVelocity; +} XrSpaceVelocity; + +typedef struct XrQuaternionf { + float x; + float y; + float z; + float w; +} XrQuaternionf; + +typedef struct XrPosef { + XrQuaternionf orientation; + XrVector3f position; +} XrPosef; + +typedef struct XrReferenceSpaceCreateInfo { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrReferenceSpaceType referenceSpaceType; + XrPosef poseInReferenceSpace; +} XrReferenceSpaceCreateInfo; + +typedef struct XrExtent2Df { + float width; + float height; +} XrExtent2Df; + +typedef struct XrActionSpaceCreateInfo { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrAction action; + XrPath subactionPath; + XrPosef poseInActionSpace; +} XrActionSpaceCreateInfo; + +typedef struct XrSpaceLocation { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrSpaceLocationFlags locationFlags; + XrPosef pose; +} XrSpaceLocation; + +typedef struct XrViewConfigurationProperties { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrViewConfigurationType viewConfigurationType; + XrBool32 fovMutable; +} XrViewConfigurationProperties; + +typedef struct XrViewConfigurationView { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint32_t recommendedImageRectWidth; + uint32_t maxImageRectWidth; + uint32_t recommendedImageRectHeight; + uint32_t maxImageRectHeight; + uint32_t recommendedSwapchainSampleCount; + uint32_t maxSwapchainSampleCount; +} XrViewConfigurationView; + +typedef struct XrSwapchainCreateInfo { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSwapchainCreateFlags createFlags; + XrSwapchainUsageFlags usageFlags; + int64_t format; + uint32_t sampleCount; + uint32_t width; + uint32_t height; + uint32_t faceCount; + uint32_t arraySize; + uint32_t mipCount; +} XrSwapchainCreateInfo; + +typedef struct XR_MAY_ALIAS XrSwapchainImageBaseHeader { + XrStructureType type; + void* XR_MAY_ALIAS next; +} XrSwapchainImageBaseHeader; + +typedef struct XrSwapchainImageAcquireInfo { + XrStructureType type; + const void* XR_MAY_ALIAS next; +} XrSwapchainImageAcquireInfo; + +typedef struct XrSwapchainImageWaitInfo { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrDuration timeout; +} XrSwapchainImageWaitInfo; + +typedef struct XrSwapchainImageReleaseInfo { + XrStructureType type; + const void* XR_MAY_ALIAS next; +} XrSwapchainImageReleaseInfo; + +typedef struct XrSessionBeginInfo { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrViewConfigurationType primaryViewConfigurationType; +} XrSessionBeginInfo; + +typedef struct XrFrameWaitInfo { + XrStructureType type; + const void* XR_MAY_ALIAS next; +} XrFrameWaitInfo; + +typedef struct XrFrameState { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrTime predictedDisplayTime; + XrDuration predictedDisplayPeriod; + XrBool32 shouldRender; +} XrFrameState; + +typedef struct XrFrameBeginInfo { + XrStructureType type; + const void* XR_MAY_ALIAS next; +} XrFrameBeginInfo; + +typedef struct XR_MAY_ALIAS XrCompositionLayerBaseHeader { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrCompositionLayerFlags layerFlags; + XrSpace space; +} XrCompositionLayerBaseHeader; + +typedef struct XrFrameEndInfo { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrTime displayTime; + XrEnvironmentBlendMode environmentBlendMode; + uint32_t layerCount; + const XrCompositionLayerBaseHeader* const* layers; +} XrFrameEndInfo; + +typedef struct XrViewLocateInfo { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrViewConfigurationType viewConfigurationType; + XrTime displayTime; + XrSpace space; +} XrViewLocateInfo; + +typedef struct XrViewState { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrViewStateFlags viewStateFlags; +} XrViewState; + +typedef struct XrFovf { + float angleLeft; + float angleRight; + float angleUp; + float angleDown; +} XrFovf; + +typedef struct XrView { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrPosef pose; + XrFovf fov; +} XrView; + +typedef struct XrActionSetCreateInfo { + XrStructureType type; + const void* XR_MAY_ALIAS next; + char actionSetName[XR_MAX_ACTION_SET_NAME_SIZE]; + char localizedActionSetName[XR_MAX_LOCALIZED_ACTION_SET_NAME_SIZE]; + uint32_t priority; +} XrActionSetCreateInfo; + +typedef struct XrActionCreateInfo { + XrStructureType type; + const void* XR_MAY_ALIAS next; + char actionName[XR_MAX_ACTION_NAME_SIZE]; + XrActionType actionType; + uint32_t countSubactionPaths; + const XrPath* subactionPaths; + char localizedActionName[XR_MAX_LOCALIZED_ACTION_NAME_SIZE]; +} XrActionCreateInfo; + +typedef struct XrActionSuggestedBinding { + XrAction action; + XrPath binding; +} XrActionSuggestedBinding; + +typedef struct XrInteractionProfileSuggestedBinding { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrPath interactionProfile; + uint32_t countSuggestedBindings; + const XrActionSuggestedBinding* suggestedBindings; +} XrInteractionProfileSuggestedBinding; + +typedef struct XrSessionActionSetsAttachInfo { + XrStructureType type; + const void* XR_MAY_ALIAS next; + uint32_t countActionSets; + const XrActionSet* actionSets; +} XrSessionActionSetsAttachInfo; + +typedef struct XrInteractionProfileState { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrPath interactionProfile; +} XrInteractionProfileState; + +typedef struct XrActionStateGetInfo { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrAction action; + XrPath subactionPath; +} XrActionStateGetInfo; + +typedef struct XrActionStateBoolean { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrBool32 currentState; + XrBool32 changedSinceLastSync; + XrTime lastChangeTime; + XrBool32 isActive; +} XrActionStateBoolean; + +typedef struct XrActionStateFloat { + XrStructureType type; + void* XR_MAY_ALIAS next; + float currentState; + XrBool32 changedSinceLastSync; + XrTime lastChangeTime; + XrBool32 isActive; +} XrActionStateFloat; + +typedef struct XrVector2f { + float x; + float y; +} XrVector2f; + +typedef struct XrActionStateVector2f { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrVector2f currentState; + XrBool32 changedSinceLastSync; + XrTime lastChangeTime; + XrBool32 isActive; +} XrActionStateVector2f; + +typedef struct XrActionStatePose { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrBool32 isActive; +} XrActionStatePose; + +typedef struct XrActiveActionSet { + XrActionSet actionSet; + XrPath subactionPath; +} XrActiveActionSet; + +typedef struct XrActionsSyncInfo { + XrStructureType type; + const void* XR_MAY_ALIAS next; + uint32_t countActiveActionSets; + const XrActiveActionSet* activeActionSets; +} XrActionsSyncInfo; + +typedef struct XrBoundSourcesForActionEnumerateInfo { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrAction action; +} XrBoundSourcesForActionEnumerateInfo; + +typedef struct XrInputSourceLocalizedNameGetInfo { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrPath sourcePath; + XrInputSourceLocalizedNameFlags whichComponents; +} XrInputSourceLocalizedNameGetInfo; + +typedef struct XrHapticActionInfo { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrAction action; + XrPath subactionPath; +} XrHapticActionInfo; + +typedef struct XR_MAY_ALIAS XrHapticBaseHeader { + XrStructureType type; + const void* XR_MAY_ALIAS next; +} XrHapticBaseHeader; + +typedef struct XR_MAY_ALIAS XrBaseInStructure { + XrStructureType type; + const struct XrBaseInStructure* next; +} XrBaseInStructure; + +typedef struct XR_MAY_ALIAS XrBaseOutStructure { + XrStructureType type; + struct XrBaseOutStructure* next; +} XrBaseOutStructure; + +typedef struct XrOffset2Di { + int32_t x; + int32_t y; +} XrOffset2Di; + +typedef struct XrExtent2Di { + int32_t width; + int32_t height; +} XrExtent2Di; + +typedef struct XrRect2Di { + XrOffset2Di offset; + XrExtent2Di extent; +} XrRect2Di; + +typedef struct XrSwapchainSubImage { + XrSwapchain swapchain; + XrRect2Di imageRect; + uint32_t imageArrayIndex; +} XrSwapchainSubImage; + +typedef struct XrCompositionLayerProjectionView { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrPosef pose; + XrFovf fov; + XrSwapchainSubImage subImage; +} XrCompositionLayerProjectionView; + +typedef struct XrCompositionLayerProjection { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrCompositionLayerFlags layerFlags; + XrSpace space; + uint32_t viewCount; + const XrCompositionLayerProjectionView* views; +} XrCompositionLayerProjection; + +typedef struct XrCompositionLayerQuad { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrCompositionLayerFlags layerFlags; + XrSpace space; + XrEyeVisibility eyeVisibility; + XrSwapchainSubImage subImage; + XrPosef pose; + XrExtent2Df size; +} XrCompositionLayerQuad; + +typedef struct XR_MAY_ALIAS XrEventDataBaseHeader { + XrStructureType type; + const void* XR_MAY_ALIAS next; +} XrEventDataBaseHeader; + +typedef struct XrEventDataEventsLost { + XrStructureType type; + const void* XR_MAY_ALIAS next; + uint32_t lostEventCount; +} XrEventDataEventsLost; + +typedef struct XrEventDataInstanceLossPending { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrTime lossTime; +} XrEventDataInstanceLossPending; + +typedef struct XrEventDataSessionStateChanged { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSession session; + XrSessionState state; + XrTime time; +} XrEventDataSessionStateChanged; + +typedef struct XrEventDataReferenceSpaceChangePending { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSession session; + XrReferenceSpaceType referenceSpaceType; + XrTime changeTime; + XrBool32 poseValid; + XrPosef poseInPreviousSpace; +} XrEventDataReferenceSpaceChangePending; + +typedef struct XrEventDataInteractionProfileChanged { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSession session; +} XrEventDataInteractionProfileChanged; + +typedef struct XrHapticVibration { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrDuration duration; + float frequency; + float amplitude; +} XrHapticVibration; + +typedef struct XrOffset2Df { + float x; + float y; +} XrOffset2Df; + +typedef struct XrRect2Df { + XrOffset2Df offset; + XrExtent2Df extent; +} XrRect2Df; + +typedef struct XrVector4f { + float x; + float y; + float z; + float w; +} XrVector4f; + +typedef struct XrColor4f { + float r; + float g; + float b; + float a; +} XrColor4f; + +typedef XrResult (XRAPI_PTR *PFN_xrGetInstanceProcAddr)(XrInstance instance, const char* name, PFN_xrVoidFunction* function); +typedef XrResult (XRAPI_PTR *PFN_xrEnumerateApiLayerProperties)(uint32_t propertyCapacityInput, uint32_t* propertyCountOutput, XrApiLayerProperties* properties); +typedef XrResult (XRAPI_PTR *PFN_xrEnumerateInstanceExtensionProperties)(const char* layerName, uint32_t propertyCapacityInput, uint32_t* propertyCountOutput, XrExtensionProperties* properties); +typedef XrResult (XRAPI_PTR *PFN_xrCreateInstance)(const XrInstanceCreateInfo* createInfo, XrInstance* instance); +typedef XrResult (XRAPI_PTR *PFN_xrDestroyInstance)(XrInstance instance); +typedef XrResult (XRAPI_PTR *PFN_xrGetInstanceProperties)(XrInstance instance, XrInstanceProperties* instanceProperties); +typedef XrResult (XRAPI_PTR *PFN_xrPollEvent)(XrInstance instance, XrEventDataBuffer* eventData); +typedef XrResult (XRAPI_PTR *PFN_xrResultToString)(XrInstance instance, XrResult value, char buffer[XR_MAX_RESULT_STRING_SIZE]); +typedef XrResult (XRAPI_PTR *PFN_xrStructureTypeToString)(XrInstance instance, XrStructureType value, char buffer[XR_MAX_STRUCTURE_NAME_SIZE]); +typedef XrResult (XRAPI_PTR *PFN_xrGetSystem)(XrInstance instance, const XrSystemGetInfo* getInfo, XrSystemId* systemId); +typedef XrResult (XRAPI_PTR *PFN_xrGetSystemProperties)(XrInstance instance, XrSystemId systemId, XrSystemProperties* properties); +typedef XrResult (XRAPI_PTR *PFN_xrEnumerateEnvironmentBlendModes)(XrInstance instance, XrSystemId systemId, XrViewConfigurationType viewConfigurationType, uint32_t environmentBlendModeCapacityInput, uint32_t* environmentBlendModeCountOutput, XrEnvironmentBlendMode* environmentBlendModes); +typedef XrResult (XRAPI_PTR *PFN_xrCreateSession)(XrInstance instance, const XrSessionCreateInfo* createInfo, XrSession* session); +typedef XrResult (XRAPI_PTR *PFN_xrDestroySession)(XrSession session); +typedef XrResult (XRAPI_PTR *PFN_xrEnumerateReferenceSpaces)(XrSession session, uint32_t spaceCapacityInput, uint32_t* spaceCountOutput, XrReferenceSpaceType* spaces); +typedef XrResult (XRAPI_PTR *PFN_xrCreateReferenceSpace)(XrSession session, const XrReferenceSpaceCreateInfo* createInfo, XrSpace* space); +typedef XrResult (XRAPI_PTR *PFN_xrGetReferenceSpaceBoundsRect)(XrSession session, XrReferenceSpaceType referenceSpaceType, XrExtent2Df* bounds); +typedef XrResult (XRAPI_PTR *PFN_xrCreateActionSpace)(XrSession session, const XrActionSpaceCreateInfo* createInfo, XrSpace* space); +typedef XrResult (XRAPI_PTR *PFN_xrLocateSpace)(XrSpace space, XrSpace baseSpace, XrTime time, XrSpaceLocation* location); +typedef XrResult (XRAPI_PTR *PFN_xrDestroySpace)(XrSpace space); +typedef XrResult (XRAPI_PTR *PFN_xrEnumerateViewConfigurations)(XrInstance instance, XrSystemId systemId, uint32_t viewConfigurationTypeCapacityInput, uint32_t* viewConfigurationTypeCountOutput, XrViewConfigurationType* viewConfigurationTypes); +typedef XrResult (XRAPI_PTR *PFN_xrGetViewConfigurationProperties)(XrInstance instance, XrSystemId systemId, XrViewConfigurationType viewConfigurationType, XrViewConfigurationProperties* configurationProperties); +typedef XrResult (XRAPI_PTR *PFN_xrEnumerateViewConfigurationViews)(XrInstance instance, XrSystemId systemId, XrViewConfigurationType viewConfigurationType, uint32_t viewCapacityInput, uint32_t* viewCountOutput, XrViewConfigurationView* views); +typedef XrResult (XRAPI_PTR *PFN_xrEnumerateSwapchainFormats)(XrSession session, uint32_t formatCapacityInput, uint32_t* formatCountOutput, int64_t* formats); +typedef XrResult (XRAPI_PTR *PFN_xrCreateSwapchain)(XrSession session, const XrSwapchainCreateInfo* createInfo, XrSwapchain* swapchain); +typedef XrResult (XRAPI_PTR *PFN_xrDestroySwapchain)(XrSwapchain swapchain); +typedef XrResult (XRAPI_PTR *PFN_xrEnumerateSwapchainImages)(XrSwapchain swapchain, uint32_t imageCapacityInput, uint32_t* imageCountOutput, XrSwapchainImageBaseHeader* images); +typedef XrResult (XRAPI_PTR *PFN_xrAcquireSwapchainImage)(XrSwapchain swapchain, const XrSwapchainImageAcquireInfo* acquireInfo, uint32_t* index); +typedef XrResult (XRAPI_PTR *PFN_xrWaitSwapchainImage)(XrSwapchain swapchain, const XrSwapchainImageWaitInfo* waitInfo); +typedef XrResult (XRAPI_PTR *PFN_xrReleaseSwapchainImage)(XrSwapchain swapchain, const XrSwapchainImageReleaseInfo* releaseInfo); +typedef XrResult (XRAPI_PTR *PFN_xrBeginSession)(XrSession session, const XrSessionBeginInfo* beginInfo); +typedef XrResult (XRAPI_PTR *PFN_xrEndSession)(XrSession session); +typedef XrResult (XRAPI_PTR *PFN_xrRequestExitSession)(XrSession session); +typedef XrResult (XRAPI_PTR *PFN_xrWaitFrame)(XrSession session, const XrFrameWaitInfo* frameWaitInfo, XrFrameState* frameState); +typedef XrResult (XRAPI_PTR *PFN_xrBeginFrame)(XrSession session, const XrFrameBeginInfo* frameBeginInfo); +typedef XrResult (XRAPI_PTR *PFN_xrEndFrame)(XrSession session, const XrFrameEndInfo* frameEndInfo); +typedef XrResult (XRAPI_PTR *PFN_xrLocateViews)(XrSession session, const XrViewLocateInfo* viewLocateInfo, XrViewState* viewState, uint32_t viewCapacityInput, uint32_t* viewCountOutput, XrView* views); +typedef XrResult (XRAPI_PTR *PFN_xrStringToPath)(XrInstance instance, const char* pathString, XrPath* path); +typedef XrResult (XRAPI_PTR *PFN_xrPathToString)(XrInstance instance, XrPath path, uint32_t bufferCapacityInput, uint32_t* bufferCountOutput, char* buffer); +typedef XrResult (XRAPI_PTR *PFN_xrCreateActionSet)(XrInstance instance, const XrActionSetCreateInfo* createInfo, XrActionSet* actionSet); +typedef XrResult (XRAPI_PTR *PFN_xrDestroyActionSet)(XrActionSet actionSet); +typedef XrResult (XRAPI_PTR *PFN_xrCreateAction)(XrActionSet actionSet, const XrActionCreateInfo* createInfo, XrAction* action); +typedef XrResult (XRAPI_PTR *PFN_xrDestroyAction)(XrAction action); +typedef XrResult (XRAPI_PTR *PFN_xrSuggestInteractionProfileBindings)(XrInstance instance, const XrInteractionProfileSuggestedBinding* suggestedBindings); +typedef XrResult (XRAPI_PTR *PFN_xrAttachSessionActionSets)(XrSession session, const XrSessionActionSetsAttachInfo* attachInfo); +typedef XrResult (XRAPI_PTR *PFN_xrGetCurrentInteractionProfile)(XrSession session, XrPath topLevelUserPath, XrInteractionProfileState* interactionProfile); +typedef XrResult (XRAPI_PTR *PFN_xrGetActionStateBoolean)(XrSession session, const XrActionStateGetInfo* getInfo, XrActionStateBoolean* state); +typedef XrResult (XRAPI_PTR *PFN_xrGetActionStateFloat)(XrSession session, const XrActionStateGetInfo* getInfo, XrActionStateFloat* state); +typedef XrResult (XRAPI_PTR *PFN_xrGetActionStateVector2f)(XrSession session, const XrActionStateGetInfo* getInfo, XrActionStateVector2f* state); +typedef XrResult (XRAPI_PTR *PFN_xrGetActionStatePose)(XrSession session, const XrActionStateGetInfo* getInfo, XrActionStatePose* state); +typedef XrResult (XRAPI_PTR *PFN_xrSyncActions)(XrSession session, const XrActionsSyncInfo* syncInfo); +typedef XrResult (XRAPI_PTR *PFN_xrEnumerateBoundSourcesForAction)(XrSession session, const XrBoundSourcesForActionEnumerateInfo* enumerateInfo, uint32_t sourceCapacityInput, uint32_t* sourceCountOutput, XrPath* sources); +typedef XrResult (XRAPI_PTR *PFN_xrGetInputSourceLocalizedName)(XrSession session, const XrInputSourceLocalizedNameGetInfo* getInfo, uint32_t bufferCapacityInput, uint32_t* bufferCountOutput, char* buffer); +typedef XrResult (XRAPI_PTR *PFN_xrApplyHapticFeedback)(XrSession session, const XrHapticActionInfo* hapticActionInfo, const XrHapticBaseHeader* hapticFeedback); +typedef XrResult (XRAPI_PTR *PFN_xrStopHapticFeedback)(XrSession session, const XrHapticActionInfo* hapticActionInfo); + +#ifndef XR_NO_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrGetInstanceProcAddr( + XrInstance instance, + const char* name, + PFN_xrVoidFunction* function); + +XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateApiLayerProperties( + uint32_t propertyCapacityInput, + uint32_t* propertyCountOutput, + XrApiLayerProperties* properties); + +XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateInstanceExtensionProperties( + const char* layerName, + uint32_t propertyCapacityInput, + uint32_t* propertyCountOutput, + XrExtensionProperties* properties); + +XRAPI_ATTR XrResult XRAPI_CALL xrCreateInstance( + const XrInstanceCreateInfo* createInfo, + XrInstance* instance); + +XRAPI_ATTR XrResult XRAPI_CALL xrDestroyInstance( + XrInstance instance); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetInstanceProperties( + XrInstance instance, + XrInstanceProperties* instanceProperties); + +XRAPI_ATTR XrResult XRAPI_CALL xrPollEvent( + XrInstance instance, + XrEventDataBuffer* eventData); + +XRAPI_ATTR XrResult XRAPI_CALL xrResultToString( + XrInstance instance, + XrResult value, + char buffer[XR_MAX_RESULT_STRING_SIZE]); + +XRAPI_ATTR XrResult XRAPI_CALL xrStructureTypeToString( + XrInstance instance, + XrStructureType value, + char buffer[XR_MAX_STRUCTURE_NAME_SIZE]); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetSystem( + XrInstance instance, + const XrSystemGetInfo* getInfo, + XrSystemId* systemId); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetSystemProperties( + XrInstance instance, + XrSystemId systemId, + XrSystemProperties* properties); + +XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateEnvironmentBlendModes( + XrInstance instance, + XrSystemId systemId, + XrViewConfigurationType viewConfigurationType, + uint32_t environmentBlendModeCapacityInput, + uint32_t* environmentBlendModeCountOutput, + XrEnvironmentBlendMode* environmentBlendModes); + +XRAPI_ATTR XrResult XRAPI_CALL xrCreateSession( + XrInstance instance, + const XrSessionCreateInfo* createInfo, + XrSession* session); + +XRAPI_ATTR XrResult XRAPI_CALL xrDestroySession( + XrSession session); + +XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateReferenceSpaces( + XrSession session, + uint32_t spaceCapacityInput, + uint32_t* spaceCountOutput, + XrReferenceSpaceType* spaces); + +XRAPI_ATTR XrResult XRAPI_CALL xrCreateReferenceSpace( + XrSession session, + const XrReferenceSpaceCreateInfo* createInfo, + XrSpace* space); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetReferenceSpaceBoundsRect( + XrSession session, + XrReferenceSpaceType referenceSpaceType, + XrExtent2Df* bounds); + +XRAPI_ATTR XrResult XRAPI_CALL xrCreateActionSpace( + XrSession session, + const XrActionSpaceCreateInfo* createInfo, + XrSpace* space); + +XRAPI_ATTR XrResult XRAPI_CALL xrLocateSpace( + XrSpace space, + XrSpace baseSpace, + XrTime time, + XrSpaceLocation* location); + +XRAPI_ATTR XrResult XRAPI_CALL xrDestroySpace( + XrSpace space); + +XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateViewConfigurations( + XrInstance instance, + XrSystemId systemId, + uint32_t viewConfigurationTypeCapacityInput, + uint32_t* viewConfigurationTypeCountOutput, + XrViewConfigurationType* viewConfigurationTypes); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetViewConfigurationProperties( + XrInstance instance, + XrSystemId systemId, + XrViewConfigurationType viewConfigurationType, + XrViewConfigurationProperties* configurationProperties); + +XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateViewConfigurationViews( + XrInstance instance, + XrSystemId systemId, + XrViewConfigurationType viewConfigurationType, + uint32_t viewCapacityInput, + uint32_t* viewCountOutput, + XrViewConfigurationView* views); + +XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateSwapchainFormats( + XrSession session, + uint32_t formatCapacityInput, + uint32_t* formatCountOutput, + int64_t* formats); + +XRAPI_ATTR XrResult XRAPI_CALL xrCreateSwapchain( + XrSession session, + const XrSwapchainCreateInfo* createInfo, + XrSwapchain* swapchain); + +XRAPI_ATTR XrResult XRAPI_CALL xrDestroySwapchain( + XrSwapchain swapchain); + +XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateSwapchainImages( + XrSwapchain swapchain, + uint32_t imageCapacityInput, + uint32_t* imageCountOutput, + XrSwapchainImageBaseHeader* images); + +XRAPI_ATTR XrResult XRAPI_CALL xrAcquireSwapchainImage( + XrSwapchain swapchain, + const XrSwapchainImageAcquireInfo* acquireInfo, + uint32_t* index); + +XRAPI_ATTR XrResult XRAPI_CALL xrWaitSwapchainImage( + XrSwapchain swapchain, + const XrSwapchainImageWaitInfo* waitInfo); + +XRAPI_ATTR XrResult XRAPI_CALL xrReleaseSwapchainImage( + XrSwapchain swapchain, + const XrSwapchainImageReleaseInfo* releaseInfo); + +XRAPI_ATTR XrResult XRAPI_CALL xrBeginSession( + XrSession session, + const XrSessionBeginInfo* beginInfo); + +XRAPI_ATTR XrResult XRAPI_CALL xrEndSession( + XrSession session); + +XRAPI_ATTR XrResult XRAPI_CALL xrRequestExitSession( + XrSession session); + +XRAPI_ATTR XrResult XRAPI_CALL xrWaitFrame( + XrSession session, + const XrFrameWaitInfo* frameWaitInfo, + XrFrameState* frameState); + +XRAPI_ATTR XrResult XRAPI_CALL xrBeginFrame( + XrSession session, + const XrFrameBeginInfo* frameBeginInfo); + +XRAPI_ATTR XrResult XRAPI_CALL xrEndFrame( + XrSession session, + const XrFrameEndInfo* frameEndInfo); + +XRAPI_ATTR XrResult XRAPI_CALL xrLocateViews( + XrSession session, + const XrViewLocateInfo* viewLocateInfo, + XrViewState* viewState, + uint32_t viewCapacityInput, + uint32_t* viewCountOutput, + XrView* views); + +XRAPI_ATTR XrResult XRAPI_CALL xrStringToPath( + XrInstance instance, + const char* pathString, + XrPath* path); + +XRAPI_ATTR XrResult XRAPI_CALL xrPathToString( + XrInstance instance, + XrPath path, + uint32_t bufferCapacityInput, + uint32_t* bufferCountOutput, + char* buffer); + +XRAPI_ATTR XrResult XRAPI_CALL xrCreateActionSet( + XrInstance instance, + const XrActionSetCreateInfo* createInfo, + XrActionSet* actionSet); + +XRAPI_ATTR XrResult XRAPI_CALL xrDestroyActionSet( + XrActionSet actionSet); + +XRAPI_ATTR XrResult XRAPI_CALL xrCreateAction( + XrActionSet actionSet, + const XrActionCreateInfo* createInfo, + XrAction* action); + +XRAPI_ATTR XrResult XRAPI_CALL xrDestroyAction( + XrAction action); + +XRAPI_ATTR XrResult XRAPI_CALL xrSuggestInteractionProfileBindings( + XrInstance instance, + const XrInteractionProfileSuggestedBinding* suggestedBindings); + +XRAPI_ATTR XrResult XRAPI_CALL xrAttachSessionActionSets( + XrSession session, + const XrSessionActionSetsAttachInfo* attachInfo); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetCurrentInteractionProfile( + XrSession session, + XrPath topLevelUserPath, + XrInteractionProfileState* interactionProfile); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetActionStateBoolean( + XrSession session, + const XrActionStateGetInfo* getInfo, + XrActionStateBoolean* state); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetActionStateFloat( + XrSession session, + const XrActionStateGetInfo* getInfo, + XrActionStateFloat* state); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetActionStateVector2f( + XrSession session, + const XrActionStateGetInfo* getInfo, + XrActionStateVector2f* state); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetActionStatePose( + XrSession session, + const XrActionStateGetInfo* getInfo, + XrActionStatePose* state); + +XRAPI_ATTR XrResult XRAPI_CALL xrSyncActions( + XrSession session, + const XrActionsSyncInfo* syncInfo); + +XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateBoundSourcesForAction( + XrSession session, + const XrBoundSourcesForActionEnumerateInfo* enumerateInfo, + uint32_t sourceCapacityInput, + uint32_t* sourceCountOutput, + XrPath* sources); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetInputSourceLocalizedName( + XrSession session, + const XrInputSourceLocalizedNameGetInfo* getInfo, + uint32_t bufferCapacityInput, + uint32_t* bufferCountOutput, + char* buffer); + +XRAPI_ATTR XrResult XRAPI_CALL xrApplyHapticFeedback( + XrSession session, + const XrHapticActionInfo* hapticActionInfo, + const XrHapticBaseHeader* hapticFeedback); + +XRAPI_ATTR XrResult XRAPI_CALL xrStopHapticFeedback( + XrSession session, + const XrHapticActionInfo* hapticActionInfo); +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_KHR_composition_layer_cube 1 +#define XR_KHR_composition_layer_cube_SPEC_VERSION 8 +#define XR_KHR_COMPOSITION_LAYER_CUBE_EXTENSION_NAME "XR_KHR_composition_layer_cube" +typedef struct XrCompositionLayerCubeKHR { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrCompositionLayerFlags layerFlags; + XrSpace space; + XrEyeVisibility eyeVisibility; + XrSwapchain swapchain; + uint32_t imageArrayIndex; + XrQuaternionf orientation; +} XrCompositionLayerCubeKHR; + + + +#define XR_KHR_composition_layer_depth 1 +#define XR_KHR_composition_layer_depth_SPEC_VERSION 6 +#define XR_KHR_COMPOSITION_LAYER_DEPTH_EXTENSION_NAME "XR_KHR_composition_layer_depth" +// XrCompositionLayerDepthInfoKHR extends XrCompositionLayerProjectionView +typedef struct XrCompositionLayerDepthInfoKHR { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSwapchainSubImage subImage; + float minDepth; + float maxDepth; + float nearZ; + float farZ; +} XrCompositionLayerDepthInfoKHR; + + + +#define XR_KHR_composition_layer_cylinder 1 +#define XR_KHR_composition_layer_cylinder_SPEC_VERSION 4 +#define XR_KHR_COMPOSITION_LAYER_CYLINDER_EXTENSION_NAME "XR_KHR_composition_layer_cylinder" +typedef struct XrCompositionLayerCylinderKHR { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrCompositionLayerFlags layerFlags; + XrSpace space; + XrEyeVisibility eyeVisibility; + XrSwapchainSubImage subImage; + XrPosef pose; + float radius; + float centralAngle; + float aspectRatio; +} XrCompositionLayerCylinderKHR; + + + +#define XR_KHR_composition_layer_equirect 1 +#define XR_KHR_composition_layer_equirect_SPEC_VERSION 3 +#define XR_KHR_COMPOSITION_LAYER_EQUIRECT_EXTENSION_NAME "XR_KHR_composition_layer_equirect" +typedef struct XrCompositionLayerEquirectKHR { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrCompositionLayerFlags layerFlags; + XrSpace space; + XrEyeVisibility eyeVisibility; + XrSwapchainSubImage subImage; + XrPosef pose; + float radius; + XrVector2f scale; + XrVector2f bias; +} XrCompositionLayerEquirectKHR; + + + +#define XR_KHR_visibility_mask 1 +#define XR_KHR_visibility_mask_SPEC_VERSION 2 +#define XR_KHR_VISIBILITY_MASK_EXTENSION_NAME "XR_KHR_visibility_mask" + +typedef enum XrVisibilityMaskTypeKHR { + XR_VISIBILITY_MASK_TYPE_HIDDEN_TRIANGLE_MESH_KHR = 1, + XR_VISIBILITY_MASK_TYPE_VISIBLE_TRIANGLE_MESH_KHR = 2, + XR_VISIBILITY_MASK_TYPE_LINE_LOOP_KHR = 3, + XR_VISIBILITY_MASK_TYPE_MAX_ENUM_KHR = 0x7FFFFFFF +} XrVisibilityMaskTypeKHR; +typedef struct XrVisibilityMaskKHR { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint32_t vertexCapacityInput; + uint32_t vertexCountOutput; + XrVector2f* vertices; + uint32_t indexCapacityInput; + uint32_t indexCountOutput; + uint32_t* indices; +} XrVisibilityMaskKHR; + +typedef struct XrEventDataVisibilityMaskChangedKHR { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSession session; + XrViewConfigurationType viewConfigurationType; + uint32_t viewIndex; +} XrEventDataVisibilityMaskChangedKHR; + +typedef XrResult (XRAPI_PTR *PFN_xrGetVisibilityMaskKHR)(XrSession session, XrViewConfigurationType viewConfigurationType, uint32_t viewIndex, XrVisibilityMaskTypeKHR visibilityMaskType, XrVisibilityMaskKHR* visibilityMask); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrGetVisibilityMaskKHR( + XrSession session, + XrViewConfigurationType viewConfigurationType, + uint32_t viewIndex, + XrVisibilityMaskTypeKHR visibilityMaskType, + XrVisibilityMaskKHR* visibilityMask); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_KHR_composition_layer_color_scale_bias 1 +#define XR_KHR_composition_layer_color_scale_bias_SPEC_VERSION 5 +#define XR_KHR_COMPOSITION_LAYER_COLOR_SCALE_BIAS_EXTENSION_NAME "XR_KHR_composition_layer_color_scale_bias" +// XrCompositionLayerColorScaleBiasKHR extends XrCompositionLayerBaseHeader +typedef struct XrCompositionLayerColorScaleBiasKHR { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrColor4f colorScale; + XrColor4f colorBias; +} XrCompositionLayerColorScaleBiasKHR; + + + +#define XR_KHR_loader_init 1 +#define XR_KHR_loader_init_SPEC_VERSION 1 +#define XR_KHR_LOADER_INIT_EXTENSION_NAME "XR_KHR_loader_init" +typedef struct XR_MAY_ALIAS XrLoaderInitInfoBaseHeaderKHR { + XrStructureType type; + const void* XR_MAY_ALIAS next; +} XrLoaderInitInfoBaseHeaderKHR; + +typedef XrResult (XRAPI_PTR *PFN_xrInitializeLoaderKHR)(const XrLoaderInitInfoBaseHeaderKHR* loaderInitInfo); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrInitializeLoaderKHR( + const XrLoaderInitInfoBaseHeaderKHR* loaderInitInfo); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_KHR_composition_layer_equirect2 1 +#define XR_KHR_composition_layer_equirect2_SPEC_VERSION 1 +#define XR_KHR_COMPOSITION_LAYER_EQUIRECT2_EXTENSION_NAME "XR_KHR_composition_layer_equirect2" +typedef struct XrCompositionLayerEquirect2KHR { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrCompositionLayerFlags layerFlags; + XrSpace space; + XrEyeVisibility eyeVisibility; + XrSwapchainSubImage subImage; + XrPosef pose; + float radius; + float centralHorizontalAngle; + float upperVerticalAngle; + float lowerVerticalAngle; +} XrCompositionLayerEquirect2KHR; + + + +#define XR_KHR_binding_modification 1 +#define XR_KHR_binding_modification_SPEC_VERSION 1 +#define XR_KHR_BINDING_MODIFICATION_EXTENSION_NAME "XR_KHR_binding_modification" +typedef struct XR_MAY_ALIAS XrBindingModificationBaseHeaderKHR { + XrStructureType type; + const void* XR_MAY_ALIAS next; +} XrBindingModificationBaseHeaderKHR; + +// XrBindingModificationsKHR extends XrInteractionProfileSuggestedBinding +typedef struct XrBindingModificationsKHR { + XrStructureType type; + const void* XR_MAY_ALIAS next; + uint32_t bindingModificationCount; + const XrBindingModificationBaseHeaderKHR* const* bindingModifications; +} XrBindingModificationsKHR; + + + +#define XR_KHR_swapchain_usage_input_attachment_bit 1 +#define XR_KHR_swapchain_usage_input_attachment_bit_SPEC_VERSION 3 +#define XR_KHR_SWAPCHAIN_USAGE_INPUT_ATTACHMENT_BIT_EXTENSION_NAME "XR_KHR_swapchain_usage_input_attachment_bit" + + +#define XR_EXT_performance_settings 1 +#define XR_EXT_performance_settings_SPEC_VERSION 3 +#define XR_EXT_PERFORMANCE_SETTINGS_EXTENSION_NAME "XR_EXT_performance_settings" + +typedef enum XrPerfSettingsDomainEXT { + XR_PERF_SETTINGS_DOMAIN_CPU_EXT = 1, + XR_PERF_SETTINGS_DOMAIN_GPU_EXT = 2, + XR_PERF_SETTINGS_DOMAIN_MAX_ENUM_EXT = 0x7FFFFFFF +} XrPerfSettingsDomainEXT; + +typedef enum XrPerfSettingsSubDomainEXT { + XR_PERF_SETTINGS_SUB_DOMAIN_COMPOSITING_EXT = 1, + XR_PERF_SETTINGS_SUB_DOMAIN_RENDERING_EXT = 2, + XR_PERF_SETTINGS_SUB_DOMAIN_THERMAL_EXT = 3, + XR_PERF_SETTINGS_SUB_DOMAIN_MAX_ENUM_EXT = 0x7FFFFFFF +} XrPerfSettingsSubDomainEXT; + +typedef enum XrPerfSettingsLevelEXT { + XR_PERF_SETTINGS_LEVEL_POWER_SAVINGS_EXT = 0, + XR_PERF_SETTINGS_LEVEL_SUSTAINED_LOW_EXT = 25, + XR_PERF_SETTINGS_LEVEL_SUSTAINED_HIGH_EXT = 50, + XR_PERF_SETTINGS_LEVEL_BOOST_EXT = 75, + XR_PERF_SETTINGS_LEVEL_MAX_ENUM_EXT = 0x7FFFFFFF +} XrPerfSettingsLevelEXT; + +typedef enum XrPerfSettingsNotificationLevelEXT { + XR_PERF_SETTINGS_NOTIF_LEVEL_NORMAL_EXT = 0, + XR_PERF_SETTINGS_NOTIF_LEVEL_WARNING_EXT = 25, + XR_PERF_SETTINGS_NOTIF_LEVEL_IMPAIRED_EXT = 75, + XR_PERF_SETTINGS_NOTIFICATION_LEVEL_MAX_ENUM_EXT = 0x7FFFFFFF +} XrPerfSettingsNotificationLevelEXT; +typedef struct XrEventDataPerfSettingsEXT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrPerfSettingsDomainEXT domain; + XrPerfSettingsSubDomainEXT subDomain; + XrPerfSettingsNotificationLevelEXT fromLevel; + XrPerfSettingsNotificationLevelEXT toLevel; +} XrEventDataPerfSettingsEXT; + +typedef XrResult (XRAPI_PTR *PFN_xrPerfSettingsSetPerformanceLevelEXT)(XrSession session, XrPerfSettingsDomainEXT domain, XrPerfSettingsLevelEXT level); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrPerfSettingsSetPerformanceLevelEXT( + XrSession session, + XrPerfSettingsDomainEXT domain, + XrPerfSettingsLevelEXT level); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_EXT_thermal_query 1 +#define XR_EXT_thermal_query_SPEC_VERSION 2 +#define XR_EXT_THERMAL_QUERY_EXTENSION_NAME "XR_EXT_thermal_query" +typedef XrResult (XRAPI_PTR *PFN_xrThermalGetTemperatureTrendEXT)(XrSession session, XrPerfSettingsDomainEXT domain, XrPerfSettingsNotificationLevelEXT* notificationLevel, float* tempHeadroom, float* tempSlope); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrThermalGetTemperatureTrendEXT( + XrSession session, + XrPerfSettingsDomainEXT domain, + XrPerfSettingsNotificationLevelEXT* notificationLevel, + float* tempHeadroom, + float* tempSlope); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_EXT_debug_utils 1 +XR_DEFINE_HANDLE(XrDebugUtilsMessengerEXT) +#define XR_EXT_debug_utils_SPEC_VERSION 4 +#define XR_EXT_DEBUG_UTILS_EXTENSION_NAME "XR_EXT_debug_utils" +typedef XrFlags64 XrDebugUtilsMessageSeverityFlagsEXT; + +// Flag bits for XrDebugUtilsMessageSeverityFlagsEXT +static const XrDebugUtilsMessageSeverityFlagsEXT XR_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT = 0x00000001; +static const XrDebugUtilsMessageSeverityFlagsEXT XR_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT = 0x00000010; +static const XrDebugUtilsMessageSeverityFlagsEXT XR_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT = 0x00000100; +static const XrDebugUtilsMessageSeverityFlagsEXT XR_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT = 0x00001000; + +typedef XrFlags64 XrDebugUtilsMessageTypeFlagsEXT; + +// Flag bits for XrDebugUtilsMessageTypeFlagsEXT +static const XrDebugUtilsMessageTypeFlagsEXT XR_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT = 0x00000001; +static const XrDebugUtilsMessageTypeFlagsEXT XR_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT = 0x00000002; +static const XrDebugUtilsMessageTypeFlagsEXT XR_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT = 0x00000004; +static const XrDebugUtilsMessageTypeFlagsEXT XR_DEBUG_UTILS_MESSAGE_TYPE_CONFORMANCE_BIT_EXT = 0x00000008; + +typedef struct XrDebugUtilsObjectNameInfoEXT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrObjectType objectType; + uint64_t objectHandle; + const char* objectName; +} XrDebugUtilsObjectNameInfoEXT; + +typedef struct XrDebugUtilsLabelEXT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + const char* labelName; +} XrDebugUtilsLabelEXT; + +typedef struct XrDebugUtilsMessengerCallbackDataEXT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + const char* messageId; + const char* functionName; + const char* message; + uint32_t objectCount; + XrDebugUtilsObjectNameInfoEXT* objects; + uint32_t sessionLabelCount; + XrDebugUtilsLabelEXT* sessionLabels; +} XrDebugUtilsMessengerCallbackDataEXT; + +typedef XrBool32 (XRAPI_PTR *PFN_xrDebugUtilsMessengerCallbackEXT)( + XrDebugUtilsMessageSeverityFlagsEXT messageSeverity, + XrDebugUtilsMessageTypeFlagsEXT messageTypes, + const XrDebugUtilsMessengerCallbackDataEXT* callbackData, + void* userData); + + +// XrDebugUtilsMessengerCreateInfoEXT extends XrInstanceCreateInfo +typedef struct XrDebugUtilsMessengerCreateInfoEXT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrDebugUtilsMessageSeverityFlagsEXT messageSeverities; + XrDebugUtilsMessageTypeFlagsEXT messageTypes; + PFN_xrDebugUtilsMessengerCallbackEXT userCallback; + void* XR_MAY_ALIAS userData; +} XrDebugUtilsMessengerCreateInfoEXT; + +typedef XrResult (XRAPI_PTR *PFN_xrSetDebugUtilsObjectNameEXT)(XrInstance instance, const XrDebugUtilsObjectNameInfoEXT* nameInfo); +typedef XrResult (XRAPI_PTR *PFN_xrCreateDebugUtilsMessengerEXT)(XrInstance instance, const XrDebugUtilsMessengerCreateInfoEXT* createInfo, XrDebugUtilsMessengerEXT* messenger); +typedef XrResult (XRAPI_PTR *PFN_xrDestroyDebugUtilsMessengerEXT)(XrDebugUtilsMessengerEXT messenger); +typedef XrResult (XRAPI_PTR *PFN_xrSubmitDebugUtilsMessageEXT)(XrInstance instance, XrDebugUtilsMessageSeverityFlagsEXT messageSeverity, XrDebugUtilsMessageTypeFlagsEXT messageTypes, const XrDebugUtilsMessengerCallbackDataEXT* callbackData); +typedef XrResult (XRAPI_PTR *PFN_xrSessionBeginDebugUtilsLabelRegionEXT)(XrSession session, const XrDebugUtilsLabelEXT* labelInfo); +typedef XrResult (XRAPI_PTR *PFN_xrSessionEndDebugUtilsLabelRegionEXT)(XrSession session); +typedef XrResult (XRAPI_PTR *PFN_xrSessionInsertDebugUtilsLabelEXT)(XrSession session, const XrDebugUtilsLabelEXT* labelInfo); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrSetDebugUtilsObjectNameEXT( + XrInstance instance, + const XrDebugUtilsObjectNameInfoEXT* nameInfo); + +XRAPI_ATTR XrResult XRAPI_CALL xrCreateDebugUtilsMessengerEXT( + XrInstance instance, + const XrDebugUtilsMessengerCreateInfoEXT* createInfo, + XrDebugUtilsMessengerEXT* messenger); + +XRAPI_ATTR XrResult XRAPI_CALL xrDestroyDebugUtilsMessengerEXT( + XrDebugUtilsMessengerEXT messenger); + +XRAPI_ATTR XrResult XRAPI_CALL xrSubmitDebugUtilsMessageEXT( + XrInstance instance, + XrDebugUtilsMessageSeverityFlagsEXT messageSeverity, + XrDebugUtilsMessageTypeFlagsEXT messageTypes, + const XrDebugUtilsMessengerCallbackDataEXT* callbackData); + +XRAPI_ATTR XrResult XRAPI_CALL xrSessionBeginDebugUtilsLabelRegionEXT( + XrSession session, + const XrDebugUtilsLabelEXT* labelInfo); + +XRAPI_ATTR XrResult XRAPI_CALL xrSessionEndDebugUtilsLabelRegionEXT( + XrSession session); + +XRAPI_ATTR XrResult XRAPI_CALL xrSessionInsertDebugUtilsLabelEXT( + XrSession session, + const XrDebugUtilsLabelEXT* labelInfo); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_EXT_eye_gaze_interaction 1 +#define XR_EXT_eye_gaze_interaction_SPEC_VERSION 2 +#define XR_EXT_EYE_GAZE_INTERACTION_EXTENSION_NAME "XR_EXT_eye_gaze_interaction" +// XrSystemEyeGazeInteractionPropertiesEXT extends XrSystemProperties +typedef struct XrSystemEyeGazeInteractionPropertiesEXT { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrBool32 supportsEyeGazeInteraction; +} XrSystemEyeGazeInteractionPropertiesEXT; + +// XrEyeGazeSampleTimeEXT extends XrSpaceLocation +typedef struct XrEyeGazeSampleTimeEXT { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrTime time; +} XrEyeGazeSampleTimeEXT; + + + +#define XR_EXTX_overlay 1 +#define XR_EXTX_overlay_SPEC_VERSION 5 +#define XR_EXTX_OVERLAY_EXTENSION_NAME "XR_EXTX_overlay" +typedef XrFlags64 XrOverlaySessionCreateFlagsEXTX; + +// Flag bits for XrOverlaySessionCreateFlagsEXTX + +typedef XrFlags64 XrOverlayMainSessionFlagsEXTX; + +// Flag bits for XrOverlayMainSessionFlagsEXTX +static const XrOverlayMainSessionFlagsEXTX XR_OVERLAY_MAIN_SESSION_ENABLED_COMPOSITION_LAYER_INFO_DEPTH_BIT_EXTX = 0x00000001; + +// XrSessionCreateInfoOverlayEXTX extends XrSessionCreateInfo +typedef struct XrSessionCreateInfoOverlayEXTX { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrOverlaySessionCreateFlagsEXTX createFlags; + uint32_t sessionLayersPlacement; +} XrSessionCreateInfoOverlayEXTX; + +typedef struct XrEventDataMainSessionVisibilityChangedEXTX { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrBool32 visible; + XrOverlayMainSessionFlagsEXTX flags; +} XrEventDataMainSessionVisibilityChangedEXTX; + + + +#define XR_VARJO_quad_views 1 +#define XR_VARJO_quad_views_SPEC_VERSION 1 +#define XR_VARJO_QUAD_VIEWS_EXTENSION_NAME "XR_VARJO_quad_views" + + +#define XR_MSFT_unbounded_reference_space 1 +#define XR_MSFT_unbounded_reference_space_SPEC_VERSION 1 +#define XR_MSFT_UNBOUNDED_REFERENCE_SPACE_EXTENSION_NAME "XR_MSFT_unbounded_reference_space" + + +#define XR_MSFT_spatial_anchor 1 +XR_DEFINE_HANDLE(XrSpatialAnchorMSFT) +#define XR_MSFT_spatial_anchor_SPEC_VERSION 2 +#define XR_MSFT_SPATIAL_ANCHOR_EXTENSION_NAME "XR_MSFT_spatial_anchor" +typedef struct XrSpatialAnchorCreateInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSpace space; + XrPosef pose; + XrTime time; +} XrSpatialAnchorCreateInfoMSFT; + +typedef struct XrSpatialAnchorSpaceCreateInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSpatialAnchorMSFT anchor; + XrPosef poseInAnchorSpace; +} XrSpatialAnchorSpaceCreateInfoMSFT; + +typedef XrResult (XRAPI_PTR *PFN_xrCreateSpatialAnchorMSFT)(XrSession session, const XrSpatialAnchorCreateInfoMSFT* createInfo, XrSpatialAnchorMSFT* anchor); +typedef XrResult (XRAPI_PTR *PFN_xrCreateSpatialAnchorSpaceMSFT)(XrSession session, const XrSpatialAnchorSpaceCreateInfoMSFT* createInfo, XrSpace* space); +typedef XrResult (XRAPI_PTR *PFN_xrDestroySpatialAnchorMSFT)(XrSpatialAnchorMSFT anchor); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrCreateSpatialAnchorMSFT( + XrSession session, + const XrSpatialAnchorCreateInfoMSFT* createInfo, + XrSpatialAnchorMSFT* anchor); + +XRAPI_ATTR XrResult XRAPI_CALL xrCreateSpatialAnchorSpaceMSFT( + XrSession session, + const XrSpatialAnchorSpaceCreateInfoMSFT* createInfo, + XrSpace* space); + +XRAPI_ATTR XrResult XRAPI_CALL xrDestroySpatialAnchorMSFT( + XrSpatialAnchorMSFT anchor); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_FB_composition_layer_image_layout 1 +#define XR_FB_composition_layer_image_layout_SPEC_VERSION 1 +#define XR_FB_COMPOSITION_LAYER_IMAGE_LAYOUT_EXTENSION_NAME "XR_FB_composition_layer_image_layout" +typedef XrFlags64 XrCompositionLayerImageLayoutFlagsFB; + +// Flag bits for XrCompositionLayerImageLayoutFlagsFB +static const XrCompositionLayerImageLayoutFlagsFB XR_COMPOSITION_LAYER_IMAGE_LAYOUT_VERTICAL_FLIP_BIT_FB = 0x00000001; + +// XrCompositionLayerImageLayoutFB extends XrCompositionLayerBaseHeader +typedef struct XrCompositionLayerImageLayoutFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrCompositionLayerImageLayoutFlagsFB flags; +} XrCompositionLayerImageLayoutFB; + + + +#define XR_FB_composition_layer_alpha_blend 1 +#define XR_FB_composition_layer_alpha_blend_SPEC_VERSION 2 +#define XR_FB_COMPOSITION_LAYER_ALPHA_BLEND_EXTENSION_NAME "XR_FB_composition_layer_alpha_blend" + +typedef enum XrBlendFactorFB { + XR_BLEND_FACTOR_ZERO_FB = 0, + XR_BLEND_FACTOR_ONE_FB = 1, + XR_BLEND_FACTOR_SRC_ALPHA_FB = 2, + XR_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA_FB = 3, + XR_BLEND_FACTOR_DST_ALPHA_FB = 4, + XR_BLEND_FACTOR_ONE_MINUS_DST_ALPHA_FB = 5, + XR_BLEND_FACTOR_MAX_ENUM_FB = 0x7FFFFFFF +} XrBlendFactorFB; +// XrCompositionLayerAlphaBlendFB extends XrCompositionLayerBaseHeader +typedef struct XrCompositionLayerAlphaBlendFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrBlendFactorFB srcFactorColor; + XrBlendFactorFB dstFactorColor; + XrBlendFactorFB srcFactorAlpha; + XrBlendFactorFB dstFactorAlpha; +} XrCompositionLayerAlphaBlendFB; + + + +#define XR_MND_headless 1 +#define XR_MND_headless_SPEC_VERSION 2 +#define XR_MND_HEADLESS_EXTENSION_NAME "XR_MND_headless" + + +#define XR_OCULUS_android_session_state_enable 1 +#define XR_OCULUS_android_session_state_enable_SPEC_VERSION 1 +#define XR_OCULUS_ANDROID_SESSION_STATE_ENABLE_EXTENSION_NAME "XR_OCULUS_android_session_state_enable" + + +#define XR_EXT_view_configuration_depth_range 1 +#define XR_EXT_view_configuration_depth_range_SPEC_VERSION 1 +#define XR_EXT_VIEW_CONFIGURATION_DEPTH_RANGE_EXTENSION_NAME "XR_EXT_view_configuration_depth_range" +// XrViewConfigurationDepthRangeEXT extends XrViewConfigurationView +typedef struct XrViewConfigurationDepthRangeEXT { + XrStructureType type; + void* XR_MAY_ALIAS next; + float recommendedNearZ; + float minNearZ; + float recommendedFarZ; + float maxFarZ; +} XrViewConfigurationDepthRangeEXT; + + + +#define XR_EXT_conformance_automation 1 +#define XR_EXT_conformance_automation_SPEC_VERSION 3 +#define XR_EXT_CONFORMANCE_AUTOMATION_EXTENSION_NAME "XR_EXT_conformance_automation" +typedef XrResult (XRAPI_PTR *PFN_xrSetInputDeviceActiveEXT)(XrSession session, XrPath interactionProfile, XrPath topLevelPath, XrBool32 isActive); +typedef XrResult (XRAPI_PTR *PFN_xrSetInputDeviceStateBoolEXT)(XrSession session, XrPath topLevelPath, XrPath inputSourcePath, XrBool32 state); +typedef XrResult (XRAPI_PTR *PFN_xrSetInputDeviceStateFloatEXT)(XrSession session, XrPath topLevelPath, XrPath inputSourcePath, float state); +typedef XrResult (XRAPI_PTR *PFN_xrSetInputDeviceStateVector2fEXT)(XrSession session, XrPath topLevelPath, XrPath inputSourcePath, XrVector2f state); +typedef XrResult (XRAPI_PTR *PFN_xrSetInputDeviceLocationEXT)(XrSession session, XrPath topLevelPath, XrPath inputSourcePath, XrSpace space, XrPosef pose); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrSetInputDeviceActiveEXT( + XrSession session, + XrPath interactionProfile, + XrPath topLevelPath, + XrBool32 isActive); + +XRAPI_ATTR XrResult XRAPI_CALL xrSetInputDeviceStateBoolEXT( + XrSession session, + XrPath topLevelPath, + XrPath inputSourcePath, + XrBool32 state); + +XRAPI_ATTR XrResult XRAPI_CALL xrSetInputDeviceStateFloatEXT( + XrSession session, + XrPath topLevelPath, + XrPath inputSourcePath, + float state); + +XRAPI_ATTR XrResult XRAPI_CALL xrSetInputDeviceStateVector2fEXT( + XrSession session, + XrPath topLevelPath, + XrPath inputSourcePath, + XrVector2f state); + +XRAPI_ATTR XrResult XRAPI_CALL xrSetInputDeviceLocationEXT( + XrSession session, + XrPath topLevelPath, + XrPath inputSourcePath, + XrSpace space, + XrPosef pose); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_MSFT_spatial_graph_bridge 1 +XR_DEFINE_HANDLE(XrSpatialGraphNodeBindingMSFT) +#define XR_MSFT_spatial_graph_bridge_SPEC_VERSION 2 +#define XR_MSFT_SPATIAL_GRAPH_BRIDGE_EXTENSION_NAME "XR_MSFT_spatial_graph_bridge" +#define XR_GUID_SIZE_MSFT 16 + +typedef enum XrSpatialGraphNodeTypeMSFT { + XR_SPATIAL_GRAPH_NODE_TYPE_STATIC_MSFT = 1, + XR_SPATIAL_GRAPH_NODE_TYPE_DYNAMIC_MSFT = 2, + XR_SPATIAL_GRAPH_NODE_TYPE_MAX_ENUM_MSFT = 0x7FFFFFFF +} XrSpatialGraphNodeTypeMSFT; +typedef struct XrSpatialGraphNodeSpaceCreateInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSpatialGraphNodeTypeMSFT nodeType; + uint8_t nodeId[XR_GUID_SIZE_MSFT]; + XrPosef pose; +} XrSpatialGraphNodeSpaceCreateInfoMSFT; + +typedef struct XrSpatialGraphStaticNodeBindingCreateInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSpace space; + XrPosef poseInSpace; + XrTime time; +} XrSpatialGraphStaticNodeBindingCreateInfoMSFT; + +typedef struct XrSpatialGraphNodeBindingPropertiesGetInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; +} XrSpatialGraphNodeBindingPropertiesGetInfoMSFT; + +typedef struct XrSpatialGraphNodeBindingPropertiesMSFT { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint8_t nodeId[XR_GUID_SIZE_MSFT]; + XrPosef poseInNodeSpace; +} XrSpatialGraphNodeBindingPropertiesMSFT; + +typedef XrResult (XRAPI_PTR *PFN_xrCreateSpatialGraphNodeSpaceMSFT)(XrSession session, const XrSpatialGraphNodeSpaceCreateInfoMSFT* createInfo, XrSpace* space); +typedef XrResult (XRAPI_PTR *PFN_xrTryCreateSpatialGraphStaticNodeBindingMSFT)(XrSession session, const XrSpatialGraphStaticNodeBindingCreateInfoMSFT* createInfo, XrSpatialGraphNodeBindingMSFT* nodeBinding); +typedef XrResult (XRAPI_PTR *PFN_xrDestroySpatialGraphNodeBindingMSFT)(XrSpatialGraphNodeBindingMSFT nodeBinding); +typedef XrResult (XRAPI_PTR *PFN_xrGetSpatialGraphNodeBindingPropertiesMSFT)(XrSpatialGraphNodeBindingMSFT nodeBinding, const XrSpatialGraphNodeBindingPropertiesGetInfoMSFT* getInfo, XrSpatialGraphNodeBindingPropertiesMSFT* properties); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrCreateSpatialGraphNodeSpaceMSFT( + XrSession session, + const XrSpatialGraphNodeSpaceCreateInfoMSFT* createInfo, + XrSpace* space); + +XRAPI_ATTR XrResult XRAPI_CALL xrTryCreateSpatialGraphStaticNodeBindingMSFT( + XrSession session, + const XrSpatialGraphStaticNodeBindingCreateInfoMSFT* createInfo, + XrSpatialGraphNodeBindingMSFT* nodeBinding); + +XRAPI_ATTR XrResult XRAPI_CALL xrDestroySpatialGraphNodeBindingMSFT( + XrSpatialGraphNodeBindingMSFT nodeBinding); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetSpatialGraphNodeBindingPropertiesMSFT( + XrSpatialGraphNodeBindingMSFT nodeBinding, + const XrSpatialGraphNodeBindingPropertiesGetInfoMSFT* getInfo, + XrSpatialGraphNodeBindingPropertiesMSFT* properties); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_MSFT_hand_interaction 1 +#define XR_MSFT_hand_interaction_SPEC_VERSION 1 +#define XR_MSFT_HAND_INTERACTION_EXTENSION_NAME "XR_MSFT_hand_interaction" + + +#define XR_EXT_hand_tracking 1 + +#define XR_HAND_JOINT_COUNT_EXT 26 + +XR_DEFINE_HANDLE(XrHandTrackerEXT) +#define XR_EXT_hand_tracking_SPEC_VERSION 4 +#define XR_EXT_HAND_TRACKING_EXTENSION_NAME "XR_EXT_hand_tracking" + +typedef enum XrHandEXT { + XR_HAND_LEFT_EXT = 1, + XR_HAND_RIGHT_EXT = 2, + XR_HAND_MAX_ENUM_EXT = 0x7FFFFFFF +} XrHandEXT; + +typedef enum XrHandJointEXT { + XR_HAND_JOINT_PALM_EXT = 0, + XR_HAND_JOINT_WRIST_EXT = 1, + XR_HAND_JOINT_THUMB_METACARPAL_EXT = 2, + XR_HAND_JOINT_THUMB_PROXIMAL_EXT = 3, + XR_HAND_JOINT_THUMB_DISTAL_EXT = 4, + XR_HAND_JOINT_THUMB_TIP_EXT = 5, + XR_HAND_JOINT_INDEX_METACARPAL_EXT = 6, + XR_HAND_JOINT_INDEX_PROXIMAL_EXT = 7, + XR_HAND_JOINT_INDEX_INTERMEDIATE_EXT = 8, + XR_HAND_JOINT_INDEX_DISTAL_EXT = 9, + XR_HAND_JOINT_INDEX_TIP_EXT = 10, + XR_HAND_JOINT_MIDDLE_METACARPAL_EXT = 11, + XR_HAND_JOINT_MIDDLE_PROXIMAL_EXT = 12, + XR_HAND_JOINT_MIDDLE_INTERMEDIATE_EXT = 13, + XR_HAND_JOINT_MIDDLE_DISTAL_EXT = 14, + XR_HAND_JOINT_MIDDLE_TIP_EXT = 15, + XR_HAND_JOINT_RING_METACARPAL_EXT = 16, + XR_HAND_JOINT_RING_PROXIMAL_EXT = 17, + XR_HAND_JOINT_RING_INTERMEDIATE_EXT = 18, + XR_HAND_JOINT_RING_DISTAL_EXT = 19, + XR_HAND_JOINT_RING_TIP_EXT = 20, + XR_HAND_JOINT_LITTLE_METACARPAL_EXT = 21, + XR_HAND_JOINT_LITTLE_PROXIMAL_EXT = 22, + XR_HAND_JOINT_LITTLE_INTERMEDIATE_EXT = 23, + XR_HAND_JOINT_LITTLE_DISTAL_EXT = 24, + XR_HAND_JOINT_LITTLE_TIP_EXT = 25, + XR_HAND_JOINT_MAX_ENUM_EXT = 0x7FFFFFFF +} XrHandJointEXT; + +typedef enum XrHandJointSetEXT { + XR_HAND_JOINT_SET_DEFAULT_EXT = 0, + XR_HAND_JOINT_SET_HAND_WITH_FOREARM_ULTRALEAP = 1000149000, + XR_HAND_JOINT_SET_MAX_ENUM_EXT = 0x7FFFFFFF +} XrHandJointSetEXT; +// XrSystemHandTrackingPropertiesEXT extends XrSystemProperties +typedef struct XrSystemHandTrackingPropertiesEXT { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrBool32 supportsHandTracking; +} XrSystemHandTrackingPropertiesEXT; + +typedef struct XrHandTrackerCreateInfoEXT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrHandEXT hand; + XrHandJointSetEXT handJointSet; +} XrHandTrackerCreateInfoEXT; + +typedef struct XrHandJointsLocateInfoEXT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSpace baseSpace; + XrTime time; +} XrHandJointsLocateInfoEXT; + +typedef struct XrHandJointLocationEXT { + XrSpaceLocationFlags locationFlags; + XrPosef pose; + float radius; +} XrHandJointLocationEXT; + +typedef struct XrHandJointVelocityEXT { + XrSpaceVelocityFlags velocityFlags; + XrVector3f linearVelocity; + XrVector3f angularVelocity; +} XrHandJointVelocityEXT; + +typedef struct XrHandJointLocationsEXT { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrBool32 isActive; + uint32_t jointCount; + XrHandJointLocationEXT* jointLocations; +} XrHandJointLocationsEXT; + +// XrHandJointVelocitiesEXT extends XrHandJointLocationsEXT +typedef struct XrHandJointVelocitiesEXT { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint32_t jointCount; + XrHandJointVelocityEXT* jointVelocities; +} XrHandJointVelocitiesEXT; + +typedef XrResult (XRAPI_PTR *PFN_xrCreateHandTrackerEXT)(XrSession session, const XrHandTrackerCreateInfoEXT* createInfo, XrHandTrackerEXT* handTracker); +typedef XrResult (XRAPI_PTR *PFN_xrDestroyHandTrackerEXT)(XrHandTrackerEXT handTracker); +typedef XrResult (XRAPI_PTR *PFN_xrLocateHandJointsEXT)(XrHandTrackerEXT handTracker, const XrHandJointsLocateInfoEXT* locateInfo, XrHandJointLocationsEXT* locations); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrCreateHandTrackerEXT( + XrSession session, + const XrHandTrackerCreateInfoEXT* createInfo, + XrHandTrackerEXT* handTracker); + +XRAPI_ATTR XrResult XRAPI_CALL xrDestroyHandTrackerEXT( + XrHandTrackerEXT handTracker); + +XRAPI_ATTR XrResult XRAPI_CALL xrLocateHandJointsEXT( + XrHandTrackerEXT handTracker, + const XrHandJointsLocateInfoEXT* locateInfo, + XrHandJointLocationsEXT* locations); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_MSFT_hand_tracking_mesh 1 +#define XR_MSFT_hand_tracking_mesh_SPEC_VERSION 4 +#define XR_MSFT_HAND_TRACKING_MESH_EXTENSION_NAME "XR_MSFT_hand_tracking_mesh" + +typedef enum XrHandPoseTypeMSFT { + XR_HAND_POSE_TYPE_TRACKED_MSFT = 0, + XR_HAND_POSE_TYPE_REFERENCE_OPEN_PALM_MSFT = 1, + XR_HAND_POSE_TYPE_MAX_ENUM_MSFT = 0x7FFFFFFF +} XrHandPoseTypeMSFT; +// XrSystemHandTrackingMeshPropertiesMSFT extends XrSystemProperties +typedef struct XrSystemHandTrackingMeshPropertiesMSFT { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrBool32 supportsHandTrackingMesh; + uint32_t maxHandMeshIndexCount; + uint32_t maxHandMeshVertexCount; +} XrSystemHandTrackingMeshPropertiesMSFT; + +typedef struct XrHandMeshSpaceCreateInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrHandPoseTypeMSFT handPoseType; + XrPosef poseInHandMeshSpace; +} XrHandMeshSpaceCreateInfoMSFT; + +typedef struct XrHandMeshUpdateInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrTime time; + XrHandPoseTypeMSFT handPoseType; +} XrHandMeshUpdateInfoMSFT; + +typedef struct XrHandMeshIndexBufferMSFT { + uint32_t indexBufferKey; + uint32_t indexCapacityInput; + uint32_t indexCountOutput; + uint32_t* indices; +} XrHandMeshIndexBufferMSFT; + +typedef struct XrHandMeshVertexMSFT { + XrVector3f position; + XrVector3f normal; +} XrHandMeshVertexMSFT; + +typedef struct XrHandMeshVertexBufferMSFT { + XrTime vertexUpdateTime; + uint32_t vertexCapacityInput; + uint32_t vertexCountOutput; + XrHandMeshVertexMSFT* vertices; +} XrHandMeshVertexBufferMSFT; + +typedef struct XrHandMeshMSFT { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrBool32 isActive; + XrBool32 indexBufferChanged; + XrBool32 vertexBufferChanged; + XrHandMeshIndexBufferMSFT indexBuffer; + XrHandMeshVertexBufferMSFT vertexBuffer; +} XrHandMeshMSFT; + +// XrHandPoseTypeInfoMSFT extends XrHandTrackerCreateInfoEXT +typedef struct XrHandPoseTypeInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrHandPoseTypeMSFT handPoseType; +} XrHandPoseTypeInfoMSFT; + +typedef XrResult (XRAPI_PTR *PFN_xrCreateHandMeshSpaceMSFT)(XrHandTrackerEXT handTracker, const XrHandMeshSpaceCreateInfoMSFT* createInfo, XrSpace* space); +typedef XrResult (XRAPI_PTR *PFN_xrUpdateHandMeshMSFT)(XrHandTrackerEXT handTracker, const XrHandMeshUpdateInfoMSFT* updateInfo, XrHandMeshMSFT* handMesh); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrCreateHandMeshSpaceMSFT( + XrHandTrackerEXT handTracker, + const XrHandMeshSpaceCreateInfoMSFT* createInfo, + XrSpace* space); + +XRAPI_ATTR XrResult XRAPI_CALL xrUpdateHandMeshMSFT( + XrHandTrackerEXT handTracker, + const XrHandMeshUpdateInfoMSFT* updateInfo, + XrHandMeshMSFT* handMesh); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_MSFT_secondary_view_configuration 1 +#define XR_MSFT_secondary_view_configuration_SPEC_VERSION 1 +#define XR_MSFT_SECONDARY_VIEW_CONFIGURATION_EXTENSION_NAME "XR_MSFT_secondary_view_configuration" +// XrSecondaryViewConfigurationSessionBeginInfoMSFT extends XrSessionBeginInfo +typedef struct XrSecondaryViewConfigurationSessionBeginInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + uint32_t viewConfigurationCount; + const XrViewConfigurationType* enabledViewConfigurationTypes; +} XrSecondaryViewConfigurationSessionBeginInfoMSFT; + +typedef struct XrSecondaryViewConfigurationStateMSFT { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrViewConfigurationType viewConfigurationType; + XrBool32 active; +} XrSecondaryViewConfigurationStateMSFT; + +// XrSecondaryViewConfigurationFrameStateMSFT extends XrFrameState +typedef struct XrSecondaryViewConfigurationFrameStateMSFT { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint32_t viewConfigurationCount; + XrSecondaryViewConfigurationStateMSFT* viewConfigurationStates; +} XrSecondaryViewConfigurationFrameStateMSFT; + +typedef struct XrSecondaryViewConfigurationLayerInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrViewConfigurationType viewConfigurationType; + XrEnvironmentBlendMode environmentBlendMode; + uint32_t layerCount; + const XrCompositionLayerBaseHeader* const* layers; +} XrSecondaryViewConfigurationLayerInfoMSFT; + +// XrSecondaryViewConfigurationFrameEndInfoMSFT extends XrFrameEndInfo +typedef struct XrSecondaryViewConfigurationFrameEndInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + uint32_t viewConfigurationCount; + const XrSecondaryViewConfigurationLayerInfoMSFT* viewConfigurationLayersInfo; +} XrSecondaryViewConfigurationFrameEndInfoMSFT; + +// XrSecondaryViewConfigurationSwapchainCreateInfoMSFT extends XrSwapchainCreateInfo +typedef struct XrSecondaryViewConfigurationSwapchainCreateInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrViewConfigurationType viewConfigurationType; +} XrSecondaryViewConfigurationSwapchainCreateInfoMSFT; + + + +#define XR_MSFT_first_person_observer 1 +#define XR_MSFT_first_person_observer_SPEC_VERSION 1 +#define XR_MSFT_FIRST_PERSON_OBSERVER_EXTENSION_NAME "XR_MSFT_first_person_observer" + + +#define XR_MSFT_controller_model 1 + +#define XR_NULL_CONTROLLER_MODEL_KEY_MSFT 0 + +XR_DEFINE_ATOM(XrControllerModelKeyMSFT) +#define XR_MSFT_controller_model_SPEC_VERSION 2 +#define XR_MSFT_CONTROLLER_MODEL_EXTENSION_NAME "XR_MSFT_controller_model" +#define XR_MAX_CONTROLLER_MODEL_NODE_NAME_SIZE_MSFT 64 +typedef struct XrControllerModelKeyStateMSFT { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrControllerModelKeyMSFT modelKey; +} XrControllerModelKeyStateMSFT; + +typedef struct XrControllerModelNodePropertiesMSFT { + XrStructureType type; + void* XR_MAY_ALIAS next; + char parentNodeName[XR_MAX_CONTROLLER_MODEL_NODE_NAME_SIZE_MSFT]; + char nodeName[XR_MAX_CONTROLLER_MODEL_NODE_NAME_SIZE_MSFT]; +} XrControllerModelNodePropertiesMSFT; + +typedef struct XrControllerModelPropertiesMSFT { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint32_t nodeCapacityInput; + uint32_t nodeCountOutput; + XrControllerModelNodePropertiesMSFT* nodeProperties; +} XrControllerModelPropertiesMSFT; + +typedef struct XrControllerModelNodeStateMSFT { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrPosef nodePose; +} XrControllerModelNodeStateMSFT; + +typedef struct XrControllerModelStateMSFT { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint32_t nodeCapacityInput; + uint32_t nodeCountOutput; + XrControllerModelNodeStateMSFT* nodeStates; +} XrControllerModelStateMSFT; + +typedef XrResult (XRAPI_PTR *PFN_xrGetControllerModelKeyMSFT)(XrSession session, XrPath topLevelUserPath, XrControllerModelKeyStateMSFT* controllerModelKeyState); +typedef XrResult (XRAPI_PTR *PFN_xrLoadControllerModelMSFT)(XrSession session, XrControllerModelKeyMSFT modelKey, uint32_t bufferCapacityInput, uint32_t* bufferCountOutput, uint8_t* buffer); +typedef XrResult (XRAPI_PTR *PFN_xrGetControllerModelPropertiesMSFT)(XrSession session, XrControllerModelKeyMSFT modelKey, XrControllerModelPropertiesMSFT* properties); +typedef XrResult (XRAPI_PTR *PFN_xrGetControllerModelStateMSFT)(XrSession session, XrControllerModelKeyMSFT modelKey, XrControllerModelStateMSFT* state); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrGetControllerModelKeyMSFT( + XrSession session, + XrPath topLevelUserPath, + XrControllerModelKeyStateMSFT* controllerModelKeyState); + +XRAPI_ATTR XrResult XRAPI_CALL xrLoadControllerModelMSFT( + XrSession session, + XrControllerModelKeyMSFT modelKey, + uint32_t bufferCapacityInput, + uint32_t* bufferCountOutput, + uint8_t* buffer); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetControllerModelPropertiesMSFT( + XrSession session, + XrControllerModelKeyMSFT modelKey, + XrControllerModelPropertiesMSFT* properties); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetControllerModelStateMSFT( + XrSession session, + XrControllerModelKeyMSFT modelKey, + XrControllerModelStateMSFT* state); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_EXT_win32_appcontainer_compatible 1 +#define XR_EXT_win32_appcontainer_compatible_SPEC_VERSION 1 +#define XR_EXT_WIN32_APPCONTAINER_COMPATIBLE_EXTENSION_NAME "XR_EXT_win32_appcontainer_compatible" + + +#define XR_EPIC_view_configuration_fov 1 +#define XR_EPIC_view_configuration_fov_SPEC_VERSION 2 +#define XR_EPIC_VIEW_CONFIGURATION_FOV_EXTENSION_NAME "XR_EPIC_view_configuration_fov" +// XrViewConfigurationViewFovEPIC extends XrViewConfigurationView +typedef struct XrViewConfigurationViewFovEPIC { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrFovf recommendedFov; + XrFovf maxMutableFov; +} XrViewConfigurationViewFovEPIC; + + + +#define XR_MSFT_composition_layer_reprojection 1 +#define XR_MSFT_composition_layer_reprojection_SPEC_VERSION 1 +#define XR_MSFT_COMPOSITION_LAYER_REPROJECTION_EXTENSION_NAME "XR_MSFT_composition_layer_reprojection" + +typedef enum XrReprojectionModeMSFT { + XR_REPROJECTION_MODE_DEPTH_MSFT = 1, + XR_REPROJECTION_MODE_PLANAR_FROM_DEPTH_MSFT = 2, + XR_REPROJECTION_MODE_PLANAR_MANUAL_MSFT = 3, + XR_REPROJECTION_MODE_ORIENTATION_ONLY_MSFT = 4, + XR_REPROJECTION_MODE_MAX_ENUM_MSFT = 0x7FFFFFFF +} XrReprojectionModeMSFT; +// XrCompositionLayerReprojectionInfoMSFT extends XrCompositionLayerProjection +typedef struct XrCompositionLayerReprojectionInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrReprojectionModeMSFT reprojectionMode; +} XrCompositionLayerReprojectionInfoMSFT; + +// XrCompositionLayerReprojectionPlaneOverrideMSFT extends XrCompositionLayerProjection +typedef struct XrCompositionLayerReprojectionPlaneOverrideMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrVector3f position; + XrVector3f normal; + XrVector3f velocity; +} XrCompositionLayerReprojectionPlaneOverrideMSFT; + +typedef XrResult (XRAPI_PTR *PFN_xrEnumerateReprojectionModesMSFT)(XrInstance instance, XrSystemId systemId, XrViewConfigurationType viewConfigurationType, uint32_t modeCapacityInput, uint32_t* modeCountOutput, XrReprojectionModeMSFT* modes); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateReprojectionModesMSFT( + XrInstance instance, + XrSystemId systemId, + XrViewConfigurationType viewConfigurationType, + uint32_t modeCapacityInput, + uint32_t* modeCountOutput, + XrReprojectionModeMSFT* modes); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_HUAWEI_controller_interaction 1 +#define XR_HUAWEI_controller_interaction_SPEC_VERSION 1 +#define XR_HUAWEI_CONTROLLER_INTERACTION_EXTENSION_NAME "XR_HUAWEI_controller_interaction" + + +#define XR_FB_swapchain_update_state 1 +#define XR_FB_swapchain_update_state_SPEC_VERSION 3 +#define XR_FB_SWAPCHAIN_UPDATE_STATE_EXTENSION_NAME "XR_FB_swapchain_update_state" +typedef struct XR_MAY_ALIAS XrSwapchainStateBaseHeaderFB { + XrStructureType type; + void* XR_MAY_ALIAS next; +} XrSwapchainStateBaseHeaderFB; + +typedef XrResult (XRAPI_PTR *PFN_xrUpdateSwapchainFB)(XrSwapchain swapchain, const XrSwapchainStateBaseHeaderFB* state); +typedef XrResult (XRAPI_PTR *PFN_xrGetSwapchainStateFB)(XrSwapchain swapchain, XrSwapchainStateBaseHeaderFB* state); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrUpdateSwapchainFB( + XrSwapchain swapchain, + const XrSwapchainStateBaseHeaderFB* state); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetSwapchainStateFB( + XrSwapchain swapchain, + XrSwapchainStateBaseHeaderFB* state); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_FB_composition_layer_secure_content 1 +#define XR_FB_composition_layer_secure_content_SPEC_VERSION 1 +#define XR_FB_COMPOSITION_LAYER_SECURE_CONTENT_EXTENSION_NAME "XR_FB_composition_layer_secure_content" +typedef XrFlags64 XrCompositionLayerSecureContentFlagsFB; + +// Flag bits for XrCompositionLayerSecureContentFlagsFB +static const XrCompositionLayerSecureContentFlagsFB XR_COMPOSITION_LAYER_SECURE_CONTENT_EXCLUDE_LAYER_BIT_FB = 0x00000001; +static const XrCompositionLayerSecureContentFlagsFB XR_COMPOSITION_LAYER_SECURE_CONTENT_REPLACE_LAYER_BIT_FB = 0x00000002; + +// XrCompositionLayerSecureContentFB extends XrCompositionLayerBaseHeader +typedef struct XrCompositionLayerSecureContentFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrCompositionLayerSecureContentFlagsFB flags; +} XrCompositionLayerSecureContentFB; + + + +#define XR_EXT_dpad_binding 1 +#define XR_EXT_dpad_binding_SPEC_VERSION 1 +#define XR_EXT_DPAD_BINDING_EXTENSION_NAME "XR_EXT_dpad_binding" +typedef struct XrInteractionProfileDpadBindingEXT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrPath binding; + XrActionSet actionSet; + float forceThreshold; + float forceThresholdReleased; + float centerRegion; + float wedgeAngle; + XrBool32 isSticky; + const XrHapticBaseHeader* onHaptic; + const XrHapticBaseHeader* offHaptic; +} XrInteractionProfileDpadBindingEXT; + + + +#define XR_VALVE_analog_threshold 1 +#define XR_VALVE_analog_threshold_SPEC_VERSION 2 +#define XR_VALVE_ANALOG_THRESHOLD_EXTENSION_NAME "XR_VALVE_analog_threshold" +typedef struct XrInteractionProfileAnalogThresholdVALVE { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrAction action; + XrPath binding; + float onThreshold; + float offThreshold; + const XrHapticBaseHeader* onHaptic; + const XrHapticBaseHeader* offHaptic; +} XrInteractionProfileAnalogThresholdVALVE; + + + +#define XR_EXT_hand_joints_motion_range 1 +#define XR_EXT_hand_joints_motion_range_SPEC_VERSION 1 +#define XR_EXT_HAND_JOINTS_MOTION_RANGE_EXTENSION_NAME "XR_EXT_hand_joints_motion_range" + +typedef enum XrHandJointsMotionRangeEXT { + XR_HAND_JOINTS_MOTION_RANGE_UNOBSTRUCTED_EXT = 1, + XR_HAND_JOINTS_MOTION_RANGE_CONFORMING_TO_CONTROLLER_EXT = 2, + XR_HAND_JOINTS_MOTION_RANGE_MAX_ENUM_EXT = 0x7FFFFFFF +} XrHandJointsMotionRangeEXT; +// XrHandJointsMotionRangeInfoEXT extends XrHandJointsLocateInfoEXT +typedef struct XrHandJointsMotionRangeInfoEXT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrHandJointsMotionRangeEXT handJointsMotionRange; +} XrHandJointsMotionRangeInfoEXT; + + + +#define XR_EXT_samsung_odyssey_controller 1 +#define XR_EXT_samsung_odyssey_controller_SPEC_VERSION 1 +#define XR_EXT_SAMSUNG_ODYSSEY_CONTROLLER_EXTENSION_NAME "XR_EXT_samsung_odyssey_controller" + + +#define XR_EXT_hp_mixed_reality_controller 1 +#define XR_EXT_hp_mixed_reality_controller_SPEC_VERSION 1 +#define XR_EXT_HP_MIXED_REALITY_CONTROLLER_EXTENSION_NAME "XR_EXT_hp_mixed_reality_controller" + + +#define XR_MND_swapchain_usage_input_attachment_bit 1 +#define XR_MND_swapchain_usage_input_attachment_bit_SPEC_VERSION 2 +#define XR_MND_SWAPCHAIN_USAGE_INPUT_ATTACHMENT_BIT_EXTENSION_NAME "XR_MND_swapchain_usage_input_attachment_bit" + + +#define XR_MSFT_scene_understanding 1 + + XR_DEFINE_HANDLE(XrSceneObserverMSFT) + + + XR_DEFINE_HANDLE(XrSceneMSFT) + +#define XR_MSFT_scene_understanding_SPEC_VERSION 2 +#define XR_MSFT_SCENE_UNDERSTANDING_EXTENSION_NAME "XR_MSFT_scene_understanding" + +typedef enum XrSceneComputeFeatureMSFT { + XR_SCENE_COMPUTE_FEATURE_PLANE_MSFT = 1, + XR_SCENE_COMPUTE_FEATURE_PLANE_MESH_MSFT = 2, + XR_SCENE_COMPUTE_FEATURE_VISUAL_MESH_MSFT = 3, + XR_SCENE_COMPUTE_FEATURE_COLLIDER_MESH_MSFT = 4, + XR_SCENE_COMPUTE_FEATURE_SERIALIZE_SCENE_MSFT = 1000098000, + XR_SCENE_COMPUTE_FEATURE_MAX_ENUM_MSFT = 0x7FFFFFFF +} XrSceneComputeFeatureMSFT; + +typedef enum XrSceneComputeConsistencyMSFT { + XR_SCENE_COMPUTE_CONSISTENCY_SNAPSHOT_COMPLETE_MSFT = 1, + XR_SCENE_COMPUTE_CONSISTENCY_SNAPSHOT_INCOMPLETE_FAST_MSFT = 2, + XR_SCENE_COMPUTE_CONSISTENCY_OCCLUSION_OPTIMIZED_MSFT = 3, + XR_SCENE_COMPUTE_CONSISTENCY_MAX_ENUM_MSFT = 0x7FFFFFFF +} XrSceneComputeConsistencyMSFT; + +typedef enum XrMeshComputeLodMSFT { + XR_MESH_COMPUTE_LOD_COARSE_MSFT = 1, + XR_MESH_COMPUTE_LOD_MEDIUM_MSFT = 2, + XR_MESH_COMPUTE_LOD_FINE_MSFT = 3, + XR_MESH_COMPUTE_LOD_UNLIMITED_MSFT = 4, + XR_MESH_COMPUTE_LOD_MAX_ENUM_MSFT = 0x7FFFFFFF +} XrMeshComputeLodMSFT; + +typedef enum XrSceneComponentTypeMSFT { + XR_SCENE_COMPONENT_TYPE_INVALID_MSFT = -1, + XR_SCENE_COMPONENT_TYPE_OBJECT_MSFT = 1, + XR_SCENE_COMPONENT_TYPE_PLANE_MSFT = 2, + XR_SCENE_COMPONENT_TYPE_VISUAL_MESH_MSFT = 3, + XR_SCENE_COMPONENT_TYPE_COLLIDER_MESH_MSFT = 4, + XR_SCENE_COMPONENT_TYPE_SERIALIZED_SCENE_FRAGMENT_MSFT = 1000098000, + XR_SCENE_COMPONENT_TYPE_MAX_ENUM_MSFT = 0x7FFFFFFF +} XrSceneComponentTypeMSFT; + +typedef enum XrSceneObjectTypeMSFT { + XR_SCENE_OBJECT_TYPE_UNCATEGORIZED_MSFT = -1, + XR_SCENE_OBJECT_TYPE_BACKGROUND_MSFT = 1, + XR_SCENE_OBJECT_TYPE_WALL_MSFT = 2, + XR_SCENE_OBJECT_TYPE_FLOOR_MSFT = 3, + XR_SCENE_OBJECT_TYPE_CEILING_MSFT = 4, + XR_SCENE_OBJECT_TYPE_PLATFORM_MSFT = 5, + XR_SCENE_OBJECT_TYPE_INFERRED_MSFT = 6, + XR_SCENE_OBJECT_TYPE_MAX_ENUM_MSFT = 0x7FFFFFFF +} XrSceneObjectTypeMSFT; + +typedef enum XrScenePlaneAlignmentTypeMSFT { + XR_SCENE_PLANE_ALIGNMENT_TYPE_NON_ORTHOGONAL_MSFT = 0, + XR_SCENE_PLANE_ALIGNMENT_TYPE_HORIZONTAL_MSFT = 1, + XR_SCENE_PLANE_ALIGNMENT_TYPE_VERTICAL_MSFT = 2, + XR_SCENE_PLANE_ALIGNMENT_TYPE_MAX_ENUM_MSFT = 0x7FFFFFFF +} XrScenePlaneAlignmentTypeMSFT; + +typedef enum XrSceneComputeStateMSFT { + XR_SCENE_COMPUTE_STATE_NONE_MSFT = 0, + XR_SCENE_COMPUTE_STATE_UPDATING_MSFT = 1, + XR_SCENE_COMPUTE_STATE_COMPLETED_MSFT = 2, + XR_SCENE_COMPUTE_STATE_COMPLETED_WITH_ERROR_MSFT = 3, + XR_SCENE_COMPUTE_STATE_MAX_ENUM_MSFT = 0x7FFFFFFF +} XrSceneComputeStateMSFT; +typedef struct XrUuidMSFT { + uint8_t bytes[16]; +} XrUuidMSFT; + +typedef struct XrSceneObserverCreateInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; +} XrSceneObserverCreateInfoMSFT; + +typedef struct XrSceneCreateInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; +} XrSceneCreateInfoMSFT; + +typedef struct XrSceneSphereBoundMSFT { + XrVector3f center; + float radius; +} XrSceneSphereBoundMSFT; + +typedef struct XrSceneOrientedBoxBoundMSFT { + XrPosef pose; + XrVector3f extents; +} XrSceneOrientedBoxBoundMSFT; + +typedef struct XrSceneFrustumBoundMSFT { + XrPosef pose; + XrFovf fov; + float farDistance; +} XrSceneFrustumBoundMSFT; + +typedef struct XrSceneBoundsMSFT { + XrSpace space; + XrTime time; + uint32_t sphereCount; + const XrSceneSphereBoundMSFT* spheres; + uint32_t boxCount; + const XrSceneOrientedBoxBoundMSFT* boxes; + uint32_t frustumCount; + const XrSceneFrustumBoundMSFT* frustums; +} XrSceneBoundsMSFT; + +typedef struct XrNewSceneComputeInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + uint32_t requestedFeatureCount; + const XrSceneComputeFeatureMSFT* requestedFeatures; + XrSceneComputeConsistencyMSFT consistency; + XrSceneBoundsMSFT bounds; +} XrNewSceneComputeInfoMSFT; + +// XrVisualMeshComputeLodInfoMSFT extends XrNewSceneComputeInfoMSFT +typedef struct XrVisualMeshComputeLodInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrMeshComputeLodMSFT lod; +} XrVisualMeshComputeLodInfoMSFT; + +typedef struct XrSceneComponentMSFT { + XrSceneComponentTypeMSFT componentType; + XrUuidMSFT id; + XrUuidMSFT parentId; + XrTime updateTime; +} XrSceneComponentMSFT; + +typedef struct XrSceneComponentsMSFT { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint32_t componentCapacityInput; + uint32_t componentCountOutput; + XrSceneComponentMSFT* components; +} XrSceneComponentsMSFT; + +typedef struct XrSceneComponentsGetInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSceneComponentTypeMSFT componentType; +} XrSceneComponentsGetInfoMSFT; + +typedef struct XrSceneComponentLocationMSFT { + XrSpaceLocationFlags flags; + XrPosef pose; +} XrSceneComponentLocationMSFT; + +typedef struct XrSceneComponentLocationsMSFT { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint32_t locationCount; + XrSceneComponentLocationMSFT* locations; +} XrSceneComponentLocationsMSFT; + +typedef struct XrSceneComponentsLocateInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSpace baseSpace; + XrTime time; + uint32_t componentIdCount; + const XrUuidMSFT* componentIds; +} XrSceneComponentsLocateInfoMSFT; + +typedef struct XrSceneObjectMSFT { + XrSceneObjectTypeMSFT objectType; +} XrSceneObjectMSFT; + +// XrSceneObjectsMSFT extends XrSceneComponentsMSFT +typedef struct XrSceneObjectsMSFT { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint32_t sceneObjectCount; + XrSceneObjectMSFT* sceneObjects; +} XrSceneObjectsMSFT; + +// XrSceneComponentParentFilterInfoMSFT extends XrSceneComponentsGetInfoMSFT +typedef struct XrSceneComponentParentFilterInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrUuidMSFT parentId; +} XrSceneComponentParentFilterInfoMSFT; + +// XrSceneObjectTypesFilterInfoMSFT extends XrSceneComponentsGetInfoMSFT +typedef struct XrSceneObjectTypesFilterInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + uint32_t objectTypeCount; + const XrSceneObjectTypeMSFT* objectTypes; +} XrSceneObjectTypesFilterInfoMSFT; + +typedef struct XrScenePlaneMSFT { + XrScenePlaneAlignmentTypeMSFT alignment; + XrExtent2Df size; + uint64_t meshBufferId; + XrBool32 supportsIndicesUint16; +} XrScenePlaneMSFT; + +// XrScenePlanesMSFT extends XrSceneComponentsMSFT +typedef struct XrScenePlanesMSFT { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint32_t scenePlaneCount; + XrScenePlaneMSFT* scenePlanes; +} XrScenePlanesMSFT; + +// XrScenePlaneAlignmentFilterInfoMSFT extends XrSceneComponentsGetInfoMSFT +typedef struct XrScenePlaneAlignmentFilterInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + uint32_t alignmentCount; + const XrScenePlaneAlignmentTypeMSFT* alignments; +} XrScenePlaneAlignmentFilterInfoMSFT; + +typedef struct XrSceneMeshMSFT { + uint64_t meshBufferId; + XrBool32 supportsIndicesUint16; +} XrSceneMeshMSFT; + +// XrSceneMeshesMSFT extends XrSceneComponentsMSFT +typedef struct XrSceneMeshesMSFT { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint32_t sceneMeshCount; + XrSceneMeshMSFT* sceneMeshes; +} XrSceneMeshesMSFT; + +typedef struct XrSceneMeshBuffersGetInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + uint64_t meshBufferId; +} XrSceneMeshBuffersGetInfoMSFT; + +typedef struct XrSceneMeshBuffersMSFT { + XrStructureType type; + void* XR_MAY_ALIAS next; +} XrSceneMeshBuffersMSFT; + +typedef struct XrSceneMeshVertexBufferMSFT { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint32_t vertexCapacityInput; + uint32_t vertexCountOutput; + XrVector3f* vertices; +} XrSceneMeshVertexBufferMSFT; + +typedef struct XrSceneMeshIndicesUint32MSFT { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint32_t indexCapacityInput; + uint32_t indexCountOutput; + uint32_t* indices; +} XrSceneMeshIndicesUint32MSFT; + +typedef struct XrSceneMeshIndicesUint16MSFT { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint32_t indexCapacityInput; + uint32_t indexCountOutput; + uint16_t* indices; +} XrSceneMeshIndicesUint16MSFT; + +typedef XrResult (XRAPI_PTR *PFN_xrEnumerateSceneComputeFeaturesMSFT)(XrInstance instance, XrSystemId systemId, uint32_t featureCapacityInput, uint32_t* featureCountOutput, XrSceneComputeFeatureMSFT* features); +typedef XrResult (XRAPI_PTR *PFN_xrCreateSceneObserverMSFT)(XrSession session, const XrSceneObserverCreateInfoMSFT* createInfo, XrSceneObserverMSFT* sceneObserver); +typedef XrResult (XRAPI_PTR *PFN_xrDestroySceneObserverMSFT)(XrSceneObserverMSFT sceneObserver); +typedef XrResult (XRAPI_PTR *PFN_xrCreateSceneMSFT)(XrSceneObserverMSFT sceneObserver, const XrSceneCreateInfoMSFT* createInfo, XrSceneMSFT* scene); +typedef XrResult (XRAPI_PTR *PFN_xrDestroySceneMSFT)(XrSceneMSFT scene); +typedef XrResult (XRAPI_PTR *PFN_xrComputeNewSceneMSFT)(XrSceneObserverMSFT sceneObserver, const XrNewSceneComputeInfoMSFT* computeInfo); +typedef XrResult (XRAPI_PTR *PFN_xrGetSceneComputeStateMSFT)(XrSceneObserverMSFT sceneObserver, XrSceneComputeStateMSFT* state); +typedef XrResult (XRAPI_PTR *PFN_xrGetSceneComponentsMSFT)(XrSceneMSFT scene, const XrSceneComponentsGetInfoMSFT* getInfo, XrSceneComponentsMSFT* components); +typedef XrResult (XRAPI_PTR *PFN_xrLocateSceneComponentsMSFT)(XrSceneMSFT scene, const XrSceneComponentsLocateInfoMSFT* locateInfo, XrSceneComponentLocationsMSFT* locations); +typedef XrResult (XRAPI_PTR *PFN_xrGetSceneMeshBuffersMSFT)(XrSceneMSFT scene, const XrSceneMeshBuffersGetInfoMSFT* getInfo, XrSceneMeshBuffersMSFT* buffers); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateSceneComputeFeaturesMSFT( + XrInstance instance, + XrSystemId systemId, + uint32_t featureCapacityInput, + uint32_t* featureCountOutput, + XrSceneComputeFeatureMSFT* features); + +XRAPI_ATTR XrResult XRAPI_CALL xrCreateSceneObserverMSFT( + XrSession session, + const XrSceneObserverCreateInfoMSFT* createInfo, + XrSceneObserverMSFT* sceneObserver); + +XRAPI_ATTR XrResult XRAPI_CALL xrDestroySceneObserverMSFT( + XrSceneObserverMSFT sceneObserver); + +XRAPI_ATTR XrResult XRAPI_CALL xrCreateSceneMSFT( + XrSceneObserverMSFT sceneObserver, + const XrSceneCreateInfoMSFT* createInfo, + XrSceneMSFT* scene); + +XRAPI_ATTR XrResult XRAPI_CALL xrDestroySceneMSFT( + XrSceneMSFT scene); + +XRAPI_ATTR XrResult XRAPI_CALL xrComputeNewSceneMSFT( + XrSceneObserverMSFT sceneObserver, + const XrNewSceneComputeInfoMSFT* computeInfo); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetSceneComputeStateMSFT( + XrSceneObserverMSFT sceneObserver, + XrSceneComputeStateMSFT* state); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetSceneComponentsMSFT( + XrSceneMSFT scene, + const XrSceneComponentsGetInfoMSFT* getInfo, + XrSceneComponentsMSFT* components); + +XRAPI_ATTR XrResult XRAPI_CALL xrLocateSceneComponentsMSFT( + XrSceneMSFT scene, + const XrSceneComponentsLocateInfoMSFT* locateInfo, + XrSceneComponentLocationsMSFT* locations); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetSceneMeshBuffersMSFT( + XrSceneMSFT scene, + const XrSceneMeshBuffersGetInfoMSFT* getInfo, + XrSceneMeshBuffersMSFT* buffers); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_MSFT_scene_understanding_serialization 1 +#define XR_MSFT_scene_understanding_serialization_SPEC_VERSION 2 +#define XR_MSFT_SCENE_UNDERSTANDING_SERIALIZATION_EXTENSION_NAME "XR_MSFT_scene_understanding_serialization" +typedef struct XrSerializedSceneFragmentDataGetInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrUuidMSFT sceneFragmentId; +} XrSerializedSceneFragmentDataGetInfoMSFT; + +typedef struct XrDeserializeSceneFragmentMSFT { + uint32_t bufferSize; + const uint8_t* buffer; +} XrDeserializeSceneFragmentMSFT; + +typedef struct XrSceneDeserializeInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + uint32_t fragmentCount; + const XrDeserializeSceneFragmentMSFT* fragments; +} XrSceneDeserializeInfoMSFT; + +typedef XrResult (XRAPI_PTR *PFN_xrDeserializeSceneMSFT)(XrSceneObserverMSFT sceneObserver, const XrSceneDeserializeInfoMSFT* deserializeInfo); +typedef XrResult (XRAPI_PTR *PFN_xrGetSerializedSceneFragmentDataMSFT)(XrSceneMSFT scene, const XrSerializedSceneFragmentDataGetInfoMSFT* getInfo, uint32_t countInput, uint32_t* readOutput, uint8_t* buffer); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrDeserializeSceneMSFT( + XrSceneObserverMSFT sceneObserver, + const XrSceneDeserializeInfoMSFT* deserializeInfo); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetSerializedSceneFragmentDataMSFT( + XrSceneMSFT scene, + const XrSerializedSceneFragmentDataGetInfoMSFT* getInfo, + uint32_t countInput, + uint32_t* readOutput, + uint8_t* buffer); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_FB_display_refresh_rate 1 +#define XR_FB_display_refresh_rate_SPEC_VERSION 1 +#define XR_FB_DISPLAY_REFRESH_RATE_EXTENSION_NAME "XR_FB_display_refresh_rate" +typedef struct XrEventDataDisplayRefreshRateChangedFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + float fromDisplayRefreshRate; + float toDisplayRefreshRate; +} XrEventDataDisplayRefreshRateChangedFB; + +typedef XrResult (XRAPI_PTR *PFN_xrEnumerateDisplayRefreshRatesFB)(XrSession session, uint32_t displayRefreshRateCapacityInput, uint32_t* displayRefreshRateCountOutput, float* displayRefreshRates); +typedef XrResult (XRAPI_PTR *PFN_xrGetDisplayRefreshRateFB)(XrSession session, float* displayRefreshRate); +typedef XrResult (XRAPI_PTR *PFN_xrRequestDisplayRefreshRateFB)(XrSession session, float displayRefreshRate); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateDisplayRefreshRatesFB( + XrSession session, + uint32_t displayRefreshRateCapacityInput, + uint32_t* displayRefreshRateCountOutput, + float* displayRefreshRates); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetDisplayRefreshRateFB( + XrSession session, + float* displayRefreshRate); + +XRAPI_ATTR XrResult XRAPI_CALL xrRequestDisplayRefreshRateFB( + XrSession session, + float displayRefreshRate); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_HTC_vive_cosmos_controller_interaction 1 +#define XR_HTC_vive_cosmos_controller_interaction_SPEC_VERSION 1 +#define XR_HTC_VIVE_COSMOS_CONTROLLER_INTERACTION_EXTENSION_NAME "XR_HTC_vive_cosmos_controller_interaction" + + +#define XR_HTCX_vive_tracker_interaction 1 +#define XR_HTCX_vive_tracker_interaction_SPEC_VERSION 1 +#define XR_HTCX_VIVE_TRACKER_INTERACTION_EXTENSION_NAME "XR_HTCX_vive_tracker_interaction" +typedef struct XrViveTrackerPathsHTCX { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrPath persistentPath; + XrPath rolePath; +} XrViveTrackerPathsHTCX; + +typedef struct XrEventDataViveTrackerConnectedHTCX { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrViveTrackerPathsHTCX* paths; +} XrEventDataViveTrackerConnectedHTCX; + +typedef XrResult (XRAPI_PTR *PFN_xrEnumerateViveTrackerPathsHTCX)(XrInstance instance, uint32_t pathCapacityInput, uint32_t* pathCountOutput, XrViveTrackerPathsHTCX* paths); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateViveTrackerPathsHTCX( + XrInstance instance, + uint32_t pathCapacityInput, + uint32_t* pathCountOutput, + XrViveTrackerPathsHTCX* paths); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_HTC_facial_tracking 1 + +#define XR_FACIAL_EXPRESSION_EYE_COUNT_HTC 14 + + +#define XR_FACIAL_EXPRESSION_LIP_COUNT_HTC 37 + +XR_DEFINE_HANDLE(XrFacialTrackerHTC) +#define XR_HTC_facial_tracking_SPEC_VERSION 1 +#define XR_HTC_FACIAL_TRACKING_EXTENSION_NAME "XR_HTC_facial_tracking" + +typedef enum XrEyeExpressionHTC { + XR_EYE_EXPRESSION_LEFT_BLINK_HTC = 0, + XR_EYE_EXPRESSION_LEFT_WIDE_HTC = 1, + XR_EYE_EXPRESSION_RIGHT_BLINK_HTC = 2, + XR_EYE_EXPRESSION_RIGHT_WIDE_HTC = 3, + XR_EYE_EXPRESSION_LEFT_SQUEEZE_HTC = 4, + XR_EYE_EXPRESSION_RIGHT_SQUEEZE_HTC = 5, + XR_EYE_EXPRESSION_LEFT_DOWN_HTC = 6, + XR_EYE_EXPRESSION_RIGHT_DOWN_HTC = 7, + XR_EYE_EXPRESSION_LEFT_OUT_HTC = 8, + XR_EYE_EXPRESSION_RIGHT_IN_HTC = 9, + XR_EYE_EXPRESSION_LEFT_IN_HTC = 10, + XR_EYE_EXPRESSION_RIGHT_OUT_HTC = 11, + XR_EYE_EXPRESSION_LEFT_UP_HTC = 12, + XR_EYE_EXPRESSION_RIGHT_UP_HTC = 13, + XR_EYE_EXPRESSION_MAX_ENUM_HTC = 0x7FFFFFFF +} XrEyeExpressionHTC; + +typedef enum XrLipExpressionHTC { + XR_LIP_EXPRESSION_JAW_RIGHT_HTC = 0, + XR_LIP_EXPRESSION_JAW_LEFT_HTC = 1, + XR_LIP_EXPRESSION_JAW_FORWARD_HTC = 2, + XR_LIP_EXPRESSION_JAW_OPEN_HTC = 3, + XR_LIP_EXPRESSION_MOUTH_APE_SHAPE_HTC = 4, + XR_LIP_EXPRESSION_MOUTH_UPPER_RIGHT_HTC = 5, + XR_LIP_EXPRESSION_MOUTH_UPPER_LEFT_HTC = 6, + XR_LIP_EXPRESSION_MOUTH_LOWER_RIGHT_HTC = 7, + XR_LIP_EXPRESSION_MOUTH_LOWER_LEFT_HTC = 8, + XR_LIP_EXPRESSION_MOUTH_UPPER_OVERTURN_HTC = 9, + XR_LIP_EXPRESSION_MOUTH_LOWER_OVERTURN_HTC = 10, + XR_LIP_EXPRESSION_MOUTH_POUT_HTC = 11, + XR_LIP_EXPRESSION_MOUTH_SMILE_RIGHT_HTC = 12, + XR_LIP_EXPRESSION_MOUTH_SMILE_LEFT_HTC = 13, + XR_LIP_EXPRESSION_MOUTH_SAD_RIGHT_HTC = 14, + XR_LIP_EXPRESSION_MOUTH_SAD_LEFT_HTC = 15, + XR_LIP_EXPRESSION_CHEEK_PUFF_RIGHT_HTC = 16, + XR_LIP_EXPRESSION_CHEEK_PUFF_LEFT_HTC = 17, + XR_LIP_EXPRESSION_CHEEK_SUCK_HTC = 18, + XR_LIP_EXPRESSION_MOUTH_UPPER_UPRIGHT_HTC = 19, + XR_LIP_EXPRESSION_MOUTH_UPPER_UPLEFT_HTC = 20, + XR_LIP_EXPRESSION_MOUTH_LOWER_DOWNRIGHT_HTC = 21, + XR_LIP_EXPRESSION_MOUTH_LOWER_DOWNLEFT_HTC = 22, + XR_LIP_EXPRESSION_MOUTH_UPPER_INSIDE_HTC = 23, + XR_LIP_EXPRESSION_MOUTH_LOWER_INSIDE_HTC = 24, + XR_LIP_EXPRESSION_MOUTH_LOWER_OVERLAY_HTC = 25, + XR_LIP_EXPRESSION_TONGUE_LONGSTEP1_HTC = 26, + XR_LIP_EXPRESSION_TONGUE_LEFT_HTC = 27, + XR_LIP_EXPRESSION_TONGUE_RIGHT_HTC = 28, + XR_LIP_EXPRESSION_TONGUE_UP_HTC = 29, + XR_LIP_EXPRESSION_TONGUE_DOWN_HTC = 30, + XR_LIP_EXPRESSION_TONGUE_ROLL_HTC = 31, + XR_LIP_EXPRESSION_TONGUE_LONGSTEP2_HTC = 32, + XR_LIP_EXPRESSION_TONGUE_UPRIGHT_MORPH_HTC = 33, + XR_LIP_EXPRESSION_TONGUE_UPLEFT_MORPH_HTC = 34, + XR_LIP_EXPRESSION_TONGUE_DOWNRIGHT_MORPH_HTC = 35, + XR_LIP_EXPRESSION_TONGUE_DOWNLEFT_MORPH_HTC = 36, + XR_LIP_EXPRESSION_MAX_ENUM_HTC = 0x7FFFFFFF +} XrLipExpressionHTC; + +typedef enum XrFacialTrackingTypeHTC { + XR_FACIAL_TRACKING_TYPE_EYE_DEFAULT_HTC = 1, + XR_FACIAL_TRACKING_TYPE_LIP_DEFAULT_HTC = 2, + XR_FACIAL_TRACKING_TYPE_MAX_ENUM_HTC = 0x7FFFFFFF +} XrFacialTrackingTypeHTC; +// XrSystemFacialTrackingPropertiesHTC extends XrSystemProperties +typedef struct XrSystemFacialTrackingPropertiesHTC { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrBool32 supportEyeFacialTracking; + XrBool32 supportLipFacialTracking; +} XrSystemFacialTrackingPropertiesHTC; + +typedef struct XrFacialExpressionsHTC { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrBool32 isActive; + XrTime sampleTime; + uint32_t expressionCount; + float* expressionWeightings; +} XrFacialExpressionsHTC; + +typedef struct XrFacialTrackerCreateInfoHTC { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrFacialTrackingTypeHTC facialTrackingType; +} XrFacialTrackerCreateInfoHTC; + +typedef XrResult (XRAPI_PTR *PFN_xrCreateFacialTrackerHTC)(XrSession session, const XrFacialTrackerCreateInfoHTC* createInfo, XrFacialTrackerHTC* facialTracker); +typedef XrResult (XRAPI_PTR *PFN_xrDestroyFacialTrackerHTC)(XrFacialTrackerHTC facialTracker); +typedef XrResult (XRAPI_PTR *PFN_xrGetFacialExpressionsHTC)(XrFacialTrackerHTC facialTracker, XrFacialExpressionsHTC* facialExpressions); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrCreateFacialTrackerHTC( + XrSession session, + const XrFacialTrackerCreateInfoHTC* createInfo, + XrFacialTrackerHTC* facialTracker); + +XRAPI_ATTR XrResult XRAPI_CALL xrDestroyFacialTrackerHTC( + XrFacialTrackerHTC facialTracker); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetFacialExpressionsHTC( + XrFacialTrackerHTC facialTracker, + XrFacialExpressionsHTC* facialExpressions); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_HTC_vive_focus3_controller_interaction 1 +#define XR_HTC_vive_focus3_controller_interaction_SPEC_VERSION 2 +#define XR_HTC_VIVE_FOCUS3_CONTROLLER_INTERACTION_EXTENSION_NAME "XR_HTC_vive_focus3_controller_interaction" + + +#define XR_HTC_hand_interaction 1 +#define XR_HTC_hand_interaction_SPEC_VERSION 1 +#define XR_HTC_HAND_INTERACTION_EXTENSION_NAME "XR_HTC_hand_interaction" + + +#define XR_HTC_vive_wrist_tracker_interaction 1 +#define XR_HTC_vive_wrist_tracker_interaction_SPEC_VERSION 1 +#define XR_HTC_VIVE_WRIST_TRACKER_INTERACTION_EXTENSION_NAME "XR_HTC_vive_wrist_tracker_interaction" + + +#define XR_FB_color_space 1 +#define XR_FB_color_space_SPEC_VERSION 3 +#define XR_FB_COLOR_SPACE_EXTENSION_NAME "XR_FB_color_space" + +typedef enum XrColorSpaceFB { + XR_COLOR_SPACE_UNMANAGED_FB = 0, + XR_COLOR_SPACE_REC2020_FB = 1, + XR_COLOR_SPACE_REC709_FB = 2, + XR_COLOR_SPACE_RIFT_CV1_FB = 3, + XR_COLOR_SPACE_RIFT_S_FB = 4, + XR_COLOR_SPACE_QUEST_FB = 5, + XR_COLOR_SPACE_P3_FB = 6, + XR_COLOR_SPACE_ADOBE_RGB_FB = 7, + XR_COLOR_SPACE_MAX_ENUM_FB = 0x7FFFFFFF +} XrColorSpaceFB; +// XrSystemColorSpacePropertiesFB extends XrSystemProperties +typedef struct XrSystemColorSpacePropertiesFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrColorSpaceFB colorSpace; +} XrSystemColorSpacePropertiesFB; + +typedef XrResult (XRAPI_PTR *PFN_xrEnumerateColorSpacesFB)(XrSession session, uint32_t colorSpaceCapacityInput, uint32_t* colorSpaceCountOutput, XrColorSpaceFB* colorSpaces); +typedef XrResult (XRAPI_PTR *PFN_xrSetColorSpaceFB)(XrSession session, const XrColorSpaceFB colorspace); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateColorSpacesFB( + XrSession session, + uint32_t colorSpaceCapacityInput, + uint32_t* colorSpaceCountOutput, + XrColorSpaceFB* colorSpaces); + +XRAPI_ATTR XrResult XRAPI_CALL xrSetColorSpaceFB( + XrSession session, + const XrColorSpaceFB colorspace); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_FB_hand_tracking_mesh 1 +#define XR_FB_hand_tracking_mesh_SPEC_VERSION 3 +#define XR_FB_HAND_TRACKING_MESH_EXTENSION_NAME "XR_FB_hand_tracking_mesh" +typedef struct XrVector4sFB { + int16_t x; + int16_t y; + int16_t z; + int16_t w; +} XrVector4sFB; + +typedef struct XrHandTrackingMeshFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint32_t jointCapacityInput; + uint32_t jointCountOutput; + XrPosef* jointBindPoses; + float* jointRadii; + XrHandJointEXT* jointParents; + uint32_t vertexCapacityInput; + uint32_t vertexCountOutput; + XrVector3f* vertexPositions; + XrVector3f* vertexNormals; + XrVector2f* vertexUVs; + XrVector4sFB* vertexBlendIndices; + XrVector4f* vertexBlendWeights; + uint32_t indexCapacityInput; + uint32_t indexCountOutput; + int16_t* indices; +} XrHandTrackingMeshFB; + +// XrHandTrackingScaleFB extends XrHandJointLocationsEXT +typedef struct XrHandTrackingScaleFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + float sensorOutput; + float currentOutput; + XrBool32 overrideHandScale; + float overrideValueInput; +} XrHandTrackingScaleFB; + +typedef XrResult (XRAPI_PTR *PFN_xrGetHandMeshFB)(XrHandTrackerEXT handTracker, XrHandTrackingMeshFB* mesh); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrGetHandMeshFB( + XrHandTrackerEXT handTracker, + XrHandTrackingMeshFB* mesh); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_FB_hand_tracking_aim 1 +#define XR_FB_hand_tracking_aim_SPEC_VERSION 2 +#define XR_FB_HAND_TRACKING_AIM_EXTENSION_NAME "XR_FB_hand_tracking_aim" +typedef XrFlags64 XrHandTrackingAimFlagsFB; + +// Flag bits for XrHandTrackingAimFlagsFB +static const XrHandTrackingAimFlagsFB XR_HAND_TRACKING_AIM_COMPUTED_BIT_FB = 0x00000001; +static const XrHandTrackingAimFlagsFB XR_HAND_TRACKING_AIM_VALID_BIT_FB = 0x00000002; +static const XrHandTrackingAimFlagsFB XR_HAND_TRACKING_AIM_INDEX_PINCHING_BIT_FB = 0x00000004; +static const XrHandTrackingAimFlagsFB XR_HAND_TRACKING_AIM_MIDDLE_PINCHING_BIT_FB = 0x00000008; +static const XrHandTrackingAimFlagsFB XR_HAND_TRACKING_AIM_RING_PINCHING_BIT_FB = 0x00000010; +static const XrHandTrackingAimFlagsFB XR_HAND_TRACKING_AIM_LITTLE_PINCHING_BIT_FB = 0x00000020; +static const XrHandTrackingAimFlagsFB XR_HAND_TRACKING_AIM_SYSTEM_GESTURE_BIT_FB = 0x00000040; +static const XrHandTrackingAimFlagsFB XR_HAND_TRACKING_AIM_DOMINANT_HAND_BIT_FB = 0x00000080; +static const XrHandTrackingAimFlagsFB XR_HAND_TRACKING_AIM_MENU_PRESSED_BIT_FB = 0x00000100; + +// XrHandTrackingAimStateFB extends XrHandJointLocationsEXT +typedef struct XrHandTrackingAimStateFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrHandTrackingAimFlagsFB status; + XrPosef aimPose; + float pinchStrengthIndex; + float pinchStrengthMiddle; + float pinchStrengthRing; + float pinchStrengthLittle; +} XrHandTrackingAimStateFB; + + + +#define XR_FB_hand_tracking_capsules 1 +#define XR_HAND_TRACKING_CAPSULE_POINT_COUNT_FB 2 +#define XR_HAND_TRACKING_CAPSULE_COUNT_FB 19 +#define XR_FB_hand_tracking_capsules_SPEC_VERSION 3 +#define XR_FB_HAND_TRACKING_CAPSULES_EXTENSION_NAME "XR_FB_hand_tracking_capsules" +#define XR_FB_HAND_TRACKING_CAPSULE_POINT_COUNT XR_HAND_TRACKING_CAPSULE_POINT_COUNT_FB +#define XR_FB_HAND_TRACKING_CAPSULE_COUNT XR_HAND_TRACKING_CAPSULE_COUNT_FB +typedef struct XrHandCapsuleFB { + XrVector3f points[XR_HAND_TRACKING_CAPSULE_POINT_COUNT_FB]; + float radius; + XrHandJointEXT joint; +} XrHandCapsuleFB; + +// XrHandTrackingCapsulesStateFB extends XrHandJointLocationsEXT +typedef struct XrHandTrackingCapsulesStateFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrHandCapsuleFB capsules[XR_HAND_TRACKING_CAPSULE_COUNT_FB]; +} XrHandTrackingCapsulesStateFB; + + + +#define XR_FB_spatial_entity 1 +XR_DEFINE_ATOM(XrAsyncRequestIdFB) +#define XR_UUID_SIZE_EXT 16 +#define XR_FB_spatial_entity_SPEC_VERSION 1 +#define XR_FB_SPATIAL_ENTITY_EXTENSION_NAME "XR_FB_spatial_entity" + +typedef enum XrSpaceComponentTypeFB { + XR_SPACE_COMPONENT_TYPE_LOCATABLE_FB = 0, + XR_SPACE_COMPONENT_TYPE_STORABLE_FB = 1, + XR_SPACE_COMPONENT_TYPE_BOUNDED_2D_FB = 3, + XR_SPACE_COMPONENT_TYPE_BOUNDED_3D_FB = 4, + XR_SPACE_COMPONENT_TYPE_SEMANTIC_LABELS_FB = 5, + XR_SPACE_COMPONENT_TYPE_ROOM_LAYOUT_FB = 6, + XR_SPACE_COMPONENT_TYPE_SPACE_CONTAINER_FB = 7, + XR_SPACE_COMPONENT_TYPE_MAX_ENUM_FB = 0x7FFFFFFF +} XrSpaceComponentTypeFB; +// XrSystemSpatialEntityPropertiesFB extends XrSystemProperties +typedef struct XrSystemSpatialEntityPropertiesFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrBool32 supportsSpatialEntity; +} XrSystemSpatialEntityPropertiesFB; + +typedef struct XrSpatialAnchorCreateInfoFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSpace space; + XrPosef poseInSpace; + XrTime time; +} XrSpatialAnchorCreateInfoFB; + +typedef struct XrSpaceComponentStatusSetInfoFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSpaceComponentTypeFB componentType; + XrBool32 enabled; + XrDuration timeout; +} XrSpaceComponentStatusSetInfoFB; + +typedef struct XrSpaceComponentStatusFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrBool32 enabled; + XrBool32 changePending; +} XrSpaceComponentStatusFB; + +typedef struct XrUuidEXT { + uint8_t data[XR_UUID_SIZE_EXT]; +} XrUuidEXT; + +typedef struct XrEventDataSpatialAnchorCreateCompleteFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrAsyncRequestIdFB requestId; + XrResult result; + XrSpace space; + XrUuidEXT uuid; +} XrEventDataSpatialAnchorCreateCompleteFB; + +typedef struct XrEventDataSpaceSetStatusCompleteFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrAsyncRequestIdFB requestId; + XrResult result; + XrSpace space; + XrUuidEXT uuid; + XrSpaceComponentTypeFB componentType; + XrBool32 enabled; +} XrEventDataSpaceSetStatusCompleteFB; + +typedef XrResult (XRAPI_PTR *PFN_xrCreateSpatialAnchorFB)(XrSession session, const XrSpatialAnchorCreateInfoFB* info, XrAsyncRequestIdFB* requestId); +typedef XrResult (XRAPI_PTR *PFN_xrGetSpaceUuidFB)(XrSpace space, XrUuidEXT* uuid); +typedef XrResult (XRAPI_PTR *PFN_xrEnumerateSpaceSupportedComponentsFB)(XrSpace space, uint32_t componentTypeCapacityInput, uint32_t* componentTypeCountOutput, XrSpaceComponentTypeFB* componentTypes); +typedef XrResult (XRAPI_PTR *PFN_xrSetSpaceComponentStatusFB)(XrSpace space, const XrSpaceComponentStatusSetInfoFB* info, XrAsyncRequestIdFB* requestId); +typedef XrResult (XRAPI_PTR *PFN_xrGetSpaceComponentStatusFB)(XrSpace space, XrSpaceComponentTypeFB componentType, XrSpaceComponentStatusFB* status); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrCreateSpatialAnchorFB( + XrSession session, + const XrSpatialAnchorCreateInfoFB* info, + XrAsyncRequestIdFB* requestId); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetSpaceUuidFB( + XrSpace space, + XrUuidEXT* uuid); + +XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateSpaceSupportedComponentsFB( + XrSpace space, + uint32_t componentTypeCapacityInput, + uint32_t* componentTypeCountOutput, + XrSpaceComponentTypeFB* componentTypes); + +XRAPI_ATTR XrResult XRAPI_CALL xrSetSpaceComponentStatusFB( + XrSpace space, + const XrSpaceComponentStatusSetInfoFB* info, + XrAsyncRequestIdFB* requestId); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetSpaceComponentStatusFB( + XrSpace space, + XrSpaceComponentTypeFB componentType, + XrSpaceComponentStatusFB* status); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_FB_foveation 1 +XR_DEFINE_HANDLE(XrFoveationProfileFB) +#define XR_FB_foveation_SPEC_VERSION 1 +#define XR_FB_FOVEATION_EXTENSION_NAME "XR_FB_foveation" +typedef XrFlags64 XrSwapchainCreateFoveationFlagsFB; + +// Flag bits for XrSwapchainCreateFoveationFlagsFB +static const XrSwapchainCreateFoveationFlagsFB XR_SWAPCHAIN_CREATE_FOVEATION_SCALED_BIN_BIT_FB = 0x00000001; +static const XrSwapchainCreateFoveationFlagsFB XR_SWAPCHAIN_CREATE_FOVEATION_FRAGMENT_DENSITY_MAP_BIT_FB = 0x00000002; + +typedef XrFlags64 XrSwapchainStateFoveationFlagsFB; + +// Flag bits for XrSwapchainStateFoveationFlagsFB + +typedef struct XrFoveationProfileCreateInfoFB { + XrStructureType type; + void* XR_MAY_ALIAS next; +} XrFoveationProfileCreateInfoFB; + +// XrSwapchainCreateInfoFoveationFB extends XrSwapchainCreateInfo +typedef struct XrSwapchainCreateInfoFoveationFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrSwapchainCreateFoveationFlagsFB flags; +} XrSwapchainCreateInfoFoveationFB; + +typedef struct XrSwapchainStateFoveationFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrSwapchainStateFoveationFlagsFB flags; + XrFoveationProfileFB profile; +} XrSwapchainStateFoveationFB; + +typedef XrResult (XRAPI_PTR *PFN_xrCreateFoveationProfileFB)(XrSession session, const XrFoveationProfileCreateInfoFB* createInfo, XrFoveationProfileFB* profile); +typedef XrResult (XRAPI_PTR *PFN_xrDestroyFoveationProfileFB)(XrFoveationProfileFB profile); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrCreateFoveationProfileFB( + XrSession session, + const XrFoveationProfileCreateInfoFB* createInfo, + XrFoveationProfileFB* profile); + +XRAPI_ATTR XrResult XRAPI_CALL xrDestroyFoveationProfileFB( + XrFoveationProfileFB profile); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_FB_foveation_configuration 1 +#define XR_FB_foveation_configuration_SPEC_VERSION 1 +#define XR_FB_FOVEATION_CONFIGURATION_EXTENSION_NAME "XR_FB_foveation_configuration" + +typedef enum XrFoveationLevelFB { + XR_FOVEATION_LEVEL_NONE_FB = 0, + XR_FOVEATION_LEVEL_LOW_FB = 1, + XR_FOVEATION_LEVEL_MEDIUM_FB = 2, + XR_FOVEATION_LEVEL_HIGH_FB = 3, + XR_FOVEATION_LEVEL_MAX_ENUM_FB = 0x7FFFFFFF +} XrFoveationLevelFB; + +typedef enum XrFoveationDynamicFB { + XR_FOVEATION_DYNAMIC_DISABLED_FB = 0, + XR_FOVEATION_DYNAMIC_LEVEL_ENABLED_FB = 1, + XR_FOVEATION_DYNAMIC_MAX_ENUM_FB = 0x7FFFFFFF +} XrFoveationDynamicFB; +// XrFoveationLevelProfileCreateInfoFB extends XrFoveationProfileCreateInfoFB +typedef struct XrFoveationLevelProfileCreateInfoFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrFoveationLevelFB level; + float verticalOffset; + XrFoveationDynamicFB dynamic; +} XrFoveationLevelProfileCreateInfoFB; + + + +#define XR_FB_keyboard_tracking 1 +#define XR_FB_keyboard_tracking_SPEC_VERSION 1 +#define XR_FB_KEYBOARD_TRACKING_EXTENSION_NAME "XR_FB_keyboard_tracking" +#define XR_MAX_KEYBOARD_TRACKING_NAME_SIZE_FB 128 +typedef XrFlags64 XrKeyboardTrackingFlagsFB; + +// Flag bits for XrKeyboardTrackingFlagsFB +static const XrKeyboardTrackingFlagsFB XR_KEYBOARD_TRACKING_EXISTS_BIT_FB = 0x00000001; +static const XrKeyboardTrackingFlagsFB XR_KEYBOARD_TRACKING_LOCAL_BIT_FB = 0x00000002; +static const XrKeyboardTrackingFlagsFB XR_KEYBOARD_TRACKING_REMOTE_BIT_FB = 0x00000004; +static const XrKeyboardTrackingFlagsFB XR_KEYBOARD_TRACKING_CONNECTED_BIT_FB = 0x00000008; + +typedef XrFlags64 XrKeyboardTrackingQueryFlagsFB; + +// Flag bits for XrKeyboardTrackingQueryFlagsFB +static const XrKeyboardTrackingQueryFlagsFB XR_KEYBOARD_TRACKING_QUERY_LOCAL_BIT_FB = 0x00000002; +static const XrKeyboardTrackingQueryFlagsFB XR_KEYBOARD_TRACKING_QUERY_REMOTE_BIT_FB = 0x00000004; + +// XrSystemKeyboardTrackingPropertiesFB extends XrSystemProperties +typedef struct XrSystemKeyboardTrackingPropertiesFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrBool32 supportsKeyboardTracking; +} XrSystemKeyboardTrackingPropertiesFB; + +typedef struct XrKeyboardTrackingDescriptionFB { + uint64_t trackedKeyboardId; + XrVector3f size; + XrKeyboardTrackingFlagsFB flags; + char name[XR_MAX_KEYBOARD_TRACKING_NAME_SIZE_FB]; +} XrKeyboardTrackingDescriptionFB; + +typedef struct XrKeyboardSpaceCreateInfoFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint64_t trackedKeyboardId; +} XrKeyboardSpaceCreateInfoFB; + +typedef struct XrKeyboardTrackingQueryFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrKeyboardTrackingQueryFlagsFB flags; +} XrKeyboardTrackingQueryFB; + +typedef XrResult (XRAPI_PTR *PFN_xrQuerySystemTrackedKeyboardFB)(XrSession session, const XrKeyboardTrackingQueryFB* queryInfo, XrKeyboardTrackingDescriptionFB* keyboard); +typedef XrResult (XRAPI_PTR *PFN_xrCreateKeyboardSpaceFB)(XrSession session, const XrKeyboardSpaceCreateInfoFB* createInfo, XrSpace* keyboardSpace); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrQuerySystemTrackedKeyboardFB( + XrSession session, + const XrKeyboardTrackingQueryFB* queryInfo, + XrKeyboardTrackingDescriptionFB* keyboard); + +XRAPI_ATTR XrResult XRAPI_CALL xrCreateKeyboardSpaceFB( + XrSession session, + const XrKeyboardSpaceCreateInfoFB* createInfo, + XrSpace* keyboardSpace); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_FB_triangle_mesh 1 +XR_DEFINE_HANDLE(XrTriangleMeshFB) +#define XR_FB_triangle_mesh_SPEC_VERSION 2 +#define XR_FB_TRIANGLE_MESH_EXTENSION_NAME "XR_FB_triangle_mesh" + +typedef enum XrWindingOrderFB { + XR_WINDING_ORDER_UNKNOWN_FB = 0, + XR_WINDING_ORDER_CW_FB = 1, + XR_WINDING_ORDER_CCW_FB = 2, + XR_WINDING_ORDER_MAX_ENUM_FB = 0x7FFFFFFF +} XrWindingOrderFB; +typedef XrFlags64 XrTriangleMeshFlagsFB; + +// Flag bits for XrTriangleMeshFlagsFB +static const XrTriangleMeshFlagsFB XR_TRIANGLE_MESH_MUTABLE_BIT_FB = 0x00000001; + +typedef struct XrTriangleMeshCreateInfoFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrTriangleMeshFlagsFB flags; + XrWindingOrderFB windingOrder; + uint32_t vertexCount; + const XrVector3f* vertexBuffer; + uint32_t triangleCount; + const uint32_t* indexBuffer; +} XrTriangleMeshCreateInfoFB; + +typedef XrResult (XRAPI_PTR *PFN_xrCreateTriangleMeshFB)(XrSession session, const XrTriangleMeshCreateInfoFB* createInfo, XrTriangleMeshFB* outTriangleMesh); +typedef XrResult (XRAPI_PTR *PFN_xrDestroyTriangleMeshFB)(XrTriangleMeshFB mesh); +typedef XrResult (XRAPI_PTR *PFN_xrTriangleMeshGetVertexBufferFB)(XrTriangleMeshFB mesh, XrVector3f** outVertexBuffer); +typedef XrResult (XRAPI_PTR *PFN_xrTriangleMeshGetIndexBufferFB)(XrTriangleMeshFB mesh, uint32_t** outIndexBuffer); +typedef XrResult (XRAPI_PTR *PFN_xrTriangleMeshBeginUpdateFB)(XrTriangleMeshFB mesh); +typedef XrResult (XRAPI_PTR *PFN_xrTriangleMeshEndUpdateFB)(XrTriangleMeshFB mesh, uint32_t vertexCount, uint32_t triangleCount); +typedef XrResult (XRAPI_PTR *PFN_xrTriangleMeshBeginVertexBufferUpdateFB)(XrTriangleMeshFB mesh, uint32_t* outVertexCount); +typedef XrResult (XRAPI_PTR *PFN_xrTriangleMeshEndVertexBufferUpdateFB)(XrTriangleMeshFB mesh); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrCreateTriangleMeshFB( + XrSession session, + const XrTriangleMeshCreateInfoFB* createInfo, + XrTriangleMeshFB* outTriangleMesh); + +XRAPI_ATTR XrResult XRAPI_CALL xrDestroyTriangleMeshFB( + XrTriangleMeshFB mesh); + +XRAPI_ATTR XrResult XRAPI_CALL xrTriangleMeshGetVertexBufferFB( + XrTriangleMeshFB mesh, + XrVector3f** outVertexBuffer); + +XRAPI_ATTR XrResult XRAPI_CALL xrTriangleMeshGetIndexBufferFB( + XrTriangleMeshFB mesh, + uint32_t** outIndexBuffer); + +XRAPI_ATTR XrResult XRAPI_CALL xrTriangleMeshBeginUpdateFB( + XrTriangleMeshFB mesh); + +XRAPI_ATTR XrResult XRAPI_CALL xrTriangleMeshEndUpdateFB( + XrTriangleMeshFB mesh, + uint32_t vertexCount, + uint32_t triangleCount); + +XRAPI_ATTR XrResult XRAPI_CALL xrTriangleMeshBeginVertexBufferUpdateFB( + XrTriangleMeshFB mesh, + uint32_t* outVertexCount); + +XRAPI_ATTR XrResult XRAPI_CALL xrTriangleMeshEndVertexBufferUpdateFB( + XrTriangleMeshFB mesh); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_FB_passthrough 1 +XR_DEFINE_HANDLE(XrPassthroughFB) +XR_DEFINE_HANDLE(XrPassthroughLayerFB) +XR_DEFINE_HANDLE(XrGeometryInstanceFB) +#define XR_FB_passthrough_SPEC_VERSION 3 +#define XR_FB_PASSTHROUGH_EXTENSION_NAME "XR_FB_passthrough" +#define XR_PASSTHROUGH_COLOR_MAP_MONO_SIZE_FB 256 + +typedef enum XrPassthroughLayerPurposeFB { + XR_PASSTHROUGH_LAYER_PURPOSE_RECONSTRUCTION_FB = 0, + XR_PASSTHROUGH_LAYER_PURPOSE_PROJECTED_FB = 1, + XR_PASSTHROUGH_LAYER_PURPOSE_TRACKED_KEYBOARD_HANDS_FB = 1000203001, + XR_PASSTHROUGH_LAYER_PURPOSE_TRACKED_KEYBOARD_MASKED_HANDS_FB = 1000203002, + XR_PASSTHROUGH_LAYER_PURPOSE_MAX_ENUM_FB = 0x7FFFFFFF +} XrPassthroughLayerPurposeFB; +typedef XrFlags64 XrPassthroughCapabilityFlagsFB; + +// Flag bits for XrPassthroughCapabilityFlagsFB +static const XrPassthroughCapabilityFlagsFB XR_PASSTHROUGH_CAPABILITY_BIT_FB = 0x00000001; +static const XrPassthroughCapabilityFlagsFB XR_PASSTHROUGH_CAPABILITY_COLOR_BIT_FB = 0x00000002; +static const XrPassthroughCapabilityFlagsFB XR_PASSTHROUGH_CAPABILITY_LAYER_DEPTH_BIT_FB = 0x00000004; + +typedef XrFlags64 XrPassthroughFlagsFB; + +// Flag bits for XrPassthroughFlagsFB +static const XrPassthroughFlagsFB XR_PASSTHROUGH_IS_RUNNING_AT_CREATION_BIT_FB = 0x00000001; +static const XrPassthroughFlagsFB XR_PASSTHROUGH_LAYER_DEPTH_BIT_FB = 0x00000002; + +typedef XrFlags64 XrPassthroughStateChangedFlagsFB; + +// Flag bits for XrPassthroughStateChangedFlagsFB +static const XrPassthroughStateChangedFlagsFB XR_PASSTHROUGH_STATE_CHANGED_REINIT_REQUIRED_BIT_FB = 0x00000001; +static const XrPassthroughStateChangedFlagsFB XR_PASSTHROUGH_STATE_CHANGED_NON_RECOVERABLE_ERROR_BIT_FB = 0x00000002; +static const XrPassthroughStateChangedFlagsFB XR_PASSTHROUGH_STATE_CHANGED_RECOVERABLE_ERROR_BIT_FB = 0x00000004; +static const XrPassthroughStateChangedFlagsFB XR_PASSTHROUGH_STATE_CHANGED_RESTORED_ERROR_BIT_FB = 0x00000008; + +// XrSystemPassthroughPropertiesFB extends XrSystemProperties +typedef struct XrSystemPassthroughPropertiesFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrBool32 supportsPassthrough; +} XrSystemPassthroughPropertiesFB; + +// XrSystemPassthroughProperties2FB extends XrSystemProperties +typedef struct XrSystemPassthroughProperties2FB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrPassthroughCapabilityFlagsFB capabilities; +} XrSystemPassthroughProperties2FB; + +typedef struct XrPassthroughCreateInfoFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrPassthroughFlagsFB flags; +} XrPassthroughCreateInfoFB; + +typedef struct XrPassthroughLayerCreateInfoFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrPassthroughFB passthrough; + XrPassthroughFlagsFB flags; + XrPassthroughLayerPurposeFB purpose; +} XrPassthroughLayerCreateInfoFB; + +// XrCompositionLayerPassthroughFB extends XrCompositionLayerBaseHeader +typedef struct XrCompositionLayerPassthroughFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrCompositionLayerFlags flags; + XrSpace space; + XrPassthroughLayerFB layerHandle; +} XrCompositionLayerPassthroughFB; + +typedef struct XrGeometryInstanceCreateInfoFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrPassthroughLayerFB layer; + XrTriangleMeshFB mesh; + XrSpace baseSpace; + XrPosef pose; + XrVector3f scale; +} XrGeometryInstanceCreateInfoFB; + +typedef struct XrGeometryInstanceTransformFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSpace baseSpace; + XrTime time; + XrPosef pose; + XrVector3f scale; +} XrGeometryInstanceTransformFB; + +typedef struct XrPassthroughStyleFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + float textureOpacityFactor; + XrColor4f edgeColor; +} XrPassthroughStyleFB; + +// XrPassthroughColorMapMonoToRgbaFB extends XrPassthroughStyleFB +typedef struct XrPassthroughColorMapMonoToRgbaFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrColor4f textureColorMap[XR_PASSTHROUGH_COLOR_MAP_MONO_SIZE_FB]; +} XrPassthroughColorMapMonoToRgbaFB; + +// XrPassthroughColorMapMonoToMonoFB extends XrPassthroughStyleFB +typedef struct XrPassthroughColorMapMonoToMonoFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + uint8_t textureColorMap[XR_PASSTHROUGH_COLOR_MAP_MONO_SIZE_FB]; +} XrPassthroughColorMapMonoToMonoFB; + +// XrPassthroughBrightnessContrastSaturationFB extends XrPassthroughStyleFB +typedef struct XrPassthroughBrightnessContrastSaturationFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + float brightness; + float contrast; + float saturation; +} XrPassthroughBrightnessContrastSaturationFB; + +typedef struct XrEventDataPassthroughStateChangedFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrPassthroughStateChangedFlagsFB flags; +} XrEventDataPassthroughStateChangedFB; + +typedef XrResult (XRAPI_PTR *PFN_xrCreatePassthroughFB)(XrSession session, const XrPassthroughCreateInfoFB* createInfo, XrPassthroughFB* outPassthrough); +typedef XrResult (XRAPI_PTR *PFN_xrDestroyPassthroughFB)(XrPassthroughFB passthrough); +typedef XrResult (XRAPI_PTR *PFN_xrPassthroughStartFB)(XrPassthroughFB passthrough); +typedef XrResult (XRAPI_PTR *PFN_xrPassthroughPauseFB)(XrPassthroughFB passthrough); +typedef XrResult (XRAPI_PTR *PFN_xrCreatePassthroughLayerFB)(XrSession session, const XrPassthroughLayerCreateInfoFB* createInfo, XrPassthroughLayerFB* outLayer); +typedef XrResult (XRAPI_PTR *PFN_xrDestroyPassthroughLayerFB)(XrPassthroughLayerFB layer); +typedef XrResult (XRAPI_PTR *PFN_xrPassthroughLayerPauseFB)(XrPassthroughLayerFB layer); +typedef XrResult (XRAPI_PTR *PFN_xrPassthroughLayerResumeFB)(XrPassthroughLayerFB layer); +typedef XrResult (XRAPI_PTR *PFN_xrPassthroughLayerSetStyleFB)(XrPassthroughLayerFB layer, const XrPassthroughStyleFB* style); +typedef XrResult (XRAPI_PTR *PFN_xrCreateGeometryInstanceFB)(XrSession session, const XrGeometryInstanceCreateInfoFB* createInfo, XrGeometryInstanceFB* outGeometryInstance); +typedef XrResult (XRAPI_PTR *PFN_xrDestroyGeometryInstanceFB)(XrGeometryInstanceFB instance); +typedef XrResult (XRAPI_PTR *PFN_xrGeometryInstanceSetTransformFB)(XrGeometryInstanceFB instance, const XrGeometryInstanceTransformFB* transformation); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrCreatePassthroughFB( + XrSession session, + const XrPassthroughCreateInfoFB* createInfo, + XrPassthroughFB* outPassthrough); + +XRAPI_ATTR XrResult XRAPI_CALL xrDestroyPassthroughFB( + XrPassthroughFB passthrough); + +XRAPI_ATTR XrResult XRAPI_CALL xrPassthroughStartFB( + XrPassthroughFB passthrough); + +XRAPI_ATTR XrResult XRAPI_CALL xrPassthroughPauseFB( + XrPassthroughFB passthrough); + +XRAPI_ATTR XrResult XRAPI_CALL xrCreatePassthroughLayerFB( + XrSession session, + const XrPassthroughLayerCreateInfoFB* createInfo, + XrPassthroughLayerFB* outLayer); + +XRAPI_ATTR XrResult XRAPI_CALL xrDestroyPassthroughLayerFB( + XrPassthroughLayerFB layer); + +XRAPI_ATTR XrResult XRAPI_CALL xrPassthroughLayerPauseFB( + XrPassthroughLayerFB layer); + +XRAPI_ATTR XrResult XRAPI_CALL xrPassthroughLayerResumeFB( + XrPassthroughLayerFB layer); + +XRAPI_ATTR XrResult XRAPI_CALL xrPassthroughLayerSetStyleFB( + XrPassthroughLayerFB layer, + const XrPassthroughStyleFB* style); + +XRAPI_ATTR XrResult XRAPI_CALL xrCreateGeometryInstanceFB( + XrSession session, + const XrGeometryInstanceCreateInfoFB* createInfo, + XrGeometryInstanceFB* outGeometryInstance); + +XRAPI_ATTR XrResult XRAPI_CALL xrDestroyGeometryInstanceFB( + XrGeometryInstanceFB instance); + +XRAPI_ATTR XrResult XRAPI_CALL xrGeometryInstanceSetTransformFB( + XrGeometryInstanceFB instance, + const XrGeometryInstanceTransformFB* transformation); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_FB_render_model 1 + +#define XR_NULL_RENDER_MODEL_KEY_FB 0 + +XR_DEFINE_ATOM(XrRenderModelKeyFB) +#define XR_FB_render_model_SPEC_VERSION 3 +#define XR_FB_RENDER_MODEL_EXTENSION_NAME "XR_FB_render_model" +#define XR_MAX_RENDER_MODEL_NAME_SIZE_FB 64 +typedef XrFlags64 XrRenderModelFlagsFB; + +// Flag bits for XrRenderModelFlagsFB +static const XrRenderModelFlagsFB XR_RENDER_MODEL_SUPPORTS_GLTF_2_0_SUBSET_1_BIT_FB = 0x00000001; +static const XrRenderModelFlagsFB XR_RENDER_MODEL_SUPPORTS_GLTF_2_0_SUBSET_2_BIT_FB = 0x00000002; + +typedef struct XrRenderModelPathInfoFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrPath path; +} XrRenderModelPathInfoFB; + +typedef struct XrRenderModelPropertiesFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint32_t vendorId; + char modelName[XR_MAX_RENDER_MODEL_NAME_SIZE_FB]; + XrRenderModelKeyFB modelKey; + uint32_t modelVersion; + XrRenderModelFlagsFB flags; +} XrRenderModelPropertiesFB; + +typedef struct XrRenderModelBufferFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint32_t bufferCapacityInput; + uint32_t bufferCountOutput; + uint8_t* buffer; +} XrRenderModelBufferFB; + +typedef struct XrRenderModelLoadInfoFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrRenderModelKeyFB modelKey; +} XrRenderModelLoadInfoFB; + +// XrSystemRenderModelPropertiesFB extends XrSystemProperties +typedef struct XrSystemRenderModelPropertiesFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrBool32 supportsRenderModelLoading; +} XrSystemRenderModelPropertiesFB; + +// XrRenderModelCapabilitiesRequestFB extends XrSystemProperties +typedef struct XrRenderModelCapabilitiesRequestFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrRenderModelFlagsFB flags; +} XrRenderModelCapabilitiesRequestFB; + +typedef XrResult (XRAPI_PTR *PFN_xrEnumerateRenderModelPathsFB)(XrSession session, uint32_t pathCapacityInput, uint32_t* pathCountOutput, XrRenderModelPathInfoFB* paths); +typedef XrResult (XRAPI_PTR *PFN_xrGetRenderModelPropertiesFB)(XrSession session, XrPath path, XrRenderModelPropertiesFB* properties); +typedef XrResult (XRAPI_PTR *PFN_xrLoadRenderModelFB)(XrSession session, const XrRenderModelLoadInfoFB* info, XrRenderModelBufferFB* buffer); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateRenderModelPathsFB( + XrSession session, + uint32_t pathCapacityInput, + uint32_t* pathCountOutput, + XrRenderModelPathInfoFB* paths); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetRenderModelPropertiesFB( + XrSession session, + XrPath path, + XrRenderModelPropertiesFB* properties); + +XRAPI_ATTR XrResult XRAPI_CALL xrLoadRenderModelFB( + XrSession session, + const XrRenderModelLoadInfoFB* info, + XrRenderModelBufferFB* buffer); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_VARJO_foveated_rendering 1 +#define XR_VARJO_foveated_rendering_SPEC_VERSION 2 +#define XR_VARJO_FOVEATED_RENDERING_EXTENSION_NAME "XR_VARJO_foveated_rendering" +// XrViewLocateFoveatedRenderingVARJO extends XrViewLocateInfo +typedef struct XrViewLocateFoveatedRenderingVARJO { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrBool32 foveatedRenderingActive; +} XrViewLocateFoveatedRenderingVARJO; + +// XrFoveatedViewConfigurationViewVARJO extends XrViewConfigurationView +typedef struct XrFoveatedViewConfigurationViewVARJO { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrBool32 foveatedRenderingActive; +} XrFoveatedViewConfigurationViewVARJO; + +// XrSystemFoveatedRenderingPropertiesVARJO extends XrSystemProperties +typedef struct XrSystemFoveatedRenderingPropertiesVARJO { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrBool32 supportsFoveatedRendering; +} XrSystemFoveatedRenderingPropertiesVARJO; + + + +#define XR_VARJO_composition_layer_depth_test 1 +#define XR_VARJO_composition_layer_depth_test_SPEC_VERSION 2 +#define XR_VARJO_COMPOSITION_LAYER_DEPTH_TEST_EXTENSION_NAME "XR_VARJO_composition_layer_depth_test" +// XrCompositionLayerDepthTestVARJO extends XrCompositionLayerProjection +typedef struct XrCompositionLayerDepthTestVARJO { + XrStructureType type; + const void* XR_MAY_ALIAS next; + float depthTestRangeNearZ; + float depthTestRangeFarZ; +} XrCompositionLayerDepthTestVARJO; + + + +#define XR_VARJO_environment_depth_estimation 1 +#define XR_VARJO_environment_depth_estimation_SPEC_VERSION 1 +#define XR_VARJO_ENVIRONMENT_DEPTH_ESTIMATION_EXTENSION_NAME "XR_VARJO_environment_depth_estimation" +typedef XrResult (XRAPI_PTR *PFN_xrSetEnvironmentDepthEstimationVARJO)(XrSession session, XrBool32 enabled); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrSetEnvironmentDepthEstimationVARJO( + XrSession session, + XrBool32 enabled); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_VARJO_marker_tracking 1 +#define XR_VARJO_marker_tracking_SPEC_VERSION 1 +#define XR_VARJO_MARKER_TRACKING_EXTENSION_NAME "XR_VARJO_marker_tracking" +// XrSystemMarkerTrackingPropertiesVARJO extends XrSystemProperties +typedef struct XrSystemMarkerTrackingPropertiesVARJO { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrBool32 supportsMarkerTracking; +} XrSystemMarkerTrackingPropertiesVARJO; + +typedef struct XrEventDataMarkerTrackingUpdateVARJO { + XrStructureType type; + const void* XR_MAY_ALIAS next; + uint64_t markerId; + XrBool32 isActive; + XrBool32 isPredicted; + XrTime time; +} XrEventDataMarkerTrackingUpdateVARJO; + +typedef struct XrMarkerSpaceCreateInfoVARJO { + XrStructureType type; + const void* XR_MAY_ALIAS next; + uint64_t markerId; + XrPosef poseInMarkerSpace; +} XrMarkerSpaceCreateInfoVARJO; + +typedef XrResult (XRAPI_PTR *PFN_xrSetMarkerTrackingVARJO)(XrSession session, XrBool32 enabled); +typedef XrResult (XRAPI_PTR *PFN_xrSetMarkerTrackingTimeoutVARJO)(XrSession session, uint64_t markerId, XrDuration timeout); +typedef XrResult (XRAPI_PTR *PFN_xrSetMarkerTrackingPredictionVARJO)(XrSession session, uint64_t markerId, XrBool32 enabled); +typedef XrResult (XRAPI_PTR *PFN_xrGetMarkerSizeVARJO)(XrSession session, uint64_t markerId, XrExtent2Df* size); +typedef XrResult (XRAPI_PTR *PFN_xrCreateMarkerSpaceVARJO)(XrSession session, const XrMarkerSpaceCreateInfoVARJO* createInfo, XrSpace* space); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrSetMarkerTrackingVARJO( + XrSession session, + XrBool32 enabled); + +XRAPI_ATTR XrResult XRAPI_CALL xrSetMarkerTrackingTimeoutVARJO( + XrSession session, + uint64_t markerId, + XrDuration timeout); + +XRAPI_ATTR XrResult XRAPI_CALL xrSetMarkerTrackingPredictionVARJO( + XrSession session, + uint64_t markerId, + XrBool32 enabled); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetMarkerSizeVARJO( + XrSession session, + uint64_t markerId, + XrExtent2Df* size); + +XRAPI_ATTR XrResult XRAPI_CALL xrCreateMarkerSpaceVARJO( + XrSession session, + const XrMarkerSpaceCreateInfoVARJO* createInfo, + XrSpace* space); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_VARJO_view_offset 1 +#define XR_VARJO_view_offset_SPEC_VERSION 1 +#define XR_VARJO_VIEW_OFFSET_EXTENSION_NAME "XR_VARJO_view_offset" +typedef XrResult (XRAPI_PTR *PFN_xrSetViewOffsetVARJO)(XrSession session, float offset); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrSetViewOffsetVARJO( + XrSession session, + float offset); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_ML_ml2_controller_interaction 1 +#define XR_ML_ml2_controller_interaction_SPEC_VERSION 1 +#define XR_ML_ML2_CONTROLLER_INTERACTION_EXTENSION_NAME "XR_ML_ml2_controller_interaction" + + +#define XR_MSFT_spatial_anchor_persistence 1 +XR_DEFINE_HANDLE(XrSpatialAnchorStoreConnectionMSFT) +#define XR_MAX_SPATIAL_ANCHOR_NAME_SIZE_MSFT 256 +#define XR_MSFT_spatial_anchor_persistence_SPEC_VERSION 2 +#define XR_MSFT_SPATIAL_ANCHOR_PERSISTENCE_EXTENSION_NAME "XR_MSFT_spatial_anchor_persistence" +typedef struct XrSpatialAnchorPersistenceNameMSFT { + char name[XR_MAX_SPATIAL_ANCHOR_NAME_SIZE_MSFT]; +} XrSpatialAnchorPersistenceNameMSFT; + +typedef struct XrSpatialAnchorPersistenceInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSpatialAnchorPersistenceNameMSFT spatialAnchorPersistenceName; + XrSpatialAnchorMSFT spatialAnchor; +} XrSpatialAnchorPersistenceInfoMSFT; + +typedef struct XrSpatialAnchorFromPersistedAnchorCreateInfoMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSpatialAnchorStoreConnectionMSFT spatialAnchorStore; + XrSpatialAnchorPersistenceNameMSFT spatialAnchorPersistenceName; +} XrSpatialAnchorFromPersistedAnchorCreateInfoMSFT; + +typedef XrResult (XRAPI_PTR *PFN_xrCreateSpatialAnchorStoreConnectionMSFT)(XrSession session, XrSpatialAnchorStoreConnectionMSFT* spatialAnchorStore); +typedef XrResult (XRAPI_PTR *PFN_xrDestroySpatialAnchorStoreConnectionMSFT)(XrSpatialAnchorStoreConnectionMSFT spatialAnchorStore); +typedef XrResult (XRAPI_PTR *PFN_xrPersistSpatialAnchorMSFT)(XrSpatialAnchorStoreConnectionMSFT spatialAnchorStore, const XrSpatialAnchorPersistenceInfoMSFT* spatialAnchorPersistenceInfo); +typedef XrResult (XRAPI_PTR *PFN_xrEnumeratePersistedSpatialAnchorNamesMSFT)(XrSpatialAnchorStoreConnectionMSFT spatialAnchorStore, uint32_t spatialAnchorNamesCapacityInput, uint32_t* spatialAnchorNamesCountOutput, XrSpatialAnchorPersistenceNameMSFT* persistedAnchorNames); +typedef XrResult (XRAPI_PTR *PFN_xrCreateSpatialAnchorFromPersistedNameMSFT)(XrSession session, const XrSpatialAnchorFromPersistedAnchorCreateInfoMSFT* spatialAnchorCreateInfo, XrSpatialAnchorMSFT* spatialAnchor); +typedef XrResult (XRAPI_PTR *PFN_xrUnpersistSpatialAnchorMSFT)(XrSpatialAnchorStoreConnectionMSFT spatialAnchorStore, const XrSpatialAnchorPersistenceNameMSFT* spatialAnchorPersistenceName); +typedef XrResult (XRAPI_PTR *PFN_xrClearSpatialAnchorStoreMSFT)(XrSpatialAnchorStoreConnectionMSFT spatialAnchorStore); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrCreateSpatialAnchorStoreConnectionMSFT( + XrSession session, + XrSpatialAnchorStoreConnectionMSFT* spatialAnchorStore); + +XRAPI_ATTR XrResult XRAPI_CALL xrDestroySpatialAnchorStoreConnectionMSFT( + XrSpatialAnchorStoreConnectionMSFT spatialAnchorStore); + +XRAPI_ATTR XrResult XRAPI_CALL xrPersistSpatialAnchorMSFT( + XrSpatialAnchorStoreConnectionMSFT spatialAnchorStore, + const XrSpatialAnchorPersistenceInfoMSFT* spatialAnchorPersistenceInfo); + +XRAPI_ATTR XrResult XRAPI_CALL xrEnumeratePersistedSpatialAnchorNamesMSFT( + XrSpatialAnchorStoreConnectionMSFT spatialAnchorStore, + uint32_t spatialAnchorNamesCapacityInput, + uint32_t* spatialAnchorNamesCountOutput, + XrSpatialAnchorPersistenceNameMSFT* persistedAnchorNames); + +XRAPI_ATTR XrResult XRAPI_CALL xrCreateSpatialAnchorFromPersistedNameMSFT( + XrSession session, + const XrSpatialAnchorFromPersistedAnchorCreateInfoMSFT* spatialAnchorCreateInfo, + XrSpatialAnchorMSFT* spatialAnchor); + +XRAPI_ATTR XrResult XRAPI_CALL xrUnpersistSpatialAnchorMSFT( + XrSpatialAnchorStoreConnectionMSFT spatialAnchorStore, + const XrSpatialAnchorPersistenceNameMSFT* spatialAnchorPersistenceName); + +XRAPI_ATTR XrResult XRAPI_CALL xrClearSpatialAnchorStoreMSFT( + XrSpatialAnchorStoreConnectionMSFT spatialAnchorStore); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_ULTRALEAP_hand_tracking_forearm 1 + +#define XR_HAND_FOREARM_JOINT_COUNT_ULTRALEAP 27 + +#define XR_ULTRALEAP_hand_tracking_forearm_SPEC_VERSION 1 +#define XR_ULTRALEAP_HAND_TRACKING_FOREARM_EXTENSION_NAME "XR_ULTRALEAP_hand_tracking_forearm" + +typedef enum XrHandForearmJointULTRALEAP { + XR_HAND_FOREARM_JOINT_PALM_ULTRALEAP = 0, + XR_HAND_FOREARM_JOINT_WRIST_ULTRALEAP = 1, + XR_HAND_FOREARM_JOINT_THUMB_METACARPAL_ULTRALEAP = 2, + XR_HAND_FOREARM_JOINT_THUMB_PROXIMAL_ULTRALEAP = 3, + XR_HAND_FOREARM_JOINT_THUMB_DISTAL_ULTRALEAP = 4, + XR_HAND_FOREARM_JOINT_THUMB_TIP_ULTRALEAP = 5, + XR_HAND_FOREARM_JOINT_INDEX_METACARPAL_ULTRALEAP = 6, + XR_HAND_FOREARM_JOINT_INDEX_PROXIMAL_ULTRALEAP = 7, + XR_HAND_FOREARM_JOINT_INDEX_INTERMEDIATE_ULTRALEAP = 8, + XR_HAND_FOREARM_JOINT_INDEX_DISTAL_ULTRALEAP = 9, + XR_HAND_FOREARM_JOINT_INDEX_TIP_ULTRALEAP = 10, + XR_HAND_FOREARM_JOINT_MIDDLE_METACARPAL_ULTRALEAP = 11, + XR_HAND_FOREARM_JOINT_MIDDLE_PROXIMAL_ULTRALEAP = 12, + XR_HAND_FOREARM_JOINT_MIDDLE_INTERMEDIATE_ULTRALEAP = 13, + XR_HAND_FOREARM_JOINT_MIDDLE_DISTAL_ULTRALEAP = 14, + XR_HAND_FOREARM_JOINT_MIDDLE_TIP_ULTRALEAP = 15, + XR_HAND_FOREARM_JOINT_RING_METACARPAL_ULTRALEAP = 16, + XR_HAND_FOREARM_JOINT_RING_PROXIMAL_ULTRALEAP = 17, + XR_HAND_FOREARM_JOINT_RING_INTERMEDIATE_ULTRALEAP = 18, + XR_HAND_FOREARM_JOINT_RING_DISTAL_ULTRALEAP = 19, + XR_HAND_FOREARM_JOINT_RING_TIP_ULTRALEAP = 20, + XR_HAND_FOREARM_JOINT_LITTLE_METACARPAL_ULTRALEAP = 21, + XR_HAND_FOREARM_JOINT_LITTLE_PROXIMAL_ULTRALEAP = 22, + XR_HAND_FOREARM_JOINT_LITTLE_INTERMEDIATE_ULTRALEAP = 23, + XR_HAND_FOREARM_JOINT_LITTLE_DISTAL_ULTRALEAP = 24, + XR_HAND_FOREARM_JOINT_LITTLE_TIP_ULTRALEAP = 25, + XR_HAND_FOREARM_JOINT_ELBOW_ULTRALEAP = 26, + XR_HAND_FOREARM_JOINT_MAX_ENUM_ULTRALEAP = 0x7FFFFFFF +} XrHandForearmJointULTRALEAP; + + +#define XR_FB_spatial_entity_query 1 +#define XR_FB_spatial_entity_query_SPEC_VERSION 1 +#define XR_FB_SPATIAL_ENTITY_QUERY_EXTENSION_NAME "XR_FB_spatial_entity_query" + +typedef enum XrSpaceQueryActionFB { + XR_SPACE_QUERY_ACTION_LOAD_FB = 0, + XR_SPACE_QUERY_ACTION_MAX_ENUM_FB = 0x7FFFFFFF +} XrSpaceQueryActionFB; + +typedef enum XrSpaceStorageLocationFB { + XR_SPACE_STORAGE_LOCATION_INVALID_FB = 0, + XR_SPACE_STORAGE_LOCATION_LOCAL_FB = 1, + XR_SPACE_STORAGE_LOCATION_MAX_ENUM_FB = 0x7FFFFFFF +} XrSpaceStorageLocationFB; +typedef struct XR_MAY_ALIAS XrSpaceQueryInfoBaseHeaderFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; +} XrSpaceQueryInfoBaseHeaderFB; + +typedef struct XR_MAY_ALIAS XrSpaceFilterInfoBaseHeaderFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; +} XrSpaceFilterInfoBaseHeaderFB; + +typedef struct XrSpaceQueryInfoFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSpaceQueryActionFB queryAction; + uint32_t maxResultCount; + XrDuration timeout; + const XrSpaceFilterInfoBaseHeaderFB* filter; + const XrSpaceFilterInfoBaseHeaderFB* excludeFilter; +} XrSpaceQueryInfoFB; + +// XrSpaceStorageLocationFilterInfoFB extends XrSpaceFilterInfoBaseHeaderFB +typedef struct XrSpaceStorageLocationFilterInfoFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSpaceStorageLocationFB location; +} XrSpaceStorageLocationFilterInfoFB; + +typedef struct XrSpaceUuidFilterInfoFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + uint32_t uuidCount; + XrUuidEXT* uuids; +} XrSpaceUuidFilterInfoFB; + +typedef struct XrSpaceComponentFilterInfoFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSpaceComponentTypeFB componentType; +} XrSpaceComponentFilterInfoFB; + +typedef struct XrSpaceQueryResultFB { + XrSpace space; + XrUuidEXT uuid; +} XrSpaceQueryResultFB; + +typedef struct XrSpaceQueryResultsFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint32_t resultCapacityInput; + uint32_t resultCountOutput; + XrSpaceQueryResultFB* results; +} XrSpaceQueryResultsFB; + +typedef struct XrEventDataSpaceQueryResultsAvailableFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrAsyncRequestIdFB requestId; +} XrEventDataSpaceQueryResultsAvailableFB; + +typedef struct XrEventDataSpaceQueryCompleteFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrAsyncRequestIdFB requestId; + XrResult result; +} XrEventDataSpaceQueryCompleteFB; + +typedef XrResult (XRAPI_PTR *PFN_xrQuerySpacesFB)(XrSession session, const XrSpaceQueryInfoBaseHeaderFB* info, XrAsyncRequestIdFB* requestId); +typedef XrResult (XRAPI_PTR *PFN_xrRetrieveSpaceQueryResultsFB)(XrSession session, XrAsyncRequestIdFB requestId, XrSpaceQueryResultsFB* results); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrQuerySpacesFB( + XrSession session, + const XrSpaceQueryInfoBaseHeaderFB* info, + XrAsyncRequestIdFB* requestId); + +XRAPI_ATTR XrResult XRAPI_CALL xrRetrieveSpaceQueryResultsFB( + XrSession session, + XrAsyncRequestIdFB requestId, + XrSpaceQueryResultsFB* results); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_FB_spatial_entity_storage 1 +#define XR_FB_spatial_entity_storage_SPEC_VERSION 1 +#define XR_FB_SPATIAL_ENTITY_STORAGE_EXTENSION_NAME "XR_FB_spatial_entity_storage" + +typedef enum XrSpacePersistenceModeFB { + XR_SPACE_PERSISTENCE_MODE_INVALID_FB = 0, + XR_SPACE_PERSISTENCE_MODE_INDEFINITE_FB = 1, + XR_SPACE_PERSISTENCE_MODE_MAX_ENUM_FB = 0x7FFFFFFF +} XrSpacePersistenceModeFB; +typedef struct XrSpaceSaveInfoFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSpace space; + XrSpaceStorageLocationFB location; + XrSpacePersistenceModeFB persistenceMode; +} XrSpaceSaveInfoFB; + +typedef struct XrSpaceEraseInfoFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSpace space; + XrSpaceStorageLocationFB location; +} XrSpaceEraseInfoFB; + +typedef struct XrEventDataSpaceSaveCompleteFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrAsyncRequestIdFB requestId; + XrResult result; + XrSpace space; + XrUuidEXT uuid; + XrSpaceStorageLocationFB location; +} XrEventDataSpaceSaveCompleteFB; + +typedef struct XrEventDataSpaceEraseCompleteFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrAsyncRequestIdFB requestId; + XrResult result; + XrSpace space; + XrUuidEXT uuid; + XrSpaceStorageLocationFB location; +} XrEventDataSpaceEraseCompleteFB; + +typedef XrResult (XRAPI_PTR *PFN_xrSaveSpaceFB)(XrSession session, const XrSpaceSaveInfoFB* info, XrAsyncRequestIdFB* requestId); +typedef XrResult (XRAPI_PTR *PFN_xrEraseSpaceFB)(XrSession session, const XrSpaceEraseInfoFB* info, XrAsyncRequestIdFB* requestId); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrSaveSpaceFB( + XrSession session, + const XrSpaceSaveInfoFB* info, + XrAsyncRequestIdFB* requestId); + +XRAPI_ATTR XrResult XRAPI_CALL xrEraseSpaceFB( + XrSession session, + const XrSpaceEraseInfoFB* info, + XrAsyncRequestIdFB* requestId); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_FB_space_warp 1 +#define XR_FB_space_warp_SPEC_VERSION 2 +#define XR_FB_SPACE_WARP_EXTENSION_NAME "XR_FB_space_warp" +typedef XrFlags64 XrCompositionLayerSpaceWarpInfoFlagsFB; + +// Flag bits for XrCompositionLayerSpaceWarpInfoFlagsFB +static const XrCompositionLayerSpaceWarpInfoFlagsFB XR_COMPOSITION_LAYER_SPACE_WARP_INFO_FRAME_SKIP_BIT_FB = 0x00000001; + +// XrCompositionLayerSpaceWarpInfoFB extends XrCompositionLayerProjectionView +typedef struct XrCompositionLayerSpaceWarpInfoFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrCompositionLayerSpaceWarpInfoFlagsFB layerFlags; + XrSwapchainSubImage motionVectorSubImage; + XrPosef appSpaceDeltaPose; + XrSwapchainSubImage depthSubImage; + float minDepth; + float maxDepth; + float nearZ; + float farZ; +} XrCompositionLayerSpaceWarpInfoFB; + +// XrSystemSpaceWarpPropertiesFB extends XrSystemProperties +typedef struct XrSystemSpaceWarpPropertiesFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint32_t recommendedMotionVectorImageRectWidth; + uint32_t recommendedMotionVectorImageRectHeight; +} XrSystemSpaceWarpPropertiesFB; + + + +#define XR_FB_scene 1 +#define XR_FB_scene_SPEC_VERSION 1 +#define XR_FB_SCENE_EXTENSION_NAME "XR_FB_scene" +typedef struct XrExtent3DfFB { + float width; + float height; + float depth; +} XrExtent3DfFB; + +typedef struct XrOffset3DfFB { + float x; + float y; + float z; +} XrOffset3DfFB; + +typedef struct XrRect3DfFB { + XrOffset3DfFB offset; + XrExtent3DfFB extent; +} XrRect3DfFB; + +typedef struct XrSemanticLabelsFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + uint32_t bufferCapacityInput; + uint32_t bufferCountOutput; + char* buffer; +} XrSemanticLabelsFB; + +typedef struct XrRoomLayoutFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrUuidEXT floorUuid; + XrUuidEXT ceilingUuid; + uint32_t wallUuidCapacityInput; + uint32_t wallUuidCountOutput; + XrUuidEXT* wallUuids; +} XrRoomLayoutFB; + +typedef struct XrBoundary2DFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + uint32_t vertexCapacityInput; + uint32_t vertexCountOutput; + XrVector2f* vertices; +} XrBoundary2DFB; + +typedef XrResult (XRAPI_PTR *PFN_xrGetSpaceBoundingBox2DFB)(XrSession session, XrSpace space, XrRect2Df* boundingBox2DOutput); +typedef XrResult (XRAPI_PTR *PFN_xrGetSpaceBoundingBox3DFB)(XrSession session, XrSpace space, XrRect3DfFB* boundingBox3DOutput); +typedef XrResult (XRAPI_PTR *PFN_xrGetSpaceSemanticLabelsFB)(XrSession session, XrSpace space, XrSemanticLabelsFB* semanticLabelsOutput); +typedef XrResult (XRAPI_PTR *PFN_xrGetSpaceBoundary2DFB)(XrSession session, XrSpace space, XrBoundary2DFB* boundary2DOutput); +typedef XrResult (XRAPI_PTR *PFN_xrGetSpaceRoomLayoutFB)(XrSession session, XrSpace space, XrRoomLayoutFB* roomLayoutOutput); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrGetSpaceBoundingBox2DFB( + XrSession session, + XrSpace space, + XrRect2Df* boundingBox2DOutput); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetSpaceBoundingBox3DFB( + XrSession session, + XrSpace space, + XrRect3DfFB* boundingBox3DOutput); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetSpaceSemanticLabelsFB( + XrSession session, + XrSpace space, + XrSemanticLabelsFB* semanticLabelsOutput); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetSpaceBoundary2DFB( + XrSession session, + XrSpace space, + XrBoundary2DFB* boundary2DOutput); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetSpaceRoomLayoutFB( + XrSession session, + XrSpace space, + XrRoomLayoutFB* roomLayoutOutput); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_EXT_palm_pose 1 +#define XR_EXT_palm_pose_SPEC_VERSION 2 +#define XR_EXT_PALM_POSE_EXTENSION_NAME "XR_EXT_palm_pose" + + +#define XR_ALMALENCE_digital_lens_control 1 +#define XR_ALMALENCE_digital_lens_control_SPEC_VERSION 1 +#define XR_ALMALENCE_DIGITAL_LENS_CONTROL_EXTENSION_NAME "XR_ALMALENCE_digital_lens_control" +typedef XrFlags64 XrDigitalLensControlFlagsALMALENCE; + +// Flag bits for XrDigitalLensControlFlagsALMALENCE +static const XrDigitalLensControlFlagsALMALENCE XR_DIGITAL_LENS_CONTROL_PROCESSING_DISABLE_BIT_ALMALENCE = 0x00000001; + +typedef struct XrDigitalLensControlALMALENCE { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrDigitalLensControlFlagsALMALENCE flags; +} XrDigitalLensControlALMALENCE; + +typedef XrResult (XRAPI_PTR *PFN_xrSetDigitalLensControlALMALENCE)(XrSession session, const XrDigitalLensControlALMALENCE* digitalLensControl); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrSetDigitalLensControlALMALENCE( + XrSession session, + const XrDigitalLensControlALMALENCE* digitalLensControl); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_FB_spatial_entity_container 1 +#define XR_FB_spatial_entity_container_SPEC_VERSION 2 +#define XR_FB_SPATIAL_ENTITY_CONTAINER_EXTENSION_NAME "XR_FB_spatial_entity_container" +typedef struct XrSpaceContainerFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + uint32_t uuidCapacityInput; + uint32_t uuidCountOutput; + XrUuidEXT* uuids; +} XrSpaceContainerFB; + +typedef XrResult (XRAPI_PTR *PFN_xrGetSpaceContainerFB)(XrSession session, XrSpace space, XrSpaceContainerFB* spaceContainerOutput); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrGetSpaceContainerFB( + XrSession session, + XrSpace space, + XrSpaceContainerFB* spaceContainerOutput); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_FB_passthrough_keyboard_hands 1 +#define XR_FB_passthrough_keyboard_hands_SPEC_VERSION 2 +#define XR_FB_PASSTHROUGH_KEYBOARD_HANDS_EXTENSION_NAME "XR_FB_passthrough_keyboard_hands" +typedef struct XrPassthroughKeyboardHandsIntensityFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + float leftHandIntensity; + float rightHandIntensity; +} XrPassthroughKeyboardHandsIntensityFB; + +typedef XrResult (XRAPI_PTR *PFN_xrPassthroughLayerSetKeyboardHandsIntensityFB)(XrPassthroughLayerFB layer, const XrPassthroughKeyboardHandsIntensityFB* intensity); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrPassthroughLayerSetKeyboardHandsIntensityFB( + XrPassthroughLayerFB layer, + const XrPassthroughKeyboardHandsIntensityFB* intensity); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_FB_composition_layer_settings 1 +#define XR_FB_composition_layer_settings_SPEC_VERSION 1 +#define XR_FB_COMPOSITION_LAYER_SETTINGS_EXTENSION_NAME "XR_FB_composition_layer_settings" +typedef XrFlags64 XrCompositionLayerSettingsFlagsFB; + +// Flag bits for XrCompositionLayerSettingsFlagsFB +static const XrCompositionLayerSettingsFlagsFB XR_COMPOSITION_LAYER_SETTINGS_NORMAL_SUPER_SAMPLING_BIT_FB = 0x00000001; +static const XrCompositionLayerSettingsFlagsFB XR_COMPOSITION_LAYER_SETTINGS_QUALITY_SUPER_SAMPLING_BIT_FB = 0x00000002; +static const XrCompositionLayerSettingsFlagsFB XR_COMPOSITION_LAYER_SETTINGS_NORMAL_SHARPENING_BIT_FB = 0x00000004; +static const XrCompositionLayerSettingsFlagsFB XR_COMPOSITION_LAYER_SETTINGS_QUALITY_SHARPENING_BIT_FB = 0x00000008; + +// XrCompositionLayerSettingsFB extends XrCompositionLayerBaseHeader +typedef struct XrCompositionLayerSettingsFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrCompositionLayerSettingsFlagsFB layerFlags; +} XrCompositionLayerSettingsFB; + + + +#define XR_META_performance_metrics 1 +#define XR_META_performance_metrics_SPEC_VERSION 1 +#define XR_META_PERFORMANCE_METRICS_EXTENSION_NAME "XR_META_performance_metrics" + +typedef enum XrPerformanceMetricsCounterUnitMETA { + XR_PERFORMANCE_METRICS_COUNTER_UNIT_GENERIC_META = 0, + XR_PERFORMANCE_METRICS_COUNTER_UNIT_PERCENTAGE_META = 1, + XR_PERFORMANCE_METRICS_COUNTER_UNIT_MILLISECONDS_META = 2, + XR_PERFORMANCE_METRICS_COUNTER_UNIT_BYTES_META = 3, + XR_PERFORMANCE_METRICS_COUNTER_UNIT_HERTZ_META = 4, + XR_PERFORMANCE_METRICS_COUNTER_UNIT_MAX_ENUM_META = 0x7FFFFFFF +} XrPerformanceMetricsCounterUnitMETA; +typedef XrFlags64 XrPerformanceMetricsCounterFlagsMETA; + +// Flag bits for XrPerformanceMetricsCounterFlagsMETA +static const XrPerformanceMetricsCounterFlagsMETA XR_PERFORMANCE_METRICS_COUNTER_ANY_VALUE_VALID_BIT_META = 0x00000001; +static const XrPerformanceMetricsCounterFlagsMETA XR_PERFORMANCE_METRICS_COUNTER_UINT_VALUE_VALID_BIT_META = 0x00000002; +static const XrPerformanceMetricsCounterFlagsMETA XR_PERFORMANCE_METRICS_COUNTER_FLOAT_VALUE_VALID_BIT_META = 0x00000004; + +typedef struct XrPerformanceMetricsStateMETA { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrBool32 enabled; +} XrPerformanceMetricsStateMETA; + +typedef struct XrPerformanceMetricsCounterMETA { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrPerformanceMetricsCounterFlagsMETA counterFlags; + XrPerformanceMetricsCounterUnitMETA counterUnit; + uint32_t uintValue; + float floatValue; +} XrPerformanceMetricsCounterMETA; + +typedef XrResult (XRAPI_PTR *PFN_xrEnumeratePerformanceMetricsCounterPathsMETA)(XrInstance instance, uint32_t counterPathCapacityInput, uint32_t* counterPathCountOutput, XrPath* counterPaths); +typedef XrResult (XRAPI_PTR *PFN_xrSetPerformanceMetricsStateMETA)(XrSession session, const XrPerformanceMetricsStateMETA* state); +typedef XrResult (XRAPI_PTR *PFN_xrGetPerformanceMetricsStateMETA)(XrSession session, XrPerformanceMetricsStateMETA* state); +typedef XrResult (XRAPI_PTR *PFN_xrQueryPerformanceMetricsCounterMETA)(XrSession session, XrPath counterPath, XrPerformanceMetricsCounterMETA* counter); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrEnumeratePerformanceMetricsCounterPathsMETA( + XrInstance instance, + uint32_t counterPathCapacityInput, + uint32_t* counterPathCountOutput, + XrPath* counterPaths); + +XRAPI_ATTR XrResult XRAPI_CALL xrSetPerformanceMetricsStateMETA( + XrSession session, + const XrPerformanceMetricsStateMETA* state); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetPerformanceMetricsStateMETA( + XrSession session, + XrPerformanceMetricsStateMETA* state); + +XRAPI_ATTR XrResult XRAPI_CALL xrQueryPerformanceMetricsCounterMETA( + XrSession session, + XrPath counterPath, + XrPerformanceMetricsCounterMETA* counter); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ + + +#define XR_EXT_uuid 1 +#define XR_EXT_uuid_SPEC_VERSION 1 +#define XR_EXT_UUID_EXTENSION_NAME "XR_EXT_uuid" + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Plugins/MetaXR/Source/Thirdparty/OpenXR/include/khronos/openxr/openxr_platform.h b/Plugins/MetaXR/Source/Thirdparty/OpenXR/include/khronos/openxr/openxr_platform.h new file mode 100644 index 0000000..b3aabb2 --- /dev/null +++ b/Plugins/MetaXR/Source/Thirdparty/OpenXR/include/khronos/openxr/openxr_platform.h @@ -0,0 +1,690 @@ +#ifndef OPENXR_PLATFORM_H_ +#define OPENXR_PLATFORM_H_ 1 + +/* +** Copyright 2017-2022 The Khronos Group Inc. +** +** SPDX-License-Identifier: Apache-2.0 OR MIT +*/ + +/* +** This header is generated from the Khronos OpenXR XML API Registry. +** +*/ + +#include "openxr.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +#ifdef XR_USE_PLATFORM_ANDROID + +#define XR_KHR_android_thread_settings 1 +#define XR_KHR_android_thread_settings_SPEC_VERSION 5 +#define XR_KHR_ANDROID_THREAD_SETTINGS_EXTENSION_NAME "XR_KHR_android_thread_settings" + +typedef enum XrAndroidThreadTypeKHR { + XR_ANDROID_THREAD_TYPE_APPLICATION_MAIN_KHR = 1, + XR_ANDROID_THREAD_TYPE_APPLICATION_WORKER_KHR = 2, + XR_ANDROID_THREAD_TYPE_RENDERER_MAIN_KHR = 3, + XR_ANDROID_THREAD_TYPE_RENDERER_WORKER_KHR = 4, + XR_ANDROID_THREAD_TYPE_MAX_ENUM_KHR = 0x7FFFFFFF +} XrAndroidThreadTypeKHR; +typedef XrResult (XRAPI_PTR *PFN_xrSetAndroidApplicationThreadKHR)(XrSession session, XrAndroidThreadTypeKHR threadType, uint32_t threadId); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrSetAndroidApplicationThreadKHR( + XrSession session, + XrAndroidThreadTypeKHR threadType, + uint32_t threadId); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ +#endif /* XR_USE_PLATFORM_ANDROID */ + +#ifdef XR_USE_PLATFORM_ANDROID + +#define XR_KHR_android_surface_swapchain 1 +#define XR_KHR_android_surface_swapchain_SPEC_VERSION 4 +#define XR_KHR_ANDROID_SURFACE_SWAPCHAIN_EXTENSION_NAME "XR_KHR_android_surface_swapchain" +typedef XrResult (XRAPI_PTR *PFN_xrCreateSwapchainAndroidSurfaceKHR)(XrSession session, const XrSwapchainCreateInfo* info, XrSwapchain* swapchain, jobject* surface); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrCreateSwapchainAndroidSurfaceKHR( + XrSession session, + const XrSwapchainCreateInfo* info, + XrSwapchain* swapchain, + jobject* surface); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ +#endif /* XR_USE_PLATFORM_ANDROID */ + +#ifdef XR_USE_PLATFORM_ANDROID + +#define XR_KHR_android_create_instance 1 +#define XR_KHR_android_create_instance_SPEC_VERSION 3 +#define XR_KHR_ANDROID_CREATE_INSTANCE_EXTENSION_NAME "XR_KHR_android_create_instance" +// XrInstanceCreateInfoAndroidKHR extends XrInstanceCreateInfo +typedef struct XrInstanceCreateInfoAndroidKHR { + XrStructureType type; + const void* XR_MAY_ALIAS next; + void* XR_MAY_ALIAS applicationVM; + void* XR_MAY_ALIAS applicationActivity; +} XrInstanceCreateInfoAndroidKHR; + +#endif /* XR_USE_PLATFORM_ANDROID */ + +#ifdef XR_USE_GRAPHICS_API_VULKAN + +#define XR_KHR_vulkan_swapchain_format_list 1 +#define XR_KHR_vulkan_swapchain_format_list_SPEC_VERSION 4 +#define XR_KHR_VULKAN_SWAPCHAIN_FORMAT_LIST_EXTENSION_NAME "XR_KHR_vulkan_swapchain_format_list" +typedef struct XrVulkanSwapchainFormatListCreateInfoKHR { + XrStructureType type; + const void* XR_MAY_ALIAS next; + uint32_t viewFormatCount; + const VkFormat* viewFormats; +} XrVulkanSwapchainFormatListCreateInfoKHR; + +#endif /* XR_USE_GRAPHICS_API_VULKAN */ + +#ifdef XR_USE_GRAPHICS_API_OPENGL + +#define XR_KHR_opengl_enable 1 +#define XR_KHR_opengl_enable_SPEC_VERSION 10 +#define XR_KHR_OPENGL_ENABLE_EXTENSION_NAME "XR_KHR_opengl_enable" +#ifdef XR_USE_PLATFORM_WIN32 +// XrGraphicsBindingOpenGLWin32KHR extends XrSessionCreateInfo +typedef struct XrGraphicsBindingOpenGLWin32KHR { + XrStructureType type; + const void* XR_MAY_ALIAS next; + HDC hDC; + HGLRC hGLRC; +} XrGraphicsBindingOpenGLWin32KHR; +#endif // XR_USE_PLATFORM_WIN32 + +#ifdef XR_USE_PLATFORM_XLIB +// XrGraphicsBindingOpenGLXlibKHR extends XrSessionCreateInfo +typedef struct XrGraphicsBindingOpenGLXlibKHR { + XrStructureType type; + const void* XR_MAY_ALIAS next; + Display* xDisplay; + uint32_t visualid; + GLXFBConfig glxFBConfig; + GLXDrawable glxDrawable; + GLXContext glxContext; +} XrGraphicsBindingOpenGLXlibKHR; +#endif // XR_USE_PLATFORM_XLIB + +#ifdef XR_USE_PLATFORM_XCB +// XrGraphicsBindingOpenGLXcbKHR extends XrSessionCreateInfo +typedef struct XrGraphicsBindingOpenGLXcbKHR { + XrStructureType type; + const void* XR_MAY_ALIAS next; + xcb_connection_t* connection; + uint32_t screenNumber; + xcb_glx_fbconfig_t fbconfigid; + xcb_visualid_t visualid; + xcb_glx_drawable_t glxDrawable; + xcb_glx_context_t glxContext; +} XrGraphicsBindingOpenGLXcbKHR; +#endif // XR_USE_PLATFORM_XCB + +#ifdef XR_USE_PLATFORM_WAYLAND +// XrGraphicsBindingOpenGLWaylandKHR extends XrSessionCreateInfo +typedef struct XrGraphicsBindingOpenGLWaylandKHR { + XrStructureType type; + const void* XR_MAY_ALIAS next; + struct wl_display* display; +} XrGraphicsBindingOpenGLWaylandKHR; +#endif // XR_USE_PLATFORM_WAYLAND + +typedef struct XrSwapchainImageOpenGLKHR { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint32_t image; +} XrSwapchainImageOpenGLKHR; + +typedef struct XrGraphicsRequirementsOpenGLKHR { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrVersion minApiVersionSupported; + XrVersion maxApiVersionSupported; +} XrGraphicsRequirementsOpenGLKHR; + +typedef XrResult (XRAPI_PTR *PFN_xrGetOpenGLGraphicsRequirementsKHR)(XrInstance instance, XrSystemId systemId, XrGraphicsRequirementsOpenGLKHR* graphicsRequirements); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrGetOpenGLGraphicsRequirementsKHR( + XrInstance instance, + XrSystemId systemId, + XrGraphicsRequirementsOpenGLKHR* graphicsRequirements); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ +#endif /* XR_USE_GRAPHICS_API_OPENGL */ + +#ifdef XR_USE_GRAPHICS_API_OPENGL_ES + +#define XR_KHR_opengl_es_enable 1 +#define XR_KHR_opengl_es_enable_SPEC_VERSION 8 +#define XR_KHR_OPENGL_ES_ENABLE_EXTENSION_NAME "XR_KHR_opengl_es_enable" +#ifdef XR_USE_PLATFORM_ANDROID +// XrGraphicsBindingOpenGLESAndroidKHR extends XrSessionCreateInfo +typedef struct XrGraphicsBindingOpenGLESAndroidKHR { + XrStructureType type; + const void* XR_MAY_ALIAS next; + EGLDisplay display; + EGLConfig config; + EGLContext context; +} XrGraphicsBindingOpenGLESAndroidKHR; +#endif // XR_USE_PLATFORM_ANDROID + +typedef struct XrSwapchainImageOpenGLESKHR { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint32_t image; +} XrSwapchainImageOpenGLESKHR; + +typedef struct XrGraphicsRequirementsOpenGLESKHR { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrVersion minApiVersionSupported; + XrVersion maxApiVersionSupported; +} XrGraphicsRequirementsOpenGLESKHR; + +typedef XrResult (XRAPI_PTR *PFN_xrGetOpenGLESGraphicsRequirementsKHR)(XrInstance instance, XrSystemId systemId, XrGraphicsRequirementsOpenGLESKHR* graphicsRequirements); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrGetOpenGLESGraphicsRequirementsKHR( + XrInstance instance, + XrSystemId systemId, + XrGraphicsRequirementsOpenGLESKHR* graphicsRequirements); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ +#endif /* XR_USE_GRAPHICS_API_OPENGL_ES */ + +#ifdef XR_USE_GRAPHICS_API_VULKAN + +#define XR_KHR_vulkan_enable 1 +#define XR_KHR_vulkan_enable_SPEC_VERSION 8 +#define XR_KHR_VULKAN_ENABLE_EXTENSION_NAME "XR_KHR_vulkan_enable" +// XrGraphicsBindingVulkanKHR extends XrSessionCreateInfo +typedef struct XrGraphicsBindingVulkanKHR { + XrStructureType type; + const void* XR_MAY_ALIAS next; + VkInstance instance; + VkPhysicalDevice physicalDevice; + VkDevice device; + uint32_t queueFamilyIndex; + uint32_t queueIndex; +} XrGraphicsBindingVulkanKHR; + +typedef struct XrSwapchainImageVulkanKHR { + XrStructureType type; + void* XR_MAY_ALIAS next; + VkImage image; +} XrSwapchainImageVulkanKHR; + +typedef struct XrGraphicsRequirementsVulkanKHR { + XrStructureType type; + void* XR_MAY_ALIAS next; + XrVersion minApiVersionSupported; + XrVersion maxApiVersionSupported; +} XrGraphicsRequirementsVulkanKHR; + +typedef XrResult (XRAPI_PTR *PFN_xrGetVulkanInstanceExtensionsKHR)(XrInstance instance, XrSystemId systemId, uint32_t bufferCapacityInput, uint32_t* bufferCountOutput, char* buffer); +typedef XrResult (XRAPI_PTR *PFN_xrGetVulkanDeviceExtensionsKHR)(XrInstance instance, XrSystemId systemId, uint32_t bufferCapacityInput, uint32_t* bufferCountOutput, char* buffer); +typedef XrResult (XRAPI_PTR *PFN_xrGetVulkanGraphicsDeviceKHR)(XrInstance instance, XrSystemId systemId, VkInstance vkInstance, VkPhysicalDevice* vkPhysicalDevice); +typedef XrResult (XRAPI_PTR *PFN_xrGetVulkanGraphicsRequirementsKHR)(XrInstance instance, XrSystemId systemId, XrGraphicsRequirementsVulkanKHR* graphicsRequirements); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrGetVulkanInstanceExtensionsKHR( + XrInstance instance, + XrSystemId systemId, + uint32_t bufferCapacityInput, + uint32_t* bufferCountOutput, + char* buffer); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetVulkanDeviceExtensionsKHR( + XrInstance instance, + XrSystemId systemId, + uint32_t bufferCapacityInput, + uint32_t* bufferCountOutput, + char* buffer); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetVulkanGraphicsDeviceKHR( + XrInstance instance, + XrSystemId systemId, + VkInstance vkInstance, + VkPhysicalDevice* vkPhysicalDevice); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetVulkanGraphicsRequirementsKHR( + XrInstance instance, + XrSystemId systemId, + XrGraphicsRequirementsVulkanKHR* graphicsRequirements); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ +#endif /* XR_USE_GRAPHICS_API_VULKAN */ + +#ifdef XR_USE_GRAPHICS_API_D3D11 + +#define XR_KHR_D3D11_enable 1 +#define XR_KHR_D3D11_enable_SPEC_VERSION 9 +#define XR_KHR_D3D11_ENABLE_EXTENSION_NAME "XR_KHR_D3D11_enable" +// XrGraphicsBindingD3D11KHR extends XrSessionCreateInfo +typedef struct XrGraphicsBindingD3D11KHR { + XrStructureType type; + const void* XR_MAY_ALIAS next; + ID3D11Device* device; +} XrGraphicsBindingD3D11KHR; + +typedef struct XrSwapchainImageD3D11KHR { + XrStructureType type; + void* XR_MAY_ALIAS next; + ID3D11Texture2D* texture; +} XrSwapchainImageD3D11KHR; + +typedef struct XrGraphicsRequirementsD3D11KHR { + XrStructureType type; + void* XR_MAY_ALIAS next; + LUID adapterLuid; + D3D_FEATURE_LEVEL minFeatureLevel; +} XrGraphicsRequirementsD3D11KHR; + +typedef XrResult (XRAPI_PTR *PFN_xrGetD3D11GraphicsRequirementsKHR)(XrInstance instance, XrSystemId systemId, XrGraphicsRequirementsD3D11KHR* graphicsRequirements); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrGetD3D11GraphicsRequirementsKHR( + XrInstance instance, + XrSystemId systemId, + XrGraphicsRequirementsD3D11KHR* graphicsRequirements); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ +#endif /* XR_USE_GRAPHICS_API_D3D11 */ + +#ifdef XR_USE_GRAPHICS_API_D3D12 + +#define XR_KHR_D3D12_enable 1 +#define XR_KHR_D3D12_enable_SPEC_VERSION 9 +#define XR_KHR_D3D12_ENABLE_EXTENSION_NAME "XR_KHR_D3D12_enable" +// XrGraphicsBindingD3D12KHR extends XrSessionCreateInfo +typedef struct XrGraphicsBindingD3D12KHR { + XrStructureType type; + const void* XR_MAY_ALIAS next; + ID3D12Device* device; + ID3D12CommandQueue* queue; +} XrGraphicsBindingD3D12KHR; + +typedef struct XrSwapchainImageD3D12KHR { + XrStructureType type; + void* XR_MAY_ALIAS next; + ID3D12Resource* texture; +} XrSwapchainImageD3D12KHR; + +typedef struct XrGraphicsRequirementsD3D12KHR { + XrStructureType type; + void* XR_MAY_ALIAS next; + LUID adapterLuid; + D3D_FEATURE_LEVEL minFeatureLevel; +} XrGraphicsRequirementsD3D12KHR; + +typedef XrResult (XRAPI_PTR *PFN_xrGetD3D12GraphicsRequirementsKHR)(XrInstance instance, XrSystemId systemId, XrGraphicsRequirementsD3D12KHR* graphicsRequirements); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrGetD3D12GraphicsRequirementsKHR( + XrInstance instance, + XrSystemId systemId, + XrGraphicsRequirementsD3D12KHR* graphicsRequirements); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ +#endif /* XR_USE_GRAPHICS_API_D3D12 */ + +#ifdef XR_USE_PLATFORM_WIN32 + +#define XR_KHR_win32_convert_performance_counter_time 1 +#define XR_KHR_win32_convert_performance_counter_time_SPEC_VERSION 1 +#define XR_KHR_WIN32_CONVERT_PERFORMANCE_COUNTER_TIME_EXTENSION_NAME "XR_KHR_win32_convert_performance_counter_time" +typedef XrResult (XRAPI_PTR *PFN_xrConvertWin32PerformanceCounterToTimeKHR)(XrInstance instance, const LARGE_INTEGER* performanceCounter, XrTime* time); +typedef XrResult (XRAPI_PTR *PFN_xrConvertTimeToWin32PerformanceCounterKHR)(XrInstance instance, XrTime time, LARGE_INTEGER* performanceCounter); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrConvertWin32PerformanceCounterToTimeKHR( + XrInstance instance, + const LARGE_INTEGER* performanceCounter, + XrTime* time); + +XRAPI_ATTR XrResult XRAPI_CALL xrConvertTimeToWin32PerformanceCounterKHR( + XrInstance instance, + XrTime time, + LARGE_INTEGER* performanceCounter); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ +#endif /* XR_USE_PLATFORM_WIN32 */ + +#ifdef XR_USE_TIMESPEC + +#define XR_KHR_convert_timespec_time 1 +#define XR_KHR_convert_timespec_time_SPEC_VERSION 1 +#define XR_KHR_CONVERT_TIMESPEC_TIME_EXTENSION_NAME "XR_KHR_convert_timespec_time" +typedef XrResult (XRAPI_PTR *PFN_xrConvertTimespecTimeToTimeKHR)(XrInstance instance, const struct timespec* timespecTime, XrTime* time); +typedef XrResult (XRAPI_PTR *PFN_xrConvertTimeToTimespecTimeKHR)(XrInstance instance, XrTime time, struct timespec* timespecTime); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrConvertTimespecTimeToTimeKHR( + XrInstance instance, + const struct timespec* timespecTime, + XrTime* time); + +XRAPI_ATTR XrResult XRAPI_CALL xrConvertTimeToTimespecTimeKHR( + XrInstance instance, + XrTime time, + struct timespec* timespecTime); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ +#endif /* XR_USE_TIMESPEC */ + +#ifdef XR_USE_PLATFORM_ANDROID + +#define XR_KHR_loader_init_android 1 +#define XR_KHR_loader_init_android_SPEC_VERSION 1 +#define XR_KHR_LOADER_INIT_ANDROID_EXTENSION_NAME "XR_KHR_loader_init_android" +typedef struct XrLoaderInitInfoAndroidKHR { + XrStructureType type; + const void* XR_MAY_ALIAS next; + void* XR_MAY_ALIAS applicationVM; + void* XR_MAY_ALIAS applicationContext; +} XrLoaderInitInfoAndroidKHR; + +#endif /* XR_USE_PLATFORM_ANDROID */ + +#ifdef XR_USE_GRAPHICS_API_VULKAN + +#define XR_KHR_vulkan_enable2 1 +#define XR_KHR_vulkan_enable2_SPEC_VERSION 2 +#define XR_KHR_VULKAN_ENABLE2_EXTENSION_NAME "XR_KHR_vulkan_enable2" +typedef XrFlags64 XrVulkanInstanceCreateFlagsKHR; + +// Flag bits for XrVulkanInstanceCreateFlagsKHR + +typedef XrFlags64 XrVulkanDeviceCreateFlagsKHR; + +// Flag bits for XrVulkanDeviceCreateFlagsKHR + +typedef struct XrVulkanInstanceCreateInfoKHR { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSystemId systemId; + XrVulkanInstanceCreateFlagsKHR createFlags; + PFN_vkGetInstanceProcAddr pfnGetInstanceProcAddr; + const VkInstanceCreateInfo* vulkanCreateInfo; + const VkAllocationCallbacks* vulkanAllocator; +} XrVulkanInstanceCreateInfoKHR; + +typedef struct XrVulkanDeviceCreateInfoKHR { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSystemId systemId; + XrVulkanDeviceCreateFlagsKHR createFlags; + PFN_vkGetInstanceProcAddr pfnGetInstanceProcAddr; + VkPhysicalDevice vulkanPhysicalDevice; + const VkDeviceCreateInfo* vulkanCreateInfo; + const VkAllocationCallbacks* vulkanAllocator; +} XrVulkanDeviceCreateInfoKHR; + +typedef XrGraphicsBindingVulkanKHR XrGraphicsBindingVulkan2KHR; + +typedef struct XrVulkanGraphicsDeviceGetInfoKHR { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrSystemId systemId; + VkInstance vulkanInstance; +} XrVulkanGraphicsDeviceGetInfoKHR; + +typedef XrSwapchainImageVulkanKHR XrSwapchainImageVulkan2KHR; + +typedef XrGraphicsRequirementsVulkanKHR XrGraphicsRequirementsVulkan2KHR; + +typedef XrResult (XRAPI_PTR *PFN_xrCreateVulkanInstanceKHR)(XrInstance instance, const XrVulkanInstanceCreateInfoKHR* createInfo, VkInstance* vulkanInstance, VkResult* vulkanResult); +typedef XrResult (XRAPI_PTR *PFN_xrCreateVulkanDeviceKHR)(XrInstance instance, const XrVulkanDeviceCreateInfoKHR* createInfo, VkDevice* vulkanDevice, VkResult* vulkanResult); +typedef XrResult (XRAPI_PTR *PFN_xrGetVulkanGraphicsDevice2KHR)(XrInstance instance, const XrVulkanGraphicsDeviceGetInfoKHR* getInfo, VkPhysicalDevice* vulkanPhysicalDevice); +typedef XrResult (XRAPI_PTR *PFN_xrGetVulkanGraphicsRequirements2KHR)(XrInstance instance, XrSystemId systemId, XrGraphicsRequirementsVulkanKHR* graphicsRequirements); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrCreateVulkanInstanceKHR( + XrInstance instance, + const XrVulkanInstanceCreateInfoKHR* createInfo, + VkInstance* vulkanInstance, + VkResult* vulkanResult); + +XRAPI_ATTR XrResult XRAPI_CALL xrCreateVulkanDeviceKHR( + XrInstance instance, + const XrVulkanDeviceCreateInfoKHR* createInfo, + VkDevice* vulkanDevice, + VkResult* vulkanResult); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetVulkanGraphicsDevice2KHR( + XrInstance instance, + const XrVulkanGraphicsDeviceGetInfoKHR* getInfo, + VkPhysicalDevice* vulkanPhysicalDevice); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetVulkanGraphicsRequirements2KHR( + XrInstance instance, + XrSystemId systemId, + XrGraphicsRequirementsVulkanKHR* graphicsRequirements); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ +#endif /* XR_USE_GRAPHICS_API_VULKAN */ + +#ifdef XR_USE_PLATFORM_EGL + +#define XR_MNDX_egl_enable 1 +#define XR_MNDX_egl_enable_SPEC_VERSION 1 +#define XR_MNDX_EGL_ENABLE_EXTENSION_NAME "XR_MNDX_egl_enable" +// XrGraphicsBindingEGLMNDX extends XrSessionCreateInfo +typedef struct XrGraphicsBindingEGLMNDX { + XrStructureType type; + const void* XR_MAY_ALIAS next; + PFNEGLGETPROCADDRESSPROC getProcAddress; + EGLDisplay display; + EGLConfig config; + EGLContext context; +} XrGraphicsBindingEGLMNDX; + +#endif /* XR_USE_PLATFORM_EGL */ + +#ifdef XR_USE_PLATFORM_WIN32 + +#define XR_MSFT_perception_anchor_interop 1 +#define XR_MSFT_perception_anchor_interop_SPEC_VERSION 1 +#define XR_MSFT_PERCEPTION_ANCHOR_INTEROP_EXTENSION_NAME "XR_MSFT_perception_anchor_interop" +typedef XrResult (XRAPI_PTR *PFN_xrCreateSpatialAnchorFromPerceptionAnchorMSFT)(XrSession session, IUnknown* perceptionAnchor, XrSpatialAnchorMSFT* anchor); +typedef XrResult (XRAPI_PTR *PFN_xrTryGetPerceptionAnchorFromSpatialAnchorMSFT)(XrSession session, XrSpatialAnchorMSFT anchor, IUnknown** perceptionAnchor); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrCreateSpatialAnchorFromPerceptionAnchorMSFT( + XrSession session, + IUnknown* perceptionAnchor, + XrSpatialAnchorMSFT* anchor); + +XRAPI_ATTR XrResult XRAPI_CALL xrTryGetPerceptionAnchorFromSpatialAnchorMSFT( + XrSession session, + XrSpatialAnchorMSFT anchor, + IUnknown** perceptionAnchor); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ +#endif /* XR_USE_PLATFORM_WIN32 */ + +#ifdef XR_USE_PLATFORM_WIN32 + +#define XR_MSFT_holographic_window_attachment 1 +#define XR_MSFT_holographic_window_attachment_SPEC_VERSION 1 +#define XR_MSFT_HOLOGRAPHIC_WINDOW_ATTACHMENT_EXTENSION_NAME "XR_MSFT_holographic_window_attachment" +#ifdef XR_USE_PLATFORM_WIN32 +// XrHolographicWindowAttachmentMSFT extends XrSessionCreateInfo +typedef struct XrHolographicWindowAttachmentMSFT { + XrStructureType type; + const void* XR_MAY_ALIAS next; + IUnknown* holographicSpace; + IUnknown* coreWindow; +} XrHolographicWindowAttachmentMSFT; +#endif // XR_USE_PLATFORM_WIN32 + +#endif /* XR_USE_PLATFORM_WIN32 */ + +#ifdef XR_USE_PLATFORM_ANDROID + +#define XR_FB_android_surface_swapchain_create 1 +#define XR_FB_android_surface_swapchain_create_SPEC_VERSION 1 +#define XR_FB_ANDROID_SURFACE_SWAPCHAIN_CREATE_EXTENSION_NAME "XR_FB_android_surface_swapchain_create" +typedef XrFlags64 XrAndroidSurfaceSwapchainFlagsFB; + +// Flag bits for XrAndroidSurfaceSwapchainFlagsFB +static const XrAndroidSurfaceSwapchainFlagsFB XR_ANDROID_SURFACE_SWAPCHAIN_SYNCHRONOUS_BIT_FB = 0x00000001; +static const XrAndroidSurfaceSwapchainFlagsFB XR_ANDROID_SURFACE_SWAPCHAIN_USE_TIMESTAMPS_BIT_FB = 0x00000002; + +#ifdef XR_USE_PLATFORM_ANDROID +// XrAndroidSurfaceSwapchainCreateInfoFB extends XrSwapchainCreateInfo +typedef struct XrAndroidSurfaceSwapchainCreateInfoFB { + XrStructureType type; + const void* XR_MAY_ALIAS next; + XrAndroidSurfaceSwapchainFlagsFB createFlags; +} XrAndroidSurfaceSwapchainCreateInfoFB; +#endif // XR_USE_PLATFORM_ANDROID + +#endif /* XR_USE_PLATFORM_ANDROID */ + +#ifdef XR_USE_PLATFORM_WIN32 + +#define XR_OCULUS_audio_device_guid 1 +#define XR_OCULUS_audio_device_guid_SPEC_VERSION 1 +#define XR_OCULUS_AUDIO_DEVICE_GUID_EXTENSION_NAME "XR_OCULUS_audio_device_guid" +#define XR_MAX_AUDIO_DEVICE_STR_SIZE_OCULUS 128 +typedef XrResult (XRAPI_PTR *PFN_xrGetAudioOutputDeviceGuidOculus)(XrInstance instance, wchar_t buffer[XR_MAX_AUDIO_DEVICE_STR_SIZE_OCULUS]); +typedef XrResult (XRAPI_PTR *PFN_xrGetAudioInputDeviceGuidOculus)(XrInstance instance, wchar_t buffer[XR_MAX_AUDIO_DEVICE_STR_SIZE_OCULUS]); + +#ifndef XR_NO_PROTOTYPES +#ifdef XR_EXTENSION_PROTOTYPES +XRAPI_ATTR XrResult XRAPI_CALL xrGetAudioOutputDeviceGuidOculus( + XrInstance instance, + wchar_t buffer[XR_MAX_AUDIO_DEVICE_STR_SIZE_OCULUS]); + +XRAPI_ATTR XrResult XRAPI_CALL xrGetAudioInputDeviceGuidOculus( + XrInstance instance, + wchar_t buffer[XR_MAX_AUDIO_DEVICE_STR_SIZE_OCULUS]); +#endif /* XR_EXTENSION_PROTOTYPES */ +#endif /* !XR_NO_PROTOTYPES */ +#endif /* XR_USE_PLATFORM_WIN32 */ + +#ifdef XR_USE_GRAPHICS_API_VULKAN + +#define XR_FB_foveation_vulkan 1 +#define XR_FB_foveation_vulkan_SPEC_VERSION 1 +#define XR_FB_FOVEATION_VULKAN_EXTENSION_NAME "XR_FB_foveation_vulkan" +// XrSwapchainImageFoveationVulkanFB extends XrSwapchainImageVulkanKHR +typedef struct XrSwapchainImageFoveationVulkanFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + VkImage image; + uint32_t width; + uint32_t height; +} XrSwapchainImageFoveationVulkanFB; + +#endif /* XR_USE_GRAPHICS_API_VULKAN */ + +#ifdef XR_USE_PLATFORM_ANDROID + +#define XR_FB_swapchain_update_state_android_surface 1 +#define XR_FB_swapchain_update_state_android_surface_SPEC_VERSION 1 +#define XR_FB_SWAPCHAIN_UPDATE_STATE_ANDROID_SURFACE_EXTENSION_NAME "XR_FB_swapchain_update_state_android_surface" +#ifdef XR_USE_PLATFORM_ANDROID +typedef struct XrSwapchainStateAndroidSurfaceDimensionsFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + uint32_t width; + uint32_t height; +} XrSwapchainStateAndroidSurfaceDimensionsFB; +#endif // XR_USE_PLATFORM_ANDROID + +#endif /* XR_USE_PLATFORM_ANDROID */ + +#ifdef XR_USE_GRAPHICS_API_OPENGL_ES + +#define XR_FB_swapchain_update_state_opengl_es 1 +#define XR_FB_swapchain_update_state_opengl_es_SPEC_VERSION 1 +#define XR_FB_SWAPCHAIN_UPDATE_STATE_OPENGL_ES_EXTENSION_NAME "XR_FB_swapchain_update_state_opengl_es" +#ifdef XR_USE_GRAPHICS_API_OPENGL_ES +typedef struct XrSwapchainStateSamplerOpenGLESFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + EGLenum minFilter; + EGLenum magFilter; + EGLenum wrapModeS; + EGLenum wrapModeT; + EGLenum swizzleRed; + EGLenum swizzleGreen; + EGLenum swizzleBlue; + EGLenum swizzleAlpha; + float maxAnisotropy; + XrColor4f borderColor; +} XrSwapchainStateSamplerOpenGLESFB; +#endif // XR_USE_GRAPHICS_API_OPENGL_ES + +#endif /* XR_USE_GRAPHICS_API_OPENGL_ES */ + +#ifdef XR_USE_GRAPHICS_API_VULKAN + +#define XR_FB_swapchain_update_state_vulkan 1 +#define XR_FB_swapchain_update_state_vulkan_SPEC_VERSION 1 +#define XR_FB_SWAPCHAIN_UPDATE_STATE_VULKAN_EXTENSION_NAME "XR_FB_swapchain_update_state_vulkan" +#ifdef XR_USE_GRAPHICS_API_VULKAN +typedef struct XrSwapchainStateSamplerVulkanFB { + XrStructureType type; + void* XR_MAY_ALIAS next; + VkFilter minFilter; + VkFilter magFilter; + VkSamplerMipmapMode mipmapMode; + VkSamplerAddressMode wrapModeS; + VkSamplerAddressMode wrapModeT; + VkComponentSwizzle swizzleRed; + VkComponentSwizzle swizzleGreen; + VkComponentSwizzle swizzleBlue; + VkComponentSwizzle swizzleAlpha; + float maxAnisotropy; + XrColor4f borderColor; +} XrSwapchainStateSamplerVulkanFB; +#endif // XR_USE_GRAPHICS_API_VULKAN + +#endif /* XR_USE_GRAPHICS_API_VULKAN */ + +#ifdef XR_USE_GRAPHICS_API_VULKAN + +#define XR_META_vulkan_swapchain_create_info 1 +#define XR_META_vulkan_swapchain_create_info_SPEC_VERSION 1 +#define XR_META_VULKAN_SWAPCHAIN_CREATE_INFO_EXTENSION_NAME "XR_META_vulkan_swapchain_create_info" +// XrVulkanSwapchainCreateInfoMETA extends XrSwapchainCreateInfo +typedef struct XrVulkanSwapchainCreateInfoMETA { + XrStructureType type; + const void* XR_MAY_ALIAS next; + VkImageCreateFlags additionalCreateFlags; + VkImageUsageFlags additionalUsageFlags; +} XrVulkanSwapchainCreateInfoMETA; + +#endif /* XR_USE_GRAPHICS_API_VULKAN */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Plugins/MetaXR/Source/Thirdparty/OpenXR/include/khronos/openxr/openxr_platform_defines.h b/Plugins/MetaXR/Source/Thirdparty/OpenXR/include/khronos/openxr/openxr_platform_defines.h new file mode 100644 index 0000000..31fa05a --- /dev/null +++ b/Plugins/MetaXR/Source/Thirdparty/OpenXR/include/khronos/openxr/openxr_platform_defines.h @@ -0,0 +1,110 @@ +/* +** Copyright (c) 2017-2022, The Khronos Group Inc. +** +** SPDX-License-Identifier: Apache-2.0 OR MIT +*/ + +#ifndef OPENXR_PLATFORM_DEFINES_H_ +#define OPENXR_PLATFORM_DEFINES_H_ 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/* Platform-specific calling convention macros. + * + * Platforms should define these so that OpenXR clients call OpenXR functions + * with the same calling conventions that the OpenXR implementation expects. + * + * XRAPI_ATTR - Placed before the return type in function declarations. + * Useful for C++11 and GCC/Clang-style function attribute syntax. + * XRAPI_CALL - Placed after the return type in function declarations. + * Useful for MSVC-style calling convention syntax. + * XRAPI_PTR - Placed between the '(' and '*' in function pointer types. + * + * Function declaration: XRAPI_ATTR void XRAPI_CALL xrFunction(void); + * Function pointer type: typedef void (XRAPI_PTR *PFN_xrFunction)(void); + */ +#if defined(_WIN32) +#define XRAPI_ATTR +// On Windows, functions use the stdcall convention +#define XRAPI_CALL __stdcall +#define XRAPI_PTR XRAPI_CALL +#elif defined(__ANDROID__) && defined(__ARM_ARCH) && __ARM_ARCH < 7 +#error "API not supported for the 'armeabi' NDK ABI" +#elif defined(__ANDROID__) && defined(__ARM_ARCH) && __ARM_ARCH >= 7 && defined(__ARM_32BIT_STATE) +// On Android 32-bit ARM targets, functions use the "hardfloat" +// calling convention, i.e. float parameters are passed in registers. This +// is true even if the rest of the application passes floats on the stack, +// as it does by default when compiling for the armeabi-v7a NDK ABI. +#define XRAPI_ATTR __attribute__((pcs("aapcs-vfp"))) +#define XRAPI_CALL +#define XRAPI_PTR XRAPI_ATTR +#else +// On other platforms, use the default calling convention +#define XRAPI_ATTR +#define XRAPI_CALL +#define XRAPI_PTR +#endif + +#include + +#if !defined(XR_NO_STDINT_H) +#if defined(_MSC_VER) && (_MSC_VER < 1600) +typedef signed __int8 int8_t; +typedef unsigned __int8 uint8_t; +typedef signed __int16 int16_t; +typedef unsigned __int16 uint16_t; +typedef signed __int32 int32_t; +typedef unsigned __int32 uint32_t; +typedef signed __int64 int64_t; +typedef unsigned __int64 uint64_t; +#else +#include +#endif +#endif // !defined( XR_NO_STDINT_H ) + +// XR_PTR_SIZE (in bytes) +#if (defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__) ) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__)) +#define XR_PTR_SIZE 8 +#else +#define XR_PTR_SIZE 4 +#endif + +// Needed so we can use clang __has_feature portably. +#if !defined(XR_COMPILER_HAS_FEATURE) +#if defined(__clang__) +#define XR_COMPILER_HAS_FEATURE(x) __has_feature(x) +#else +#define XR_COMPILER_HAS_FEATURE(x) 0 +#endif +#endif + +// Identifies if the current compiler has C++11 support enabled. +// Does not by itself identify if any given C++11 feature is present. +#if !defined(XR_CPP11_ENABLED) && defined(__cplusplus) +#if defined(__GNUC__) && defined(__GXX_EXPERIMENTAL_CXX0X__) +#define XR_CPP11_ENABLED 1 +#elif defined(_MSC_VER) && (_MSC_VER >= 1600) +#define XR_CPP11_ENABLED 1 +#elif (__cplusplus >= 201103L) // 201103 is the first C++11 version. +#define XR_CPP11_ENABLED 1 +#endif +#endif + +// Identifies if the current compiler supports C++11 nullptr. +#if !defined(XR_CPP_NULLPTR_SUPPORTED) +#if defined(XR_CPP11_ENABLED) && \ + ((defined(__clang__) && XR_COMPILER_HAS_FEATURE(cxx_nullptr)) || \ + (defined(__GNUC__) && (((__GNUC__ * 1000) + __GNUC_MINOR__) >= 4006)) || \ + (defined(_MSC_VER) && (_MSC_VER >= 1600)) || \ + (defined(__EDG_VERSION__) && (__EDG_VERSION__ >= 403))) +#define XR_CPP_NULLPTR_SUPPORTED 1 +#endif +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Plugins/MetaXR/Source/Thirdparty/OpenXR/include/khronos/openxr/openxr_reflection.h b/Plugins/MetaXR/Source/Thirdparty/OpenXR/include/khronos/openxr/openxr_reflection.h new file mode 100644 index 0000000..ac6f452 --- /dev/null +++ b/Plugins/MetaXR/Source/Thirdparty/OpenXR/include/khronos/openxr/openxr_reflection.h @@ -0,0 +1,3158 @@ +#ifndef OPENXR_REFLECTION_H_ +#define OPENXR_REFLECTION_H_ 1 + +/* +** Copyright (c) 2017-2022, The Khronos Group Inc. +** +** SPDX-License-Identifier: Apache-2.0 OR MIT +*/ + +/* +** This header is generated from the Khronos OpenXR XML API Registry. +** +*/ + +#include "openxr.h" + +/* +This file contains expansion macros (X Macros) for OpenXR enumerations and structures. +Example of how to use expansion macros to make an enum-to-string function: + +#define XR_ENUM_CASE_STR(name, val) case name: return #name; +#define XR_ENUM_STR(enumType) \ + constexpr const char* XrEnumStr(enumType e) { \ + switch (e) { \ + XR_LIST_ENUM_##enumType(XR_ENUM_CASE_STR) \ + default: return "Unknown"; \ + } \ + } \ + +XR_ENUM_STR(XrResult); +*/ + +#define XR_LIST_ENUM_XrResult(_) \ + _(XR_SUCCESS, 0) \ + _(XR_TIMEOUT_EXPIRED, 1) \ + _(XR_SESSION_LOSS_PENDING, 3) \ + _(XR_EVENT_UNAVAILABLE, 4) \ + _(XR_SPACE_BOUNDS_UNAVAILABLE, 7) \ + _(XR_SESSION_NOT_FOCUSED, 8) \ + _(XR_FRAME_DISCARDED, 9) \ + _(XR_ERROR_VALIDATION_FAILURE, -1) \ + _(XR_ERROR_RUNTIME_FAILURE, -2) \ + _(XR_ERROR_OUT_OF_MEMORY, -3) \ + _(XR_ERROR_API_VERSION_UNSUPPORTED, -4) \ + _(XR_ERROR_INITIALIZATION_FAILED, -6) \ + _(XR_ERROR_FUNCTION_UNSUPPORTED, -7) \ + _(XR_ERROR_FEATURE_UNSUPPORTED, -8) \ + _(XR_ERROR_EXTENSION_NOT_PRESENT, -9) \ + _(XR_ERROR_LIMIT_REACHED, -10) \ + _(XR_ERROR_SIZE_INSUFFICIENT, -11) \ + _(XR_ERROR_HANDLE_INVALID, -12) \ + _(XR_ERROR_INSTANCE_LOST, -13) \ + _(XR_ERROR_SESSION_RUNNING, -14) \ + _(XR_ERROR_SESSION_NOT_RUNNING, -16) \ + _(XR_ERROR_SESSION_LOST, -17) \ + _(XR_ERROR_SYSTEM_INVALID, -18) \ + _(XR_ERROR_PATH_INVALID, -19) \ + _(XR_ERROR_PATH_COUNT_EXCEEDED, -20) \ + _(XR_ERROR_PATH_FORMAT_INVALID, -21) \ + _(XR_ERROR_PATH_UNSUPPORTED, -22) \ + _(XR_ERROR_LAYER_INVALID, -23) \ + _(XR_ERROR_LAYER_LIMIT_EXCEEDED, -24) \ + _(XR_ERROR_SWAPCHAIN_RECT_INVALID, -25) \ + _(XR_ERROR_SWAPCHAIN_FORMAT_UNSUPPORTED, -26) \ + _(XR_ERROR_ACTION_TYPE_MISMATCH, -27) \ + _(XR_ERROR_SESSION_NOT_READY, -28) \ + _(XR_ERROR_SESSION_NOT_STOPPING, -29) \ + _(XR_ERROR_TIME_INVALID, -30) \ + _(XR_ERROR_REFERENCE_SPACE_UNSUPPORTED, -31) \ + _(XR_ERROR_FILE_ACCESS_ERROR, -32) \ + _(XR_ERROR_FILE_CONTENTS_INVALID, -33) \ + _(XR_ERROR_FORM_FACTOR_UNSUPPORTED, -34) \ + _(XR_ERROR_FORM_FACTOR_UNAVAILABLE, -35) \ + _(XR_ERROR_API_LAYER_NOT_PRESENT, -36) \ + _(XR_ERROR_CALL_ORDER_INVALID, -37) \ + _(XR_ERROR_GRAPHICS_DEVICE_INVALID, -38) \ + _(XR_ERROR_POSE_INVALID, -39) \ + _(XR_ERROR_INDEX_OUT_OF_RANGE, -40) \ + _(XR_ERROR_VIEW_CONFIGURATION_TYPE_UNSUPPORTED, -41) \ + _(XR_ERROR_ENVIRONMENT_BLEND_MODE_UNSUPPORTED, -42) \ + _(XR_ERROR_NAME_DUPLICATED, -44) \ + _(XR_ERROR_NAME_INVALID, -45) \ + _(XR_ERROR_ACTIONSET_NOT_ATTACHED, -46) \ + _(XR_ERROR_ACTIONSETS_ALREADY_ATTACHED, -47) \ + _(XR_ERROR_LOCALIZED_NAME_DUPLICATED, -48) \ + _(XR_ERROR_LOCALIZED_NAME_INVALID, -49) \ + _(XR_ERROR_GRAPHICS_REQUIREMENTS_CALL_MISSING, -50) \ + _(XR_ERROR_RUNTIME_UNAVAILABLE, -51) \ + _(XR_ERROR_ANDROID_THREAD_SETTINGS_ID_INVALID_KHR, -1000003000) \ + _(XR_ERROR_ANDROID_THREAD_SETTINGS_FAILURE_KHR, -1000003001) \ + _(XR_ERROR_CREATE_SPATIAL_ANCHOR_FAILED_MSFT, -1000039001) \ + _(XR_ERROR_SECONDARY_VIEW_CONFIGURATION_TYPE_NOT_ENABLED_MSFT, -1000053000) \ + _(XR_ERROR_CONTROLLER_MODEL_KEY_INVALID_MSFT, -1000055000) \ + _(XR_ERROR_REPROJECTION_MODE_UNSUPPORTED_MSFT, -1000066000) \ + _(XR_ERROR_COMPUTE_NEW_SCENE_NOT_COMPLETED_MSFT, -1000097000) \ + _(XR_ERROR_SCENE_COMPONENT_ID_INVALID_MSFT, -1000097001) \ + _(XR_ERROR_SCENE_COMPONENT_TYPE_MISMATCH_MSFT, -1000097002) \ + _(XR_ERROR_SCENE_MESH_BUFFER_ID_INVALID_MSFT, -1000097003) \ + _(XR_ERROR_SCENE_COMPUTE_FEATURE_INCOMPATIBLE_MSFT, -1000097004) \ + _(XR_ERROR_SCENE_COMPUTE_CONSISTENCY_MISMATCH_MSFT, -1000097005) \ + _(XR_ERROR_DISPLAY_REFRESH_RATE_UNSUPPORTED_FB, -1000101000) \ + _(XR_ERROR_COLOR_SPACE_UNSUPPORTED_FB, -1000108000) \ + _(XR_ERROR_SPACE_COMPONENT_NOT_SUPPORTED_FB, -1000113000) \ + _(XR_ERROR_SPACE_COMPONENT_NOT_ENABLED_FB, -1000113001) \ + _(XR_ERROR_SPACE_COMPONENT_STATUS_PENDING_FB, -1000113002) \ + _(XR_ERROR_SPACE_COMPONENT_STATUS_ALREADY_SET_FB, -1000113003) \ + _(XR_ERROR_UNEXPECTED_STATE_PASSTHROUGH_FB, -1000118000) \ + _(XR_ERROR_FEATURE_ALREADY_CREATED_PASSTHROUGH_FB, -1000118001) \ + _(XR_ERROR_FEATURE_REQUIRED_PASSTHROUGH_FB, -1000118002) \ + _(XR_ERROR_NOT_PERMITTED_PASSTHROUGH_FB, -1000118003) \ + _(XR_ERROR_INSUFFICIENT_RESOURCES_PASSTHROUGH_FB, -1000118004) \ + _(XR_ERROR_UNKNOWN_PASSTHROUGH_FB, -1000118050) \ + _(XR_ERROR_RENDER_MODEL_KEY_INVALID_FB, -1000119000) \ + _(XR_RENDER_MODEL_UNAVAILABLE_FB, 1000119020) \ + _(XR_ERROR_MARKER_NOT_TRACKED_VARJO, -1000124000) \ + _(XR_ERROR_MARKER_ID_INVALID_VARJO, -1000124001) \ + _(XR_ERROR_SPATIAL_ANCHOR_NAME_NOT_FOUND_MSFT, -1000142001) \ + _(XR_ERROR_SPATIAL_ANCHOR_NAME_INVALID_MSFT, -1000142002) \ + _(XR_RESULT_MAX_ENUM, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrStructureType(_) \ + _(XR_TYPE_UNKNOWN, 0) \ + _(XR_TYPE_API_LAYER_PROPERTIES, 1) \ + _(XR_TYPE_EXTENSION_PROPERTIES, 2) \ + _(XR_TYPE_INSTANCE_CREATE_INFO, 3) \ + _(XR_TYPE_SYSTEM_GET_INFO, 4) \ + _(XR_TYPE_SYSTEM_PROPERTIES, 5) \ + _(XR_TYPE_VIEW_LOCATE_INFO, 6) \ + _(XR_TYPE_VIEW, 7) \ + _(XR_TYPE_SESSION_CREATE_INFO, 8) \ + _(XR_TYPE_SWAPCHAIN_CREATE_INFO, 9) \ + _(XR_TYPE_SESSION_BEGIN_INFO, 10) \ + _(XR_TYPE_VIEW_STATE, 11) \ + _(XR_TYPE_FRAME_END_INFO, 12) \ + _(XR_TYPE_HAPTIC_VIBRATION, 13) \ + _(XR_TYPE_EVENT_DATA_BUFFER, 16) \ + _(XR_TYPE_EVENT_DATA_INSTANCE_LOSS_PENDING, 17) \ + _(XR_TYPE_EVENT_DATA_SESSION_STATE_CHANGED, 18) \ + _(XR_TYPE_ACTION_STATE_BOOLEAN, 23) \ + _(XR_TYPE_ACTION_STATE_FLOAT, 24) \ + _(XR_TYPE_ACTION_STATE_VECTOR2F, 25) \ + _(XR_TYPE_ACTION_STATE_POSE, 27) \ + _(XR_TYPE_ACTION_SET_CREATE_INFO, 28) \ + _(XR_TYPE_ACTION_CREATE_INFO, 29) \ + _(XR_TYPE_INSTANCE_PROPERTIES, 32) \ + _(XR_TYPE_FRAME_WAIT_INFO, 33) \ + _(XR_TYPE_COMPOSITION_LAYER_PROJECTION, 35) \ + _(XR_TYPE_COMPOSITION_LAYER_QUAD, 36) \ + _(XR_TYPE_REFERENCE_SPACE_CREATE_INFO, 37) \ + _(XR_TYPE_ACTION_SPACE_CREATE_INFO, 38) \ + _(XR_TYPE_EVENT_DATA_REFERENCE_SPACE_CHANGE_PENDING, 40) \ + _(XR_TYPE_VIEW_CONFIGURATION_VIEW, 41) \ + _(XR_TYPE_SPACE_LOCATION, 42) \ + _(XR_TYPE_SPACE_VELOCITY, 43) \ + _(XR_TYPE_FRAME_STATE, 44) \ + _(XR_TYPE_VIEW_CONFIGURATION_PROPERTIES, 45) \ + _(XR_TYPE_FRAME_BEGIN_INFO, 46) \ + _(XR_TYPE_COMPOSITION_LAYER_PROJECTION_VIEW, 48) \ + _(XR_TYPE_EVENT_DATA_EVENTS_LOST, 49) \ + _(XR_TYPE_INTERACTION_PROFILE_SUGGESTED_BINDING, 51) \ + _(XR_TYPE_EVENT_DATA_INTERACTION_PROFILE_CHANGED, 52) \ + _(XR_TYPE_INTERACTION_PROFILE_STATE, 53) \ + _(XR_TYPE_SWAPCHAIN_IMAGE_ACQUIRE_INFO, 55) \ + _(XR_TYPE_SWAPCHAIN_IMAGE_WAIT_INFO, 56) \ + _(XR_TYPE_SWAPCHAIN_IMAGE_RELEASE_INFO, 57) \ + _(XR_TYPE_ACTION_STATE_GET_INFO, 58) \ + _(XR_TYPE_HAPTIC_ACTION_INFO, 59) \ + _(XR_TYPE_SESSION_ACTION_SETS_ATTACH_INFO, 60) \ + _(XR_TYPE_ACTIONS_SYNC_INFO, 61) \ + _(XR_TYPE_BOUND_SOURCES_FOR_ACTION_ENUMERATE_INFO, 62) \ + _(XR_TYPE_INPUT_SOURCE_LOCALIZED_NAME_GET_INFO, 63) \ + _(XR_TYPE_COMPOSITION_LAYER_CUBE_KHR, 1000006000) \ + _(XR_TYPE_INSTANCE_CREATE_INFO_ANDROID_KHR, 1000008000) \ + _(XR_TYPE_COMPOSITION_LAYER_DEPTH_INFO_KHR, 1000010000) \ + _(XR_TYPE_VULKAN_SWAPCHAIN_FORMAT_LIST_CREATE_INFO_KHR, 1000014000) \ + _(XR_TYPE_EVENT_DATA_PERF_SETTINGS_EXT, 1000015000) \ + _(XR_TYPE_COMPOSITION_LAYER_CYLINDER_KHR, 1000017000) \ + _(XR_TYPE_COMPOSITION_LAYER_EQUIRECT_KHR, 1000018000) \ + _(XR_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT, 1000019000) \ + _(XR_TYPE_DEBUG_UTILS_MESSENGER_CALLBACK_DATA_EXT, 1000019001) \ + _(XR_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT, 1000019002) \ + _(XR_TYPE_DEBUG_UTILS_LABEL_EXT, 1000019003) \ + _(XR_TYPE_GRAPHICS_BINDING_OPENGL_WIN32_KHR, 1000023000) \ + _(XR_TYPE_GRAPHICS_BINDING_OPENGL_XLIB_KHR, 1000023001) \ + _(XR_TYPE_GRAPHICS_BINDING_OPENGL_XCB_KHR, 1000023002) \ + _(XR_TYPE_GRAPHICS_BINDING_OPENGL_WAYLAND_KHR, 1000023003) \ + _(XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_KHR, 1000023004) \ + _(XR_TYPE_GRAPHICS_REQUIREMENTS_OPENGL_KHR, 1000023005) \ + _(XR_TYPE_GRAPHICS_BINDING_OPENGL_ES_ANDROID_KHR, 1000024001) \ + _(XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_ES_KHR, 1000024002) \ + _(XR_TYPE_GRAPHICS_REQUIREMENTS_OPENGL_ES_KHR, 1000024003) \ + _(XR_TYPE_GRAPHICS_BINDING_VULKAN_KHR, 1000025000) \ + _(XR_TYPE_SWAPCHAIN_IMAGE_VULKAN_KHR, 1000025001) \ + _(XR_TYPE_GRAPHICS_REQUIREMENTS_VULKAN_KHR, 1000025002) \ + _(XR_TYPE_GRAPHICS_BINDING_D3D11_KHR, 1000027000) \ + _(XR_TYPE_SWAPCHAIN_IMAGE_D3D11_KHR, 1000027001) \ + _(XR_TYPE_GRAPHICS_REQUIREMENTS_D3D11_KHR, 1000027002) \ + _(XR_TYPE_GRAPHICS_BINDING_D3D12_KHR, 1000028000) \ + _(XR_TYPE_SWAPCHAIN_IMAGE_D3D12_KHR, 1000028001) \ + _(XR_TYPE_GRAPHICS_REQUIREMENTS_D3D12_KHR, 1000028002) \ + _(XR_TYPE_SYSTEM_EYE_GAZE_INTERACTION_PROPERTIES_EXT, 1000030000) \ + _(XR_TYPE_EYE_GAZE_SAMPLE_TIME_EXT, 1000030001) \ + _(XR_TYPE_VISIBILITY_MASK_KHR, 1000031000) \ + _(XR_TYPE_EVENT_DATA_VISIBILITY_MASK_CHANGED_KHR, 1000031001) \ + _(XR_TYPE_SESSION_CREATE_INFO_OVERLAY_EXTX, 1000033000) \ + _(XR_TYPE_EVENT_DATA_MAIN_SESSION_VISIBILITY_CHANGED_EXTX, 1000033003) \ + _(XR_TYPE_COMPOSITION_LAYER_COLOR_SCALE_BIAS_KHR, 1000034000) \ + _(XR_TYPE_SPATIAL_ANCHOR_CREATE_INFO_MSFT, 1000039000) \ + _(XR_TYPE_SPATIAL_ANCHOR_SPACE_CREATE_INFO_MSFT, 1000039001) \ + _(XR_TYPE_COMPOSITION_LAYER_IMAGE_LAYOUT_FB, 1000040000) \ + _(XR_TYPE_COMPOSITION_LAYER_ALPHA_BLEND_FB, 1000041001) \ + _(XR_TYPE_VIEW_CONFIGURATION_DEPTH_RANGE_EXT, 1000046000) \ + _(XR_TYPE_GRAPHICS_BINDING_EGL_MNDX, 1000048004) \ + _(XR_TYPE_SPATIAL_GRAPH_NODE_SPACE_CREATE_INFO_MSFT, 1000049000) \ + _(XR_TYPE_SPATIAL_GRAPH_STATIC_NODE_BINDING_CREATE_INFO_MSFT, 1000049001) \ + _(XR_TYPE_SPATIAL_GRAPH_NODE_BINDING_PROPERTIES_GET_INFO_MSFT, 1000049002) \ + _(XR_TYPE_SPATIAL_GRAPH_NODE_BINDING_PROPERTIES_MSFT, 1000049003) \ + _(XR_TYPE_SYSTEM_HAND_TRACKING_PROPERTIES_EXT, 1000051000) \ + _(XR_TYPE_HAND_TRACKER_CREATE_INFO_EXT, 1000051001) \ + _(XR_TYPE_HAND_JOINTS_LOCATE_INFO_EXT, 1000051002) \ + _(XR_TYPE_HAND_JOINT_LOCATIONS_EXT, 1000051003) \ + _(XR_TYPE_HAND_JOINT_VELOCITIES_EXT, 1000051004) \ + _(XR_TYPE_SYSTEM_HAND_TRACKING_MESH_PROPERTIES_MSFT, 1000052000) \ + _(XR_TYPE_HAND_MESH_SPACE_CREATE_INFO_MSFT, 1000052001) \ + _(XR_TYPE_HAND_MESH_UPDATE_INFO_MSFT, 1000052002) \ + _(XR_TYPE_HAND_MESH_MSFT, 1000052003) \ + _(XR_TYPE_HAND_POSE_TYPE_INFO_MSFT, 1000052004) \ + _(XR_TYPE_SECONDARY_VIEW_CONFIGURATION_SESSION_BEGIN_INFO_MSFT, 1000053000) \ + _(XR_TYPE_SECONDARY_VIEW_CONFIGURATION_STATE_MSFT, 1000053001) \ + _(XR_TYPE_SECONDARY_VIEW_CONFIGURATION_FRAME_STATE_MSFT, 1000053002) \ + _(XR_TYPE_SECONDARY_VIEW_CONFIGURATION_FRAME_END_INFO_MSFT, 1000053003) \ + _(XR_TYPE_SECONDARY_VIEW_CONFIGURATION_LAYER_INFO_MSFT, 1000053004) \ + _(XR_TYPE_SECONDARY_VIEW_CONFIGURATION_SWAPCHAIN_CREATE_INFO_MSFT, 1000053005) \ + _(XR_TYPE_CONTROLLER_MODEL_KEY_STATE_MSFT, 1000055000) \ + _(XR_TYPE_CONTROLLER_MODEL_NODE_PROPERTIES_MSFT, 1000055001) \ + _(XR_TYPE_CONTROLLER_MODEL_PROPERTIES_MSFT, 1000055002) \ + _(XR_TYPE_CONTROLLER_MODEL_NODE_STATE_MSFT, 1000055003) \ + _(XR_TYPE_CONTROLLER_MODEL_STATE_MSFT, 1000055004) \ + _(XR_TYPE_VIEW_CONFIGURATION_VIEW_FOV_EPIC, 1000059000) \ + _(XR_TYPE_HOLOGRAPHIC_WINDOW_ATTACHMENT_MSFT, 1000063000) \ + _(XR_TYPE_COMPOSITION_LAYER_REPROJECTION_INFO_MSFT, 1000066000) \ + _(XR_TYPE_COMPOSITION_LAYER_REPROJECTION_PLANE_OVERRIDE_MSFT, 1000066001) \ + _(XR_TYPE_ANDROID_SURFACE_SWAPCHAIN_CREATE_INFO_FB, 1000070000) \ + _(XR_TYPE_COMPOSITION_LAYER_SECURE_CONTENT_FB, 1000072000) \ + _(XR_TYPE_INTERACTION_PROFILE_DPAD_BINDING_EXT, 1000078000) \ + _(XR_TYPE_INTERACTION_PROFILE_ANALOG_THRESHOLD_VALVE, 1000079000) \ + _(XR_TYPE_HAND_JOINTS_MOTION_RANGE_INFO_EXT, 1000080000) \ + _(XR_TYPE_LOADER_INIT_INFO_ANDROID_KHR, 1000089000) \ + _(XR_TYPE_VULKAN_INSTANCE_CREATE_INFO_KHR, 1000090000) \ + _(XR_TYPE_VULKAN_DEVICE_CREATE_INFO_KHR, 1000090001) \ + _(XR_TYPE_VULKAN_GRAPHICS_DEVICE_GET_INFO_KHR, 1000090003) \ + _(XR_TYPE_COMPOSITION_LAYER_EQUIRECT2_KHR, 1000091000) \ + _(XR_TYPE_SCENE_OBSERVER_CREATE_INFO_MSFT, 1000097000) \ + _(XR_TYPE_SCENE_CREATE_INFO_MSFT, 1000097001) \ + _(XR_TYPE_NEW_SCENE_COMPUTE_INFO_MSFT, 1000097002) \ + _(XR_TYPE_VISUAL_MESH_COMPUTE_LOD_INFO_MSFT, 1000097003) \ + _(XR_TYPE_SCENE_COMPONENTS_MSFT, 1000097004) \ + _(XR_TYPE_SCENE_COMPONENTS_GET_INFO_MSFT, 1000097005) \ + _(XR_TYPE_SCENE_COMPONENT_LOCATIONS_MSFT, 1000097006) \ + _(XR_TYPE_SCENE_COMPONENTS_LOCATE_INFO_MSFT, 1000097007) \ + _(XR_TYPE_SCENE_OBJECTS_MSFT, 1000097008) \ + _(XR_TYPE_SCENE_COMPONENT_PARENT_FILTER_INFO_MSFT, 1000097009) \ + _(XR_TYPE_SCENE_OBJECT_TYPES_FILTER_INFO_MSFT, 1000097010) \ + _(XR_TYPE_SCENE_PLANES_MSFT, 1000097011) \ + _(XR_TYPE_SCENE_PLANE_ALIGNMENT_FILTER_INFO_MSFT, 1000097012) \ + _(XR_TYPE_SCENE_MESHES_MSFT, 1000097013) \ + _(XR_TYPE_SCENE_MESH_BUFFERS_GET_INFO_MSFT, 1000097014) \ + _(XR_TYPE_SCENE_MESH_BUFFERS_MSFT, 1000097015) \ + _(XR_TYPE_SCENE_MESH_VERTEX_BUFFER_MSFT, 1000097016) \ + _(XR_TYPE_SCENE_MESH_INDICES_UINT32_MSFT, 1000097017) \ + _(XR_TYPE_SCENE_MESH_INDICES_UINT16_MSFT, 1000097018) \ + _(XR_TYPE_SERIALIZED_SCENE_FRAGMENT_DATA_GET_INFO_MSFT, 1000098000) \ + _(XR_TYPE_SCENE_DESERIALIZE_INFO_MSFT, 1000098001) \ + _(XR_TYPE_EVENT_DATA_DISPLAY_REFRESH_RATE_CHANGED_FB, 1000101000) \ + _(XR_TYPE_VIVE_TRACKER_PATHS_HTCX, 1000103000) \ + _(XR_TYPE_EVENT_DATA_VIVE_TRACKER_CONNECTED_HTCX, 1000103001) \ + _(XR_TYPE_SYSTEM_FACIAL_TRACKING_PROPERTIES_HTC, 1000104000) \ + _(XR_TYPE_FACIAL_TRACKER_CREATE_INFO_HTC, 1000104001) \ + _(XR_TYPE_FACIAL_EXPRESSIONS_HTC, 1000104002) \ + _(XR_TYPE_SYSTEM_COLOR_SPACE_PROPERTIES_FB, 1000108000) \ + _(XR_TYPE_HAND_TRACKING_MESH_FB, 1000110001) \ + _(XR_TYPE_HAND_TRACKING_SCALE_FB, 1000110003) \ + _(XR_TYPE_HAND_TRACKING_AIM_STATE_FB, 1000111001) \ + _(XR_TYPE_HAND_TRACKING_CAPSULES_STATE_FB, 1000112000) \ + _(XR_TYPE_SYSTEM_SPATIAL_ENTITY_PROPERTIES_FB, 1000113004) \ + _(XR_TYPE_SPATIAL_ANCHOR_CREATE_INFO_FB, 1000113003) \ + _(XR_TYPE_SPACE_COMPONENT_STATUS_SET_INFO_FB, 1000113007) \ + _(XR_TYPE_SPACE_COMPONENT_STATUS_FB, 1000113001) \ + _(XR_TYPE_EVENT_DATA_SPATIAL_ANCHOR_CREATE_COMPLETE_FB, 1000113005) \ + _(XR_TYPE_EVENT_DATA_SPACE_SET_STATUS_COMPLETE_FB, 1000113006) \ + _(XR_TYPE_FOVEATION_PROFILE_CREATE_INFO_FB, 1000114000) \ + _(XR_TYPE_SWAPCHAIN_CREATE_INFO_FOVEATION_FB, 1000114001) \ + _(XR_TYPE_SWAPCHAIN_STATE_FOVEATION_FB, 1000114002) \ + _(XR_TYPE_FOVEATION_LEVEL_PROFILE_CREATE_INFO_FB, 1000115000) \ + _(XR_TYPE_KEYBOARD_SPACE_CREATE_INFO_FB, 1000116009) \ + _(XR_TYPE_KEYBOARD_TRACKING_QUERY_FB, 1000116004) \ + _(XR_TYPE_SYSTEM_KEYBOARD_TRACKING_PROPERTIES_FB, 1000116002) \ + _(XR_TYPE_TRIANGLE_MESH_CREATE_INFO_FB, 1000117001) \ + _(XR_TYPE_SYSTEM_PASSTHROUGH_PROPERTIES_FB, 1000118000) \ + _(XR_TYPE_PASSTHROUGH_CREATE_INFO_FB, 1000118001) \ + _(XR_TYPE_PASSTHROUGH_LAYER_CREATE_INFO_FB, 1000118002) \ + _(XR_TYPE_COMPOSITION_LAYER_PASSTHROUGH_FB, 1000118003) \ + _(XR_TYPE_GEOMETRY_INSTANCE_CREATE_INFO_FB, 1000118004) \ + _(XR_TYPE_GEOMETRY_INSTANCE_TRANSFORM_FB, 1000118005) \ + _(XR_TYPE_SYSTEM_PASSTHROUGH_PROPERTIES2_FB, 1000118006) \ + _(XR_TYPE_PASSTHROUGH_STYLE_FB, 1000118020) \ + _(XR_TYPE_PASSTHROUGH_COLOR_MAP_MONO_TO_RGBA_FB, 1000118021) \ + _(XR_TYPE_PASSTHROUGH_COLOR_MAP_MONO_TO_MONO_FB, 1000118022) \ + _(XR_TYPE_PASSTHROUGH_BRIGHTNESS_CONTRAST_SATURATION_FB, 1000118023) \ + _(XR_TYPE_EVENT_DATA_PASSTHROUGH_STATE_CHANGED_FB, 1000118030) \ + _(XR_TYPE_RENDER_MODEL_PATH_INFO_FB, 1000119000) \ + _(XR_TYPE_RENDER_MODEL_PROPERTIES_FB, 1000119001) \ + _(XR_TYPE_RENDER_MODEL_BUFFER_FB, 1000119002) \ + _(XR_TYPE_RENDER_MODEL_LOAD_INFO_FB, 1000119003) \ + _(XR_TYPE_SYSTEM_RENDER_MODEL_PROPERTIES_FB, 1000119004) \ + _(XR_TYPE_RENDER_MODEL_CAPABILITIES_REQUEST_FB, 1000119005) \ + _(XR_TYPE_BINDING_MODIFICATIONS_KHR, 1000120000) \ + _(XR_TYPE_VIEW_LOCATE_FOVEATED_RENDERING_VARJO, 1000121000) \ + _(XR_TYPE_FOVEATED_VIEW_CONFIGURATION_VIEW_VARJO, 1000121001) \ + _(XR_TYPE_SYSTEM_FOVEATED_RENDERING_PROPERTIES_VARJO, 1000121002) \ + _(XR_TYPE_COMPOSITION_LAYER_DEPTH_TEST_VARJO, 1000122000) \ + _(XR_TYPE_SYSTEM_MARKER_TRACKING_PROPERTIES_VARJO, 1000124000) \ + _(XR_TYPE_EVENT_DATA_MARKER_TRACKING_UPDATE_VARJO, 1000124001) \ + _(XR_TYPE_MARKER_SPACE_CREATE_INFO_VARJO, 1000124002) \ + _(XR_TYPE_SPATIAL_ANCHOR_PERSISTENCE_INFO_MSFT, 1000142000) \ + _(XR_TYPE_SPATIAL_ANCHOR_FROM_PERSISTED_ANCHOR_CREATE_INFO_MSFT, 1000142001) \ + _(XR_TYPE_SPACE_QUERY_INFO_FB, 1000156001) \ + _(XR_TYPE_SPACE_QUERY_RESULTS_FB, 1000156002) \ + _(XR_TYPE_SPACE_STORAGE_LOCATION_FILTER_INFO_FB, 1000156003) \ + _(XR_TYPE_SPACE_UUID_FILTER_INFO_FB, 1000156054) \ + _(XR_TYPE_SPACE_COMPONENT_FILTER_INFO_FB, 1000156052) \ + _(XR_TYPE_EVENT_DATA_SPACE_QUERY_RESULTS_AVAILABLE_FB, 1000156103) \ + _(XR_TYPE_EVENT_DATA_SPACE_QUERY_COMPLETE_FB, 1000156104) \ + _(XR_TYPE_SPACE_SAVE_INFO_FB, 1000158000) \ + _(XR_TYPE_SPACE_ERASE_INFO_FB, 1000158001) \ + _(XR_TYPE_EVENT_DATA_SPACE_SAVE_COMPLETE_FB, 1000158106) \ + _(XR_TYPE_EVENT_DATA_SPACE_ERASE_COMPLETE_FB, 1000158107) \ + _(XR_TYPE_SWAPCHAIN_IMAGE_FOVEATION_VULKAN_FB, 1000160000) \ + _(XR_TYPE_SWAPCHAIN_STATE_ANDROID_SURFACE_DIMENSIONS_FB, 1000161000) \ + _(XR_TYPE_SWAPCHAIN_STATE_SAMPLER_OPENGL_ES_FB, 1000162000) \ + _(XR_TYPE_SWAPCHAIN_STATE_SAMPLER_VULKAN_FB, 1000163000) \ + _(XR_TYPE_COMPOSITION_LAYER_SPACE_WARP_INFO_FB, 1000171000) \ + _(XR_TYPE_SYSTEM_SPACE_WARP_PROPERTIES_FB, 1000171001) \ + _(XR_TYPE_SEMANTIC_LABELS_FB, 1000175000) \ + _(XR_TYPE_ROOM_LAYOUT_FB, 1000175001) \ + _(XR_TYPE_BOUNDARY_2D_FB, 1000175002) \ + _(XR_TYPE_DIGITAL_LENS_CONTROL_ALMALENCE, 1000196000) \ + _(XR_TYPE_SPACE_CONTAINER_FB, 1000199000) \ + _(XR_TYPE_PASSTHROUGH_KEYBOARD_HANDS_INTENSITY_FB, 1000203002) \ + _(XR_TYPE_COMPOSITION_LAYER_SETTINGS_FB, 1000204000) \ + _(XR_TYPE_VULKAN_SWAPCHAIN_CREATE_INFO_META, 1000227000) \ + _(XR_TYPE_PERFORMANCE_METRICS_STATE_META, 1000232001) \ + _(XR_TYPE_PERFORMANCE_METRICS_COUNTER_META, 1000232002) \ + _(XR_STRUCTURE_TYPE_MAX_ENUM, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrFormFactor(_) \ + _(XR_FORM_FACTOR_HEAD_MOUNTED_DISPLAY, 1) \ + _(XR_FORM_FACTOR_HANDHELD_DISPLAY, 2) \ + _(XR_FORM_FACTOR_MAX_ENUM, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrViewConfigurationType(_) \ + _(XR_VIEW_CONFIGURATION_TYPE_PRIMARY_MONO, 1) \ + _(XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO, 2) \ + _(XR_VIEW_CONFIGURATION_TYPE_PRIMARY_QUAD_VARJO, 1000037000) \ + _(XR_VIEW_CONFIGURATION_TYPE_SECONDARY_MONO_FIRST_PERSON_OBSERVER_MSFT, 1000054000) \ + _(XR_VIEW_CONFIGURATION_TYPE_MAX_ENUM, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrEnvironmentBlendMode(_) \ + _(XR_ENVIRONMENT_BLEND_MODE_OPAQUE, 1) \ + _(XR_ENVIRONMENT_BLEND_MODE_ADDITIVE, 2) \ + _(XR_ENVIRONMENT_BLEND_MODE_ALPHA_BLEND, 3) \ + _(XR_ENVIRONMENT_BLEND_MODE_MAX_ENUM, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrReferenceSpaceType(_) \ + _(XR_REFERENCE_SPACE_TYPE_VIEW, 1) \ + _(XR_REFERENCE_SPACE_TYPE_LOCAL, 2) \ + _(XR_REFERENCE_SPACE_TYPE_STAGE, 3) \ + _(XR_REFERENCE_SPACE_TYPE_UNBOUNDED_MSFT, 1000038000) \ + _(XR_REFERENCE_SPACE_TYPE_COMBINED_EYE_VARJO, 1000121000) \ + _(XR_REFERENCE_SPACE_TYPE_MAX_ENUM, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrActionType(_) \ + _(XR_ACTION_TYPE_BOOLEAN_INPUT, 1) \ + _(XR_ACTION_TYPE_FLOAT_INPUT, 2) \ + _(XR_ACTION_TYPE_VECTOR2F_INPUT, 3) \ + _(XR_ACTION_TYPE_POSE_INPUT, 4) \ + _(XR_ACTION_TYPE_VIBRATION_OUTPUT, 100) \ + _(XR_ACTION_TYPE_MAX_ENUM, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrEyeVisibility(_) \ + _(XR_EYE_VISIBILITY_BOTH, 0) \ + _(XR_EYE_VISIBILITY_LEFT, 1) \ + _(XR_EYE_VISIBILITY_RIGHT, 2) \ + _(XR_EYE_VISIBILITY_MAX_ENUM, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrSessionState(_) \ + _(XR_SESSION_STATE_UNKNOWN, 0) \ + _(XR_SESSION_STATE_IDLE, 1) \ + _(XR_SESSION_STATE_READY, 2) \ + _(XR_SESSION_STATE_SYNCHRONIZED, 3) \ + _(XR_SESSION_STATE_VISIBLE, 4) \ + _(XR_SESSION_STATE_FOCUSED, 5) \ + _(XR_SESSION_STATE_STOPPING, 6) \ + _(XR_SESSION_STATE_LOSS_PENDING, 7) \ + _(XR_SESSION_STATE_EXITING, 8) \ + _(XR_SESSION_STATE_MAX_ENUM, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrObjectType(_) \ + _(XR_OBJECT_TYPE_UNKNOWN, 0) \ + _(XR_OBJECT_TYPE_INSTANCE, 1) \ + _(XR_OBJECT_TYPE_SESSION, 2) \ + _(XR_OBJECT_TYPE_SWAPCHAIN, 3) \ + _(XR_OBJECT_TYPE_SPACE, 4) \ + _(XR_OBJECT_TYPE_ACTION_SET, 5) \ + _(XR_OBJECT_TYPE_ACTION, 6) \ + _(XR_OBJECT_TYPE_DEBUG_UTILS_MESSENGER_EXT, 1000019000) \ + _(XR_OBJECT_TYPE_SPATIAL_ANCHOR_MSFT, 1000039000) \ + _(XR_OBJECT_TYPE_SPATIAL_GRAPH_NODE_BINDING_MSFT, 1000049000) \ + _(XR_OBJECT_TYPE_HAND_TRACKER_EXT, 1000051000) \ + _(XR_OBJECT_TYPE_SCENE_OBSERVER_MSFT, 1000097000) \ + _(XR_OBJECT_TYPE_SCENE_MSFT, 1000097001) \ + _(XR_OBJECT_TYPE_FACIAL_TRACKER_HTC, 1000104000) \ + _(XR_OBJECT_TYPE_FOVEATION_PROFILE_FB, 1000114000) \ + _(XR_OBJECT_TYPE_TRIANGLE_MESH_FB, 1000117000) \ + _(XR_OBJECT_TYPE_PASSTHROUGH_FB, 1000118000) \ + _(XR_OBJECT_TYPE_PASSTHROUGH_LAYER_FB, 1000118002) \ + _(XR_OBJECT_TYPE_GEOMETRY_INSTANCE_FB, 1000118004) \ + _(XR_OBJECT_TYPE_SPATIAL_ANCHOR_STORE_CONNECTION_MSFT, 1000142000) \ + _(XR_OBJECT_TYPE_MAX_ENUM, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrAndroidThreadTypeKHR(_) \ + _(XR_ANDROID_THREAD_TYPE_APPLICATION_MAIN_KHR, 1) \ + _(XR_ANDROID_THREAD_TYPE_APPLICATION_WORKER_KHR, 2) \ + _(XR_ANDROID_THREAD_TYPE_RENDERER_MAIN_KHR, 3) \ + _(XR_ANDROID_THREAD_TYPE_RENDERER_WORKER_KHR, 4) \ + _(XR_ANDROID_THREAD_TYPE_MAX_ENUM_KHR, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrVisibilityMaskTypeKHR(_) \ + _(XR_VISIBILITY_MASK_TYPE_HIDDEN_TRIANGLE_MESH_KHR, 1) \ + _(XR_VISIBILITY_MASK_TYPE_VISIBLE_TRIANGLE_MESH_KHR, 2) \ + _(XR_VISIBILITY_MASK_TYPE_LINE_LOOP_KHR, 3) \ + _(XR_VISIBILITY_MASK_TYPE_MAX_ENUM_KHR, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrPerfSettingsDomainEXT(_) \ + _(XR_PERF_SETTINGS_DOMAIN_CPU_EXT, 1) \ + _(XR_PERF_SETTINGS_DOMAIN_GPU_EXT, 2) \ + _(XR_PERF_SETTINGS_DOMAIN_MAX_ENUM_EXT, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrPerfSettingsSubDomainEXT(_) \ + _(XR_PERF_SETTINGS_SUB_DOMAIN_COMPOSITING_EXT, 1) \ + _(XR_PERF_SETTINGS_SUB_DOMAIN_RENDERING_EXT, 2) \ + _(XR_PERF_SETTINGS_SUB_DOMAIN_THERMAL_EXT, 3) \ + _(XR_PERF_SETTINGS_SUB_DOMAIN_MAX_ENUM_EXT, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrPerfSettingsLevelEXT(_) \ + _(XR_PERF_SETTINGS_LEVEL_POWER_SAVINGS_EXT, 0) \ + _(XR_PERF_SETTINGS_LEVEL_SUSTAINED_LOW_EXT, 25) \ + _(XR_PERF_SETTINGS_LEVEL_SUSTAINED_HIGH_EXT, 50) \ + _(XR_PERF_SETTINGS_LEVEL_BOOST_EXT, 75) \ + _(XR_PERF_SETTINGS_LEVEL_MAX_ENUM_EXT, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrPerfSettingsNotificationLevelEXT(_) \ + _(XR_PERF_SETTINGS_NOTIF_LEVEL_NORMAL_EXT, 0) \ + _(XR_PERF_SETTINGS_NOTIF_LEVEL_WARNING_EXT, 25) \ + _(XR_PERF_SETTINGS_NOTIF_LEVEL_IMPAIRED_EXT, 75) \ + _(XR_PERF_SETTINGS_NOTIFICATION_LEVEL_MAX_ENUM_EXT, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrBlendFactorFB(_) \ + _(XR_BLEND_FACTOR_ZERO_FB, 0) \ + _(XR_BLEND_FACTOR_ONE_FB, 1) \ + _(XR_BLEND_FACTOR_SRC_ALPHA_FB, 2) \ + _(XR_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA_FB, 3) \ + _(XR_BLEND_FACTOR_DST_ALPHA_FB, 4) \ + _(XR_BLEND_FACTOR_ONE_MINUS_DST_ALPHA_FB, 5) \ + _(XR_BLEND_FACTOR_MAX_ENUM_FB, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrSpatialGraphNodeTypeMSFT(_) \ + _(XR_SPATIAL_GRAPH_NODE_TYPE_STATIC_MSFT, 1) \ + _(XR_SPATIAL_GRAPH_NODE_TYPE_DYNAMIC_MSFT, 2) \ + _(XR_SPATIAL_GRAPH_NODE_TYPE_MAX_ENUM_MSFT, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrHandEXT(_) \ + _(XR_HAND_LEFT_EXT, 1) \ + _(XR_HAND_RIGHT_EXT, 2) \ + _(XR_HAND_MAX_ENUM_EXT, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrHandJointEXT(_) \ + _(XR_HAND_JOINT_PALM_EXT, 0) \ + _(XR_HAND_JOINT_WRIST_EXT, 1) \ + _(XR_HAND_JOINT_THUMB_METACARPAL_EXT, 2) \ + _(XR_HAND_JOINT_THUMB_PROXIMAL_EXT, 3) \ + _(XR_HAND_JOINT_THUMB_DISTAL_EXT, 4) \ + _(XR_HAND_JOINT_THUMB_TIP_EXT, 5) \ + _(XR_HAND_JOINT_INDEX_METACARPAL_EXT, 6) \ + _(XR_HAND_JOINT_INDEX_PROXIMAL_EXT, 7) \ + _(XR_HAND_JOINT_INDEX_INTERMEDIATE_EXT, 8) \ + _(XR_HAND_JOINT_INDEX_DISTAL_EXT, 9) \ + _(XR_HAND_JOINT_INDEX_TIP_EXT, 10) \ + _(XR_HAND_JOINT_MIDDLE_METACARPAL_EXT, 11) \ + _(XR_HAND_JOINT_MIDDLE_PROXIMAL_EXT, 12) \ + _(XR_HAND_JOINT_MIDDLE_INTERMEDIATE_EXT, 13) \ + _(XR_HAND_JOINT_MIDDLE_DISTAL_EXT, 14) \ + _(XR_HAND_JOINT_MIDDLE_TIP_EXT, 15) \ + _(XR_HAND_JOINT_RING_METACARPAL_EXT, 16) \ + _(XR_HAND_JOINT_RING_PROXIMAL_EXT, 17) \ + _(XR_HAND_JOINT_RING_INTERMEDIATE_EXT, 18) \ + _(XR_HAND_JOINT_RING_DISTAL_EXT, 19) \ + _(XR_HAND_JOINT_RING_TIP_EXT, 20) \ + _(XR_HAND_JOINT_LITTLE_METACARPAL_EXT, 21) \ + _(XR_HAND_JOINT_LITTLE_PROXIMAL_EXT, 22) \ + _(XR_HAND_JOINT_LITTLE_INTERMEDIATE_EXT, 23) \ + _(XR_HAND_JOINT_LITTLE_DISTAL_EXT, 24) \ + _(XR_HAND_JOINT_LITTLE_TIP_EXT, 25) \ + _(XR_HAND_JOINT_MAX_ENUM_EXT, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrHandJointSetEXT(_) \ + _(XR_HAND_JOINT_SET_DEFAULT_EXT, 0) \ + _(XR_HAND_JOINT_SET_HAND_WITH_FOREARM_ULTRALEAP, 1000149000) \ + _(XR_HAND_JOINT_SET_MAX_ENUM_EXT, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrHandPoseTypeMSFT(_) \ + _(XR_HAND_POSE_TYPE_TRACKED_MSFT, 0) \ + _(XR_HAND_POSE_TYPE_REFERENCE_OPEN_PALM_MSFT, 1) \ + _(XR_HAND_POSE_TYPE_MAX_ENUM_MSFT, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrReprojectionModeMSFT(_) \ + _(XR_REPROJECTION_MODE_DEPTH_MSFT, 1) \ + _(XR_REPROJECTION_MODE_PLANAR_FROM_DEPTH_MSFT, 2) \ + _(XR_REPROJECTION_MODE_PLANAR_MANUAL_MSFT, 3) \ + _(XR_REPROJECTION_MODE_ORIENTATION_ONLY_MSFT, 4) \ + _(XR_REPROJECTION_MODE_MAX_ENUM_MSFT, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrHandJointsMotionRangeEXT(_) \ + _(XR_HAND_JOINTS_MOTION_RANGE_UNOBSTRUCTED_EXT, 1) \ + _(XR_HAND_JOINTS_MOTION_RANGE_CONFORMING_TO_CONTROLLER_EXT, 2) \ + _(XR_HAND_JOINTS_MOTION_RANGE_MAX_ENUM_EXT, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrSceneComputeFeatureMSFT(_) \ + _(XR_SCENE_COMPUTE_FEATURE_PLANE_MSFT, 1) \ + _(XR_SCENE_COMPUTE_FEATURE_PLANE_MESH_MSFT, 2) \ + _(XR_SCENE_COMPUTE_FEATURE_VISUAL_MESH_MSFT, 3) \ + _(XR_SCENE_COMPUTE_FEATURE_COLLIDER_MESH_MSFT, 4) \ + _(XR_SCENE_COMPUTE_FEATURE_SERIALIZE_SCENE_MSFT, 1000098000) \ + _(XR_SCENE_COMPUTE_FEATURE_MAX_ENUM_MSFT, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrSceneComputeConsistencyMSFT(_) \ + _(XR_SCENE_COMPUTE_CONSISTENCY_SNAPSHOT_COMPLETE_MSFT, 1) \ + _(XR_SCENE_COMPUTE_CONSISTENCY_SNAPSHOT_INCOMPLETE_FAST_MSFT, 2) \ + _(XR_SCENE_COMPUTE_CONSISTENCY_OCCLUSION_OPTIMIZED_MSFT, 3) \ + _(XR_SCENE_COMPUTE_CONSISTENCY_MAX_ENUM_MSFT, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrMeshComputeLodMSFT(_) \ + _(XR_MESH_COMPUTE_LOD_COARSE_MSFT, 1) \ + _(XR_MESH_COMPUTE_LOD_MEDIUM_MSFT, 2) \ + _(XR_MESH_COMPUTE_LOD_FINE_MSFT, 3) \ + _(XR_MESH_COMPUTE_LOD_UNLIMITED_MSFT, 4) \ + _(XR_MESH_COMPUTE_LOD_MAX_ENUM_MSFT, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrSceneComponentTypeMSFT(_) \ + _(XR_SCENE_COMPONENT_TYPE_INVALID_MSFT, -1) \ + _(XR_SCENE_COMPONENT_TYPE_OBJECT_MSFT, 1) \ + _(XR_SCENE_COMPONENT_TYPE_PLANE_MSFT, 2) \ + _(XR_SCENE_COMPONENT_TYPE_VISUAL_MESH_MSFT, 3) \ + _(XR_SCENE_COMPONENT_TYPE_COLLIDER_MESH_MSFT, 4) \ + _(XR_SCENE_COMPONENT_TYPE_SERIALIZED_SCENE_FRAGMENT_MSFT, 1000098000) \ + _(XR_SCENE_COMPONENT_TYPE_MAX_ENUM_MSFT, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrSceneObjectTypeMSFT(_) \ + _(XR_SCENE_OBJECT_TYPE_UNCATEGORIZED_MSFT, -1) \ + _(XR_SCENE_OBJECT_TYPE_BACKGROUND_MSFT, 1) \ + _(XR_SCENE_OBJECT_TYPE_WALL_MSFT, 2) \ + _(XR_SCENE_OBJECT_TYPE_FLOOR_MSFT, 3) \ + _(XR_SCENE_OBJECT_TYPE_CEILING_MSFT, 4) \ + _(XR_SCENE_OBJECT_TYPE_PLATFORM_MSFT, 5) \ + _(XR_SCENE_OBJECT_TYPE_INFERRED_MSFT, 6) \ + _(XR_SCENE_OBJECT_TYPE_MAX_ENUM_MSFT, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrScenePlaneAlignmentTypeMSFT(_) \ + _(XR_SCENE_PLANE_ALIGNMENT_TYPE_NON_ORTHOGONAL_MSFT, 0) \ + _(XR_SCENE_PLANE_ALIGNMENT_TYPE_HORIZONTAL_MSFT, 1) \ + _(XR_SCENE_PLANE_ALIGNMENT_TYPE_VERTICAL_MSFT, 2) \ + _(XR_SCENE_PLANE_ALIGNMENT_TYPE_MAX_ENUM_MSFT, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrSceneComputeStateMSFT(_) \ + _(XR_SCENE_COMPUTE_STATE_NONE_MSFT, 0) \ + _(XR_SCENE_COMPUTE_STATE_UPDATING_MSFT, 1) \ + _(XR_SCENE_COMPUTE_STATE_COMPLETED_MSFT, 2) \ + _(XR_SCENE_COMPUTE_STATE_COMPLETED_WITH_ERROR_MSFT, 3) \ + _(XR_SCENE_COMPUTE_STATE_MAX_ENUM_MSFT, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrEyeExpressionHTC(_) \ + _(XR_EYE_EXPRESSION_LEFT_BLINK_HTC, 0) \ + _(XR_EYE_EXPRESSION_LEFT_WIDE_HTC, 1) \ + _(XR_EYE_EXPRESSION_RIGHT_BLINK_HTC, 2) \ + _(XR_EYE_EXPRESSION_RIGHT_WIDE_HTC, 3) \ + _(XR_EYE_EXPRESSION_LEFT_SQUEEZE_HTC, 4) \ + _(XR_EYE_EXPRESSION_RIGHT_SQUEEZE_HTC, 5) \ + _(XR_EYE_EXPRESSION_LEFT_DOWN_HTC, 6) \ + _(XR_EYE_EXPRESSION_RIGHT_DOWN_HTC, 7) \ + _(XR_EYE_EXPRESSION_LEFT_OUT_HTC, 8) \ + _(XR_EYE_EXPRESSION_RIGHT_IN_HTC, 9) \ + _(XR_EYE_EXPRESSION_LEFT_IN_HTC, 10) \ + _(XR_EYE_EXPRESSION_RIGHT_OUT_HTC, 11) \ + _(XR_EYE_EXPRESSION_LEFT_UP_HTC, 12) \ + _(XR_EYE_EXPRESSION_RIGHT_UP_HTC, 13) \ + _(XR_EYE_EXPRESSION_MAX_ENUM_HTC, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrLipExpressionHTC(_) \ + _(XR_LIP_EXPRESSION_JAW_RIGHT_HTC, 0) \ + _(XR_LIP_EXPRESSION_JAW_LEFT_HTC, 1) \ + _(XR_LIP_EXPRESSION_JAW_FORWARD_HTC, 2) \ + _(XR_LIP_EXPRESSION_JAW_OPEN_HTC, 3) \ + _(XR_LIP_EXPRESSION_MOUTH_APE_SHAPE_HTC, 4) \ + _(XR_LIP_EXPRESSION_MOUTH_UPPER_RIGHT_HTC, 5) \ + _(XR_LIP_EXPRESSION_MOUTH_UPPER_LEFT_HTC, 6) \ + _(XR_LIP_EXPRESSION_MOUTH_LOWER_RIGHT_HTC, 7) \ + _(XR_LIP_EXPRESSION_MOUTH_LOWER_LEFT_HTC, 8) \ + _(XR_LIP_EXPRESSION_MOUTH_UPPER_OVERTURN_HTC, 9) \ + _(XR_LIP_EXPRESSION_MOUTH_LOWER_OVERTURN_HTC, 10) \ + _(XR_LIP_EXPRESSION_MOUTH_POUT_HTC, 11) \ + _(XR_LIP_EXPRESSION_MOUTH_SMILE_RIGHT_HTC, 12) \ + _(XR_LIP_EXPRESSION_MOUTH_SMILE_LEFT_HTC, 13) \ + _(XR_LIP_EXPRESSION_MOUTH_SAD_RIGHT_HTC, 14) \ + _(XR_LIP_EXPRESSION_MOUTH_SAD_LEFT_HTC, 15) \ + _(XR_LIP_EXPRESSION_CHEEK_PUFF_RIGHT_HTC, 16) \ + _(XR_LIP_EXPRESSION_CHEEK_PUFF_LEFT_HTC, 17) \ + _(XR_LIP_EXPRESSION_CHEEK_SUCK_HTC, 18) \ + _(XR_LIP_EXPRESSION_MOUTH_UPPER_UPRIGHT_HTC, 19) \ + _(XR_LIP_EXPRESSION_MOUTH_UPPER_UPLEFT_HTC, 20) \ + _(XR_LIP_EXPRESSION_MOUTH_LOWER_DOWNRIGHT_HTC, 21) \ + _(XR_LIP_EXPRESSION_MOUTH_LOWER_DOWNLEFT_HTC, 22) \ + _(XR_LIP_EXPRESSION_MOUTH_UPPER_INSIDE_HTC, 23) \ + _(XR_LIP_EXPRESSION_MOUTH_LOWER_INSIDE_HTC, 24) \ + _(XR_LIP_EXPRESSION_MOUTH_LOWER_OVERLAY_HTC, 25) \ + _(XR_LIP_EXPRESSION_TONGUE_LONGSTEP1_HTC, 26) \ + _(XR_LIP_EXPRESSION_TONGUE_LEFT_HTC, 27) \ + _(XR_LIP_EXPRESSION_TONGUE_RIGHT_HTC, 28) \ + _(XR_LIP_EXPRESSION_TONGUE_UP_HTC, 29) \ + _(XR_LIP_EXPRESSION_TONGUE_DOWN_HTC, 30) \ + _(XR_LIP_EXPRESSION_TONGUE_ROLL_HTC, 31) \ + _(XR_LIP_EXPRESSION_TONGUE_LONGSTEP2_HTC, 32) \ + _(XR_LIP_EXPRESSION_TONGUE_UPRIGHT_MORPH_HTC, 33) \ + _(XR_LIP_EXPRESSION_TONGUE_UPLEFT_MORPH_HTC, 34) \ + _(XR_LIP_EXPRESSION_TONGUE_DOWNRIGHT_MORPH_HTC, 35) \ + _(XR_LIP_EXPRESSION_TONGUE_DOWNLEFT_MORPH_HTC, 36) \ + _(XR_LIP_EXPRESSION_MAX_ENUM_HTC, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrFacialTrackingTypeHTC(_) \ + _(XR_FACIAL_TRACKING_TYPE_EYE_DEFAULT_HTC, 1) \ + _(XR_FACIAL_TRACKING_TYPE_LIP_DEFAULT_HTC, 2) \ + _(XR_FACIAL_TRACKING_TYPE_MAX_ENUM_HTC, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrColorSpaceFB(_) \ + _(XR_COLOR_SPACE_UNMANAGED_FB, 0) \ + _(XR_COLOR_SPACE_REC2020_FB, 1) \ + _(XR_COLOR_SPACE_REC709_FB, 2) \ + _(XR_COLOR_SPACE_RIFT_CV1_FB, 3) \ + _(XR_COLOR_SPACE_RIFT_S_FB, 4) \ + _(XR_COLOR_SPACE_QUEST_FB, 5) \ + _(XR_COLOR_SPACE_P3_FB, 6) \ + _(XR_COLOR_SPACE_ADOBE_RGB_FB, 7) \ + _(XR_COLOR_SPACE_MAX_ENUM_FB, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrSpaceComponentTypeFB(_) \ + _(XR_SPACE_COMPONENT_TYPE_LOCATABLE_FB, 0) \ + _(XR_SPACE_COMPONENT_TYPE_STORABLE_FB, 1) \ + _(XR_SPACE_COMPONENT_TYPE_BOUNDED_2D_FB, 3) \ + _(XR_SPACE_COMPONENT_TYPE_BOUNDED_3D_FB, 4) \ + _(XR_SPACE_COMPONENT_TYPE_SEMANTIC_LABELS_FB, 5) \ + _(XR_SPACE_COMPONENT_TYPE_ROOM_LAYOUT_FB, 6) \ + _(XR_SPACE_COMPONENT_TYPE_SPACE_CONTAINER_FB, 7) \ + _(XR_SPACE_COMPONENT_TYPE_MAX_ENUM_FB, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrFoveationLevelFB(_) \ + _(XR_FOVEATION_LEVEL_NONE_FB, 0) \ + _(XR_FOVEATION_LEVEL_LOW_FB, 1) \ + _(XR_FOVEATION_LEVEL_MEDIUM_FB, 2) \ + _(XR_FOVEATION_LEVEL_HIGH_FB, 3) \ + _(XR_FOVEATION_LEVEL_MAX_ENUM_FB, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrFoveationDynamicFB(_) \ + _(XR_FOVEATION_DYNAMIC_DISABLED_FB, 0) \ + _(XR_FOVEATION_DYNAMIC_LEVEL_ENABLED_FB, 1) \ + _(XR_FOVEATION_DYNAMIC_MAX_ENUM_FB, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrWindingOrderFB(_) \ + _(XR_WINDING_ORDER_UNKNOWN_FB, 0) \ + _(XR_WINDING_ORDER_CW_FB, 1) \ + _(XR_WINDING_ORDER_CCW_FB, 2) \ + _(XR_WINDING_ORDER_MAX_ENUM_FB, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrPassthroughLayerPurposeFB(_) \ + _(XR_PASSTHROUGH_LAYER_PURPOSE_RECONSTRUCTION_FB, 0) \ + _(XR_PASSTHROUGH_LAYER_PURPOSE_PROJECTED_FB, 1) \ + _(XR_PASSTHROUGH_LAYER_PURPOSE_TRACKED_KEYBOARD_HANDS_FB, 1000203001) \ + _(XR_PASSTHROUGH_LAYER_PURPOSE_TRACKED_KEYBOARD_MASKED_HANDS_FB, 1000203002) \ + _(XR_PASSTHROUGH_LAYER_PURPOSE_MAX_ENUM_FB, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrHandForearmJointULTRALEAP(_) \ + _(XR_HAND_FOREARM_JOINT_PALM_ULTRALEAP, 0) \ + _(XR_HAND_FOREARM_JOINT_WRIST_ULTRALEAP, 1) \ + _(XR_HAND_FOREARM_JOINT_THUMB_METACARPAL_ULTRALEAP, 2) \ + _(XR_HAND_FOREARM_JOINT_THUMB_PROXIMAL_ULTRALEAP, 3) \ + _(XR_HAND_FOREARM_JOINT_THUMB_DISTAL_ULTRALEAP, 4) \ + _(XR_HAND_FOREARM_JOINT_THUMB_TIP_ULTRALEAP, 5) \ + _(XR_HAND_FOREARM_JOINT_INDEX_METACARPAL_ULTRALEAP, 6) \ + _(XR_HAND_FOREARM_JOINT_INDEX_PROXIMAL_ULTRALEAP, 7) \ + _(XR_HAND_FOREARM_JOINT_INDEX_INTERMEDIATE_ULTRALEAP, 8) \ + _(XR_HAND_FOREARM_JOINT_INDEX_DISTAL_ULTRALEAP, 9) \ + _(XR_HAND_FOREARM_JOINT_INDEX_TIP_ULTRALEAP, 10) \ + _(XR_HAND_FOREARM_JOINT_MIDDLE_METACARPAL_ULTRALEAP, 11) \ + _(XR_HAND_FOREARM_JOINT_MIDDLE_PROXIMAL_ULTRALEAP, 12) \ + _(XR_HAND_FOREARM_JOINT_MIDDLE_INTERMEDIATE_ULTRALEAP, 13) \ + _(XR_HAND_FOREARM_JOINT_MIDDLE_DISTAL_ULTRALEAP, 14) \ + _(XR_HAND_FOREARM_JOINT_MIDDLE_TIP_ULTRALEAP, 15) \ + _(XR_HAND_FOREARM_JOINT_RING_METACARPAL_ULTRALEAP, 16) \ + _(XR_HAND_FOREARM_JOINT_RING_PROXIMAL_ULTRALEAP, 17) \ + _(XR_HAND_FOREARM_JOINT_RING_INTERMEDIATE_ULTRALEAP, 18) \ + _(XR_HAND_FOREARM_JOINT_RING_DISTAL_ULTRALEAP, 19) \ + _(XR_HAND_FOREARM_JOINT_RING_TIP_ULTRALEAP, 20) \ + _(XR_HAND_FOREARM_JOINT_LITTLE_METACARPAL_ULTRALEAP, 21) \ + _(XR_HAND_FOREARM_JOINT_LITTLE_PROXIMAL_ULTRALEAP, 22) \ + _(XR_HAND_FOREARM_JOINT_LITTLE_INTERMEDIATE_ULTRALEAP, 23) \ + _(XR_HAND_FOREARM_JOINT_LITTLE_DISTAL_ULTRALEAP, 24) \ + _(XR_HAND_FOREARM_JOINT_LITTLE_TIP_ULTRALEAP, 25) \ + _(XR_HAND_FOREARM_JOINT_ELBOW_ULTRALEAP, 26) \ + _(XR_HAND_FOREARM_JOINT_MAX_ENUM_ULTRALEAP, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrSpaceQueryActionFB(_) \ + _(XR_SPACE_QUERY_ACTION_LOAD_FB, 0) \ + _(XR_SPACE_QUERY_ACTION_MAX_ENUM_FB, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrSpaceStorageLocationFB(_) \ + _(XR_SPACE_STORAGE_LOCATION_INVALID_FB, 0) \ + _(XR_SPACE_STORAGE_LOCATION_LOCAL_FB, 1) \ + _(XR_SPACE_STORAGE_LOCATION_MAX_ENUM_FB, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrSpacePersistenceModeFB(_) \ + _(XR_SPACE_PERSISTENCE_MODE_INVALID_FB, 0) \ + _(XR_SPACE_PERSISTENCE_MODE_INDEFINITE_FB, 1) \ + _(XR_SPACE_PERSISTENCE_MODE_MAX_ENUM_FB, 0x7FFFFFFF) + +#define XR_LIST_ENUM_XrPerformanceMetricsCounterUnitMETA(_) \ + _(XR_PERFORMANCE_METRICS_COUNTER_UNIT_GENERIC_META, 0) \ + _(XR_PERFORMANCE_METRICS_COUNTER_UNIT_PERCENTAGE_META, 1) \ + _(XR_PERFORMANCE_METRICS_COUNTER_UNIT_MILLISECONDS_META, 2) \ + _(XR_PERFORMANCE_METRICS_COUNTER_UNIT_BYTES_META, 3) \ + _(XR_PERFORMANCE_METRICS_COUNTER_UNIT_HERTZ_META, 4) \ + _(XR_PERFORMANCE_METRICS_COUNTER_UNIT_MAX_ENUM_META, 0x7FFFFFFF) + +#define XR_LIST_BITS_XrInstanceCreateFlags(_) + +#define XR_LIST_BITS_XrSessionCreateFlags(_) + +#define XR_LIST_BITS_XrSpaceVelocityFlags(_) \ + _(XR_SPACE_VELOCITY_LINEAR_VALID_BIT, 0x00000001) \ + _(XR_SPACE_VELOCITY_ANGULAR_VALID_BIT, 0x00000002) \ + +#define XR_LIST_BITS_XrSpaceLocationFlags(_) \ + _(XR_SPACE_LOCATION_ORIENTATION_VALID_BIT, 0x00000001) \ + _(XR_SPACE_LOCATION_POSITION_VALID_BIT, 0x00000002) \ + _(XR_SPACE_LOCATION_ORIENTATION_TRACKED_BIT, 0x00000004) \ + _(XR_SPACE_LOCATION_POSITION_TRACKED_BIT, 0x00000008) \ + +#define XR_LIST_BITS_XrSwapchainCreateFlags(_) \ + _(XR_SWAPCHAIN_CREATE_PROTECTED_CONTENT_BIT, 0x00000001) \ + _(XR_SWAPCHAIN_CREATE_STATIC_IMAGE_BIT, 0x00000002) \ + +#define XR_LIST_BITS_XrSwapchainUsageFlags(_) \ + _(XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT, 0x00000001) \ + _(XR_SWAPCHAIN_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, 0x00000002) \ + _(XR_SWAPCHAIN_USAGE_UNORDERED_ACCESS_BIT, 0x00000004) \ + _(XR_SWAPCHAIN_USAGE_TRANSFER_SRC_BIT, 0x00000008) \ + _(XR_SWAPCHAIN_USAGE_TRANSFER_DST_BIT, 0x00000010) \ + _(XR_SWAPCHAIN_USAGE_SAMPLED_BIT, 0x00000020) \ + _(XR_SWAPCHAIN_USAGE_MUTABLE_FORMAT_BIT, 0x00000040) \ + _(XR_SWAPCHAIN_USAGE_INPUT_ATTACHMENT_BIT_MND, 0x00000080) \ + _(XR_SWAPCHAIN_USAGE_INPUT_ATTACHMENT_BIT_KHR, XR_SWAPCHAIN_USAGE_INPUT_ATTACHMENT_BIT_MND) \ + +#define XR_LIST_BITS_XrCompositionLayerFlags(_) \ + _(XR_COMPOSITION_LAYER_CORRECT_CHROMATIC_ABERRATION_BIT, 0x00000001) \ + _(XR_COMPOSITION_LAYER_BLEND_TEXTURE_SOURCE_ALPHA_BIT, 0x00000002) \ + _(XR_COMPOSITION_LAYER_UNPREMULTIPLIED_ALPHA_BIT, 0x00000004) \ + +#define XR_LIST_BITS_XrViewStateFlags(_) \ + _(XR_VIEW_STATE_ORIENTATION_VALID_BIT, 0x00000001) \ + _(XR_VIEW_STATE_POSITION_VALID_BIT, 0x00000002) \ + _(XR_VIEW_STATE_ORIENTATION_TRACKED_BIT, 0x00000004) \ + _(XR_VIEW_STATE_POSITION_TRACKED_BIT, 0x00000008) \ + +#define XR_LIST_BITS_XrInputSourceLocalizedNameFlags(_) \ + _(XR_INPUT_SOURCE_LOCALIZED_NAME_USER_PATH_BIT, 0x00000001) \ + _(XR_INPUT_SOURCE_LOCALIZED_NAME_INTERACTION_PROFILE_BIT, 0x00000002) \ + _(XR_INPUT_SOURCE_LOCALIZED_NAME_COMPONENT_BIT, 0x00000004) \ + +#define XR_LIST_BITS_XrVulkanInstanceCreateFlagsKHR(_) + +#define XR_LIST_BITS_XrVulkanDeviceCreateFlagsKHR(_) + +#define XR_LIST_BITS_XrDebugUtilsMessageSeverityFlagsEXT(_) \ + _(XR_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT, 0x00000001) \ + _(XR_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT, 0x00000010) \ + _(XR_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT, 0x00000100) \ + _(XR_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT, 0x00001000) \ + +#define XR_LIST_BITS_XrDebugUtilsMessageTypeFlagsEXT(_) \ + _(XR_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT, 0x00000001) \ + _(XR_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT, 0x00000002) \ + _(XR_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT, 0x00000004) \ + _(XR_DEBUG_UTILS_MESSAGE_TYPE_CONFORMANCE_BIT_EXT, 0x00000008) \ + +#define XR_LIST_BITS_XrOverlaySessionCreateFlagsEXTX(_) + +#define XR_LIST_BITS_XrOverlayMainSessionFlagsEXTX(_) \ + _(XR_OVERLAY_MAIN_SESSION_ENABLED_COMPOSITION_LAYER_INFO_DEPTH_BIT_EXTX, 0x00000001) \ + +#define XR_LIST_BITS_XrCompositionLayerImageLayoutFlagsFB(_) \ + _(XR_COMPOSITION_LAYER_IMAGE_LAYOUT_VERTICAL_FLIP_BIT_FB, 0x00000001) \ + +#define XR_LIST_BITS_XrAndroidSurfaceSwapchainFlagsFB(_) \ + _(XR_ANDROID_SURFACE_SWAPCHAIN_SYNCHRONOUS_BIT_FB, 0x00000001) \ + _(XR_ANDROID_SURFACE_SWAPCHAIN_USE_TIMESTAMPS_BIT_FB, 0x00000002) \ + +#define XR_LIST_BITS_XrCompositionLayerSecureContentFlagsFB(_) \ + _(XR_COMPOSITION_LAYER_SECURE_CONTENT_EXCLUDE_LAYER_BIT_FB, 0x00000001) \ + _(XR_COMPOSITION_LAYER_SECURE_CONTENT_REPLACE_LAYER_BIT_FB, 0x00000002) \ + +#define XR_LIST_BITS_XrHandTrackingAimFlagsFB(_) \ + _(XR_HAND_TRACKING_AIM_COMPUTED_BIT_FB, 0x00000001) \ + _(XR_HAND_TRACKING_AIM_VALID_BIT_FB, 0x00000002) \ + _(XR_HAND_TRACKING_AIM_INDEX_PINCHING_BIT_FB, 0x00000004) \ + _(XR_HAND_TRACKING_AIM_MIDDLE_PINCHING_BIT_FB, 0x00000008) \ + _(XR_HAND_TRACKING_AIM_RING_PINCHING_BIT_FB, 0x00000010) \ + _(XR_HAND_TRACKING_AIM_LITTLE_PINCHING_BIT_FB, 0x00000020) \ + _(XR_HAND_TRACKING_AIM_SYSTEM_GESTURE_BIT_FB, 0x00000040) \ + _(XR_HAND_TRACKING_AIM_DOMINANT_HAND_BIT_FB, 0x00000080) \ + _(XR_HAND_TRACKING_AIM_MENU_PRESSED_BIT_FB, 0x00000100) \ + +#define XR_LIST_BITS_XrSwapchainCreateFoveationFlagsFB(_) \ + _(XR_SWAPCHAIN_CREATE_FOVEATION_SCALED_BIN_BIT_FB, 0x00000001) \ + _(XR_SWAPCHAIN_CREATE_FOVEATION_FRAGMENT_DENSITY_MAP_BIT_FB, 0x00000002) \ + +#define XR_LIST_BITS_XrSwapchainStateFoveationFlagsFB(_) + +#define XR_LIST_BITS_XrKeyboardTrackingFlagsFB(_) \ + _(XR_KEYBOARD_TRACKING_EXISTS_BIT_FB, 0x00000001) \ + _(XR_KEYBOARD_TRACKING_LOCAL_BIT_FB, 0x00000002) \ + _(XR_KEYBOARD_TRACKING_REMOTE_BIT_FB, 0x00000004) \ + _(XR_KEYBOARD_TRACKING_CONNECTED_BIT_FB, 0x00000008) \ + +#define XR_LIST_BITS_XrKeyboardTrackingQueryFlagsFB(_) \ + _(XR_KEYBOARD_TRACKING_QUERY_LOCAL_BIT_FB, 0x00000002) \ + _(XR_KEYBOARD_TRACKING_QUERY_REMOTE_BIT_FB, 0x00000004) \ + +#define XR_LIST_BITS_XrTriangleMeshFlagsFB(_) \ + _(XR_TRIANGLE_MESH_MUTABLE_BIT_FB, 0x00000001) \ + +#define XR_LIST_BITS_XrPassthroughCapabilityFlagsFB(_) \ + _(XR_PASSTHROUGH_CAPABILITY_BIT_FB, 0x00000001) \ + _(XR_PASSTHROUGH_CAPABILITY_COLOR_BIT_FB, 0x00000002) \ + _(XR_PASSTHROUGH_CAPABILITY_LAYER_DEPTH_BIT_FB, 0x00000004) \ + +#define XR_LIST_BITS_XrPassthroughFlagsFB(_) \ + _(XR_PASSTHROUGH_IS_RUNNING_AT_CREATION_BIT_FB, 0x00000001) \ + _(XR_PASSTHROUGH_LAYER_DEPTH_BIT_FB, 0x00000002) \ + +#define XR_LIST_BITS_XrPassthroughStateChangedFlagsFB(_) \ + _(XR_PASSTHROUGH_STATE_CHANGED_REINIT_REQUIRED_BIT_FB, 0x00000001) \ + _(XR_PASSTHROUGH_STATE_CHANGED_NON_RECOVERABLE_ERROR_BIT_FB, 0x00000002) \ + _(XR_PASSTHROUGH_STATE_CHANGED_RECOVERABLE_ERROR_BIT_FB, 0x00000004) \ + _(XR_PASSTHROUGH_STATE_CHANGED_RESTORED_ERROR_BIT_FB, 0x00000008) \ + +#define XR_LIST_BITS_XrRenderModelFlagsFB(_) \ + _(XR_RENDER_MODEL_SUPPORTS_GLTF_2_0_SUBSET_1_BIT_FB, 0x00000001) \ + _(XR_RENDER_MODEL_SUPPORTS_GLTF_2_0_SUBSET_2_BIT_FB, 0x00000002) \ + +#define XR_LIST_BITS_XrCompositionLayerSpaceWarpInfoFlagsFB(_) \ + _(XR_COMPOSITION_LAYER_SPACE_WARP_INFO_FRAME_SKIP_BIT_FB, 0x00000001) \ + +#define XR_LIST_BITS_XrDigitalLensControlFlagsALMALENCE(_) \ + _(XR_DIGITAL_LENS_CONTROL_PROCESSING_DISABLE_BIT_ALMALENCE, 0x00000001) \ + +#define XR_LIST_BITS_XrCompositionLayerSettingsFlagsFB(_) \ + _(XR_COMPOSITION_LAYER_SETTINGS_NORMAL_SUPER_SAMPLING_BIT_FB, 0x00000001) \ + _(XR_COMPOSITION_LAYER_SETTINGS_QUALITY_SUPER_SAMPLING_BIT_FB, 0x00000002) \ + _(XR_COMPOSITION_LAYER_SETTINGS_NORMAL_SHARPENING_BIT_FB, 0x00000004) \ + _(XR_COMPOSITION_LAYER_SETTINGS_QUALITY_SHARPENING_BIT_FB, 0x00000008) \ + +#define XR_LIST_BITS_XrPerformanceMetricsCounterFlagsMETA(_) \ + _(XR_PERFORMANCE_METRICS_COUNTER_ANY_VALUE_VALID_BIT_META, 0x00000001) \ + _(XR_PERFORMANCE_METRICS_COUNTER_UINT_VALUE_VALID_BIT_META, 0x00000002) \ + _(XR_PERFORMANCE_METRICS_COUNTER_FLOAT_VALUE_VALID_BIT_META, 0x00000004) \ + +#define XR_LIST_STRUCT_XrApiLayerProperties(_) \ + _(type) \ + _(next) \ + _(layerName) \ + _(specVersion) \ + _(layerVersion) \ + _(description) \ + +#define XR_LIST_STRUCT_XrExtensionProperties(_) \ + _(type) \ + _(next) \ + _(extensionName) \ + _(extensionVersion) \ + +#define XR_LIST_STRUCT_XrApplicationInfo(_) \ + _(applicationName) \ + _(applicationVersion) \ + _(engineName) \ + _(engineVersion) \ + _(apiVersion) \ + +#define XR_LIST_STRUCT_XrInstanceCreateInfo(_) \ + _(type) \ + _(next) \ + _(createFlags) \ + _(applicationInfo) \ + _(enabledApiLayerCount) \ + _(enabledApiLayerNames) \ + _(enabledExtensionCount) \ + _(enabledExtensionNames) \ + +#define XR_LIST_STRUCT_XrInstanceProperties(_) \ + _(type) \ + _(next) \ + _(runtimeVersion) \ + _(runtimeName) \ + +#define XR_LIST_STRUCT_XrEventDataBuffer(_) \ + _(type) \ + _(next) \ + _(varying) \ + +#define XR_LIST_STRUCT_XrSystemGetInfo(_) \ + _(type) \ + _(next) \ + _(formFactor) \ + +#define XR_LIST_STRUCT_XrSystemGraphicsProperties(_) \ + _(maxSwapchainImageHeight) \ + _(maxSwapchainImageWidth) \ + _(maxLayerCount) \ + +#define XR_LIST_STRUCT_XrSystemTrackingProperties(_) \ + _(orientationTracking) \ + _(positionTracking) \ + +#define XR_LIST_STRUCT_XrSystemProperties(_) \ + _(type) \ + _(next) \ + _(systemId) \ + _(vendorId) \ + _(systemName) \ + _(graphicsProperties) \ + _(trackingProperties) \ + +#define XR_LIST_STRUCT_XrSessionCreateInfo(_) \ + _(type) \ + _(next) \ + _(createFlags) \ + _(systemId) \ + +#define XR_LIST_STRUCT_XrVector3f(_) \ + _(x) \ + _(y) \ + _(z) \ + +#define XR_LIST_STRUCT_XrSpaceVelocity(_) \ + _(type) \ + _(next) \ + _(velocityFlags) \ + _(linearVelocity) \ + _(angularVelocity) \ + +#define XR_LIST_STRUCT_XrQuaternionf(_) \ + _(x) \ + _(y) \ + _(z) \ + _(w) \ + +#define XR_LIST_STRUCT_XrPosef(_) \ + _(orientation) \ + _(position) \ + +#define XR_LIST_STRUCT_XrReferenceSpaceCreateInfo(_) \ + _(type) \ + _(next) \ + _(referenceSpaceType) \ + _(poseInReferenceSpace) \ + +#define XR_LIST_STRUCT_XrExtent2Df(_) \ + _(width) \ + _(height) \ + +#define XR_LIST_STRUCT_XrActionSpaceCreateInfo(_) \ + _(type) \ + _(next) \ + _(action) \ + _(subactionPath) \ + _(poseInActionSpace) \ + +#define XR_LIST_STRUCT_XrSpaceLocation(_) \ + _(type) \ + _(next) \ + _(locationFlags) \ + _(pose) \ + +#define XR_LIST_STRUCT_XrViewConfigurationProperties(_) \ + _(type) \ + _(next) \ + _(viewConfigurationType) \ + _(fovMutable) \ + +#define XR_LIST_STRUCT_XrViewConfigurationView(_) \ + _(type) \ + _(next) \ + _(recommendedImageRectWidth) \ + _(maxImageRectWidth) \ + _(recommendedImageRectHeight) \ + _(maxImageRectHeight) \ + _(recommendedSwapchainSampleCount) \ + _(maxSwapchainSampleCount) \ + +#define XR_LIST_STRUCT_XrSwapchainCreateInfo(_) \ + _(type) \ + _(next) \ + _(createFlags) \ + _(usageFlags) \ + _(format) \ + _(sampleCount) \ + _(width) \ + _(height) \ + _(faceCount) \ + _(arraySize) \ + _(mipCount) \ + +#define XR_LIST_STRUCT_XrSwapchainImageBaseHeader(_) \ + _(type) \ + _(next) \ + +#define XR_LIST_STRUCT_XrSwapchainImageAcquireInfo(_) \ + _(type) \ + _(next) \ + +#define XR_LIST_STRUCT_XrSwapchainImageWaitInfo(_) \ + _(type) \ + _(next) \ + _(timeout) \ + +#define XR_LIST_STRUCT_XrSwapchainImageReleaseInfo(_) \ + _(type) \ + _(next) \ + +#define XR_LIST_STRUCT_XrSessionBeginInfo(_) \ + _(type) \ + _(next) \ + _(primaryViewConfigurationType) \ + +#define XR_LIST_STRUCT_XrFrameWaitInfo(_) \ + _(type) \ + _(next) \ + +#define XR_LIST_STRUCT_XrFrameState(_) \ + _(type) \ + _(next) \ + _(predictedDisplayTime) \ + _(predictedDisplayPeriod) \ + _(shouldRender) \ + +#define XR_LIST_STRUCT_XrFrameBeginInfo(_) \ + _(type) \ + _(next) \ + +#define XR_LIST_STRUCT_XrCompositionLayerBaseHeader(_) \ + _(type) \ + _(next) \ + _(layerFlags) \ + _(space) \ + +#define XR_LIST_STRUCT_XrFrameEndInfo(_) \ + _(type) \ + _(next) \ + _(displayTime) \ + _(environmentBlendMode) \ + _(layerCount) \ + _(layers) \ + +#define XR_LIST_STRUCT_XrViewLocateInfo(_) \ + _(type) \ + _(next) \ + _(viewConfigurationType) \ + _(displayTime) \ + _(space) \ + +#define XR_LIST_STRUCT_XrViewState(_) \ + _(type) \ + _(next) \ + _(viewStateFlags) \ + +#define XR_LIST_STRUCT_XrFovf(_) \ + _(angleLeft) \ + _(angleRight) \ + _(angleUp) \ + _(angleDown) \ + +#define XR_LIST_STRUCT_XrView(_) \ + _(type) \ + _(next) \ + _(pose) \ + _(fov) \ + +#define XR_LIST_STRUCT_XrActionSetCreateInfo(_) \ + _(type) \ + _(next) \ + _(actionSetName) \ + _(localizedActionSetName) \ + _(priority) \ + +#define XR_LIST_STRUCT_XrActionCreateInfo(_) \ + _(type) \ + _(next) \ + _(actionName) \ + _(actionType) \ + _(countSubactionPaths) \ + _(subactionPaths) \ + _(localizedActionName) \ + +#define XR_LIST_STRUCT_XrActionSuggestedBinding(_) \ + _(action) \ + _(binding) \ + +#define XR_LIST_STRUCT_XrInteractionProfileSuggestedBinding(_) \ + _(type) \ + _(next) \ + _(interactionProfile) \ + _(countSuggestedBindings) \ + _(suggestedBindings) \ + +#define XR_LIST_STRUCT_XrSessionActionSetsAttachInfo(_) \ + _(type) \ + _(next) \ + _(countActionSets) \ + _(actionSets) \ + +#define XR_LIST_STRUCT_XrInteractionProfileState(_) \ + _(type) \ + _(next) \ + _(interactionProfile) \ + +#define XR_LIST_STRUCT_XrActionStateGetInfo(_) \ + _(type) \ + _(next) \ + _(action) \ + _(subactionPath) \ + +#define XR_LIST_STRUCT_XrActionStateBoolean(_) \ + _(type) \ + _(next) \ + _(currentState) \ + _(changedSinceLastSync) \ + _(lastChangeTime) \ + _(isActive) \ + +#define XR_LIST_STRUCT_XrActionStateFloat(_) \ + _(type) \ + _(next) \ + _(currentState) \ + _(changedSinceLastSync) \ + _(lastChangeTime) \ + _(isActive) \ + +#define XR_LIST_STRUCT_XrVector2f(_) \ + _(x) \ + _(y) \ + +#define XR_LIST_STRUCT_XrActionStateVector2f(_) \ + _(type) \ + _(next) \ + _(currentState) \ + _(changedSinceLastSync) \ + _(lastChangeTime) \ + _(isActive) \ + +#define XR_LIST_STRUCT_XrActionStatePose(_) \ + _(type) \ + _(next) \ + _(isActive) \ + +#define XR_LIST_STRUCT_XrActiveActionSet(_) \ + _(actionSet) \ + _(subactionPath) \ + +#define XR_LIST_STRUCT_XrActionsSyncInfo(_) \ + _(type) \ + _(next) \ + _(countActiveActionSets) \ + _(activeActionSets) \ + +#define XR_LIST_STRUCT_XrBoundSourcesForActionEnumerateInfo(_) \ + _(type) \ + _(next) \ + _(action) \ + +#define XR_LIST_STRUCT_XrInputSourceLocalizedNameGetInfo(_) \ + _(type) \ + _(next) \ + _(sourcePath) \ + _(whichComponents) \ + +#define XR_LIST_STRUCT_XrHapticActionInfo(_) \ + _(type) \ + _(next) \ + _(action) \ + _(subactionPath) \ + +#define XR_LIST_STRUCT_XrHapticBaseHeader(_) \ + _(type) \ + _(next) \ + +#define XR_LIST_STRUCT_XrBaseInStructure(_) \ + _(type) \ + _(next) \ + +#define XR_LIST_STRUCT_XrBaseOutStructure(_) \ + _(type) \ + _(next) \ + +#define XR_LIST_STRUCT_XrOffset2Di(_) \ + _(x) \ + _(y) \ + +#define XR_LIST_STRUCT_XrExtent2Di(_) \ + _(width) \ + _(height) \ + +#define XR_LIST_STRUCT_XrRect2Di(_) \ + _(offset) \ + _(extent) \ + +#define XR_LIST_STRUCT_XrSwapchainSubImage(_) \ + _(swapchain) \ + _(imageRect) \ + _(imageArrayIndex) \ + +#define XR_LIST_STRUCT_XrCompositionLayerProjectionView(_) \ + _(type) \ + _(next) \ + _(pose) \ + _(fov) \ + _(subImage) \ + +#define XR_LIST_STRUCT_XrCompositionLayerProjection(_) \ + _(type) \ + _(next) \ + _(layerFlags) \ + _(space) \ + _(viewCount) \ + _(views) \ + +#define XR_LIST_STRUCT_XrCompositionLayerQuad(_) \ + _(type) \ + _(next) \ + _(layerFlags) \ + _(space) \ + _(eyeVisibility) \ + _(subImage) \ + _(pose) \ + _(size) \ + +#define XR_LIST_STRUCT_XrEventDataBaseHeader(_) \ + _(type) \ + _(next) \ + +#define XR_LIST_STRUCT_XrEventDataEventsLost(_) \ + _(type) \ + _(next) \ + _(lostEventCount) \ + +#define XR_LIST_STRUCT_XrEventDataInstanceLossPending(_) \ + _(type) \ + _(next) \ + _(lossTime) \ + +#define XR_LIST_STRUCT_XrEventDataSessionStateChanged(_) \ + _(type) \ + _(next) \ + _(session) \ + _(state) \ + _(time) \ + +#define XR_LIST_STRUCT_XrEventDataReferenceSpaceChangePending(_) \ + _(type) \ + _(next) \ + _(session) \ + _(referenceSpaceType) \ + _(changeTime) \ + _(poseValid) \ + _(poseInPreviousSpace) \ + +#define XR_LIST_STRUCT_XrEventDataInteractionProfileChanged(_) \ + _(type) \ + _(next) \ + _(session) \ + +#define XR_LIST_STRUCT_XrHapticVibration(_) \ + _(type) \ + _(next) \ + _(duration) \ + _(frequency) \ + _(amplitude) \ + +#define XR_LIST_STRUCT_XrOffset2Df(_) \ + _(x) \ + _(y) \ + +#define XR_LIST_STRUCT_XrRect2Df(_) \ + _(offset) \ + _(extent) \ + +#define XR_LIST_STRUCT_XrVector4f(_) \ + _(x) \ + _(y) \ + _(z) \ + _(w) \ + +#define XR_LIST_STRUCT_XrColor4f(_) \ + _(r) \ + _(g) \ + _(b) \ + _(a) \ + +#define XR_LIST_STRUCT_XrCompositionLayerCubeKHR(_) \ + _(type) \ + _(next) \ + _(layerFlags) \ + _(space) \ + _(eyeVisibility) \ + _(swapchain) \ + _(imageArrayIndex) \ + _(orientation) \ + +#define XR_LIST_STRUCT_XrInstanceCreateInfoAndroidKHR(_) \ + _(type) \ + _(next) \ + _(applicationVM) \ + _(applicationActivity) \ + +#define XR_LIST_STRUCT_XrCompositionLayerDepthInfoKHR(_) \ + _(type) \ + _(next) \ + _(subImage) \ + _(minDepth) \ + _(maxDepth) \ + _(nearZ) \ + _(farZ) \ + +#define XR_LIST_STRUCT_XrVulkanSwapchainFormatListCreateInfoKHR(_) \ + _(type) \ + _(next) \ + _(viewFormatCount) \ + _(viewFormats) \ + +#define XR_LIST_STRUCT_XrCompositionLayerCylinderKHR(_) \ + _(type) \ + _(next) \ + _(layerFlags) \ + _(space) \ + _(eyeVisibility) \ + _(subImage) \ + _(pose) \ + _(radius) \ + _(centralAngle) \ + _(aspectRatio) \ + +#define XR_LIST_STRUCT_XrCompositionLayerEquirectKHR(_) \ + _(type) \ + _(next) \ + _(layerFlags) \ + _(space) \ + _(eyeVisibility) \ + _(subImage) \ + _(pose) \ + _(radius) \ + _(scale) \ + _(bias) \ + +#define XR_LIST_STRUCT_XrGraphicsBindingOpenGLWin32KHR(_) \ + _(type) \ + _(next) \ + _(hDC) \ + _(hGLRC) \ + +#define XR_LIST_STRUCT_XrGraphicsBindingOpenGLXlibKHR(_) \ + _(type) \ + _(next) \ + _(xDisplay) \ + _(visualid) \ + _(glxFBConfig) \ + _(glxDrawable) \ + _(glxContext) \ + +#define XR_LIST_STRUCT_XrGraphicsBindingOpenGLXcbKHR(_) \ + _(type) \ + _(next) \ + _(connection) \ + _(screenNumber) \ + _(fbconfigid) \ + _(visualid) \ + _(glxDrawable) \ + _(glxContext) \ + +#define XR_LIST_STRUCT_XrGraphicsBindingOpenGLWaylandKHR(_) \ + _(type) \ + _(next) \ + _(display) \ + +#define XR_LIST_STRUCT_XrSwapchainImageOpenGLKHR(_) \ + _(type) \ + _(next) \ + _(image) \ + +#define XR_LIST_STRUCT_XrGraphicsRequirementsOpenGLKHR(_) \ + _(type) \ + _(next) \ + _(minApiVersionSupported) \ + _(maxApiVersionSupported) \ + +#define XR_LIST_STRUCT_XrGraphicsBindingOpenGLESAndroidKHR(_) \ + _(type) \ + _(next) \ + _(display) \ + _(config) \ + _(context) \ + +#define XR_LIST_STRUCT_XrSwapchainImageOpenGLESKHR(_) \ + _(type) \ + _(next) \ + _(image) \ + +#define XR_LIST_STRUCT_XrGraphicsRequirementsOpenGLESKHR(_) \ + _(type) \ + _(next) \ + _(minApiVersionSupported) \ + _(maxApiVersionSupported) \ + +#define XR_LIST_STRUCT_XrGraphicsBindingVulkanKHR(_) \ + _(type) \ + _(next) \ + _(instance) \ + _(physicalDevice) \ + _(device) \ + _(queueFamilyIndex) \ + _(queueIndex) \ + +#define XR_LIST_STRUCT_XrSwapchainImageVulkanKHR(_) \ + _(type) \ + _(next) \ + _(image) \ + +#define XR_LIST_STRUCT_XrGraphicsRequirementsVulkanKHR(_) \ + _(type) \ + _(next) \ + _(minApiVersionSupported) \ + _(maxApiVersionSupported) \ + +#define XR_LIST_STRUCT_XrGraphicsBindingD3D11KHR(_) \ + _(type) \ + _(next) \ + _(device) \ + +#define XR_LIST_STRUCT_XrSwapchainImageD3D11KHR(_) \ + _(type) \ + _(next) \ + _(texture) \ + +#define XR_LIST_STRUCT_XrGraphicsRequirementsD3D11KHR(_) \ + _(type) \ + _(next) \ + _(adapterLuid) \ + _(minFeatureLevel) \ + +#define XR_LIST_STRUCT_XrGraphicsBindingD3D12KHR(_) \ + _(type) \ + _(next) \ + _(device) \ + _(queue) \ + +#define XR_LIST_STRUCT_XrSwapchainImageD3D12KHR(_) \ + _(type) \ + _(next) \ + _(texture) \ + +#define XR_LIST_STRUCT_XrGraphicsRequirementsD3D12KHR(_) \ + _(type) \ + _(next) \ + _(adapterLuid) \ + _(minFeatureLevel) \ + +#define XR_LIST_STRUCT_XrVisibilityMaskKHR(_) \ + _(type) \ + _(next) \ + _(vertexCapacityInput) \ + _(vertexCountOutput) \ + _(vertices) \ + _(indexCapacityInput) \ + _(indexCountOutput) \ + _(indices) \ + +#define XR_LIST_STRUCT_XrEventDataVisibilityMaskChangedKHR(_) \ + _(type) \ + _(next) \ + _(session) \ + _(viewConfigurationType) \ + _(viewIndex) \ + +#define XR_LIST_STRUCT_XrCompositionLayerColorScaleBiasKHR(_) \ + _(type) \ + _(next) \ + _(colorScale) \ + _(colorBias) \ + +#define XR_LIST_STRUCT_XrLoaderInitInfoBaseHeaderKHR(_) \ + _(type) \ + _(next) \ + +#define XR_LIST_STRUCT_XrLoaderInitInfoAndroidKHR(_) \ + _(type) \ + _(next) \ + _(applicationVM) \ + _(applicationContext) \ + +#define XR_LIST_STRUCT_XrVulkanInstanceCreateInfoKHR(_) \ + _(type) \ + _(next) \ + _(systemId) \ + _(createFlags) \ + _(pfnGetInstanceProcAddr) \ + _(vulkanCreateInfo) \ + _(vulkanAllocator) \ + +#define XR_LIST_STRUCT_XrVulkanDeviceCreateInfoKHR(_) \ + _(type) \ + _(next) \ + _(systemId) \ + _(createFlags) \ + _(pfnGetInstanceProcAddr) \ + _(vulkanPhysicalDevice) \ + _(vulkanCreateInfo) \ + _(vulkanAllocator) \ + +#define XR_LIST_STRUCT_XrVulkanGraphicsDeviceGetInfoKHR(_) \ + _(type) \ + _(next) \ + _(systemId) \ + _(vulkanInstance) \ + +#define XR_LIST_STRUCT_XrCompositionLayerEquirect2KHR(_) \ + _(type) \ + _(next) \ + _(layerFlags) \ + _(space) \ + _(eyeVisibility) \ + _(subImage) \ + _(pose) \ + _(radius) \ + _(centralHorizontalAngle) \ + _(upperVerticalAngle) \ + _(lowerVerticalAngle) \ + +#define XR_LIST_STRUCT_XrBindingModificationBaseHeaderKHR(_) \ + _(type) \ + _(next) \ + +#define XR_LIST_STRUCT_XrBindingModificationsKHR(_) \ + _(type) \ + _(next) \ + _(bindingModificationCount) \ + _(bindingModifications) \ + +#define XR_LIST_STRUCT_XrEventDataPerfSettingsEXT(_) \ + _(type) \ + _(next) \ + _(domain) \ + _(subDomain) \ + _(fromLevel) \ + _(toLevel) \ + +#define XR_LIST_STRUCT_XrDebugUtilsObjectNameInfoEXT(_) \ + _(type) \ + _(next) \ + _(objectType) \ + _(objectHandle) \ + _(objectName) \ + +#define XR_LIST_STRUCT_XrDebugUtilsLabelEXT(_) \ + _(type) \ + _(next) \ + _(labelName) \ + +#define XR_LIST_STRUCT_XrDebugUtilsMessengerCallbackDataEXT(_) \ + _(type) \ + _(next) \ + _(messageId) \ + _(functionName) \ + _(message) \ + _(objectCount) \ + _(objects) \ + _(sessionLabelCount) \ + _(sessionLabels) \ + +#define XR_LIST_STRUCT_XrDebugUtilsMessengerCreateInfoEXT(_) \ + _(type) \ + _(next) \ + _(messageSeverities) \ + _(messageTypes) \ + _(userCallback) \ + _(userData) \ + +#define XR_LIST_STRUCT_XrSystemEyeGazeInteractionPropertiesEXT(_) \ + _(type) \ + _(next) \ + _(supportsEyeGazeInteraction) \ + +#define XR_LIST_STRUCT_XrEyeGazeSampleTimeEXT(_) \ + _(type) \ + _(next) \ + _(time) \ + +#define XR_LIST_STRUCT_XrSessionCreateInfoOverlayEXTX(_) \ + _(type) \ + _(next) \ + _(createFlags) \ + _(sessionLayersPlacement) \ + +#define XR_LIST_STRUCT_XrEventDataMainSessionVisibilityChangedEXTX(_) \ + _(type) \ + _(next) \ + _(visible) \ + _(flags) \ + +#define XR_LIST_STRUCT_XrSpatialAnchorCreateInfoMSFT(_) \ + _(type) \ + _(next) \ + _(space) \ + _(pose) \ + _(time) \ + +#define XR_LIST_STRUCT_XrSpatialAnchorSpaceCreateInfoMSFT(_) \ + _(type) \ + _(next) \ + _(anchor) \ + _(poseInAnchorSpace) \ + +#define XR_LIST_STRUCT_XrCompositionLayerImageLayoutFB(_) \ + _(type) \ + _(next) \ + _(flags) \ + +#define XR_LIST_STRUCT_XrCompositionLayerAlphaBlendFB(_) \ + _(type) \ + _(next) \ + _(srcFactorColor) \ + _(dstFactorColor) \ + _(srcFactorAlpha) \ + _(dstFactorAlpha) \ + +#define XR_LIST_STRUCT_XrViewConfigurationDepthRangeEXT(_) \ + _(type) \ + _(next) \ + _(recommendedNearZ) \ + _(minNearZ) \ + _(recommendedFarZ) \ + _(maxFarZ) \ + +#define XR_LIST_STRUCT_XrGraphicsBindingEGLMNDX(_) \ + _(type) \ + _(next) \ + _(getProcAddress) \ + _(display) \ + _(config) \ + _(context) \ + +#define XR_LIST_STRUCT_XrSpatialGraphNodeSpaceCreateInfoMSFT(_) \ + _(type) \ + _(next) \ + _(nodeType) \ + _(nodeId) \ + _(pose) \ + +#define XR_LIST_STRUCT_XrSpatialGraphStaticNodeBindingCreateInfoMSFT(_) \ + _(type) \ + _(next) \ + _(space) \ + _(poseInSpace) \ + _(time) \ + +#define XR_LIST_STRUCT_XrSpatialGraphNodeBindingPropertiesGetInfoMSFT(_) \ + _(type) \ + _(next) \ + +#define XR_LIST_STRUCT_XrSpatialGraphNodeBindingPropertiesMSFT(_) \ + _(type) \ + _(next) \ + _(nodeId) \ + _(poseInNodeSpace) \ + +#define XR_LIST_STRUCT_XrSystemHandTrackingPropertiesEXT(_) \ + _(type) \ + _(next) \ + _(supportsHandTracking) \ + +#define XR_LIST_STRUCT_XrHandTrackerCreateInfoEXT(_) \ + _(type) \ + _(next) \ + _(hand) \ + _(handJointSet) \ + +#define XR_LIST_STRUCT_XrHandJointsLocateInfoEXT(_) \ + _(type) \ + _(next) \ + _(baseSpace) \ + _(time) \ + +#define XR_LIST_STRUCT_XrHandJointLocationEXT(_) \ + _(locationFlags) \ + _(pose) \ + _(radius) \ + +#define XR_LIST_STRUCT_XrHandJointVelocityEXT(_) \ + _(velocityFlags) \ + _(linearVelocity) \ + _(angularVelocity) \ + +#define XR_LIST_STRUCT_XrHandJointLocationsEXT(_) \ + _(type) \ + _(next) \ + _(isActive) \ + _(jointCount) \ + _(jointLocations) \ + +#define XR_LIST_STRUCT_XrHandJointVelocitiesEXT(_) \ + _(type) \ + _(next) \ + _(jointCount) \ + _(jointVelocities) \ + +#define XR_LIST_STRUCT_XrSystemHandTrackingMeshPropertiesMSFT(_) \ + _(type) \ + _(next) \ + _(supportsHandTrackingMesh) \ + _(maxHandMeshIndexCount) \ + _(maxHandMeshVertexCount) \ + +#define XR_LIST_STRUCT_XrHandMeshSpaceCreateInfoMSFT(_) \ + _(type) \ + _(next) \ + _(handPoseType) \ + _(poseInHandMeshSpace) \ + +#define XR_LIST_STRUCT_XrHandMeshUpdateInfoMSFT(_) \ + _(type) \ + _(next) \ + _(time) \ + _(handPoseType) \ + +#define XR_LIST_STRUCT_XrHandMeshIndexBufferMSFT(_) \ + _(indexBufferKey) \ + _(indexCapacityInput) \ + _(indexCountOutput) \ + _(indices) \ + +#define XR_LIST_STRUCT_XrHandMeshVertexMSFT(_) \ + _(position) \ + _(normal) \ + +#define XR_LIST_STRUCT_XrHandMeshVertexBufferMSFT(_) \ + _(vertexUpdateTime) \ + _(vertexCapacityInput) \ + _(vertexCountOutput) \ + _(vertices) \ + +#define XR_LIST_STRUCT_XrHandMeshMSFT(_) \ + _(type) \ + _(next) \ + _(isActive) \ + _(indexBufferChanged) \ + _(vertexBufferChanged) \ + _(indexBuffer) \ + _(vertexBuffer) \ + +#define XR_LIST_STRUCT_XrHandPoseTypeInfoMSFT(_) \ + _(type) \ + _(next) \ + _(handPoseType) \ + +#define XR_LIST_STRUCT_XrSecondaryViewConfigurationSessionBeginInfoMSFT(_) \ + _(type) \ + _(next) \ + _(viewConfigurationCount) \ + _(enabledViewConfigurationTypes) \ + +#define XR_LIST_STRUCT_XrSecondaryViewConfigurationStateMSFT(_) \ + _(type) \ + _(next) \ + _(viewConfigurationType) \ + _(active) \ + +#define XR_LIST_STRUCT_XrSecondaryViewConfigurationFrameStateMSFT(_) \ + _(type) \ + _(next) \ + _(viewConfigurationCount) \ + _(viewConfigurationStates) \ + +#define XR_LIST_STRUCT_XrSecondaryViewConfigurationLayerInfoMSFT(_) \ + _(type) \ + _(next) \ + _(viewConfigurationType) \ + _(environmentBlendMode) \ + _(layerCount) \ + _(layers) \ + +#define XR_LIST_STRUCT_XrSecondaryViewConfigurationFrameEndInfoMSFT(_) \ + _(type) \ + _(next) \ + _(viewConfigurationCount) \ + _(viewConfigurationLayersInfo) \ + +#define XR_LIST_STRUCT_XrSecondaryViewConfigurationSwapchainCreateInfoMSFT(_) \ + _(type) \ + _(next) \ + _(viewConfigurationType) \ + +#define XR_LIST_STRUCT_XrControllerModelKeyStateMSFT(_) \ + _(type) \ + _(next) \ + _(modelKey) \ + +#define XR_LIST_STRUCT_XrControllerModelNodePropertiesMSFT(_) \ + _(type) \ + _(next) \ + _(parentNodeName) \ + _(nodeName) \ + +#define XR_LIST_STRUCT_XrControllerModelPropertiesMSFT(_) \ + _(type) \ + _(next) \ + _(nodeCapacityInput) \ + _(nodeCountOutput) \ + _(nodeProperties) \ + +#define XR_LIST_STRUCT_XrControllerModelNodeStateMSFT(_) \ + _(type) \ + _(next) \ + _(nodePose) \ + +#define XR_LIST_STRUCT_XrControllerModelStateMSFT(_) \ + _(type) \ + _(next) \ + _(nodeCapacityInput) \ + _(nodeCountOutput) \ + _(nodeStates) \ + +#define XR_LIST_STRUCT_XrViewConfigurationViewFovEPIC(_) \ + _(type) \ + _(next) \ + _(recommendedFov) \ + _(maxMutableFov) \ + +#define XR_LIST_STRUCT_XrHolographicWindowAttachmentMSFT(_) \ + _(type) \ + _(next) \ + _(holographicSpace) \ + _(coreWindow) \ + +#define XR_LIST_STRUCT_XrCompositionLayerReprojectionInfoMSFT(_) \ + _(type) \ + _(next) \ + _(reprojectionMode) \ + +#define XR_LIST_STRUCT_XrCompositionLayerReprojectionPlaneOverrideMSFT(_) \ + _(type) \ + _(next) \ + _(position) \ + _(normal) \ + _(velocity) \ + +#define XR_LIST_STRUCT_XrAndroidSurfaceSwapchainCreateInfoFB(_) \ + _(type) \ + _(next) \ + _(createFlags) \ + +#define XR_LIST_STRUCT_XrSwapchainStateBaseHeaderFB(_) \ + _(type) \ + _(next) \ + +#define XR_LIST_STRUCT_XrCompositionLayerSecureContentFB(_) \ + _(type) \ + _(next) \ + _(flags) \ + +#define XR_LIST_STRUCT_XrInteractionProfileDpadBindingEXT(_) \ + _(type) \ + _(next) \ + _(binding) \ + _(actionSet) \ + _(forceThreshold) \ + _(forceThresholdReleased) \ + _(centerRegion) \ + _(wedgeAngle) \ + _(isSticky) \ + _(onHaptic) \ + _(offHaptic) \ + +#define XR_LIST_STRUCT_XrInteractionProfileAnalogThresholdVALVE(_) \ + _(type) \ + _(next) \ + _(action) \ + _(binding) \ + _(onThreshold) \ + _(offThreshold) \ + _(onHaptic) \ + _(offHaptic) \ + +#define XR_LIST_STRUCT_XrHandJointsMotionRangeInfoEXT(_) \ + _(type) \ + _(next) \ + _(handJointsMotionRange) \ + +#define XR_LIST_STRUCT_XrUuidMSFT(_) \ + _(bytes) \ + +#define XR_LIST_STRUCT_XrSceneObserverCreateInfoMSFT(_) \ + _(type) \ + _(next) \ + +#define XR_LIST_STRUCT_XrSceneCreateInfoMSFT(_) \ + _(type) \ + _(next) \ + +#define XR_LIST_STRUCT_XrSceneSphereBoundMSFT(_) \ + _(center) \ + _(radius) \ + +#define XR_LIST_STRUCT_XrSceneOrientedBoxBoundMSFT(_) \ + _(pose) \ + _(extents) \ + +#define XR_LIST_STRUCT_XrSceneFrustumBoundMSFT(_) \ + _(pose) \ + _(fov) \ + _(farDistance) \ + +#define XR_LIST_STRUCT_XrSceneBoundsMSFT(_) \ + _(space) \ + _(time) \ + _(sphereCount) \ + _(spheres) \ + _(boxCount) \ + _(boxes) \ + _(frustumCount) \ + _(frustums) \ + +#define XR_LIST_STRUCT_XrNewSceneComputeInfoMSFT(_) \ + _(type) \ + _(next) \ + _(requestedFeatureCount) \ + _(requestedFeatures) \ + _(consistency) \ + _(bounds) \ + +#define XR_LIST_STRUCT_XrVisualMeshComputeLodInfoMSFT(_) \ + _(type) \ + _(next) \ + _(lod) \ + +#define XR_LIST_STRUCT_XrSceneComponentMSFT(_) \ + _(componentType) \ + _(id) \ + _(parentId) \ + _(updateTime) \ + +#define XR_LIST_STRUCT_XrSceneComponentsMSFT(_) \ + _(type) \ + _(next) \ + _(componentCapacityInput) \ + _(componentCountOutput) \ + _(components) \ + +#define XR_LIST_STRUCT_XrSceneComponentsGetInfoMSFT(_) \ + _(type) \ + _(next) \ + _(componentType) \ + +#define XR_LIST_STRUCT_XrSceneComponentLocationMSFT(_) \ + _(flags) \ + _(pose) \ + +#define XR_LIST_STRUCT_XrSceneComponentLocationsMSFT(_) \ + _(type) \ + _(next) \ + _(locationCount) \ + _(locations) \ + +#define XR_LIST_STRUCT_XrSceneComponentsLocateInfoMSFT(_) \ + _(type) \ + _(next) \ + _(baseSpace) \ + _(time) \ + _(componentIdCount) \ + _(componentIds) \ + +#define XR_LIST_STRUCT_XrSceneObjectMSFT(_) \ + _(objectType) \ + +#define XR_LIST_STRUCT_XrSceneObjectsMSFT(_) \ + _(type) \ + _(next) \ + _(sceneObjectCount) \ + _(sceneObjects) \ + +#define XR_LIST_STRUCT_XrSceneComponentParentFilterInfoMSFT(_) \ + _(type) \ + _(next) \ + _(parentId) \ + +#define XR_LIST_STRUCT_XrSceneObjectTypesFilterInfoMSFT(_) \ + _(type) \ + _(next) \ + _(objectTypeCount) \ + _(objectTypes) \ + +#define XR_LIST_STRUCT_XrScenePlaneMSFT(_) \ + _(alignment) \ + _(size) \ + _(meshBufferId) \ + _(supportsIndicesUint16) \ + +#define XR_LIST_STRUCT_XrScenePlanesMSFT(_) \ + _(type) \ + _(next) \ + _(scenePlaneCount) \ + _(scenePlanes) \ + +#define XR_LIST_STRUCT_XrScenePlaneAlignmentFilterInfoMSFT(_) \ + _(type) \ + _(next) \ + _(alignmentCount) \ + _(alignments) \ + +#define XR_LIST_STRUCT_XrSceneMeshMSFT(_) \ + _(meshBufferId) \ + _(supportsIndicesUint16) \ + +#define XR_LIST_STRUCT_XrSceneMeshesMSFT(_) \ + _(type) \ + _(next) \ + _(sceneMeshCount) \ + _(sceneMeshes) \ + +#define XR_LIST_STRUCT_XrSceneMeshBuffersGetInfoMSFT(_) \ + _(type) \ + _(next) \ + _(meshBufferId) \ + +#define XR_LIST_STRUCT_XrSceneMeshBuffersMSFT(_) \ + _(type) \ + _(next) \ + +#define XR_LIST_STRUCT_XrSceneMeshVertexBufferMSFT(_) \ + _(type) \ + _(next) \ + _(vertexCapacityInput) \ + _(vertexCountOutput) \ + _(vertices) \ + +#define XR_LIST_STRUCT_XrSceneMeshIndicesUint32MSFT(_) \ + _(type) \ + _(next) \ + _(indexCapacityInput) \ + _(indexCountOutput) \ + _(indices) \ + +#define XR_LIST_STRUCT_XrSceneMeshIndicesUint16MSFT(_) \ + _(type) \ + _(next) \ + _(indexCapacityInput) \ + _(indexCountOutput) \ + _(indices) \ + +#define XR_LIST_STRUCT_XrSerializedSceneFragmentDataGetInfoMSFT(_) \ + _(type) \ + _(next) \ + _(sceneFragmentId) \ + +#define XR_LIST_STRUCT_XrDeserializeSceneFragmentMSFT(_) \ + _(bufferSize) \ + _(buffer) \ + +#define XR_LIST_STRUCT_XrSceneDeserializeInfoMSFT(_) \ + _(type) \ + _(next) \ + _(fragmentCount) \ + _(fragments) \ + +#define XR_LIST_STRUCT_XrEventDataDisplayRefreshRateChangedFB(_) \ + _(type) \ + _(next) \ + _(fromDisplayRefreshRate) \ + _(toDisplayRefreshRate) \ + +#define XR_LIST_STRUCT_XrViveTrackerPathsHTCX(_) \ + _(type) \ + _(next) \ + _(persistentPath) \ + _(rolePath) \ + +#define XR_LIST_STRUCT_XrEventDataViveTrackerConnectedHTCX(_) \ + _(type) \ + _(next) \ + _(paths) \ + +#define XR_LIST_STRUCT_XrSystemFacialTrackingPropertiesHTC(_) \ + _(type) \ + _(next) \ + _(supportEyeFacialTracking) \ + _(supportLipFacialTracking) \ + +#define XR_LIST_STRUCT_XrFacialExpressionsHTC(_) \ + _(type) \ + _(next) \ + _(isActive) \ + _(sampleTime) \ + _(expressionCount) \ + _(expressionWeightings) \ + +#define XR_LIST_STRUCT_XrFacialTrackerCreateInfoHTC(_) \ + _(type) \ + _(next) \ + _(facialTrackingType) \ + +#define XR_LIST_STRUCT_XrSystemColorSpacePropertiesFB(_) \ + _(type) \ + _(next) \ + _(colorSpace) \ + +#define XR_LIST_STRUCT_XrVector4sFB(_) \ + _(x) \ + _(y) \ + _(z) \ + _(w) \ + +#define XR_LIST_STRUCT_XrHandTrackingMeshFB(_) \ + _(type) \ + _(next) \ + _(jointCapacityInput) \ + _(jointCountOutput) \ + _(jointBindPoses) \ + _(jointRadii) \ + _(jointParents) \ + _(vertexCapacityInput) \ + _(vertexCountOutput) \ + _(vertexPositions) \ + _(vertexNormals) \ + _(vertexUVs) \ + _(vertexBlendIndices) \ + _(vertexBlendWeights) \ + _(indexCapacityInput) \ + _(indexCountOutput) \ + _(indices) \ + +#define XR_LIST_STRUCT_XrHandTrackingScaleFB(_) \ + _(type) \ + _(next) \ + _(sensorOutput) \ + _(currentOutput) \ + _(overrideHandScale) \ + _(overrideValueInput) \ + +#define XR_LIST_STRUCT_XrHandTrackingAimStateFB(_) \ + _(type) \ + _(next) \ + _(status) \ + _(aimPose) \ + _(pinchStrengthIndex) \ + _(pinchStrengthMiddle) \ + _(pinchStrengthRing) \ + _(pinchStrengthLittle) \ + +#define XR_LIST_STRUCT_XrHandCapsuleFB(_) \ + _(points) \ + _(radius) \ + _(joint) \ + +#define XR_LIST_STRUCT_XrHandTrackingCapsulesStateFB(_) \ + _(type) \ + _(next) \ + _(capsules) \ + +#define XR_LIST_STRUCT_XrSystemSpatialEntityPropertiesFB(_) \ + _(type) \ + _(next) \ + _(supportsSpatialEntity) \ + +#define XR_LIST_STRUCT_XrSpatialAnchorCreateInfoFB(_) \ + _(type) \ + _(next) \ + _(space) \ + _(poseInSpace) \ + _(time) \ + +#define XR_LIST_STRUCT_XrSpaceComponentStatusSetInfoFB(_) \ + _(type) \ + _(next) \ + _(componentType) \ + _(enabled) \ + _(timeout) \ + +#define XR_LIST_STRUCT_XrSpaceComponentStatusFB(_) \ + _(type) \ + _(next) \ + _(enabled) \ + _(changePending) \ + +#define XR_LIST_STRUCT_XrUuidEXT(_) \ + _(data) \ + +#define XR_LIST_STRUCT_XrEventDataSpatialAnchorCreateCompleteFB(_) \ + _(type) \ + _(next) \ + _(requestId) \ + _(result) \ + _(space) \ + _(uuid) \ + +#define XR_LIST_STRUCT_XrEventDataSpaceSetStatusCompleteFB(_) \ + _(type) \ + _(next) \ + _(requestId) \ + _(result) \ + _(space) \ + _(uuid) \ + _(componentType) \ + _(enabled) \ + +#define XR_LIST_STRUCT_XrFoveationProfileCreateInfoFB(_) \ + _(type) \ + _(next) \ + +#define XR_LIST_STRUCT_XrSwapchainCreateInfoFoveationFB(_) \ + _(type) \ + _(next) \ + _(flags) \ + +#define XR_LIST_STRUCT_XrSwapchainStateFoveationFB(_) \ + _(type) \ + _(next) \ + _(flags) \ + _(profile) \ + +#define XR_LIST_STRUCT_XrFoveationLevelProfileCreateInfoFB(_) \ + _(type) \ + _(next) \ + _(level) \ + _(verticalOffset) \ + _(dynamic) \ + +#define XR_LIST_STRUCT_XrSystemKeyboardTrackingPropertiesFB(_) \ + _(type) \ + _(next) \ + _(supportsKeyboardTracking) \ + +#define XR_LIST_STRUCT_XrKeyboardTrackingDescriptionFB(_) \ + _(trackedKeyboardId) \ + _(size) \ + _(flags) \ + _(name) \ + +#define XR_LIST_STRUCT_XrKeyboardSpaceCreateInfoFB(_) \ + _(type) \ + _(next) \ + _(trackedKeyboardId) \ + +#define XR_LIST_STRUCT_XrKeyboardTrackingQueryFB(_) \ + _(type) \ + _(next) \ + _(flags) \ + +#define XR_LIST_STRUCT_XrTriangleMeshCreateInfoFB(_) \ + _(type) \ + _(next) \ + _(flags) \ + _(windingOrder) \ + _(vertexCount) \ + _(vertexBuffer) \ + _(triangleCount) \ + _(indexBuffer) \ + +#define XR_LIST_STRUCT_XrSystemPassthroughPropertiesFB(_) \ + _(type) \ + _(next) \ + _(supportsPassthrough) \ + +#define XR_LIST_STRUCT_XrSystemPassthroughProperties2FB(_) \ + _(type) \ + _(next) \ + _(capabilities) \ + +#define XR_LIST_STRUCT_XrPassthroughCreateInfoFB(_) \ + _(type) \ + _(next) \ + _(flags) \ + +#define XR_LIST_STRUCT_XrPassthroughLayerCreateInfoFB(_) \ + _(type) \ + _(next) \ + _(passthrough) \ + _(flags) \ + _(purpose) \ + +#define XR_LIST_STRUCT_XrCompositionLayerPassthroughFB(_) \ + _(type) \ + _(next) \ + _(flags) \ + _(space) \ + _(layerHandle) \ + +#define XR_LIST_STRUCT_XrGeometryInstanceCreateInfoFB(_) \ + _(type) \ + _(next) \ + _(layer) \ + _(mesh) \ + _(baseSpace) \ + _(pose) \ + _(scale) \ + +#define XR_LIST_STRUCT_XrGeometryInstanceTransformFB(_) \ + _(type) \ + _(next) \ + _(baseSpace) \ + _(time) \ + _(pose) \ + _(scale) \ + +#define XR_LIST_STRUCT_XrPassthroughStyleFB(_) \ + _(type) \ + _(next) \ + _(textureOpacityFactor) \ + _(edgeColor) \ + +#define XR_LIST_STRUCT_XrPassthroughColorMapMonoToRgbaFB(_) \ + _(type) \ + _(next) \ + _(textureColorMap) \ + +#define XR_LIST_STRUCT_XrPassthroughColorMapMonoToMonoFB(_) \ + _(type) \ + _(next) \ + _(textureColorMap) \ + +#define XR_LIST_STRUCT_XrPassthroughBrightnessContrastSaturationFB(_) \ + _(type) \ + _(next) \ + _(brightness) \ + _(contrast) \ + _(saturation) \ + +#define XR_LIST_STRUCT_XrEventDataPassthroughStateChangedFB(_) \ + _(type) \ + _(next) \ + _(flags) \ + +#define XR_LIST_STRUCT_XrRenderModelPathInfoFB(_) \ + _(type) \ + _(next) \ + _(path) \ + +#define XR_LIST_STRUCT_XrRenderModelPropertiesFB(_) \ + _(type) \ + _(next) \ + _(vendorId) \ + _(modelName) \ + _(modelKey) \ + _(modelVersion) \ + _(flags) \ + +#define XR_LIST_STRUCT_XrRenderModelBufferFB(_) \ + _(type) \ + _(next) \ + _(bufferCapacityInput) \ + _(bufferCountOutput) \ + _(buffer) \ + +#define XR_LIST_STRUCT_XrRenderModelLoadInfoFB(_) \ + _(type) \ + _(next) \ + _(modelKey) \ + +#define XR_LIST_STRUCT_XrSystemRenderModelPropertiesFB(_) \ + _(type) \ + _(next) \ + _(supportsRenderModelLoading) \ + +#define XR_LIST_STRUCT_XrRenderModelCapabilitiesRequestFB(_) \ + _(type) \ + _(next) \ + _(flags) \ + +#define XR_LIST_STRUCT_XrViewLocateFoveatedRenderingVARJO(_) \ + _(type) \ + _(next) \ + _(foveatedRenderingActive) \ + +#define XR_LIST_STRUCT_XrFoveatedViewConfigurationViewVARJO(_) \ + _(type) \ + _(next) \ + _(foveatedRenderingActive) \ + +#define XR_LIST_STRUCT_XrSystemFoveatedRenderingPropertiesVARJO(_) \ + _(type) \ + _(next) \ + _(supportsFoveatedRendering) \ + +#define XR_LIST_STRUCT_XrCompositionLayerDepthTestVARJO(_) \ + _(type) \ + _(next) \ + _(depthTestRangeNearZ) \ + _(depthTestRangeFarZ) \ + +#define XR_LIST_STRUCT_XrSystemMarkerTrackingPropertiesVARJO(_) \ + _(type) \ + _(next) \ + _(supportsMarkerTracking) \ + +#define XR_LIST_STRUCT_XrEventDataMarkerTrackingUpdateVARJO(_) \ + _(type) \ + _(next) \ + _(markerId) \ + _(isActive) \ + _(isPredicted) \ + _(time) \ + +#define XR_LIST_STRUCT_XrMarkerSpaceCreateInfoVARJO(_) \ + _(type) \ + _(next) \ + _(markerId) \ + _(poseInMarkerSpace) \ + +#define XR_LIST_STRUCT_XrSpatialAnchorPersistenceNameMSFT(_) \ + _(name) \ + +#define XR_LIST_STRUCT_XrSpatialAnchorPersistenceInfoMSFT(_) \ + _(type) \ + _(next) \ + _(spatialAnchorPersistenceName) \ + _(spatialAnchor) \ + +#define XR_LIST_STRUCT_XrSpatialAnchorFromPersistedAnchorCreateInfoMSFT(_) \ + _(type) \ + _(next) \ + _(spatialAnchorStore) \ + _(spatialAnchorPersistenceName) \ + +#define XR_LIST_STRUCT_XrSpaceQueryInfoBaseHeaderFB(_) \ + _(type) \ + _(next) \ + +#define XR_LIST_STRUCT_XrSpaceFilterInfoBaseHeaderFB(_) \ + _(type) \ + _(next) \ + +#define XR_LIST_STRUCT_XrSpaceQueryInfoFB(_) \ + _(type) \ + _(next) \ + _(queryAction) \ + _(maxResultCount) \ + _(timeout) \ + _(filter) \ + _(excludeFilter) \ + +#define XR_LIST_STRUCT_XrSpaceStorageLocationFilterInfoFB(_) \ + _(type) \ + _(next) \ + _(location) \ + +#define XR_LIST_STRUCT_XrSpaceUuidFilterInfoFB(_) \ + _(type) \ + _(next) \ + _(uuidCount) \ + _(uuids) \ + +#define XR_LIST_STRUCT_XrSpaceComponentFilterInfoFB(_) \ + _(type) \ + _(next) \ + _(componentType) \ + +#define XR_LIST_STRUCT_XrSpaceQueryResultFB(_) \ + _(space) \ + _(uuid) \ + +#define XR_LIST_STRUCT_XrSpaceQueryResultsFB(_) \ + _(type) \ + _(next) \ + _(resultCapacityInput) \ + _(resultCountOutput) \ + _(results) \ + +#define XR_LIST_STRUCT_XrEventDataSpaceQueryResultsAvailableFB(_) \ + _(type) \ + _(next) \ + _(requestId) \ + +#define XR_LIST_STRUCT_XrEventDataSpaceQueryCompleteFB(_) \ + _(type) \ + _(next) \ + _(requestId) \ + _(result) \ + +#define XR_LIST_STRUCT_XrSpaceSaveInfoFB(_) \ + _(type) \ + _(next) \ + _(space) \ + _(location) \ + _(persistenceMode) \ + +#define XR_LIST_STRUCT_XrSpaceEraseInfoFB(_) \ + _(type) \ + _(next) \ + _(space) \ + _(location) \ + +#define XR_LIST_STRUCT_XrEventDataSpaceSaveCompleteFB(_) \ + _(type) \ + _(next) \ + _(requestId) \ + _(result) \ + _(space) \ + _(uuid) \ + _(location) \ + +#define XR_LIST_STRUCT_XrEventDataSpaceEraseCompleteFB(_) \ + _(type) \ + _(next) \ + _(requestId) \ + _(result) \ + _(space) \ + _(uuid) \ + _(location) \ + +#define XR_LIST_STRUCT_XrSwapchainImageFoveationVulkanFB(_) \ + _(type) \ + _(next) \ + _(image) \ + _(width) \ + _(height) \ + +#define XR_LIST_STRUCT_XrSwapchainStateAndroidSurfaceDimensionsFB(_) \ + _(type) \ + _(next) \ + _(width) \ + _(height) \ + +#define XR_LIST_STRUCT_XrSwapchainStateSamplerOpenGLESFB(_) \ + _(type) \ + _(next) \ + _(minFilter) \ + _(magFilter) \ + _(wrapModeS) \ + _(wrapModeT) \ + _(swizzleRed) \ + _(swizzleGreen) \ + _(swizzleBlue) \ + _(swizzleAlpha) \ + _(maxAnisotropy) \ + _(borderColor) \ + +#define XR_LIST_STRUCT_XrSwapchainStateSamplerVulkanFB(_) \ + _(type) \ + _(next) \ + _(minFilter) \ + _(magFilter) \ + _(mipmapMode) \ + _(wrapModeS) \ + _(wrapModeT) \ + _(swizzleRed) \ + _(swizzleGreen) \ + _(swizzleBlue) \ + _(swizzleAlpha) \ + _(maxAnisotropy) \ + _(borderColor) \ + +#define XR_LIST_STRUCT_XrCompositionLayerSpaceWarpInfoFB(_) \ + _(type) \ + _(next) \ + _(layerFlags) \ + _(motionVectorSubImage) \ + _(appSpaceDeltaPose) \ + _(depthSubImage) \ + _(minDepth) \ + _(maxDepth) \ + _(nearZ) \ + _(farZ) \ + +#define XR_LIST_STRUCT_XrSystemSpaceWarpPropertiesFB(_) \ + _(type) \ + _(next) \ + _(recommendedMotionVectorImageRectWidth) \ + _(recommendedMotionVectorImageRectHeight) \ + +#define XR_LIST_STRUCT_XrExtent3DfFB(_) \ + _(width) \ + _(height) \ + _(depth) \ + +#define XR_LIST_STRUCT_XrOffset3DfFB(_) \ + _(x) \ + _(y) \ + _(z) \ + +#define XR_LIST_STRUCT_XrRect3DfFB(_) \ + _(offset) \ + _(extent) \ + +#define XR_LIST_STRUCT_XrSemanticLabelsFB(_) \ + _(type) \ + _(next) \ + _(bufferCapacityInput) \ + _(bufferCountOutput) \ + _(buffer) \ + +#define XR_LIST_STRUCT_XrRoomLayoutFB(_) \ + _(type) \ + _(next) \ + _(floorUuid) \ + _(ceilingUuid) \ + _(wallUuidCapacityInput) \ + _(wallUuidCountOutput) \ + _(wallUuids) \ + +#define XR_LIST_STRUCT_XrBoundary2DFB(_) \ + _(type) \ + _(next) \ + _(vertexCapacityInput) \ + _(vertexCountOutput) \ + _(vertices) \ + +#define XR_LIST_STRUCT_XrDigitalLensControlALMALENCE(_) \ + _(type) \ + _(next) \ + _(flags) \ + +#define XR_LIST_STRUCT_XrSpaceContainerFB(_) \ + _(type) \ + _(next) \ + _(uuidCapacityInput) \ + _(uuidCountOutput) \ + _(uuids) \ + +#define XR_LIST_STRUCT_XrPassthroughKeyboardHandsIntensityFB(_) \ + _(type) \ + _(next) \ + _(leftHandIntensity) \ + _(rightHandIntensity) \ + +#define XR_LIST_STRUCT_XrCompositionLayerSettingsFB(_) \ + _(type) \ + _(next) \ + _(layerFlags) \ + +#define XR_LIST_STRUCT_XrVulkanSwapchainCreateInfoMETA(_) \ + _(type) \ + _(next) \ + _(additionalCreateFlags) \ + _(additionalUsageFlags) \ + +#define XR_LIST_STRUCT_XrPerformanceMetricsStateMETA(_) \ + _(type) \ + _(next) \ + _(enabled) \ + +#define XR_LIST_STRUCT_XrPerformanceMetricsCounterMETA(_) \ + _(type) \ + _(next) \ + _(counterFlags) \ + _(counterUnit) \ + _(uintValue) \ + _(floatValue) \ + + + +#define XR_LIST_STRUCTURE_TYPES_CORE(_) \ + _(XrApiLayerProperties, XR_TYPE_API_LAYER_PROPERTIES) \ + _(XrExtensionProperties, XR_TYPE_EXTENSION_PROPERTIES) \ + _(XrInstanceCreateInfo, XR_TYPE_INSTANCE_CREATE_INFO) \ + _(XrInstanceProperties, XR_TYPE_INSTANCE_PROPERTIES) \ + _(XrEventDataBuffer, XR_TYPE_EVENT_DATA_BUFFER) \ + _(XrSystemGetInfo, XR_TYPE_SYSTEM_GET_INFO) \ + _(XrSystemProperties, XR_TYPE_SYSTEM_PROPERTIES) \ + _(XrSessionCreateInfo, XR_TYPE_SESSION_CREATE_INFO) \ + _(XrSpaceVelocity, XR_TYPE_SPACE_VELOCITY) \ + _(XrReferenceSpaceCreateInfo, XR_TYPE_REFERENCE_SPACE_CREATE_INFO) \ + _(XrActionSpaceCreateInfo, XR_TYPE_ACTION_SPACE_CREATE_INFO) \ + _(XrSpaceLocation, XR_TYPE_SPACE_LOCATION) \ + _(XrViewConfigurationProperties, XR_TYPE_VIEW_CONFIGURATION_PROPERTIES) \ + _(XrViewConfigurationView, XR_TYPE_VIEW_CONFIGURATION_VIEW) \ + _(XrSwapchainCreateInfo, XR_TYPE_SWAPCHAIN_CREATE_INFO) \ + _(XrSwapchainImageAcquireInfo, XR_TYPE_SWAPCHAIN_IMAGE_ACQUIRE_INFO) \ + _(XrSwapchainImageWaitInfo, XR_TYPE_SWAPCHAIN_IMAGE_WAIT_INFO) \ + _(XrSwapchainImageReleaseInfo, XR_TYPE_SWAPCHAIN_IMAGE_RELEASE_INFO) \ + _(XrSessionBeginInfo, XR_TYPE_SESSION_BEGIN_INFO) \ + _(XrFrameWaitInfo, XR_TYPE_FRAME_WAIT_INFO) \ + _(XrFrameState, XR_TYPE_FRAME_STATE) \ + _(XrFrameBeginInfo, XR_TYPE_FRAME_BEGIN_INFO) \ + _(XrFrameEndInfo, XR_TYPE_FRAME_END_INFO) \ + _(XrViewLocateInfo, XR_TYPE_VIEW_LOCATE_INFO) \ + _(XrViewState, XR_TYPE_VIEW_STATE) \ + _(XrView, XR_TYPE_VIEW) \ + _(XrActionSetCreateInfo, XR_TYPE_ACTION_SET_CREATE_INFO) \ + _(XrActionCreateInfo, XR_TYPE_ACTION_CREATE_INFO) \ + _(XrInteractionProfileSuggestedBinding, XR_TYPE_INTERACTION_PROFILE_SUGGESTED_BINDING) \ + _(XrSessionActionSetsAttachInfo, XR_TYPE_SESSION_ACTION_SETS_ATTACH_INFO) \ + _(XrInteractionProfileState, XR_TYPE_INTERACTION_PROFILE_STATE) \ + _(XrActionStateGetInfo, XR_TYPE_ACTION_STATE_GET_INFO) \ + _(XrActionStateBoolean, XR_TYPE_ACTION_STATE_BOOLEAN) \ + _(XrActionStateFloat, XR_TYPE_ACTION_STATE_FLOAT) \ + _(XrActionStateVector2f, XR_TYPE_ACTION_STATE_VECTOR2F) \ + _(XrActionStatePose, XR_TYPE_ACTION_STATE_POSE) \ + _(XrActionsSyncInfo, XR_TYPE_ACTIONS_SYNC_INFO) \ + _(XrBoundSourcesForActionEnumerateInfo, XR_TYPE_BOUND_SOURCES_FOR_ACTION_ENUMERATE_INFO) \ + _(XrInputSourceLocalizedNameGetInfo, XR_TYPE_INPUT_SOURCE_LOCALIZED_NAME_GET_INFO) \ + _(XrHapticActionInfo, XR_TYPE_HAPTIC_ACTION_INFO) \ + _(XrCompositionLayerProjectionView, XR_TYPE_COMPOSITION_LAYER_PROJECTION_VIEW) \ + _(XrCompositionLayerProjection, XR_TYPE_COMPOSITION_LAYER_PROJECTION) \ + _(XrCompositionLayerQuad, XR_TYPE_COMPOSITION_LAYER_QUAD) \ + _(XrEventDataEventsLost, XR_TYPE_EVENT_DATA_EVENTS_LOST) \ + _(XrEventDataInstanceLossPending, XR_TYPE_EVENT_DATA_INSTANCE_LOSS_PENDING) \ + _(XrEventDataSessionStateChanged, XR_TYPE_EVENT_DATA_SESSION_STATE_CHANGED) \ + _(XrEventDataReferenceSpaceChangePending, XR_TYPE_EVENT_DATA_REFERENCE_SPACE_CHANGE_PENDING) \ + _(XrEventDataInteractionProfileChanged, XR_TYPE_EVENT_DATA_INTERACTION_PROFILE_CHANGED) \ + _(XrHapticVibration, XR_TYPE_HAPTIC_VIBRATION) \ + _(XrCompositionLayerCubeKHR, XR_TYPE_COMPOSITION_LAYER_CUBE_KHR) \ + _(XrCompositionLayerDepthInfoKHR, XR_TYPE_COMPOSITION_LAYER_DEPTH_INFO_KHR) \ + _(XrCompositionLayerCylinderKHR, XR_TYPE_COMPOSITION_LAYER_CYLINDER_KHR) \ + _(XrCompositionLayerEquirectKHR, XR_TYPE_COMPOSITION_LAYER_EQUIRECT_KHR) \ + _(XrVisibilityMaskKHR, XR_TYPE_VISIBILITY_MASK_KHR) \ + _(XrEventDataVisibilityMaskChangedKHR, XR_TYPE_EVENT_DATA_VISIBILITY_MASK_CHANGED_KHR) \ + _(XrCompositionLayerColorScaleBiasKHR, XR_TYPE_COMPOSITION_LAYER_COLOR_SCALE_BIAS_KHR) \ + _(XrCompositionLayerEquirect2KHR, XR_TYPE_COMPOSITION_LAYER_EQUIRECT2_KHR) \ + _(XrBindingModificationsKHR, XR_TYPE_BINDING_MODIFICATIONS_KHR) \ + _(XrEventDataPerfSettingsEXT, XR_TYPE_EVENT_DATA_PERF_SETTINGS_EXT) \ + _(XrDebugUtilsObjectNameInfoEXT, XR_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT) \ + _(XrDebugUtilsLabelEXT, XR_TYPE_DEBUG_UTILS_LABEL_EXT) \ + _(XrDebugUtilsMessengerCallbackDataEXT, XR_TYPE_DEBUG_UTILS_MESSENGER_CALLBACK_DATA_EXT) \ + _(XrDebugUtilsMessengerCreateInfoEXT, XR_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT) \ + _(XrSystemEyeGazeInteractionPropertiesEXT, XR_TYPE_SYSTEM_EYE_GAZE_INTERACTION_PROPERTIES_EXT) \ + _(XrEyeGazeSampleTimeEXT, XR_TYPE_EYE_GAZE_SAMPLE_TIME_EXT) \ + _(XrSessionCreateInfoOverlayEXTX, XR_TYPE_SESSION_CREATE_INFO_OVERLAY_EXTX) \ + _(XrEventDataMainSessionVisibilityChangedEXTX, XR_TYPE_EVENT_DATA_MAIN_SESSION_VISIBILITY_CHANGED_EXTX) \ + _(XrSpatialAnchorCreateInfoMSFT, XR_TYPE_SPATIAL_ANCHOR_CREATE_INFO_MSFT) \ + _(XrSpatialAnchorSpaceCreateInfoMSFT, XR_TYPE_SPATIAL_ANCHOR_SPACE_CREATE_INFO_MSFT) \ + _(XrCompositionLayerImageLayoutFB, XR_TYPE_COMPOSITION_LAYER_IMAGE_LAYOUT_FB) \ + _(XrCompositionLayerAlphaBlendFB, XR_TYPE_COMPOSITION_LAYER_ALPHA_BLEND_FB) \ + _(XrViewConfigurationDepthRangeEXT, XR_TYPE_VIEW_CONFIGURATION_DEPTH_RANGE_EXT) \ + _(XrSpatialGraphNodeSpaceCreateInfoMSFT, XR_TYPE_SPATIAL_GRAPH_NODE_SPACE_CREATE_INFO_MSFT) \ + _(XrSpatialGraphStaticNodeBindingCreateInfoMSFT, XR_TYPE_SPATIAL_GRAPH_STATIC_NODE_BINDING_CREATE_INFO_MSFT) \ + _(XrSpatialGraphNodeBindingPropertiesGetInfoMSFT, XR_TYPE_SPATIAL_GRAPH_NODE_BINDING_PROPERTIES_GET_INFO_MSFT) \ + _(XrSpatialGraphNodeBindingPropertiesMSFT, XR_TYPE_SPATIAL_GRAPH_NODE_BINDING_PROPERTIES_MSFT) \ + _(XrSystemHandTrackingPropertiesEXT, XR_TYPE_SYSTEM_HAND_TRACKING_PROPERTIES_EXT) \ + _(XrHandTrackerCreateInfoEXT, XR_TYPE_HAND_TRACKER_CREATE_INFO_EXT) \ + _(XrHandJointsLocateInfoEXT, XR_TYPE_HAND_JOINTS_LOCATE_INFO_EXT) \ + _(XrHandJointLocationsEXT, XR_TYPE_HAND_JOINT_LOCATIONS_EXT) \ + _(XrHandJointVelocitiesEXT, XR_TYPE_HAND_JOINT_VELOCITIES_EXT) \ + _(XrSystemHandTrackingMeshPropertiesMSFT, XR_TYPE_SYSTEM_HAND_TRACKING_MESH_PROPERTIES_MSFT) \ + _(XrHandMeshSpaceCreateInfoMSFT, XR_TYPE_HAND_MESH_SPACE_CREATE_INFO_MSFT) \ + _(XrHandMeshUpdateInfoMSFT, XR_TYPE_HAND_MESH_UPDATE_INFO_MSFT) \ + _(XrHandMeshMSFT, XR_TYPE_HAND_MESH_MSFT) \ + _(XrHandPoseTypeInfoMSFT, XR_TYPE_HAND_POSE_TYPE_INFO_MSFT) \ + _(XrSecondaryViewConfigurationSessionBeginInfoMSFT, XR_TYPE_SECONDARY_VIEW_CONFIGURATION_SESSION_BEGIN_INFO_MSFT) \ + _(XrSecondaryViewConfigurationStateMSFT, XR_TYPE_SECONDARY_VIEW_CONFIGURATION_STATE_MSFT) \ + _(XrSecondaryViewConfigurationFrameStateMSFT, XR_TYPE_SECONDARY_VIEW_CONFIGURATION_FRAME_STATE_MSFT) \ + _(XrSecondaryViewConfigurationLayerInfoMSFT, XR_TYPE_SECONDARY_VIEW_CONFIGURATION_LAYER_INFO_MSFT) \ + _(XrSecondaryViewConfigurationFrameEndInfoMSFT, XR_TYPE_SECONDARY_VIEW_CONFIGURATION_FRAME_END_INFO_MSFT) \ + _(XrSecondaryViewConfigurationSwapchainCreateInfoMSFT, XR_TYPE_SECONDARY_VIEW_CONFIGURATION_SWAPCHAIN_CREATE_INFO_MSFT) \ + _(XrControllerModelKeyStateMSFT, XR_TYPE_CONTROLLER_MODEL_KEY_STATE_MSFT) \ + _(XrControllerModelNodePropertiesMSFT, XR_TYPE_CONTROLLER_MODEL_NODE_PROPERTIES_MSFT) \ + _(XrControllerModelPropertiesMSFT, XR_TYPE_CONTROLLER_MODEL_PROPERTIES_MSFT) \ + _(XrControllerModelNodeStateMSFT, XR_TYPE_CONTROLLER_MODEL_NODE_STATE_MSFT) \ + _(XrControllerModelStateMSFT, XR_TYPE_CONTROLLER_MODEL_STATE_MSFT) \ + _(XrViewConfigurationViewFovEPIC, XR_TYPE_VIEW_CONFIGURATION_VIEW_FOV_EPIC) \ + _(XrCompositionLayerReprojectionInfoMSFT, XR_TYPE_COMPOSITION_LAYER_REPROJECTION_INFO_MSFT) \ + _(XrCompositionLayerReprojectionPlaneOverrideMSFT, XR_TYPE_COMPOSITION_LAYER_REPROJECTION_PLANE_OVERRIDE_MSFT) \ + _(XrCompositionLayerSecureContentFB, XR_TYPE_COMPOSITION_LAYER_SECURE_CONTENT_FB) \ + _(XrInteractionProfileDpadBindingEXT, XR_TYPE_INTERACTION_PROFILE_DPAD_BINDING_EXT) \ + _(XrInteractionProfileAnalogThresholdVALVE, XR_TYPE_INTERACTION_PROFILE_ANALOG_THRESHOLD_VALVE) \ + _(XrHandJointsMotionRangeInfoEXT, XR_TYPE_HAND_JOINTS_MOTION_RANGE_INFO_EXT) \ + _(XrSceneObserverCreateInfoMSFT, XR_TYPE_SCENE_OBSERVER_CREATE_INFO_MSFT) \ + _(XrSceneCreateInfoMSFT, XR_TYPE_SCENE_CREATE_INFO_MSFT) \ + _(XrNewSceneComputeInfoMSFT, XR_TYPE_NEW_SCENE_COMPUTE_INFO_MSFT) \ + _(XrVisualMeshComputeLodInfoMSFT, XR_TYPE_VISUAL_MESH_COMPUTE_LOD_INFO_MSFT) \ + _(XrSceneComponentsMSFT, XR_TYPE_SCENE_COMPONENTS_MSFT) \ + _(XrSceneComponentsGetInfoMSFT, XR_TYPE_SCENE_COMPONENTS_GET_INFO_MSFT) \ + _(XrSceneComponentLocationsMSFT, XR_TYPE_SCENE_COMPONENT_LOCATIONS_MSFT) \ + _(XrSceneComponentsLocateInfoMSFT, XR_TYPE_SCENE_COMPONENTS_LOCATE_INFO_MSFT) \ + _(XrSceneObjectsMSFT, XR_TYPE_SCENE_OBJECTS_MSFT) \ + _(XrSceneComponentParentFilterInfoMSFT, XR_TYPE_SCENE_COMPONENT_PARENT_FILTER_INFO_MSFT) \ + _(XrSceneObjectTypesFilterInfoMSFT, XR_TYPE_SCENE_OBJECT_TYPES_FILTER_INFO_MSFT) \ + _(XrScenePlanesMSFT, XR_TYPE_SCENE_PLANES_MSFT) \ + _(XrScenePlaneAlignmentFilterInfoMSFT, XR_TYPE_SCENE_PLANE_ALIGNMENT_FILTER_INFO_MSFT) \ + _(XrSceneMeshesMSFT, XR_TYPE_SCENE_MESHES_MSFT) \ + _(XrSceneMeshBuffersGetInfoMSFT, XR_TYPE_SCENE_MESH_BUFFERS_GET_INFO_MSFT) \ + _(XrSceneMeshBuffersMSFT, XR_TYPE_SCENE_MESH_BUFFERS_MSFT) \ + _(XrSceneMeshVertexBufferMSFT, XR_TYPE_SCENE_MESH_VERTEX_BUFFER_MSFT) \ + _(XrSceneMeshIndicesUint32MSFT, XR_TYPE_SCENE_MESH_INDICES_UINT32_MSFT) \ + _(XrSceneMeshIndicesUint16MSFT, XR_TYPE_SCENE_MESH_INDICES_UINT16_MSFT) \ + _(XrSerializedSceneFragmentDataGetInfoMSFT, XR_TYPE_SERIALIZED_SCENE_FRAGMENT_DATA_GET_INFO_MSFT) \ + _(XrSceneDeserializeInfoMSFT, XR_TYPE_SCENE_DESERIALIZE_INFO_MSFT) \ + _(XrEventDataDisplayRefreshRateChangedFB, XR_TYPE_EVENT_DATA_DISPLAY_REFRESH_RATE_CHANGED_FB) \ + _(XrViveTrackerPathsHTCX, XR_TYPE_VIVE_TRACKER_PATHS_HTCX) \ + _(XrEventDataViveTrackerConnectedHTCX, XR_TYPE_EVENT_DATA_VIVE_TRACKER_CONNECTED_HTCX) \ + _(XrSystemFacialTrackingPropertiesHTC, XR_TYPE_SYSTEM_FACIAL_TRACKING_PROPERTIES_HTC) \ + _(XrFacialExpressionsHTC, XR_TYPE_FACIAL_EXPRESSIONS_HTC) \ + _(XrFacialTrackerCreateInfoHTC, XR_TYPE_FACIAL_TRACKER_CREATE_INFO_HTC) \ + _(XrSystemColorSpacePropertiesFB, XR_TYPE_SYSTEM_COLOR_SPACE_PROPERTIES_FB) \ + _(XrHandTrackingMeshFB, XR_TYPE_HAND_TRACKING_MESH_FB) \ + _(XrHandTrackingScaleFB, XR_TYPE_HAND_TRACKING_SCALE_FB) \ + _(XrHandTrackingAimStateFB, XR_TYPE_HAND_TRACKING_AIM_STATE_FB) \ + _(XrHandTrackingCapsulesStateFB, XR_TYPE_HAND_TRACKING_CAPSULES_STATE_FB) \ + _(XrSystemSpatialEntityPropertiesFB, XR_TYPE_SYSTEM_SPATIAL_ENTITY_PROPERTIES_FB) \ + _(XrSpatialAnchorCreateInfoFB, XR_TYPE_SPATIAL_ANCHOR_CREATE_INFO_FB) \ + _(XrSpaceComponentStatusSetInfoFB, XR_TYPE_SPACE_COMPONENT_STATUS_SET_INFO_FB) \ + _(XrSpaceComponentStatusFB, XR_TYPE_SPACE_COMPONENT_STATUS_FB) \ + _(XrEventDataSpatialAnchorCreateCompleteFB, XR_TYPE_EVENT_DATA_SPATIAL_ANCHOR_CREATE_COMPLETE_FB) \ + _(XrEventDataSpaceSetStatusCompleteFB, XR_TYPE_EVENT_DATA_SPACE_SET_STATUS_COMPLETE_FB) \ + _(XrFoveationProfileCreateInfoFB, XR_TYPE_FOVEATION_PROFILE_CREATE_INFO_FB) \ + _(XrSwapchainCreateInfoFoveationFB, XR_TYPE_SWAPCHAIN_CREATE_INFO_FOVEATION_FB) \ + _(XrSwapchainStateFoveationFB, XR_TYPE_SWAPCHAIN_STATE_FOVEATION_FB) \ + _(XrFoveationLevelProfileCreateInfoFB, XR_TYPE_FOVEATION_LEVEL_PROFILE_CREATE_INFO_FB) \ + _(XrSystemKeyboardTrackingPropertiesFB, XR_TYPE_SYSTEM_KEYBOARD_TRACKING_PROPERTIES_FB) \ + _(XrKeyboardSpaceCreateInfoFB, XR_TYPE_KEYBOARD_SPACE_CREATE_INFO_FB) \ + _(XrKeyboardTrackingQueryFB, XR_TYPE_KEYBOARD_TRACKING_QUERY_FB) \ + _(XrTriangleMeshCreateInfoFB, XR_TYPE_TRIANGLE_MESH_CREATE_INFO_FB) \ + _(XrSystemPassthroughPropertiesFB, XR_TYPE_SYSTEM_PASSTHROUGH_PROPERTIES_FB) \ + _(XrSystemPassthroughProperties2FB, XR_TYPE_SYSTEM_PASSTHROUGH_PROPERTIES2_FB) \ + _(XrPassthroughCreateInfoFB, XR_TYPE_PASSTHROUGH_CREATE_INFO_FB) \ + _(XrPassthroughLayerCreateInfoFB, XR_TYPE_PASSTHROUGH_LAYER_CREATE_INFO_FB) \ + _(XrCompositionLayerPassthroughFB, XR_TYPE_COMPOSITION_LAYER_PASSTHROUGH_FB) \ + _(XrGeometryInstanceCreateInfoFB, XR_TYPE_GEOMETRY_INSTANCE_CREATE_INFO_FB) \ + _(XrGeometryInstanceTransformFB, XR_TYPE_GEOMETRY_INSTANCE_TRANSFORM_FB) \ + _(XrPassthroughStyleFB, XR_TYPE_PASSTHROUGH_STYLE_FB) \ + _(XrPassthroughColorMapMonoToRgbaFB, XR_TYPE_PASSTHROUGH_COLOR_MAP_MONO_TO_RGBA_FB) \ + _(XrPassthroughColorMapMonoToMonoFB, XR_TYPE_PASSTHROUGH_COLOR_MAP_MONO_TO_MONO_FB) \ + _(XrPassthroughBrightnessContrastSaturationFB, XR_TYPE_PASSTHROUGH_BRIGHTNESS_CONTRAST_SATURATION_FB) \ + _(XrEventDataPassthroughStateChangedFB, XR_TYPE_EVENT_DATA_PASSTHROUGH_STATE_CHANGED_FB) \ + _(XrRenderModelPathInfoFB, XR_TYPE_RENDER_MODEL_PATH_INFO_FB) \ + _(XrRenderModelPropertiesFB, XR_TYPE_RENDER_MODEL_PROPERTIES_FB) \ + _(XrRenderModelBufferFB, XR_TYPE_RENDER_MODEL_BUFFER_FB) \ + _(XrRenderModelLoadInfoFB, XR_TYPE_RENDER_MODEL_LOAD_INFO_FB) \ + _(XrSystemRenderModelPropertiesFB, XR_TYPE_SYSTEM_RENDER_MODEL_PROPERTIES_FB) \ + _(XrRenderModelCapabilitiesRequestFB, XR_TYPE_RENDER_MODEL_CAPABILITIES_REQUEST_FB) \ + _(XrViewLocateFoveatedRenderingVARJO, XR_TYPE_VIEW_LOCATE_FOVEATED_RENDERING_VARJO) \ + _(XrFoveatedViewConfigurationViewVARJO, XR_TYPE_FOVEATED_VIEW_CONFIGURATION_VIEW_VARJO) \ + _(XrSystemFoveatedRenderingPropertiesVARJO, XR_TYPE_SYSTEM_FOVEATED_RENDERING_PROPERTIES_VARJO) \ + _(XrCompositionLayerDepthTestVARJO, XR_TYPE_COMPOSITION_LAYER_DEPTH_TEST_VARJO) \ + _(XrSystemMarkerTrackingPropertiesVARJO, XR_TYPE_SYSTEM_MARKER_TRACKING_PROPERTIES_VARJO) \ + _(XrEventDataMarkerTrackingUpdateVARJO, XR_TYPE_EVENT_DATA_MARKER_TRACKING_UPDATE_VARJO) \ + _(XrMarkerSpaceCreateInfoVARJO, XR_TYPE_MARKER_SPACE_CREATE_INFO_VARJO) \ + _(XrSpatialAnchorPersistenceInfoMSFT, XR_TYPE_SPATIAL_ANCHOR_PERSISTENCE_INFO_MSFT) \ + _(XrSpatialAnchorFromPersistedAnchorCreateInfoMSFT, XR_TYPE_SPATIAL_ANCHOR_FROM_PERSISTED_ANCHOR_CREATE_INFO_MSFT) \ + _(XrSpaceQueryInfoFB, XR_TYPE_SPACE_QUERY_INFO_FB) \ + _(XrSpaceStorageLocationFilterInfoFB, XR_TYPE_SPACE_STORAGE_LOCATION_FILTER_INFO_FB) \ + _(XrSpaceUuidFilterInfoFB, XR_TYPE_SPACE_UUID_FILTER_INFO_FB) \ + _(XrSpaceComponentFilterInfoFB, XR_TYPE_SPACE_COMPONENT_FILTER_INFO_FB) \ + _(XrSpaceQueryResultsFB, XR_TYPE_SPACE_QUERY_RESULTS_FB) \ + _(XrEventDataSpaceQueryResultsAvailableFB, XR_TYPE_EVENT_DATA_SPACE_QUERY_RESULTS_AVAILABLE_FB) \ + _(XrEventDataSpaceQueryCompleteFB, XR_TYPE_EVENT_DATA_SPACE_QUERY_COMPLETE_FB) \ + _(XrSpaceSaveInfoFB, XR_TYPE_SPACE_SAVE_INFO_FB) \ + _(XrSpaceEraseInfoFB, XR_TYPE_SPACE_ERASE_INFO_FB) \ + _(XrEventDataSpaceSaveCompleteFB, XR_TYPE_EVENT_DATA_SPACE_SAVE_COMPLETE_FB) \ + _(XrEventDataSpaceEraseCompleteFB, XR_TYPE_EVENT_DATA_SPACE_ERASE_COMPLETE_FB) \ + _(XrCompositionLayerSpaceWarpInfoFB, XR_TYPE_COMPOSITION_LAYER_SPACE_WARP_INFO_FB) \ + _(XrSystemSpaceWarpPropertiesFB, XR_TYPE_SYSTEM_SPACE_WARP_PROPERTIES_FB) \ + _(XrSemanticLabelsFB, XR_TYPE_SEMANTIC_LABELS_FB) \ + _(XrRoomLayoutFB, XR_TYPE_ROOM_LAYOUT_FB) \ + _(XrBoundary2DFB, XR_TYPE_BOUNDARY_2D_FB) \ + _(XrDigitalLensControlALMALENCE, XR_TYPE_DIGITAL_LENS_CONTROL_ALMALENCE) \ + _(XrSpaceContainerFB, XR_TYPE_SPACE_CONTAINER_FB) \ + _(XrPassthroughKeyboardHandsIntensityFB, XR_TYPE_PASSTHROUGH_KEYBOARD_HANDS_INTENSITY_FB) \ + _(XrCompositionLayerSettingsFB, XR_TYPE_COMPOSITION_LAYER_SETTINGS_FB) \ + _(XrPerformanceMetricsStateMETA, XR_TYPE_PERFORMANCE_METRICS_STATE_META) \ + _(XrPerformanceMetricsCounterMETA, XR_TYPE_PERFORMANCE_METRICS_COUNTER_META) \ + + + + +#if defined(XR_USE_GRAPHICS_API_D3D11) +#define XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_D3D11(_) \ + _(XrGraphicsBindingD3D11KHR, XR_TYPE_GRAPHICS_BINDING_D3D11_KHR) \ + _(XrSwapchainImageD3D11KHR, XR_TYPE_SWAPCHAIN_IMAGE_D3D11_KHR) \ + _(XrGraphicsRequirementsD3D11KHR, XR_TYPE_GRAPHICS_REQUIREMENTS_D3D11_KHR) \ + + +#else +#define XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_D3D11(_) +#endif + +#if defined(XR_USE_GRAPHICS_API_D3D12) +#define XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_D3D12(_) \ + _(XrGraphicsBindingD3D12KHR, XR_TYPE_GRAPHICS_BINDING_D3D12_KHR) \ + _(XrSwapchainImageD3D12KHR, XR_TYPE_SWAPCHAIN_IMAGE_D3D12_KHR) \ + _(XrGraphicsRequirementsD3D12KHR, XR_TYPE_GRAPHICS_REQUIREMENTS_D3D12_KHR) \ + + +#else +#define XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_D3D12(_) +#endif + +#if defined(XR_USE_GRAPHICS_API_OPENGL) +#define XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL(_) \ + _(XrSwapchainImageOpenGLKHR, XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_KHR) \ + _(XrGraphicsRequirementsOpenGLKHR, XR_TYPE_GRAPHICS_REQUIREMENTS_OPENGL_KHR) \ + + +#else +#define XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL(_) +#endif + +#if defined(XR_USE_GRAPHICS_API_OPENGL) && defined(XR_USE_PLATFORM_WAYLAND) +#define XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_XR_USE_PLATFORM_WAYLAND(_) \ + _(XrGraphicsBindingOpenGLWaylandKHR, XR_TYPE_GRAPHICS_BINDING_OPENGL_WAYLAND_KHR) \ + + +#else +#define XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_XR_USE_PLATFORM_WAYLAND(_) +#endif + +#if defined(XR_USE_GRAPHICS_API_OPENGL) && defined(XR_USE_PLATFORM_WIN32) +#define XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_XR_USE_PLATFORM_WIN32(_) \ + _(XrGraphicsBindingOpenGLWin32KHR, XR_TYPE_GRAPHICS_BINDING_OPENGL_WIN32_KHR) \ + + +#else +#define XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_XR_USE_PLATFORM_WIN32(_) +#endif + +#if defined(XR_USE_GRAPHICS_API_OPENGL) && defined(XR_USE_PLATFORM_XCB) +#define XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_XR_USE_PLATFORM_XCB(_) \ + _(XrGraphicsBindingOpenGLXcbKHR, XR_TYPE_GRAPHICS_BINDING_OPENGL_XCB_KHR) \ + + +#else +#define XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_XR_USE_PLATFORM_XCB(_) +#endif + +#if defined(XR_USE_GRAPHICS_API_OPENGL) && defined(XR_USE_PLATFORM_XLIB) +#define XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_XR_USE_PLATFORM_XLIB(_) \ + _(XrGraphicsBindingOpenGLXlibKHR, XR_TYPE_GRAPHICS_BINDING_OPENGL_XLIB_KHR) \ + + +#else +#define XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_XR_USE_PLATFORM_XLIB(_) +#endif + +#if defined(XR_USE_GRAPHICS_API_OPENGL_ES) +#define XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_ES(_) \ + _(XrSwapchainImageOpenGLESKHR, XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_ES_KHR) \ + _(XrGraphicsRequirementsOpenGLESKHR, XR_TYPE_GRAPHICS_REQUIREMENTS_OPENGL_ES_KHR) \ + _(XrSwapchainStateSamplerOpenGLESFB, XR_TYPE_SWAPCHAIN_STATE_SAMPLER_OPENGL_ES_FB) \ + + +#else +#define XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_ES(_) +#endif + +#if defined(XR_USE_GRAPHICS_API_OPENGL_ES) && defined(XR_USE_PLATFORM_ANDROID) +#define XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_ES_XR_USE_PLATFORM_ANDROID(_) \ + _(XrGraphicsBindingOpenGLESAndroidKHR, XR_TYPE_GRAPHICS_BINDING_OPENGL_ES_ANDROID_KHR) \ + + +#else +#define XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_ES_XR_USE_PLATFORM_ANDROID(_) +#endif + +#if defined(XR_USE_GRAPHICS_API_VULKAN) +#define XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_VULKAN(_) \ + _(XrVulkanSwapchainFormatListCreateInfoKHR, XR_TYPE_VULKAN_SWAPCHAIN_FORMAT_LIST_CREATE_INFO_KHR) \ + _(XrGraphicsBindingVulkanKHR, XR_TYPE_GRAPHICS_BINDING_VULKAN_KHR) \ + _(XrSwapchainImageVulkanKHR, XR_TYPE_SWAPCHAIN_IMAGE_VULKAN_KHR) \ + _(XrGraphicsRequirementsVulkanKHR, XR_TYPE_GRAPHICS_REQUIREMENTS_VULKAN_KHR) \ + _(XrVulkanInstanceCreateInfoKHR, XR_TYPE_VULKAN_INSTANCE_CREATE_INFO_KHR) \ + _(XrVulkanDeviceCreateInfoKHR, XR_TYPE_VULKAN_DEVICE_CREATE_INFO_KHR) \ + _(XrVulkanGraphicsDeviceGetInfoKHR, XR_TYPE_VULKAN_GRAPHICS_DEVICE_GET_INFO_KHR) \ + _(XrSwapchainImageFoveationVulkanFB, XR_TYPE_SWAPCHAIN_IMAGE_FOVEATION_VULKAN_FB) \ + _(XrSwapchainStateSamplerVulkanFB, XR_TYPE_SWAPCHAIN_STATE_SAMPLER_VULKAN_FB) \ + _(XrVulkanSwapchainCreateInfoMETA, XR_TYPE_VULKAN_SWAPCHAIN_CREATE_INFO_META) \ + + +#else +#define XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_VULKAN(_) +#endif + +#if defined(XR_USE_PLATFORM_ANDROID) +#define XR_LIST_STRUCTURE_TYPES_XR_USE_PLATFORM_ANDROID(_) \ + _(XrInstanceCreateInfoAndroidKHR, XR_TYPE_INSTANCE_CREATE_INFO_ANDROID_KHR) \ + _(XrLoaderInitInfoAndroidKHR, XR_TYPE_LOADER_INIT_INFO_ANDROID_KHR) \ + _(XrAndroidSurfaceSwapchainCreateInfoFB, XR_TYPE_ANDROID_SURFACE_SWAPCHAIN_CREATE_INFO_FB) \ + _(XrSwapchainStateAndroidSurfaceDimensionsFB, XR_TYPE_SWAPCHAIN_STATE_ANDROID_SURFACE_DIMENSIONS_FB) \ + + +#else +#define XR_LIST_STRUCTURE_TYPES_XR_USE_PLATFORM_ANDROID(_) +#endif + +#if defined(XR_USE_PLATFORM_EGL) +#define XR_LIST_STRUCTURE_TYPES_XR_USE_PLATFORM_EGL(_) \ + _(XrGraphicsBindingEGLMNDX, XR_TYPE_GRAPHICS_BINDING_EGL_MNDX) \ + + +#else +#define XR_LIST_STRUCTURE_TYPES_XR_USE_PLATFORM_EGL(_) +#endif + +#if defined(XR_USE_PLATFORM_WIN32) +#define XR_LIST_STRUCTURE_TYPES_XR_USE_PLATFORM_WIN32(_) \ + _(XrHolographicWindowAttachmentMSFT, XR_TYPE_HOLOGRAPHIC_WINDOW_ATTACHMENT_MSFT) \ + + +#else +#define XR_LIST_STRUCTURE_TYPES_XR_USE_PLATFORM_WIN32(_) +#endif + +#define XR_LIST_STRUCTURE_TYPES(_) \ + XR_LIST_STRUCTURE_TYPES_CORE(_) \ + XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_D3D11(_) \ + XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_D3D12(_) \ + XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL(_) \ + XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_XR_USE_PLATFORM_WAYLAND(_) \ + XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_XR_USE_PLATFORM_WIN32(_) \ + XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_XR_USE_PLATFORM_XCB(_) \ + XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_XR_USE_PLATFORM_XLIB(_) \ + XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_ES(_) \ + XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_ES_XR_USE_PLATFORM_ANDROID(_) \ + XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_VULKAN(_) \ + XR_LIST_STRUCTURE_TYPES_XR_USE_PLATFORM_ANDROID(_) \ + XR_LIST_STRUCTURE_TYPES_XR_USE_PLATFORM_EGL(_) \ + XR_LIST_STRUCTURE_TYPES_XR_USE_PLATFORM_WIN32(_) \ + + +#define XR_LIST_EXTENSIONS(_) \ + _(XR_KHR_android_thread_settings, 4) \ + _(XR_KHR_android_surface_swapchain, 5) \ + _(XR_KHR_composition_layer_cube, 7) \ + _(XR_KHR_android_create_instance, 9) \ + _(XR_KHR_composition_layer_depth, 11) \ + _(XR_KHR_vulkan_swapchain_format_list, 15) \ + _(XR_EXT_performance_settings, 16) \ + _(XR_EXT_thermal_query, 17) \ + _(XR_KHR_composition_layer_cylinder, 18) \ + _(XR_KHR_composition_layer_equirect, 19) \ + _(XR_EXT_debug_utils, 20) \ + _(XR_KHR_opengl_enable, 24) \ + _(XR_KHR_opengl_es_enable, 25) \ + _(XR_KHR_vulkan_enable, 26) \ + _(XR_KHR_D3D11_enable, 28) \ + _(XR_KHR_D3D12_enable, 29) \ + _(XR_EXT_eye_gaze_interaction, 31) \ + _(XR_KHR_visibility_mask, 32) \ + _(XR_EXTX_overlay, 34) \ + _(XR_KHR_composition_layer_color_scale_bias, 35) \ + _(XR_KHR_win32_convert_performance_counter_time, 36) \ + _(XR_KHR_convert_timespec_time, 37) \ + _(XR_VARJO_quad_views, 38) \ + _(XR_MSFT_unbounded_reference_space, 39) \ + _(XR_MSFT_spatial_anchor, 40) \ + _(XR_FB_composition_layer_image_layout, 41) \ + _(XR_FB_composition_layer_alpha_blend, 42) \ + _(XR_MND_headless, 43) \ + _(XR_OCULUS_android_session_state_enable, 45) \ + _(XR_EXT_view_configuration_depth_range, 47) \ + _(XR_EXT_conformance_automation, 48) \ + _(XR_MNDX_egl_enable, 49) \ + _(XR_MSFT_spatial_graph_bridge, 50) \ + _(XR_MSFT_hand_interaction, 51) \ + _(XR_EXT_hand_tracking, 52) \ + _(XR_MSFT_hand_tracking_mesh, 53) \ + _(XR_MSFT_secondary_view_configuration, 54) \ + _(XR_MSFT_first_person_observer, 55) \ + _(XR_MSFT_controller_model, 56) \ + _(XR_MSFT_perception_anchor_interop, 57) \ + _(XR_EXT_win32_appcontainer_compatible, 58) \ + _(XR_EPIC_view_configuration_fov, 60) \ + _(XR_MSFT_holographic_window_attachment, 64) \ + _(XR_MSFT_composition_layer_reprojection, 67) \ + _(XR_HUAWEI_controller_interaction, 70) \ + _(XR_FB_android_surface_swapchain_create, 71) \ + _(XR_FB_swapchain_update_state, 72) \ + _(XR_FB_composition_layer_secure_content, 73) \ + _(XR_EXT_dpad_binding, 79) \ + _(XR_VALVE_analog_threshold, 80) \ + _(XR_EXT_hand_joints_motion_range, 81) \ + _(XR_KHR_loader_init, 89) \ + _(XR_KHR_loader_init_android, 90) \ + _(XR_KHR_vulkan_enable2, 91) \ + _(XR_KHR_composition_layer_equirect2, 92) \ + _(XR_EXT_samsung_odyssey_controller, 95) \ + _(XR_EXT_hp_mixed_reality_controller, 96) \ + _(XR_MND_swapchain_usage_input_attachment_bit, 97) \ + _(XR_MSFT_scene_understanding, 98) \ + _(XR_MSFT_scene_understanding_serialization, 99) \ + _(XR_FB_display_refresh_rate, 102) \ + _(XR_HTC_vive_cosmos_controller_interaction, 103) \ + _(XR_HTCX_vive_tracker_interaction, 104) \ + _(XR_HTC_facial_tracking, 105) \ + _(XR_HTC_vive_focus3_controller_interaction, 106) \ + _(XR_HTC_hand_interaction, 107) \ + _(XR_HTC_vive_wrist_tracker_interaction, 108) \ + _(XR_FB_color_space, 109) \ + _(XR_FB_hand_tracking_mesh, 111) \ + _(XR_FB_hand_tracking_aim, 112) \ + _(XR_FB_hand_tracking_capsules, 113) \ + _(XR_FB_spatial_entity, 114) \ + _(XR_FB_foveation, 115) \ + _(XR_FB_foveation_configuration, 116) \ + _(XR_FB_keyboard_tracking, 117) \ + _(XR_FB_triangle_mesh, 118) \ + _(XR_FB_passthrough, 119) \ + _(XR_FB_render_model, 120) \ + _(XR_KHR_binding_modification, 121) \ + _(XR_VARJO_foveated_rendering, 122) \ + _(XR_VARJO_composition_layer_depth_test, 123) \ + _(XR_VARJO_environment_depth_estimation, 124) \ + _(XR_VARJO_marker_tracking, 125) \ + _(XR_VARJO_view_offset, 126) \ + _(XR_ML_ml2_controller_interaction, 135) \ + _(XR_MSFT_spatial_anchor_persistence, 143) \ + _(XR_ULTRALEAP_hand_tracking_forearm, 150) \ + _(XR_FB_spatial_entity_query, 157) \ + _(XR_FB_spatial_entity_storage, 159) \ + _(XR_OCULUS_audio_device_guid, 160) \ + _(XR_FB_foveation_vulkan, 161) \ + _(XR_FB_swapchain_update_state_android_surface, 162) \ + _(XR_FB_swapchain_update_state_opengl_es, 163) \ + _(XR_FB_swapchain_update_state_vulkan, 164) \ + _(XR_KHR_swapchain_usage_input_attachment_bit, 166) \ + _(XR_FB_space_warp, 172) \ + _(XR_FB_scene, 176) \ + _(XR_EXT_palm_pose, 177) \ + _(XR_ALMALENCE_digital_lens_control, 197) \ + _(XR_FB_spatial_entity_container, 200) \ + _(XR_FB_passthrough_keyboard_hands, 204) \ + _(XR_FB_composition_layer_settings, 205) \ + _(XR_META_vulkan_swapchain_create_info, 228) \ + _(XR_META_performance_metrics, 233) \ + _(XR_EXT_uuid, 300) \ + + +#endif + diff --git a/VRTowerDefense.uproject b/VRTowerDefense.uproject index 7f089d5..697494a 100644 --- a/VRTowerDefense.uproject +++ b/VRTowerDefense.uproject @@ -30,6 +30,15 @@ "Linux", "Android" ] + }, + { + "Name": "OculusXR", + "Enabled": true, + "MarketplaceURL": "com.epicgames.launcher://ue/marketplace/product/8313d8d7e7cf4e03a33e79eb757bccba", + "SupportedTargetPlatforms": [ + "Win64", + "Android" + ] } ], "TargetPlatforms": [