Compare commits

..

2 Commits

Author SHA1 Message Date
Henri da5ee932b3 Merge remote-tracking branch 'refs/remotes/origin/main' 2024-05-29 11:58:13 +03:00
Henri 0db31c34d1 Config for building for Quest 2024-05-29 11:53:41 +03:00
353 changed files with 74095 additions and 3 deletions

View File

@ -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

View File

@ -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")

View File

@ -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/...

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
Plugins/MetaXR/Content/Materials/OculusMR_ChromaKey.uasset (Stored with Git LFS) Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
Plugins/MetaXR/Content/Materials/PokeAHoleMaterial.uasset (Stored with Git LFS) Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
Plugins/MetaXR/Content/Materials/touchController_mat.uasset (Stored with Git LFS) Normal file

Binary file not shown.

BIN
Plugins/MetaXR/Content/Meshes/LeftMetaQuestTouchPlus.fbx (Stored with Git LFS) Normal file

Binary file not shown.

BIN
Plugins/MetaXR/Content/Meshes/LeftMetaQuestTouchPlus.uasset (Stored with Git LFS) Normal file

Binary file not shown.

Binary file not shown.

BIN
Plugins/MetaXR/Content/Meshes/LeftMetaQuestTouchPro.uasset (Stored with Git LFS) Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
Plugins/MetaXR/Content/Meshes/LeftTouchForQuest2.uasset (Stored with Git LFS) Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
Plugins/MetaXR/Content/Meshes/RightMetaQuestTouchPlus.fbx (Stored with Git LFS) Normal file

Binary file not shown.

BIN
Plugins/MetaXR/Content/Meshes/RightMetaQuestTouchPlus.uasset (Stored with Git LFS) Normal file

Binary file not shown.

Binary file not shown.

BIN
Plugins/MetaXR/Content/Meshes/RightMetaQuestTouchPro.uasset (Stored with Git LFS) Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
Plugins/MetaXR/Content/Meshes/RightTouchForQuest2.uasset (Stored with Git LFS) Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
Plugins/MetaXR/Content/MetaXRControllers.uasset (Stored with Git LFS) Normal file

Binary file not shown.

BIN
Plugins/MetaXR/Content/OculusMR_GreenKey.uasset (Stored with Git LFS) Normal file

Binary file not shown.

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<TpsData xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Name>Oculus Models</Name>
<Location>/Engine/Plugins/Runtime/Oculus/OculusVR/Content/</Location>
<Function>Provide our licensees with models that match actual physical Oculus devices.</Function>
<Eula>https://developer.oculus.com/licenses/art-1.0/</Eula>
<RedistributeTo>
<EndUserGroup>Licensees</EndUserGroup>
<EndUserGroup>Git</EndUserGroup>
<EndUserGroup>P4</EndUserGroup>
</RedistributeTo>
<LicenseFolder>/Engine/Source/ThirdParty/Licenses/OculusModels_License.txt</LicenseFolder>
</TpsData>

View File

@ -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.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
Plugins/MetaXR/Content/Textures/TouchForQuest2_Color.uasset (Stored with Git LFS) Normal file

Binary file not shown.

Binary file not shown.

View File

@ -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
}
]
}

BIN
Plugins/MetaXR/Resources/ButtonIcon_80x.png (Stored with Git LFS) Normal file

Binary file not shown.

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 8 8" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<circle cx="4" cy="4" r="4" style="fill:rgb(77,230,80);"/>
</svg>

After

Width:  |  Height:  |  Size: 511 B

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 8 8" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<circle cx="4" cy="4" r="4" style="fill:rgb(154,154,154);"/>
</svg>

After

Width:  |  Height:  |  Size: 513 B

BIN
Plugins/MetaXR/Resources/Icon128.png (Stored with Git LFS) Normal file

Binary file not shown.

View File

@ -0,0 +1,3 @@
<svg width="800" height="800" viewBox="0 0 800 800" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M125 487.5C125 372.5 182.5 252.5 250 252.5C287.5 252.5 317.5 275 365 342.5C320 412.5 292.5 455 292.5 455C232.5 550 212.5 570 180 570C147.5 572.5 125 542.5 125 487.5ZM517.5 445L475 375C465 357.5 452.5 340 442.5 325C480 267.5 510 237.5 547.5 237.5C622.5 237.5 682.5 350 682.5 490C682.5 542.5 665 572.5 630 572.5C595 572.5 582.5 550 517.5 445ZM410 275C355 202.5 307.5 175 252.5 175C137.5 175 50 327.5 50 487.5C50 587.5 97.5 650 177.5 650C235 650 275 622.5 350 492.5C350 492.5 380 437.5 402.5 400C410 412.5 417.5 425 425 440L460 500C527.5 615 565 652.5 632.5 652.5C710 652.5 752.5 587.5 752.5 485C750 315 660 175 552.5 175C495 175 450 220 410 275Z" fill="white" style="fill:white;fill:white;fill-opacity:1;"/>
</svg>

After

Width:  |  Height:  |  Size: 822 B

BIN
Plugins/MetaXR/Resources/MetaQuestBackground.png (Stored with Git LFS) Normal file

Binary file not shown.

View File

