295 lines
10 KiB
C++
295 lines
10 KiB
C++
|
// @lint-ignore-every LICENSELINT
|
||
|
// Copyright Epic Games, Inc. All Rights Reserved.
|
||
|
|
||
|
#include "OculusXRAssetManager.h"
|
||
|
#include "OculusXRHMDPrivate.h"
|
||
|
#include "OculusXRHMDModule.h"
|
||
|
#include "Engine/StaticMesh.h"
|
||
|
#include "Components/StaticMeshComponent.h"
|
||
|
#include "UObject/SoftObjectPath.h"
|
||
|
#include "Engine/SkeletalMesh.h"
|
||
|
#include "Components/SkeletalMeshComponent.h"
|
||
|
#include "OculusXRAssetDirectory.h"
|
||
|
#include "UObject/GCObject.h"
|
||
|
|
||
|
/* FOculusAssetDirectory
|
||
|
*****************************************************************************/
|
||
|
|
||
|
enum EOculusAsset
|
||
|
{
|
||
|
LeftTouchRiftS,
|
||
|
RightTouchRiftS,
|
||
|
LeftTouchQuest2,
|
||
|
RightTouchQuest2,
|
||
|
LeftTouchQuestPro,
|
||
|
RightTouchQuestPro,
|
||
|
LeftTouchQuest3,
|
||
|
RightTouchQuest3,
|
||
|
OculusAssetTotal
|
||
|
};
|
||
|
|
||
|
FSoftObjectPath FOculusAssetDirectory::AssetListing[OculusAssetTotal] = {
|
||
|
FString(TEXT("/OculusXR/Meshes/LeftTouchForQuestRiftSController.LeftTouchForQuestRiftSController")),
|
||
|
FString(TEXT("/OculusXR/Meshes/RightTouchForQuestRiftSController.RightTouchForQuestRiftSController")),
|
||
|
FString(TEXT("/OculusXR/Meshes/LeftTouchForQuest2.LeftTouchForQuest2")),
|
||
|
FString(TEXT("/OculusXR/Meshes/RightTouchForQuest2.RightTouchForQuest2")),
|
||
|
FString(TEXT("/OculusXR/Meshes/LeftMetaQuestTouchPro.LeftMetaQuestTouchPro")),
|
||
|
FString(TEXT("/OculusXR/Meshes/RightMetaQuestTouchPro.RightMetaQuestTouchPro")),
|
||
|
FString(TEXT("/OculusXR/Meshes/LeftMetaQuestTouchPlus.LeftMetaQuestTouchPlus")),
|
||
|
FString(TEXT("/OculusXR/Meshes/RightMetaQuestTouchPlus.RightMetaQuestTouchPlus")),
|
||
|
};
|
||
|
|
||
|
#if WITH_EDITORONLY_DATA
|
||
|
class FOculusAssetRepo : public FGCObject, public TArray<UObject*>
|
||
|
{
|
||
|
public:
|
||
|
// made an on-demand singleton rather than a static global, to avoid issues with FGCObject initialization
|
||
|
static FOculusAssetRepo& Get()
|
||
|
{
|
||
|
static FOculusAssetRepo AssetRepository;
|
||
|
return AssetRepository;
|
||
|
}
|
||
|
|
||
|
UObject* LoadAndAdd(const FSoftObjectPath& AssetPath)
|
||
|
{
|
||
|
UObject* AssetObj = AssetPath.TryLoad();
|
||
|
if (AssetObj != nullptr)
|
||
|
{
|
||
|
AddUnique(AssetObj);
|
||
|
}
|
||
|
return AssetObj;
|
||
|
}
|
||
|
|
||
|
public:
|
||
|
//~ FGCObject interface
|
||
|
virtual void AddReferencedObjects(FReferenceCollector& Collector) override
|
||
|
{
|
||
|
Collector.AddReferencedObjects(*this);
|
||
|
}
|
||
|
virtual FString GetReferencerName() const override
|
||
|
{
|
||
|
return TEXT("FOculusAssetRepo");
|
||
|
}
|
||
|
};
|
||
|
|
||
|
void FOculusAssetDirectory::LoadForCook()
|
||
|
{
|
||
|
FOculusAssetRepo& AssetRepro = FOculusAssetRepo::Get();
|
||
|
for (int32 AssetIndex = 0; AssetIndex < UE_ARRAY_COUNT(FOculusAssetDirectory::AssetListing); ++AssetIndex)
|
||
|
{
|
||
|
AssetRepro.LoadAndAdd(FOculusAssetDirectory::AssetListing[AssetIndex]);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void FOculusAssetDirectory::ReleaseAll()
|
||
|
{
|
||
|
FOculusAssetRepo::Get().Empty();
|
||
|
}
|
||
|
#endif // WITH_EDITORONLY_DATA
|
||
|
|
||
|
/* OculusAssetManager_Impl
|
||
|
*****************************************************************************/
|
||
|
|
||
|
namespace OculusAssetManager_Impl
|
||
|
{
|
||
|
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||
|
struct FRenderableDevice
|
||
|
{
|
||
|
ovrpNode OVRNode;
|
||
|
ovrpSystemHeadset MinDeviceRange;
|
||
|
ovrpSystemHeadset MaxDeviceRange;
|
||
|
FSoftObjectPath MeshAssetRef;
|
||
|
};
|
||
|
|
||
|
static FRenderableDevice RenderableDevices[] = {
|
||
|
#if PLATFORM_ANDROID
|
||
|
//Quest 1 & 2
|
||
|
{ ovrpNode_HandLeft, ovrpSystemHeadset_Oculus_Quest, ovrpSystemHeadset_Oculus_Quest_2, FOculusAssetDirectory::AssetListing[LeftTouchQuest2] },
|
||
|
{ ovrpNode_HandRight, ovrpSystemHeadset_Oculus_Quest, ovrpSystemHeadset_Oculus_Quest_2, FOculusAssetDirectory::AssetListing[RightTouchQuest2] },
|
||
|
|
||
|
//Quest Pro
|
||
|
{ ovrpNode_HandLeft, ovrpSystemHeadset_Meta_Quest_Pro, ovrpSystemHeadset_Meta_Quest_Pro, FOculusAssetDirectory::AssetListing[LeftTouchQuestPro] },
|
||
|
{ ovrpNode_HandRight, ovrpSystemHeadset_Meta_Quest_Pro, ovrpSystemHeadset_Meta_Quest_Pro, FOculusAssetDirectory::AssetListing[RightTouchQuestPro] },
|
||
|
|
||
|
//Quest 3
|
||
|
{ ovrpNode_HandLeft, ovrpSystemHeadset_Meta_Quest_3, ovrpSystemHeadset_Meta_Quest_3, FOculusAssetDirectory::AssetListing[LeftTouchQuest3] },
|
||
|
{ ovrpNode_HandRight, ovrpSystemHeadset_Meta_Quest_3, ovrpSystemHeadset_Meta_Quest_3, FOculusAssetDirectory::AssetListing[RightTouchQuest3] },
|
||
|
#else
|
||
|
//PC - Rift S
|
||
|
{ ovrpNode_HandLeft, ovrpSystemHeadset_Rift_S, ovrpSystemHeadset_Rift_S, FOculusAssetDirectory::AssetListing[LeftTouchRiftS] },
|
||
|
{ ovrpNode_HandRight, ovrpSystemHeadset_Rift_S, ovrpSystemHeadset_Rift_S, FOculusAssetDirectory::AssetListing[RightTouchRiftS] },
|
||
|
|
||
|
//PC - Quest 1 & 2
|
||
|
{ ovrpNode_HandLeft, ovrpSystemHeadset_Oculus_Link_Quest, ovrpSystemHeadset_Oculus_Link_Quest_2, FOculusAssetDirectory::AssetListing[LeftTouchQuest2] },
|
||
|
{ ovrpNode_HandRight, ovrpSystemHeadset_Oculus_Link_Quest, ovrpSystemHeadset_Oculus_Link_Quest_2, FOculusAssetDirectory::AssetListing[RightTouchQuest2] },
|
||
|
|
||
|
//PC - Quest Pro
|
||
|
{ ovrpNode_HandLeft, ovrpSystemHeadset_Meta_Link_Quest_Pro, ovrpSystemHeadset_Meta_Link_Quest_Pro, FOculusAssetDirectory::AssetListing[LeftTouchQuestPro] },
|
||
|
{ ovrpNode_HandRight, ovrpSystemHeadset_Meta_Link_Quest_Pro, ovrpSystemHeadset_Meta_Link_Quest_Pro, FOculusAssetDirectory::AssetListing[RightTouchQuestPro] },
|
||
|
|
||
|
//Quest 3
|
||
|
{ ovrpNode_HandLeft, ovrpSystemHeadset_Meta_Link_Quest_3, ovrpSystemHeadset_Meta_Link_Quest_3, FOculusAssetDirectory::AssetListing[LeftTouchQuest3] },
|
||
|
{ ovrpNode_HandRight, ovrpSystemHeadset_Meta_Link_Quest_3, ovrpSystemHeadset_Meta_Link_Quest_3, FOculusAssetDirectory::AssetListing[RightTouchQuest3] },
|
||
|
#endif
|
||
|
};
|
||
|
|
||
|
static uint32 RenderableDeviceCount = sizeof(RenderableDevices) / sizeof(RenderableDevices[0]);
|
||
|
#endif // #if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||
|
|
||
|
static UObject* FindDeviceMesh(const int32 DeviceID);
|
||
|
}; // namespace OculusAssetManager_Impl
|
||
|
|
||
|
static UObject* OculusAssetManager_Impl::FindDeviceMesh(const int32 DeviceID)
|
||
|
{
|
||
|
UObject* DeviceMesh = nullptr;
|
||
|
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||
|
const ovrpNode DeviceOVRNode = OculusXRHMD::ToOvrpNode(DeviceID);
|
||
|
|
||
|
bool bUseSystemHeadsetType = false;
|
||
|
ovrpSystemHeadset HeadsetType;
|
||
|
if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetSystemHeadsetType2(&HeadsetType)))
|
||
|
{
|
||
|
bUseSystemHeadsetType = true;
|
||
|
}
|
||
|
|
||
|
if (DeviceOVRNode != ovrpNode_None)
|
||
|
{
|
||
|
for (uint32 DeviceIndex = 0; DeviceIndex < RenderableDeviceCount; ++DeviceIndex)
|
||
|
{
|
||
|
const FRenderableDevice& RenderableDevice = RenderableDevices[DeviceIndex];
|
||
|
if (RenderableDevice.OVRNode == DeviceOVRNode)
|
||
|
{
|
||
|
// If we have information about the current headset, load the model based of the headset information, otherwise load defaults.
|
||
|
if (bUseSystemHeadsetType)
|
||
|
{
|
||
|
if (HeadsetType >= RenderableDevice.MinDeviceRange && HeadsetType <= RenderableDevice.MaxDeviceRange)
|
||
|
{
|
||
|
DeviceMesh = RenderableDevice.MeshAssetRef.TryLoad();
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
DeviceMesh = RenderableDevice.MeshAssetRef.TryLoad();
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
return DeviceMesh;
|
||
|
}
|
||
|
|
||
|
/* FOculusAssetManager
|
||
|
*****************************************************************************/
|
||
|
|
||
|
FOculusAssetManager::FOculusAssetManager()
|
||
|
{
|
||
|
IModularFeatures::Get().RegisterModularFeature(IXRSystemAssets::GetModularFeatureName(), this);
|
||
|
|
||
|
ResourceHolder = NewObject<UOculusXRResourceHolder>();
|
||
|
ResourceHolder->AddToRoot();
|
||
|
}
|
||
|
|
||
|
FOculusAssetManager::~FOculusAssetManager()
|
||
|
{
|
||
|
if (ResourceHolder)
|
||
|
{
|
||
|
ResourceHolder->ConditionalBeginDestroy();
|
||
|
ResourceHolder = nullptr;
|
||
|
}
|
||
|
|
||
|
IModularFeatures::Get().UnregisterModularFeature(IXRSystemAssets::GetModularFeatureName(), this);
|
||
|
}
|
||
|
|
||
|
bool FOculusAssetManager::EnumerateRenderableDevices(TArray<int32>& DeviceListOut)
|
||
|
{
|
||
|
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||
|
using namespace OculusAssetManager_Impl;
|
||
|
DeviceListOut.Empty(RenderableDeviceCount);
|
||
|
|
||
|
for (uint32 DeviceIndex = 0; DeviceIndex < RenderableDeviceCount; ++DeviceIndex)
|
||
|
{
|
||
|
const FRenderableDevice& RenderableDevice = RenderableDevices[DeviceIndex];
|
||
|
|
||
|
const int32 ExternalDeviceId = OculusXRHMD::ToExternalDeviceId(RenderableDevice.OVRNode);
|
||
|
DeviceListOut.Add(ExternalDeviceId);
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
#else
|
||
|
return false;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
int32 FOculusAssetManager::GetDeviceId(EControllerHand ControllerHand)
|
||
|
{
|
||
|
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
||
|
ovrpNode ControllerOVRNode = ovrpNode_None;
|
||
|
|
||
|
switch (ControllerHand)
|
||
|
{
|
||
|
case EControllerHand::AnyHand:
|
||
|
// @TODO: maybe check if the right is tracking, if not choose left (if tracking)?
|
||
|
case EControllerHand::Right:
|
||
|
ControllerOVRNode = ovrpNode_HandRight;
|
||
|
break;
|
||
|
case EControllerHand::Left:
|
||
|
ControllerOVRNode = ovrpNode_HandLeft;
|
||
|
break;
|
||
|
|
||
|
case EControllerHand::ExternalCamera:
|
||
|
ControllerOVRNode = ovrpNode_TrackerZero;
|
||
|
break;
|
||
|
// case EControllerHand::Special_1:
|
||
|
// ControllerOVRNode = ovrpNode_TrackerOne;
|
||
|
// break;
|
||
|
// case EControllerHand::Special_2:
|
||
|
// ControllerOVRNode = ovrpNode_TrackerTwo;
|
||
|
// break;
|
||
|
// case EControllerHand::Special_3:
|
||
|
// ControllerOVRNode = ovrpNode_TrackerThree;
|
||
|
// break;
|
||
|
|
||
|
// case EControllerHand::Special_4:
|
||
|
// ControllerOVRNode = ovrpNode_DeviceObjectZero;
|
||
|
// break;
|
||
|
|
||
|
default:
|
||
|
// ControllerOVRNode = ovrpNode_None => returns -1
|
||
|
break;
|
||
|
}
|
||
|
return OculusXRHMD::ToExternalDeviceId(ControllerOVRNode);
|
||
|
#else
|
||
|
return INDEX_NONE;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
UPrimitiveComponent* FOculusAssetManager::CreateRenderComponent(const int32 DeviceId, AActor* Owner, EObjectFlags Flags, const bool /*bForceSynchronous*/, const FXRComponentLoadComplete& OnLoadComplete)
|
||
|
{
|
||
|
UPrimitiveComponent* NewRenderComponent = nullptr;
|
||
|
if (UObject* DeviceMesh = OculusAssetManager_Impl::FindDeviceMesh(DeviceId))
|
||
|
{
|
||
|
if (UStaticMesh* AsStaticMesh = Cast<UStaticMesh>(DeviceMesh))
|
||
|
{
|
||
|
const FName ComponentName = MakeUniqueObjectName(Owner, UStaticMeshComponent::StaticClass(), *FString::Printf(TEXT("%s_Device%d"), TEXT("Oculus"), DeviceId));
|
||
|
UStaticMeshComponent* MeshComponent = NewObject<UStaticMeshComponent>(Owner, ComponentName, Flags);
|
||
|
|
||
|
MeshComponent->SetStaticMesh(AsStaticMesh);
|
||
|
NewRenderComponent = MeshComponent;
|
||
|
}
|
||
|
else if (USkeletalMesh* AsSkeletalMesh = Cast<USkeletalMesh>(DeviceMesh))
|
||
|
{
|
||
|
const FName ComponentName = MakeUniqueObjectName(Owner, USkeletalMeshComponent::StaticClass(), *FString::Printf(TEXT("%s_Device%d"), TEXT("Oculus"), DeviceId));
|
||
|
USkeletalMeshComponent* SkelMeshComponent = NewObject<USkeletalMeshComponent>(Owner, ComponentName, Flags);
|
||
|
|
||
|
SkelMeshComponent->SetSkeletalMesh(AsSkeletalMesh);
|
||
|
NewRenderComponent = SkelMeshComponent;
|
||
|
}
|
||
|
NewRenderComponent->SetCollisionEnabled(ECollisionEnabled::NoCollision);
|
||
|
}
|
||
|
|
||
|
OnLoadComplete.ExecuteIfBound(NewRenderComponent);
|
||
|
return NewRenderComponent;
|
||
|
}
|