461 lines
16 KiB
C++
461 lines
16 KiB
C++
// Copyright HTC Corporation. All Rights Reserved.
|
|
|
|
#include "ViveOpenXRAnchorModule.h"
|
|
#include "OpenXRCore.h"
|
|
#include "Misc/ConfigCacheIni.h"
|
|
#include "Modules/ModuleManager.h"
|
|
#include "Misc/DateTime.h"
|
|
#include "HAL/PlatformTime.h"
|
|
#include <string>
|
|
|
|
DEFINE_LOG_CATEGORY(ViveOXRAnchor);
|
|
|
|
FOpenXRHMD* FViveOpenXRAnchor::hmd = nullptr;
|
|
FViveOpenXRAnchor* FViveOpenXRAnchor::instance = nullptr;
|
|
|
|
FOpenXRHMD* FViveOpenXRAnchor::HMD() {
|
|
if (hmd != nullptr)
|
|
return hmd;
|
|
if (GEngine->XRSystem.IsValid())
|
|
{
|
|
hmd = static_cast<FOpenXRHMD*>(GEngine->XRSystem->GetHMDDevice());
|
|
}
|
|
return hmd;
|
|
}
|
|
|
|
FViveOpenXRAnchor* FViveOpenXRAnchor::Instance()
|
|
{
|
|
if (instance != nullptr)
|
|
{
|
|
return instance;
|
|
}
|
|
else
|
|
{
|
|
if (GEngine->XRSystem.IsValid() && HMD() != nullptr)
|
|
{
|
|
for (IOpenXRExtensionPlugin* Module : HMD()->GetExtensionPlugins())
|
|
{
|
|
if (Module->GetDisplayName() == TEXT("ViveOpenXRAnchor"))
|
|
{
|
|
instance = static_cast<FViveOpenXRAnchor*>(Module);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return instance;
|
|
}
|
|
}
|
|
|
|
|
|
void FViveOpenXRAnchor::StartupModule()
|
|
{
|
|
check(GConfig && GConfig->IsReadyForUse());
|
|
FString modeName;
|
|
if (GConfig->GetString(TEXT("/Script/ViveOpenXRRuntimeSettings.ViveOpenXRRuntimeSettings"), TEXT("bEnableAnchor"), modeName, GEngineIni))
|
|
{
|
|
if (modeName.Equals("False"))
|
|
{
|
|
m_bEnableAnchor = false;
|
|
}
|
|
else if (modeName.Equals("True"))
|
|
{
|
|
m_bEnableAnchor = true;
|
|
}
|
|
}
|
|
else
|
|
m_bEnableAnchor = false;
|
|
|
|
|
|
if (m_bEnableAnchor)
|
|
{
|
|
UE_LOG(ViveOXRAnchor, Log, TEXT("Enable Anchor."));
|
|
instance = this;
|
|
}
|
|
else
|
|
{
|
|
UE_LOG(ViveOXRAnchor, Log, TEXT("Disable Anchor."));
|
|
instance = nullptr;
|
|
|
|
return;
|
|
}
|
|
|
|
RegisterOpenXRExtensionModularFeature();
|
|
UE_LOG(ViveOXRAnchor, Log, TEXT("StartupModule() Finished."));
|
|
}
|
|
|
|
void FViveOpenXRAnchor::ShutdownModule()
|
|
{
|
|
instance = nullptr;
|
|
if (m_bEnableAnchor)
|
|
UnregisterOpenXRExtensionModularFeature();
|
|
}
|
|
|
|
FString FViveOpenXRAnchor::GetDisplayName()
|
|
{
|
|
return FString(TEXT("ViveOpenXRAnchor"));
|
|
}
|
|
|
|
bool FViveOpenXRAnchor::GetRequiredExtensions(TArray<const ANSICHAR*>& OutExtensions)
|
|
{
|
|
UE_LOG(ViveOXRAnchor, Log, TEXT("GetRequiredExtensions() Add Anchor Extension Name %s."), ANSI_TO_TCHAR(XR_HTC_ANCHOR_EXTENSION_NAME));
|
|
OutExtensions.Add(XR_HTC_ANCHOR_EXTENSION_NAME);
|
|
return true;
|
|
}
|
|
|
|
bool FViveOpenXRAnchor::GetOptionalExtensions(TArray<const ANSICHAR*>& OutExtensions) {
|
|
UE_LOG(ViveOXRAnchor, Log, TEXT("GetOptionalExtensions() Add Anchor Persistence Extension Name %s."), ANSI_TO_TCHAR(XR_HTC_ANCHOR_PERSISTENCE_EXTENSION_NAME));
|
|
OutExtensions.Add(XR_HTC_ANCHOR_PERSISTENCE_EXTENSION_NAME);
|
|
return true;
|
|
}
|
|
|
|
const void* FViveOpenXRAnchor::OnCreateSession(XrInstance InInstance, XrSystemId InSystem, const void* InNext)
|
|
{
|
|
if (!m_bEnableAnchor) return InNext;
|
|
if (HMD() == nullptr) return InNext;
|
|
|
|
UE_LOG(ViveOXRAnchor, Log, TEXT("Entry Anchor OnCreateSession."));
|
|
|
|
PFN_xrGetInstanceProcAddr GetIPA = xrGetInstanceProcAddr;
|
|
bool useMockRuntime = false;
|
|
|
|
if (!HMD()->IsExtensionEnabled(XR_HTC_ANCHOR_EXTENSION_NAME) && !useMockRuntime)
|
|
return InNext;
|
|
|
|
m_bExtAnchorEnabled = true;
|
|
|
|
XR_ENSURE(GetIPA(InInstance, "xrLocateSpace", (PFN_xrVoidFunction*)&xrLocateSpace));
|
|
XR_ENSURE(GetIPA(InInstance, "xrDestroySpace", (PFN_xrVoidFunction*)&xrDestroySpace));
|
|
XR_ENSURE(GetIPA(InInstance, "xrCreateSpatialAnchorHTC", (PFN_xrVoidFunction*)&xrCreateSpatialAnchorHTC));
|
|
XR_ENSURE(GetIPA(InInstance, "xrGetSpatialAnchorNameHTC", (PFN_xrVoidFunction*)&xrGetSpatialAnchorNameHTC));
|
|
|
|
XrSystemAnchorPropertiesHTC systemAnchorProperties = {};
|
|
systemAnchorProperties.type = XR_TYPE_SYSTEM_ANCHOR_PROPERTIES_HTC;
|
|
systemAnchorProperties.next = nullptr;
|
|
XrSystemProperties systemProperties = {};
|
|
systemProperties.type = XR_TYPE_SYSTEM_PROPERTIES;
|
|
systemProperties.next = &systemAnchorProperties;
|
|
XrResult result = xrGetSystemProperties(InInstance, InSystem, &systemProperties);
|
|
if (XR_FAILED(result))
|
|
{
|
|
UE_LOG(ViveOXRAnchor, Error, TEXT("OnCreateSession() xrGetSystemProperties failed with result %d."), result);
|
|
}
|
|
else
|
|
{
|
|
isAnchorSupported = systemAnchorProperties.supportsAnchor > 0;
|
|
UE_LOG(ViveOXRAnchor, Log, TEXT("OnCreateSession() Is Anchor support: %d."), systemAnchorProperties.supportsAnchor);
|
|
}
|
|
if (useMockRuntime)
|
|
isAnchorSupported = true;
|
|
|
|
if (!hmd->IsExtensionEnabled(XR_HTC_ANCHOR_PERSISTENCE_EXTENSION_NAME) && !useMockRuntime)
|
|
{
|
|
UE_LOG(ViveOXRAnchor, Warning, TEXT("Extension Anchor Persistence is NOT enabled."));
|
|
return InNext;
|
|
}
|
|
|
|
m_bExtAnchorPersistenceEnabled = true;
|
|
|
|
if (!hmd->IsExtensionEnabled(XR_EXT_FUTURE_EXTENSION_NAME) && !useMockRuntime)
|
|
{
|
|
UE_LOG(ViveOXRAnchor, Error, TEXT("Extension Future is NOT enabled. Thus, Anchor Persistence is not suported."));
|
|
return InNext;
|
|
}
|
|
|
|
auto futureMod = FViveOpenXRFuture::Instance();
|
|
|
|
if (futureMod == nullptr)
|
|
{
|
|
UE_LOG(ViveOXRAnchor, Error, TEXT("Failed to get Future Module."));
|
|
return InNext;
|
|
}
|
|
|
|
// Initialize new function pointers
|
|
XR_ENSURE(GetIPA(InInstance, "xrAcquirePersistedAnchorCollectionAsyncHTC", (PFN_xrVoidFunction*)&xrAcquirePersistedAnchorCollectionAsyncHTC));
|
|
XR_ENSURE(GetIPA(InInstance, "xrAcquirePersistedAnchorCollectionCompleteHTC", (PFN_xrVoidFunction*)&xrAcquirePersistedAnchorCollectionCompleteHTC));
|
|
XR_ENSURE(GetIPA(InInstance, "xrReleasePersistedAnchorCollectionHTC", (PFN_xrVoidFunction*)&xrReleasePersistedAnchorCollectionHTC));
|
|
XR_ENSURE(GetIPA(InInstance, "xrPersistSpatialAnchorAsyncHTC", (PFN_xrVoidFunction*)&xrPersistSpatialAnchorAsyncHTC));
|
|
XR_ENSURE(GetIPA(InInstance, "xrPersistSpatialAnchorCompleteHTC", (PFN_xrVoidFunction*)&xrPersistSpatialAnchorCompleteHTC));
|
|
XR_ENSURE(GetIPA(InInstance, "xrUnpersistSpatialAnchorHTC", (PFN_xrVoidFunction*)&xrUnpersistSpatialAnchorHTC));
|
|
XR_ENSURE(GetIPA(InInstance, "xrEnumeratePersistedAnchorNamesHTC", (PFN_xrVoidFunction*)&xrEnumeratePersistedAnchorNamesHTC));
|
|
XR_ENSURE(GetIPA(InInstance, "xrCreateSpatialAnchorFromPersistedAnchorAsyncHTC", (PFN_xrVoidFunction*)&xrCreateSpatialAnchorFromPersistedAnchorAsyncHTC));
|
|
XR_ENSURE(GetIPA(InInstance, "xrCreateSpatialAnchorFromPersistedAnchorCompleteHTC", (PFN_xrVoidFunction*)&xrCreateSpatialAnchorFromPersistedAnchorCompleteHTC));
|
|
XR_ENSURE(GetIPA(InInstance, "xrClearPersistedAnchorsHTC", (PFN_xrVoidFunction*)&xrClearPersistedAnchorsHTC));
|
|
XR_ENSURE(GetIPA(InInstance, "xrGetPersistedAnchorPropertiesHTC", (PFN_xrVoidFunction*)&xrGetPersistedAnchorPropertiesHTC));
|
|
XR_ENSURE(GetIPA(InInstance, "xrExportPersistedAnchorHTC", (PFN_xrVoidFunction*)&xrExportPersistedAnchorHTC));
|
|
XR_ENSURE(GetIPA(InInstance, "xrImportPersistedAnchorHTC", (PFN_xrVoidFunction*)&xrImportPersistedAnchorHTC));
|
|
XR_ENSURE(GetIPA(InInstance, "xrGetPersistedAnchorNameFromBufferHTC", (PFN_xrVoidFunction*)&xrGetPersistedAnchorNameFromBufferHTC));
|
|
|
|
isAnchorPersistenceSupported = true;
|
|
return InNext;
|
|
}
|
|
|
|
void FViveOpenXRAnchor::PostCreateSession(XrSession InSession)
|
|
{
|
|
UE_LOG(ViveOXRAnchor, Log, TEXT("Entry Anchor PostCreateSession InSession %llu."), InSession);
|
|
m_Session = InSession;
|
|
}
|
|
|
|
XrResult FViveOpenXRAnchor::LocateSpace(XrSpace space, XrSpace baseSpace, XrTime time, XrSpaceLocation* location)
|
|
{
|
|
if (xrLocateSpace == nullptr)
|
|
{
|
|
UE_LOG(ViveOXRAnchor, Error, TEXT("LocateSpace() xrLocateSpace is nullptr."));
|
|
return XR_ERROR_HANDLE_INVALID;
|
|
}
|
|
return xrLocateSpace(space, baseSpace, time, location);
|
|
}
|
|
|
|
XrResult FViveOpenXRAnchor::DestroySpace(XrSpace space)
|
|
{
|
|
if (xrDestroySpace == nullptr)
|
|
{
|
|
UE_LOG(ViveOXRAnchor, Error, TEXT("DestroySpace() xrDestroySpace is nullptr."));
|
|
return XR_ERROR_HANDLE_INVALID;
|
|
}
|
|
return xrDestroySpace(space);
|
|
}
|
|
|
|
bool FViveOpenXRAnchor::CreateSpatialAnchor(const XrSpatialAnchorCreateInfoHTC* createInfo, XrSpace* anchor)
|
|
{
|
|
UE_LOG(ViveOXRAnchor, Log, TEXT("CreateSpatialAnchor()"));
|
|
if (xrCreateSpatialAnchorHTC == nullptr)
|
|
{
|
|
UE_LOG(ViveOXRAnchor, Error, TEXT("CreateSpatialAnchor() xrCreateSpatialAnchorHTC is nullptr."));
|
|
return false;
|
|
}
|
|
|
|
if (anchor == nullptr)
|
|
{
|
|
UE_LOG(ViveOXRAnchor, Error, TEXT("CreateSpatialAnchor() anchor is nullptr."));
|
|
return false;
|
|
}
|
|
|
|
*anchor = 0;
|
|
|
|
XrResult result = xrCreateSpatialAnchorHTC(m_Session, createInfo, anchor);
|
|
if (XR_FAILED(result))
|
|
{
|
|
UE_LOG(ViveOXRAnchor, Error, TEXT("CreateSpatialAnchor() xrCreateSpatialAnchorHTC failed with result %d."), result);
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool FViveOpenXRAnchor::GetSpatialAnchorName(XrSpace anchor, XrSpatialAnchorNameHTC* name)
|
|
{
|
|
if (xrGetSpatialAnchorNameHTC == nullptr)
|
|
{
|
|
UE_LOG(ViveOXRAnchor, Error, TEXT("GetSpatialAnchorName() xrGetSpatialAnchorNameHTC is nullptr."));
|
|
return false;
|
|
}
|
|
|
|
if (name == nullptr)
|
|
{
|
|
UE_LOG(ViveOXRAnchor, Error, TEXT("GetSpatialAnchorName() name is nullptr."));
|
|
return false;
|
|
}
|
|
|
|
name->name[0] = 0;
|
|
|
|
XrResult result = xrGetSpatialAnchorNameHTC(anchor, name);
|
|
if (XR_FAILED(result))
|
|
{
|
|
UE_LOG(ViveOXRAnchor, Error, TEXT("GetSpatialAnchorName() xrGetSpatialAnchorNameHTC failed with result %d."), result);
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
XrSpatialAnchorCreateInfoHTC FViveOpenXRAnchor::MakeCreateInfo(const FVector& loc, const FQuat& rot, XrSpace baseSpace, FString name, float worldToMeterScale)
|
|
{
|
|
XrSpatialAnchorCreateInfoHTC createInfo = {};
|
|
createInfo.type = XR_TYPE_SPATIAL_ANCHOR_CREATE_INFO_HTC;
|
|
createInfo.next = nullptr;
|
|
createInfo.space = baseSpace;
|
|
createInfo.poseInSpace = XrPosef{ ToXrQuat(rot), ToXrVector(loc, worldToMeterScale) };
|
|
createInfo.name.name[0] = 0;
|
|
std::string str = TCHAR_TO_ANSI(*name);
|
|
int l = str.length();
|
|
size_t m = l < XR_MAX_SPATIAL_ANCHOR_NAME_SIZE_HTC - 1 ? l : XR_MAX_SPATIAL_ANCHOR_NAME_SIZE_HTC - 1;
|
|
|
|
#if PLATFORM_ANDROID
|
|
strncpy(createInfo.name.name, str.c_str(), m);
|
|
#else
|
|
strncpy_s(createInfo.name.name, str.c_str(), m);
|
|
#endif
|
|
createInfo.name.name[m] = 0;
|
|
|
|
return createInfo;
|
|
}
|
|
|
|
bool FViveOpenXRAnchor::LocateAnchor(XrSpace anchor, FRotator& rotation, FVector& translation)
|
|
{
|
|
if (!HMD()) return false;
|
|
if (xrLocateSpace == nullptr) return false;
|
|
XrTime time = hmd->GetDisplayTime();
|
|
XrSpace baseSpace = hmd->GetTrackingSpace();
|
|
|
|
XrSpaceLocation loc{};
|
|
|
|
auto result = xrLocateSpace((XrSpace)anchor, baseSpace, time, &loc);
|
|
if (XR_FAILED(result)) {
|
|
UE_LOG(ViveOXRAnchor, Error, TEXT("LocateAnchor() xrLocateSpace failed. result=%d."), result);
|
|
return false;
|
|
}
|
|
|
|
if ((loc.locationFlags & XR_SPACE_LOCATION_POSITION_VALID_BIT) == 0 ||
|
|
(loc.locationFlags & XR_SPACE_LOCATION_ORIENTATION_VALID_BIT) == 0) {
|
|
UE_LOG(ViveOXRAnchor, Error, TEXT("LocateAnchor() locationFlags has not valid bits. Flags=%016llX"), loc.locationFlags);
|
|
return false;
|
|
}
|
|
|
|
translation = ToFVector(loc.pose.position, hmd->GetWorldToMetersScale());
|
|
auto rot = ToFQuat(loc.pose.orientation);
|
|
rot.Normalize();
|
|
rotation = FRotator(rot);
|
|
return true;
|
|
}
|
|
|
|
FString FViveOpenXRAnchor::GenerateAnchorName(FString prefix) {
|
|
uint32_t fc = GFrameCounter;
|
|
fc %= 10000;
|
|
uint32_t time = ((uint32_t)(FPlatformTime::Seconds() * 1000)) % 1000000;
|
|
// This name will have a fixed length.
|
|
FString name = prefix + FString::Printf(TEXT("_%04u_%06u_VOXR"), fc, time);
|
|
return name;
|
|
}
|
|
|
|
FString FViveOpenXRAnchor::ToFString(const XrSpatialAnchorNameHTC& xrName)
|
|
{
|
|
ANSICHAR name[XR_MAX_SPATIAL_ANCHOR_NAME_SIZE_HTC];
|
|
#if PLATFORM_ANDROID
|
|
strncpy(name, xrName.name, XR_MAX_SPATIAL_ANCHOR_NAME_SIZE_HTC - 1);
|
|
#else
|
|
strncpy_s(name, xrName.name, XR_MAX_SPATIAL_ANCHOR_NAME_SIZE_HTC - 1);
|
|
#endif
|
|
name[XR_MAX_SPATIAL_ANCHOR_NAME_SIZE_HTC - 1] = 0;
|
|
|
|
return FString(FUTF8ToTCHAR(name));
|
|
}
|
|
|
|
XrSpatialAnchorNameHTC FViveOpenXRAnchor::FromFString(const FString& name)
|
|
{
|
|
XrSpatialAnchorNameHTC xrName = {};
|
|
std::string anchorNameStr(TCHAR_TO_UTF8(*name));
|
|
#if PLATFORM_ANDROID
|
|
strncpy(xrName.name, anchorNameStr.c_str(), XR_MAX_SPATIAL_ANCHOR_NAME_SIZE_HTC - 1);
|
|
#else
|
|
strncpy_s(xrName.name, anchorNameStr.c_str(), XR_MAX_SPATIAL_ANCHOR_NAME_SIZE_HTC - 1);
|
|
#endif
|
|
xrName.name[XR_MAX_SPATIAL_ANCHOR_NAME_SIZE_HTC - 1] = 0;
|
|
return xrName;
|
|
}
|
|
|
|
XrSpatialAnchorFromPersistedAnchorCreateInfoHTC FViveOpenXRAnchor::MakeSpatialAnchorFromPersistedAnchorCreateInfo(XrPersistedAnchorCollectionHTC collection, const FString persistedAnchorName, const FString anchorName)
|
|
{
|
|
XrSpatialAnchorFromPersistedAnchorCreateInfoHTC createInfo = {};
|
|
createInfo.type = XR_TYPE_SPATIAL_ANCHOR_FROM_PERSISTED_ANCHOR_CREATE_INFO_HTC;
|
|
createInfo.next = nullptr;
|
|
createInfo.persistedAnchorCollection = collection;
|
|
createInfo.persistedAnchorName = FromFString(persistedAnchorName);
|
|
createInfo.spatialAnchorName = FromFString(anchorName);
|
|
return createInfo;
|
|
}
|
|
|
|
// functions for the XR_HTC_anchor_persistence extension
|
|
|
|
XrResult FViveOpenXRAnchor::AcquirePersistedAnchorCollectionAsync(XrFutureEXT* future)
|
|
{
|
|
if (!isAnchorPersistenceSupported) return XR_ERROR_FUNCTION_UNSUPPORTED;
|
|
if (future == nullptr) return XR_ERROR_VALIDATION_FAILURE;
|
|
XrPersistedAnchorCollectionAcquireInfoHTC acquireInfo = {};
|
|
acquireInfo.type = XR_TYPE_PERSISTED_ANCHOR_COLLECTION_ACQUIRE_INFO_HTC;
|
|
acquireInfo.next = nullptr;
|
|
|
|
auto ret = xrAcquirePersistedAnchorCollectionAsyncHTC(m_Session, &acquireInfo, future);
|
|
return ret;
|
|
}
|
|
|
|
XrResult FViveOpenXRAnchor::AcquirePersistedAnchorCollectionComplete(XrFutureEXT future, XrPersistedAnchorCollectionAcquireCompletionHTC* completion)
|
|
{
|
|
if (!isAnchorPersistenceSupported) return XR_ERROR_FUNCTION_UNSUPPORTED;
|
|
return xrAcquirePersistedAnchorCollectionCompleteHTC(future, completion);
|
|
}
|
|
|
|
|
|
XrResult FViveOpenXRAnchor::ReleasePersistedAnchorCollection(XrPersistedAnchorCollectionHTC collection)
|
|
{
|
|
if (!isAnchorPersistenceSupported) return XR_ERROR_FUNCTION_UNSUPPORTED;
|
|
return xrReleasePersistedAnchorCollectionHTC(collection);
|
|
}
|
|
|
|
XrResult FViveOpenXRAnchor::PersistSpatialAnchorAsync(XrPersistedAnchorCollectionHTC collection, const XrSpatialAnchorPersistInfoHTC* info, XrFutureEXT* future)
|
|
{
|
|
if (!isAnchorPersistenceSupported) return XR_ERROR_FUNCTION_UNSUPPORTED;
|
|
return xrPersistSpatialAnchorAsyncHTC(collection, info, future);
|
|
}
|
|
|
|
XrResult FViveOpenXRAnchor::PersistSpatialAnchorComplete(XrFutureEXT future, XrFutureCompletionEXT* completion)
|
|
{
|
|
if (!isAnchorPersistenceSupported) return XR_ERROR_FUNCTION_UNSUPPORTED;
|
|
return xrPersistSpatialAnchorCompleteHTC(future, completion);
|
|
}
|
|
|
|
|
|
XrResult FViveOpenXRAnchor::UnpersistSpatialAnchor(XrPersistedAnchorCollectionHTC collection, const XrSpatialAnchorNameHTC* name)
|
|
{
|
|
if (!isAnchorPersistenceSupported) return XR_ERROR_FUNCTION_UNSUPPORTED;
|
|
return xrUnpersistSpatialAnchorHTC(collection, name);
|
|
}
|
|
|
|
XrResult FViveOpenXRAnchor::EnumeratePersistedAnchorNames(XrPersistedAnchorCollectionHTC collection, uint32_t nameCapacity, uint32_t* nameCount, XrSpatialAnchorNameHTC* names)
|
|
{
|
|
if (!isAnchorPersistenceSupported) return XR_ERROR_FUNCTION_UNSUPPORTED;
|
|
return xrEnumeratePersistedAnchorNamesHTC(collection, nameCapacity, nameCount, names);
|
|
}
|
|
|
|
XrResult FViveOpenXRAnchor::CreateSpatialAnchorFromPersistedAnchorAsync(const XrSpatialAnchorFromPersistedAnchorCreateInfoHTC* info, XrFutureEXT* future)
|
|
{
|
|
if (!isAnchorPersistenceSupported) return XR_ERROR_FUNCTION_UNSUPPORTED;
|
|
return xrCreateSpatialAnchorFromPersistedAnchorAsyncHTC(m_Session, info, future);
|
|
}
|
|
|
|
XrResult FViveOpenXRAnchor::CreateSpatialAnchorFromPersistedAnchorComplete(XrFutureEXT future, XrSpatialAnchorFromPersistedAnchorCreateCompletionHTC* completion)
|
|
{
|
|
if (!isAnchorPersistenceSupported) return XR_ERROR_FUNCTION_UNSUPPORTED;
|
|
return xrCreateSpatialAnchorFromPersistedAnchorCompleteHTC(future, completion);
|
|
}
|
|
|
|
XrResult FViveOpenXRAnchor::ClearPersistedAnchors(XrPersistedAnchorCollectionHTC collection)
|
|
{
|
|
if (!isAnchorPersistenceSupported) return XR_ERROR_FUNCTION_UNSUPPORTED;
|
|
return xrClearPersistedAnchorsHTC(collection);
|
|
}
|
|
|
|
XrResult FViveOpenXRAnchor::GetPersistedAnchorProperties(XrPersistedAnchorCollectionHTC collection, XrPersistedAnchorPropertiesGetInfoHTC* properties)
|
|
{
|
|
if (!isAnchorPersistenceSupported) return XR_ERROR_FUNCTION_UNSUPPORTED;
|
|
return xrGetPersistedAnchorPropertiesHTC(collection, properties);
|
|
}
|
|
|
|
XrResult FViveOpenXRAnchor::ExportPersistedAnchor(XrPersistedAnchorCollectionHTC collection, const XrSpatialAnchorNameHTC* name, uint32_t dataCapacity, uint32_t* dataCount, char* data)
|
|
{
|
|
if (!isAnchorPersistenceSupported) return XR_ERROR_FUNCTION_UNSUPPORTED;
|
|
return xrExportPersistedAnchorHTC(collection, name, dataCapacity, dataCount, data);
|
|
}
|
|
|
|
XrResult FViveOpenXRAnchor::ImportPersistedAnchor(XrPersistedAnchorCollectionHTC collection, uint32_t dataCount, const char* data)
|
|
{
|
|
if (!isAnchorPersistenceSupported) return XR_ERROR_FUNCTION_UNSUPPORTED;
|
|
return xrImportPersistedAnchorHTC(collection, dataCount, data);
|
|
}
|
|
|
|
XrResult FViveOpenXRAnchor::GetPersistedAnchorNameFromBuffer(XrPersistedAnchorCollectionHTC collection, uint32_t bufferCount, const char* buffer, XrSpatialAnchorNameHTC* name)
|
|
{
|
|
if (!isAnchorPersistenceSupported) return XR_ERROR_FUNCTION_UNSUPPORTED;
|
|
return xrGetPersistedAnchorNameFromBufferHTC(collection, bufferCount, buffer, name);
|
|
}
|
|
|
|
IMPLEMENT_MODULE(FViveOpenXRAnchor, ViveOpenXRAnchor)
|
|
|