@ -0,0 +1,3 @@
<svg width="596" height="596" viewBox="0 0 596 596" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M512.5 0.166671H83.5C61.3986 0.166671 40.2025 8.94641 24.5744 24.5744C8.94642 40.2025 0.166679 61.3986 0.166679 83.5V379.167C0.166679 401.268 8.94642 422.464 24.5744 438.092C40.2025 453.72 61.3986 462.5 83.5 462.5H180.5L168.167 562.5H131.333C126.913 562.5 122.674 564.256 119.548 567.382C116.423 570.507 114.667 574.746 114.667 579.167C114.667 583.587 116.423 587.826 119.548 590.952C122.674 594.077 126.913 595.833 131.333 595.833H465C469.42 595.833 473.66 594.077 476.785 590.952C479.911 587.826 481.667 583.587 481.667 579.167C481.667 574.746 479.911 570.507 476.785 567.382C473.66 564.256 469.42 562.5 465 562.5H428L415.667 462.5H512.667C534.768 462.5 555.964 453.72 571.592 438.092C587.22 422.464 596 401.268 596 379.167V83.5C596 72.5425 593.839 61.6925 589.641 51.5712C585.442 41.4498 579.289 32.2558 571.533 24.5154C563.777 16.775 554.571 10.6402 544.441 6.46214C534.312 2.28407 523.457 0.144756 512.5 0.166671ZM201.5 562.5L214.167 462.5H381.833L394.167 562.5H201.5ZM562.5 379.167C562.5 392.428 557.232 405.145 547.855 414.522C538.479 423.899 525.761 429.167 512.5 429.167H83.5C70.2392 429.167 57.5215 423.899 48.1447 414.522C38.7678 405.145 33.5 392.428 33.5 379.167V362.5H562.5V379.167ZM562.5 329.167H33.5V83.5C33.5 70.2392 38.7678 57.5215 48.1447 48.1447C57.5215 38.7678 70.2392 33.5 83.5 33.5H512.5C525.761 33.5 538.479 38.7678 547.855 48.1447C557.232 57.5215 562.5 70.2392 562.5 83.5V329.167Z" fill="white" style="fill:white;fill:white;fill-opacity:1;"/>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -0,0 +1,7 @@
<svg width="800" height="800" viewBox="0 0 800 800" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M247.75 490.247C247.75 503.362 237.117 513.996 224 513.996C210.883 513.996 200.25 503.362 200.25 490.247C200.25 477.131 210.883 466.498 224 466.498C237.117 466.498 247.75 477.131 247.75 490.247Z" fill="white" style="fill:white;fill:white;fill-opacity:1;"/>
<path d="M224 371.498C237.117 371.498 247.75 360.865 247.75 347.748C247.75 334.631 237.117 323.998 224 323.998C210.883 323.998 200.25 334.631 200.25 347.748C200.25 360.865 210.883 371.498 224 371.498Z" fill="white" style="fill:white;fill:white;fill-opacity:1;"/>
<path d="M580.246 490.247C580.246 503.362 569.613 513.996 556.497 513.996C543.379 513.996 532.745 503.362 532.745 490.247C532.745 477.131 543.379 466.498 556.497 466.498C569.613 466.498 580.246 477.131 580.246 490.247Z" fill="white" style="fill:white;fill:white;fill-opacity:1;"/>
<path d="M556.497 371.498C569.613 371.498 580.246 360.865 580.246 347.748C580.246 334.631 569.613 323.998 556.497 323.998C543.379 323.998 532.745 334.631 532.745 347.748C532.745 360.865 543.379 371.498 556.497 371.498Z" fill="white" style="fill:white;fill:white;fill-opacity:1;"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M319 276.5C319 250.266 340.267 229 366.5 229H414C440.231 229 461.498 250.266 461.498 276.5H532.748C585.217 276.5 627.75 319.033 627.75 371.5C640.866 371.5 651.499 382.133 651.499 395.25V442.749C651.499 455.868 640.866 466.501 627.75 466.501C627.75 518.968 585.217 561.501 532.748 561.501H466.52C449.793 558.913 434.856 549.337 425.668 535.218L422.932 528.877C419.335 520.541 412.69 513.891 404.356 510.288C386.299 502.482 365.329 510.796 357.522 528.857L354.307 536.293C345.07 549.822 330.47 558.979 314.171 561.501H247.75C195.283 561.501 152.75 518.968 152.75 466.501C139.633 466.501 129 455.868 129 442.749V395.25C129 382.133 139.633 371.5 152.75 371.5C152.75 319.033 195.283 276.5 247.75 276.5H319ZM603.998 466.501V371.5C603.998 332.15 572.101 300.25 532.748 300.25H247.75C208.4 300.25 176.5 332.15 176.5 371.5V466.501C176.5 505.851 208.4 537.752 247.75 537.752H312.113C320.651 536.039 328.299 531.297 333.528 524.508L335.721 519.432C348.732 489.332 383.68 475.479 413.781 488.489C427.669 494.494 438.744 505.572 444.737 519.466L446.57 523.713C451.8 530.92 459.705 535.974 468.58 537.752H532.748C572.101 537.752 603.998 505.851 603.998 466.501ZM437.749 276.5H342.75C342.75 263.383 353.383 252.75 366.5 252.75H414C427.116 252.75 437.749 263.383 437.749 276.5Z" fill="white" style="fill:white;fill:white;fill-opacity:1;"/>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@ -0,0 +1,10 @@
<svg width="800" height="800" viewBox="0 0 800 800" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_235_1629)">
<path fill-rule="evenodd" clip-rule="evenodd" d="M442.297 539.461C453.323 556.403 471.247 567.895 491.319 571H570.793C633.755 571 684.795 519.96 684.795 457.001V343C684.795 280.04 633.755 229 570.793 229H228.795C165.834 229 114.794 280.04 114.794 343V457.001C114.794 519.96 165.834 571 228.795 571H308.5C328.058 567.973 345.579 556.985 356.663 540.754L360.521 531.827C369.889 510.155 395.052 500.179 416.722 509.546C426.722 513.869 434.698 521.848 439.014 531.851L442.297 539.461ZM627.794 457.001C627.794 488.479 602.274 513.999 570.793 513.999H497.369C495.31 513.277 493.45 512.118 491.945 510.647L491.347 509.266C481.275 485.927 462.673 467.312 439.339 457.227C388.772 435.366 330.058 458.643 308.199 509.211L307.377 511.112C305.966 512.364 304.286 513.356 302.452 513.999H228.795C197.314 513.999 171.794 488.479 171.794 457.001V343C171.794 311.52 197.314 286 228.795 286H570.793C602.274 286 627.794 311.52 627.794 343V457.001Z" fill="white" style="fill:white;fill:white;fill-opacity:1;"/>
</g>
<defs>
<clipPath id="clip0_235_1629">
<rect width="615.6" height="342" fill="white" style="fill:white;fill:white;fill-opacity:1;" transform="translate(92 229)"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 8 8" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<circle cx="4" cy="4" r="4" style="fill:rgb(230,77,77);"/>
</svg>

After

Width:  |  Height:  |  Size: 511 B

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 8 8" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<circle cx="4" cy="4" r="4" style="fill:rgb(243,243,243);"/>
</svg>

After

Width:  |  Height:  |  Size: 513 B

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 8 8" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<circle cx="4" cy="4" r="4" style="fill:rgb(230,187,77);"/>
</svg>

After

Width:  |  Height:  |  Size: 512 B

View File

@ -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);
}

View File

@ -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 );
}

View File

@ -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",
});
}
}
}

View File

@ -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<UOculusXRSpatialAnchorComponent>();
if (SpatialAnchorComponent == nullptr)
{
SpatialAnchorComponent = Cast<UOculusXRSpatialAnchorComponent>(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<UOculusXRAnchorComponent>(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<UOculusXRLocatableAnchorComponent>(QueryResult.Space.Value, Outer);
case EOculusXRSpaceComponentType::ScenePlane:
return UOculusXRBaseAnchorComponent::FromSpace<UOculusXRPlaneAnchorComponent>(QueryResult.Space.Value, Outer);
case EOculusXRSpaceComponentType::SceneVolume:
return UOculusXRBaseAnchorComponent::FromSpace<UOculusXRVolumeAnchorComponent>(QueryResult.Space.Value, Outer);
case EOculusXRSpaceComponentType::SemanticClassification:
return UOculusXRBaseAnchorComponent::FromSpace<UOculusXRSemanticClassificationAnchorComponent>(QueryResult.Space.Value, Outer);
case EOculusXRSpaceComponentType::RoomLayout:
return UOculusXRBaseAnchorComponent::FromSpace<UOculusXRRoomLayoutAnchorComponent>(QueryResult.Space.Value, Outer);
case EOculusXRSpaceComponentType::SpaceContainer:
return UOculusXRBaseAnchorComponent::FromSpace<UOculusXRSpaceContainerAnchorComponent>(QueryResult.Space.Value, Outer);
case EOculusXRSpaceComponentType::Sharable:
return UOculusXRBaseAnchorComponent::FromSpace<UOculusXRSharableAnchorComponent>(QueryResult.Space.Value, Outer);
case EOculusXRSpaceComponentType::Storable:
return UOculusXRBaseAnchorComponent::FromSpace<UOculusXRStorableAnchorComponent>(QueryResult.Space.Value, Outer);
case EOculusXRSpaceComponentType::TriangleMesh:
return UOculusXRBaseAnchorComponent::FromSpace<UOculusXRTriangleMeshAnchorComponent>(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<FOculusXRUUID> OutWallsUuid;
const bool bSuccess = OculusXRAnchors::FOculusXRRoomLayoutManager::GetSpaceRoomLayout(Space.Value, static_cast<uint32>(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<FOculusXRUUID> spaceUUIDs;
EOculusXRAnchorResult::Type result = OculusXRAnchors::FOculusXRAnchorManager::GetSpaceContainerUUIDs(Space, spaceUUIDs);
if (UOculusXRAnchorBPFunctionLibrary::IsAnchorResultSuccess(result))
{
RoomLayoutOut.RoomObjectUUIDs = spaceUUIDs;
}
}
return bSuccess;
}

View File

@ -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<int32> 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<int32>(EOculusXRSpaceStorageLocation::Local),
StorageLocations & static_cast<int32>(EOculusXRSpaceStorageLocation::Cloud));
return (StorageLocations & static_cast<int32>(Location)) > 0;
}
void UOculusXRAnchorComponent::SetStoredLocation(EOculusXRSpaceStorageLocation Location, bool Stored)
{
if (Stored)
{
StorageLocations |= static_cast<int32>(Location);
}
else
{
StorageLocations = StorageLocations & ~static_cast<int32>(Location);
}
UE_LOG(LogOculusXRAnchors, Verbose, TEXT("Anchor UUID: %s - Saved Local: %d - Saved Cloud: %d"),
*GetUUID().ToString(),
StorageLocations & static_cast<int32>(EOculusXRSpaceStorageLocation::Local),
StorageLocations & static_cast<int32>(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;
}

View File

@ -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<FString>& 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<FOculusXRUUID>& 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<FOculusXRUUID>& outUUIDs) const
{
ensure(IsComponentEnabled());
if (!OculusXRAnchors::FOculusXRAnchorManager::GetSpaceContainer(Space, outUUIDs))
{
UE_LOG(LogOculusSpatialAnchor, Warning, TEXT("Fetching container uuids failed."));
return false;
}
return true;
}

View File

@ -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;

View File

@ -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<UOculusXRAsyncAction_CreateSpatialAnchor>();
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<UOculusXRAnchorComponent>();
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<UOculusXRAsyncAction_EraseAnchor>();
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<UOculusXRAnchorComponent>();
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<UOculusXRAsyncAction_SaveAnchor>();
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<AActor*>& TargetActors, EOculusXRSpaceStorageLocation StorageLocation)
{
UOculusXRAsyncAction_SaveAnchorList* Action = NewObject<UOculusXRAsyncAction_SaveAnchorList>();
auto ValidActorPtr = TargetActors.FindByPredicate([](AActor* Actor) { return IsValid(Actor); });
for (auto& it : TargetActors)
{
if (!IsValid(it))
{
continue;
}
UOculusXRAnchorComponent* AnchorComponent = it->FindComponentByClass<UOculusXRAnchorComponent>();
Action->TargetAnchors.Add(AnchorComponent);
}
Action->StorageLocation = StorageLocation;
if (ValidActorPtr != nullptr)
{
Action->RegisterWithGameInstance(*ValidActorPtr);
}
return Action;
}
void UOculusXRAsyncAction_SaveAnchorList::HandleSaveAnchorListComplete(EOculusXRAnchorResult::Type SaveResult, const TArray<UOculusXRAnchorComponent*>& 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<FOculusXRUUID>& UUIDs)
{
FOculusXRSpaceQueryInfo QueryInfo;
QueryInfo.FilterType = EOculusXRSpaceQueryFilterType::FilterByIds;
QueryInfo.IDFilter = UUIDs;
QueryInfo.Location = Location;
QueryInfo.MaxQuerySpaces = UUIDs.Num();
UOculusXRAsyncAction_QueryAnchors* Action = NewObject<UOculusXRAsyncAction_QueryAnchors>();
Action->QueryInfo = QueryInfo;
return Action;
}
UOculusXRAsyncAction_QueryAnchors* UOculusXRAsyncAction_QueryAnchors::OculusXRAsyncQueryAnchorsAdvanced(const FOculusXRSpaceQueryInfo& QueryInfo)
{
UOculusXRAsyncAction_QueryAnchors* Action = NewObject<UOculusXRAsyncAction_QueryAnchors>();
Action->QueryInfo = QueryInfo;
return Action;
}
void UOculusXRAsyncAction_QueryAnchors::HandleQueryAnchorsResults(EOculusXRAnchorResult::Type QueryResult, const TArray<FOculusXRSpaceQueryResult>& 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<UOculusXRAnchorComponent>();
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<UOculusXRAsyncAction_SetAnchorComponentStatus>();
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<UOculusXRAsyncAction_SetComponentStatus>();
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<AActor*>& TargetActors, const TArray<FString>& ToShareWithIds)
{
UOculusXRAsyncAction_ShareAnchors* Action = NewObject<UOculusXRAsyncAction_ShareAnchors>();
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<UOculusXRAnchorComponent>();
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<UOculusXRAnchorComponent*>& SharedAnchors, const TArray<uint64>& OculusUserIDs)
{
TArray<FString> 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<UOculusXRAnchorLaunchCaptureFlow>();
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();
}

View File

@ -0,0 +1,816 @@
// Copyright (c) Meta Platforms, Inc. and affiliates.
#include "OculusXRAnchorManager.h"
#include <vector>
#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<double>(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 <typename T>
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<ovrpSpaceQueryResult> 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<EOculusXRAnchorResult::Type>(Result);
}
EOculusXRAnchorResult::Type FOculusXRAnchorManager::DestroySpace(uint64 Space)
{
const ovrpResult Result = FOculusXRHMDModule::GetPluginWrapper().DestroySpace(static_cast<ovrpSpace*>(&Space));
UE_LOG(LogOculusXRAnchors, Verbose, TEXT("DestroySpace Space ID: %llu"), Space);
return static_cast<EOculusXRAnchorResult::Type>(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<bool>(isEnabled) == Enable && !changePending) || (static_cast<bool>(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<EOculusXRAnchorResult::Type>(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<EOculusXRAnchorResult::Type>(Result);
}
EOculusXRAnchorResult::Type FOculusXRAnchorManager::GetSupportedAnchorComponents(uint64 Handle, TArray<EOculusXRSpaceComponentType>& OutSupportedTypes)
{
if (!FOculusXRHMDModule::GetPluginWrapper().GetInitialized())
{
return EOculusXRAnchorResult::Failure;
}
ovrpSpace ovrSpace = Handle;
TArray<ovrpSpaceComponentType> ovrComponentTypes;
ovrpUInt32 input = 0;
ovrpUInt32 output = 0;
ovrpResult enumerateResult = FOculusXRHMDModule::GetPluginWrapper().EnumerateSpaceSupportedComponents(&ovrSpace, input, &output, nullptr);
if (!OVRP_SUCCESS(enumerateResult))
{
return static_cast<EOculusXRAnchorResult::Type>(enumerateResult);
}
input = output;
ovrComponentTypes.SetNumZeroed(output);
enumerateResult = FOculusXRHMDModule::GetPluginWrapper().EnumerateSpaceSupportedComponents(&ovrSpace, input, &output, ovrComponentTypes.GetData());
if (!OVRP_SUCCESS(enumerateResult))
{
return static_cast<EOculusXRAnchorResult::Type>(enumerateResult);
}
OutSupportedTypes.SetNumZeroed(ovrComponentTypes.Num());
for (int i = 0; i < ovrComponentTypes.Num(); ++i)
{
OutSupportedTypes[i] = ConvertToUEComponentType(ovrComponentTypes[i]);
}
return static_cast<EOculusXRAnchorResult::Type>(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<EOculusXRAnchorResult::Type>(Result);
}
EOculusXRAnchorResult::Type FOculusXRAnchorManager::SaveAnchorList(const TArray<uint64>& 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<EOculusXRAnchorResult::Type>(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<EOculusXRAnchorResult::Type>(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<EOculusXRAnchorResult::Type>(QuerySpacesResult);
}
EOculusXRAnchorResult::Type FOculusXRAnchorManager::ShareSpaces(const TArray<uint64>& Spaces, const TArray<uint64>& UserIds, uint64& OutRequestId)
{
TArray<const char*> stringStorage;
TArray<ovrpUser> 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<EOculusXRAnchorResult::Type>(ShareSpacesResult);
}
EOculusXRAnchorResult::Type FOculusXRAnchorManager::GetSpaceContainerUUIDs(uint64 Space, TArray<FOculusXRUUID>& OutUUIDs)
{
TArray<ovrpUuid> 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<EOculusXRAnchorResult::Type>(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<EOculusXRAnchorResult::Type>(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<EOculusXRAnchorResult::Type>(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<EOculusXRAnchorResult::Type>(Result);
}
EOculusXRAnchorResult::Type FOculusXRAnchorManager::GetSpaceSemanticClassification(uint64 Space, TArray<FString>& 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<EOculusXRAnchorResult::Type>(Result);
}
EOculusXRAnchorResult::Type FOculusXRAnchorManager::GetSpaceContainer(uint64 Space, TArray<FOculusXRUUID>& OutContainerUuids)
{
OutContainerUuids.Empty();
ovrpSpaceContainer container;
ovrpResult Result = FOculusXRHMDModule::GetPluginWrapper().GetSpaceContainer(&Space, &container);
if (OVRP_SUCCESS(Result))
{
TArray<ovrpUuid> 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<EOculusXRAnchorResult::Type>(Result);
}
EOculusXRAnchorResult::Type FOculusXRAnchorManager::GetSpaceBoundary2D(uint64 Space, TArray<FVector2f>& OutVertices)
{
TArray<ovrpVector2f> 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<EOculusXRAnchorResult::Type>(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<EOculusXRAnchorResult::Type>(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

View File

@ -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<EOculusXRSpaceComponentType>& OutSupportedTypes);
static EOculusXRAnchorResult::Type SaveAnchor(uint64 Space, EOculusXRSpaceStorageLocation StorageLocation, EOculusXRSpaceStoragePersistenceMode StoragePersistenceMode, uint64& OutRequestId);
static EOculusXRAnchorResult::Type SaveAnchorList(const TArray<uint64>& 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<uint64>& Spaces, const TArray<uint64>& UserIds, uint64& OutRequestId);
static EOculusXRAnchorResult::Type GetSpaceContainerUUIDs(uint64 Space, TArray<FOculusXRUUID>& 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<FString>& OutSemanticClassification);
static EOculusXRAnchorResult::Type GetSpaceContainer(uint64 Space, TArray<FOculusXRUUID>& OutContainerUuids);
static EOculusXRAnchorResult::Type GetSpaceBoundary2D(uint64 Space, TArray<FVector2f>& OutVertices);
static void OnPollEvent(ovrpEventDataBuffer* EventDataBuffer, bool& EventPollResult);
};
} // namespace OculusXRAnchors

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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);

View File

@ -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<UOculusXRAnchorComponent>(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<int>(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<int>(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<int>(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<EOculusXRSpaceComponentType>& 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<EOculusXRSpaceComponentType>& 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<int>(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<UOculusXRAnchorComponent*>& Anchors, TArray<uint64>& Handles, TArray<TWeakObjectPtr<UOculusXRAnchorComponent>>& 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<UOculusXRAnchorComponent*>& Anchors, EOculusXRSpaceStorageLocation StorageLocation, const FOculusXRAnchorSaveListDelegate& ResultCallback, EOculusXRAnchorResult::Type& OutResult)
{
TArray<uint64> Handles;
TArray<TWeakObjectPtr<UOculusXRAnchorComponent>> 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<UOculusXRAnchorComponent*>());
}
return bAsyncStartSuccess;
}
bool FOculusXRAnchors::QueryAnchors(const TArray<FOculusXRUUID>& 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<int>(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<FOculusXRSpaceQueryResult>());
Trace.SetResult(OculusXRTelemetry::EAction::Cancel).End();
}
return bAsyncStartSuccess;
}
bool FOculusXRAnchors::ShareAnchors(const TArray<UOculusXRAnchorComponent*>& Anchors, const TArray<uint64>& OculusUserIDs, const FOculusXRAnchorShareDelegate& ResultCallback, EOculusXRAnchorResult::Type& OutResult)
{
TArray<uint64> Handles;
TArray<TWeakObjectPtr<UOculusXRAnchorComponent>> 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<UOculusXRAnchorComponent*>(), TArray<uint64>());
}
return bAsyncStartSuccess;
}
bool FOculusXRAnchors::GetSpaceContainerUUIDs(uint64 Space, TArray<FOculusXRUUID>& 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<FString>& OutSemanticClassifications, EOculusXRAnchorResult::Type& OutResult)
{
OutResult = FOculusXRAnchorManager::GetSpaceSemanticClassification(Space, OutSemanticClassifications);
return UOculusXRAnchorBPFunctionLibrary::IsAnchorResultSuccess(OutResult);
}
bool FOculusXRAnchors::GetSpaceBoundary2D(uint64 Space, TArray<FVector2f>& 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<int>(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<EOculusXRAnchorResult::Type>(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<EOculusXRAnchorResult::Type>(Result), nullptr);
CreateSpatialAnchorBindings.Remove(RequestId.GetValue());
return;
}
AActor* TargetActor = AnchorDataPtr->Actor.Get();
UOculusXRSpatialAnchorComponent* SpatialAnchorComponent = TargetActor->FindComponentByClass<UOculusXRSpatialAnchorComponent>();
if (SpatialAnchorComponent == nullptr)
{
SpatialAnchorComponent = Cast<UOculusXRSpatialAnchorComponent>(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<EOculusXRAnchorResult::Type>(Result), SpatialAnchorComponent);
CreateSpatialAnchorBindings.Remove(RequestId.GetValue());
}
void FOculusXRAnchors::HandleAnchorEraseComplete(FOculusXRUInt64 RequestId, int Result, FOculusXRUUID UUID, EOculusXRSpaceStorageLocation Location)
{
OculusXRTelemetry::Events::FAnchorsEraseResponse(static_cast<int>(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<EOculusXRAnchorResult::Type>(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<EOculusXRAnchorResult::Type>(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<int>(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<EOculusXRAnchorResult::Type>(Result), SetStatusBinding->AnchorHandle, ComponentType, Enabled);
SetComponentStatusBindings.Remove(RequestId.GetValue());
return;
}
SetStatusBinding->Binding.ExecuteIfBound(static_cast<EOculusXRAnchorResult::Type>(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<int>(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<EOculusXRAnchorResult::Type>(Result), SaveAnchorData->Anchor.Get());
AnchorSaveBindings.Remove(RequestId.GetValue());
return;
}
if (SaveAnchorData->Anchor.IsValid())
{
SaveAnchorData->Anchor->SetStoredLocation(SaveAnchorData->Location, true);
}
SaveAnchorData->Binding.ExecuteIfBound(static_cast<EOculusXRAnchorResult::Type>(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<UOculusXRAnchorComponent*> 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<EOculusXRAnchorResult::Type>(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<EOculusXRAnchorResult::Type>(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<EOculusXRSpaceComponentType> 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<int>(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<EOculusXRAnchorResult::Type>(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<UOculusXRAnchorComponent*> SharedAnchors;
for (auto& WeakAnchor : ShareAnchorsData->SharedAnchors)
{
SharedAnchors.Add(WeakAnchor.Get());
}
ShareAnchorsData->Binding.ExecuteIfBound(static_cast<EOculusXRAnchorResult::Type>(Result), SharedAnchors, ShareAnchorsData->OculusUserIds);
ShareAnchorsBindings.Remove(RequestId.GetValue());
}
} // namespace OculusXRAnchors

View File

@ -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<FOculusXRAnchorsModule>(TEXT("OculusXRAnchors"));
return &Module.Anchors;
}
#endif // OCULUS_ANCHORS_SUPPORTED_PLATFORMS
IMPLEMENT_MODULE(FOculusXRAnchorsModule, OculusXRAnchors)
#undef LOCTEXT_NAMESPACE

View File

@ -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

View File

@ -0,0 +1,5 @@
// Copyright (c) Meta Platforms, Inc. and affiliates.
#pragma once
#include "OculusXRAnchorsModule.h"

View File

@ -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<FOculusXRUUID>& 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<ovrpUuid> 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<FVector>& Vertices, TArray<int32>& 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<ovrpVector3f> OVRPVertices;
OVRPVertices.SetNum(OVRPMesh.vertexCapacityInput);
OVRPMesh.vertices = OVRPVertices.GetData();
Triangles.SetNum(OVRPMesh.indexCapacityInput);
check(sizeof(TRemoveReference<decltype(Triangles)>::Type::ElementType) == sizeof(TRemovePointer<decltype(OVRPMesh.indices)>::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

View File

@ -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<FOculusXRUUID>& OutWallsUuid);
static bool GetSpaceTriangleMesh(uint64 Space, TArray<FVector>& Vertices, TArray<int32>& Triangles);
static void OnPollEvent(ovrpEventDataBuffer* EventDataBuffer, bool& EventPollResult);
};
} // namespace OculusXRAnchors

View File

@ -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<FVector> Vertices;
TArray<int32> Triangles;
bool Success = OculusXRAnchors::FOculusXRRoomLayoutManager::GetSpaceTriangleMesh(Space, Vertices, Triangles);
if (!Success)
{
return false;
}
// Mesh->bUseAsyncCooking = true;
TArray<FVector> EmptyNormals;
TArray<FVector2D> EmptyUV;
TArray<FColor> EmptyVertexColors;
TArray<FProcMeshTangent> EmptyTangents;
Mesh->CreateMeshSection(0, Vertices, Triangles, EmptyNormals, EmptyUV, EmptyVertexColors, EmptyTangents, CreateCollision);
return true;
}

View File

@ -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);
}

View File

@ -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

View File

@ -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

View File

@ -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<FAnchorsCreate, EScopeMode::Start>;
using FAnchorsCreateResponse = TScopedMarker<FAnchorsCreate, EScopeMode::End>;
using FAnchorsSetComponentStatus = TMarker<191962330>;
using FAnchorsSetComponentStatusRequest = TScopedMarker<FAnchorsSetComponentStatus, EScopeMode::Start>;
using FAnchorsSetComponentStatusResponse = TScopedMarker<FAnchorsSetComponentStatus, EScopeMode::End>;
using FAnchorsSave = TMarker<191961984>;
using FAnchorsSaveRequest = TScopedMarker<FAnchorsSave, EScopeMode::Start>;
using FAnchorsSaveResponse = TScopedMarker<FAnchorsSave, EScopeMode::End>;
using FAnchorsQuery = TMarker<191959258>;
using FAnchorsQueryRequest = TScopedMarker<FAnchorsQuery, EScopeMode::Start>;
using FAnchorsQueryResponse = TScopedMarker<FAnchorsQuery, EScopeMode::End>;
using FAnchorsErase = TMarker<191960591>;
using FAnchorsEraseRequest = TScopedMarker<FAnchorsErase, EScopeMode::Start>;
using FAnchorsEraseResponse = TScopedMarker<FAnchorsErase, EScopeMode::End>;
} // namespace OculusXRTelemetry::Events

View File

@ -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<IOculusXRAnchorsModule>("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");
}
};

View File

@ -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);
};

View File

@ -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;
};

View File

@ -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 <typename T>
static T* FromSpace(uint64 space, UObject* Outer)
{
T* Component = NewObject<T>(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<FString>& 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<FOculusXRUUID>& 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<FOculusXRUUID>& 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;
}
};

View File

@ -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;
};

View File

@ -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<UOculusXRAnchorComponent*>&, 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<FOculusXRSpaceQueryResult>&, 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<UOculusXRAnchorComponent*>&, SharedAnchors, const TArray<FString>&, 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<AActor*>& TargetActors, EOculusXRSpaceStorageLocation StorageLocation);
UPROPERTY(BlueprintAssignable)
FOculusXR_LatentAction_SaveAnchorList_Success Success;
UPROPERTY(BlueprintAssignable)
FOculusXR_LatentAction_SaveAnchorList_Failure Failure;
UPROPERTY(Transient)
TArray<UOculusXRAnchorComponent*> TargetAnchors;
EOculusXRSpaceStorageLocation StorageLocation;
private:
void HandleSaveAnchorListComplete(EOculusXRAnchorResult::Type SaveResult, const TArray<UOculusXRAnchorComponent*>& 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<FOculusXRUUID>& 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<FOculusXRSpaceQueryResult> QueryResults;
private:
void HandleQueryAnchorsResults(EOculusXRAnchorResult::Type QueryResult, const TArray<FOculusXRSpaceQueryResult>& 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<AActor*>& TargetActors, const TArray<FString>& ToShareWithIds);
UPROPERTY(BlueprintAssignable)
FOculusXR_LatentAction_ShareAnchors_Success Success;
UPROPERTY(BlueprintAssignable)
FOculusXR_LatentAction_ShareAnchors_Failure Failure;
// Target Spaces
UPROPERTY(Transient)
TArray<UOculusXRAnchorComponent*> TargetAnchors;
// Users to share with
TArray<uint64> ToShareWithIds;
FOculusXRUInt64 ShareSpacesRequestId;
private:
void HandleShareAnchorsComplete(EOculusXRAnchorResult::Type ShareResult, const TArray<UOculusXRAnchorComponent*>& TargetAnchors, const TArray<uint64>& 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);
};

View File

@ -0,0 +1,293 @@
// Copyright (c) Meta Platforms, Inc. and affiliates.
#pragma once
#include <memory>
#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<uint32>(EOculusLocationFlags::OrientationValid);
}
bool PositionValid() const
{
return Flags & static_cast<uint32>(EOculusLocationFlags::PositionValid);
}
bool OrientationTracked() const
{
return Flags & static_cast<uint32>(EOculusLocationFlags::OrientationTracked);
}
bool PositionTracked() const
{
return Flags & static_cast<uint32>(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<FOculusXRUUID> : public TStructOpsTypeTraitsBase2<FOculusXRUUID>
{
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<FOculusXRUInt64> : public TStructOpsTypeTraitsBase2<FOculusXRUInt64>
{
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<FOculusXRUUID> IDFilter;
UPROPERTY(BlueprintReadWrite, Category = "OculusXR|SpatialAnchor")
TArray<EOculusXRSpaceComponentType> 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<FOculusXRUUID> Uuids; // used if filtering by UUIDs
TArray<EOculusXRSpaceComponentType> 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<FOculusXRUUID> WallsUuid;
UPROPERTY(BlueprintReadOnly, Category = "OculusXR|Anchors")
TArray<FOculusXRUUID> RoomObjectUUIDs;
};

View File

@ -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<UOculusXRAnchorComponent*>& /*SavedAnchors*/);
DECLARE_DELEGATE_TwoParams(FOculusXRAnchorQueryDelegate, EOculusXRAnchorResult::Type /*Result*/, const TArray<FOculusXRSpaceQueryResult>& /*Results*/);
DECLARE_DELEGATE_ThreeParams(FOculusXRAnchorShareDelegate, EOculusXRAnchorResult::Type /*Result*/, const TArray<UOculusXRAnchorComponent*>& /*Anchors*/, const TArray<uint64>& /*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<EOculusXRSpaceComponentType>& 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<EOculusXRSpaceComponentType>& OutSupportedComponents, EOculusXRAnchorResult::Type& OutResult);
static bool SaveAnchor(UOculusXRAnchorComponent* Anchor, EOculusXRSpaceStorageLocation StorageLocation, const FOculusXRAnchorSaveDelegate& ResultCallback, EOculusXRAnchorResult::Type& OutResult);
static bool SaveAnchorList(const TArray<UOculusXRAnchorComponent*>& Anchors, EOculusXRSpaceStorageLocation StorageLocation, const FOculusXRAnchorSaveListDelegate& ResultCallback, EOculusXRAnchorResult::Type& OutResult);
static bool QueryAnchors(const TArray<FOculusXRUUID>& 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<UOculusXRAnchorComponent*>& Anchors, const TArray<uint64>& OculusUserIDs, const FOculusXRAnchorShareDelegate& ResultCallback, EOculusXRAnchorResult::Type& OutResult);
static bool GetSpaceContainerUUIDs(uint64 Space, TArray<FOculusXRUUID>& 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<FString>& OutSemanticClassifications, EOculusXRAnchorResult::Type& OutResult);
static bool GetSpaceBoundary2D(uint64 Space, TArray<FVector2f>& 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<UOculusXRAnchorComponent> Anchor;
};
struct SetComponentStatusBinding
{
FOculusXRUInt64 RequestId;
FOculusXRAnchorSetComponentStatusDelegate Binding;
uint64 AnchorHandle;
};
struct CreateAnchorBinding
{
FOculusXRUInt64 RequestId;
FOculusXRSpatialAnchorCreateDelegate Binding;
TWeakObjectPtr<AActor> Actor;
};
struct SaveAnchorBinding
{
FOculusXRUInt64 RequestId;
FOculusXRAnchorSaveDelegate Binding;
EOculusXRSpaceStorageLocation Location;
TWeakObjectPtr<UOculusXRAnchorComponent> Anchor;
};
struct SaveAnchorListBinding
{
FOculusXRUInt64 RequestId;
FOculusXRAnchorSaveListDelegate Binding;
EOculusXRSpaceStorageLocation Location;
TArray<TWeakObjectPtr<UOculusXRAnchorComponent>> SavedAnchors;
};
struct AnchorQueryBinding
{
FOculusXRUInt64 RequestId;
FOculusXRAnchorQueryDelegate Binding;
EOculusXRSpaceStorageLocation Location;
TArray<FOculusXRSpaceQueryResult> Results;
};
struct ShareAnchorsBinding
{
FOculusXRUInt64 RequestId;
FOculusXRAnchorShareDelegate Binding;
TArray<TWeakObjectPtr<UOculusXRAnchorComponent>> SharedAnchors;
TArray<uint64> OculusUserIds;
};
// Delegate bindings
TMap<uint64, CreateAnchorBinding> CreateSpatialAnchorBindings;
TMap<uint64, EraseAnchorBinding> EraseAnchorBindings;
TMap<uint64, SetComponentStatusBinding> SetComponentStatusBindings;
TMap<uint64, SaveAnchorBinding> AnchorSaveBindings;
TMap<uint64, SaveAnchorListBinding> AnchorSaveListBindings;
TMap<uint64, AnchorQueryBinding> AnchorQueryBindings;
TMap<uint64, ShareAnchorsBinding> ShareAnchorsBindings;
// Delegate handles
FDelegateHandle DelegateHandleAnchorCreate;
FDelegateHandle DelegateHandleAnchorErase;
FDelegateHandle DelegateHandleSetComponentStatus;
FDelegateHandle DelegateHandleAnchorSave;
FDelegateHandle DelegateHandleAnchorSaveList;
FDelegateHandle DelegateHandleQueryResultsBegin;
FDelegateHandle DelegateHandleQueryResultElement;
FDelegateHandle DelegateHandleQueryComplete;
FDelegateHandle DelegateHandleAnchorShare;
};
} // namespace OculusXRAnchors

View File

@ -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<uint64> EntityRequestList;
UPROPERTY(Transient)
TMap<FOculusXRUInt64, FOculusXRRoomLayout> 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);
}
}
};

View File

@ -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:
};

Some files were not shown because too many files have changed in this diff Show More