Skip to content
Snippets Groups Projects
Commit 0c4ff69e authored by David Gilbert's avatar David Gilbert :bug:
Browse files

Merge branch 'refactor/plugin_separation' into 'dev/5.3'

Plugin Separation: Move the RWTHVRCluster Module into its own Plugin with respective content. Removes Toolkit dependency to nDisplay

See merge request !79
parents 53c84a3f 2eb1d91a
Branches
Tags
2 merge requests!85UE5.3-2023.1-rc3,!79Plugin Separation: Move the RWTHVRCluster Module into its own Plugin with respective content. Removes Toolkit dependency to nDisplay
Showing
with 53 additions and 581 deletions
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Blueprint/UserWidget.h"
#include "Components/TextBlock.h"
#include "Components/Border.h"
#include "DoorOverlayData.generated.h"
/**
* Used as a parent-class in the overlay widget. Like this we can access the UMG properties in C++
*/
UCLASS()
class RWTHVRCLUSTER_API UDoorOverlayData : public UUserWidget
{
GENERATED_BODY()
public:
// These declarations are magically bound to the UMG blueprints elements,
// if they are named the same
UPROPERTY(BlueprintReadWrite, meta = (BindWidget))
UTextBlock* CornerText;
UPROPERTY(BlueprintReadWrite, meta = (BindWidget))
UBorder* BlackBox;
};
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "LiveLinkPreset.h"
#include "GameFramework/Actor.h"
#include "CaveSetup.generated.h"
/**
* Simple Actor that needs to be added to the level which spawns Cave-related actors
* such as the CaveOverlay.
* It attaches itself to the Primary Node's Pawn and then replicates on the server.
*/
UCLASS(hideCategories = (Rendering, Input, Actor, Base, Collision, Shape, Physics, HLOD))
class RWTHVRCLUSTER_API ACaveSetup : public AActor
{
GENERATED_BODY()
public:
ACaveSetup();
UPROPERTY(EditAnywhere)
TArray<UClass*> ActorsToSpawnOnCave;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
ULiveLinkPreset* LiveLinkPresetToApplyOnCave;
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
};
#pragma once
#include "CoreMinimal.h"
#include "HAL/IConsoleManager.h"
#include "Cluster/IDisplayClusterClusterManager.h"
#include "ClusterConsole.generated.h"
/**
* The ClusterConsole provides the console command "ClusterExecute"
* The code catches your command, broadcasts it to every nDisplay node and executes it everywhere
*
* This class has to be registered and unregistered. This can easily be done in every StartupModule/ShutdownModule
* functions.
*/
USTRUCT()
struct RWTHVRCLUSTER_API FClusterConsole
{
GENERATED_BODY()
private:
/* Used for ClusterExecute console command */
IConsoleCommand* ClusterConsoleCommand = nullptr;
FOnClusterEventJsonListener ClusterEventListenerDelegate;
public:
void Register();
void Unregister() const;
};
#pragma once
#include "Serialization/MemoryReader.h"
#include "Serialization/MemoryWriter.h"
#include "type_traits"
template <typename ParameterType, typename... RemainingParameterTypes>
inline void SerializeParameters(FMemoryWriter* MemoryWriter, ParameterType&& Parameter,
RemainingParameterTypes&&... RemainingParameters)
{
using NonConstType = typename std::remove_cv_t<typename TRemoveReference<ParameterType>::Type>;
// const_cast because the same operator (<<) is used for reading and writing
(*MemoryWriter) << const_cast<NonConstType&>(Parameter);
SerializeParameters(MemoryWriter, Forward<RemainingParameterTypes>(RemainingParameters)...);
}
inline void SerializeParameters(FMemoryWriter* MemoryWriter) {}
// This is a wrapper function to recursively fill the argument tuple. This overload is only used if the index indicating
// the currently handled attribute is less than the number of total attributes. I.e., if the attribute index is valid.
template <int CurrentIndex, typename... ArgTypes>
inline typename TEnableIf<(CurrentIndex < sizeof...(ArgTypes))>::Type
FillArgumentTuple(FMemoryReader* MemoryReader, TTuple<ArgTypes...>* ArgumentTuple)
{
// Read the "<<" as ">>" operator here. FArchive uses the same for both and decides based on an internal type on
// what to do. So this statement parses the bytes that were passed into reader and puts the parsed object into the
// tuple at index CurrentIndex.
(*MemoryReader) << ArgumentTuple->template Get<CurrentIndex>();
// Recursive call for the remaining attributes.
FillArgumentTuple<CurrentIndex + 1>(MemoryReader, Forward<TTuple<ArgTypes...>*>(ArgumentTuple));
}
// The overload that is called if we are "passed the end" of attributes.
template <int CurrentIndex, typename... ArgTypes>
inline typename TEnableIf<(CurrentIndex >= sizeof...(ArgTypes))>::Type
FillArgumentTuple(FMemoryReader* MemoryReader, TTuple<ArgTypes...>* ArgumentTuple)
{
}
template <typename RetType, typename... ArgTypes>
inline RetType CallDelegateWithParameterMap(const TDelegate<RetType, ArgTypes...>& Delegate,
const TMap<FString, FString>& Parameters)
{
// Create a tuple that holds all arguments. This assumes that all argument types are default constructible. However,
// all types that overload the FArchive "<<" operator probably are.
TTuple<typename std::remove_cv_t<typename TRemoveReference<ArgTypes>::Type>...> ArgumentTuple;
// This call will parse the string map and fill all values in the tuple appropriately.
FillArgumentTuple<0>(&ArgumentTuple, Parameters);
// The lambda function is only necessary because delegates do not overload the ()-operator but use the Execute()
// method instead. So, the lambda acts as a wrapper.
return ArgumentTuple.ApplyBefore([Delegate](ArgTypes&&... Arguments)
{ Delegate.Execute(Forward<ArgTypes>(Arguments)...); });
}
#pragma once
#include "IDisplayCluster.h"
#include "Cluster/IDisplayClusterClusterManager.h"
#include "Cluster/DisplayClusterClusterEvent.h"
#include "DisplayClusterEventParameterHelper.h"
#include "Templates/IsInvocable.h"
static constexpr int32 CLUSTER_EVENT_WRAPPER_EVENT_ID = 1337420;
template <typename MemberFunctionType, MemberFunctionType MemberFunction>
class ClusterEventWrapperEvent;
template <typename ObjectType, typename ReturnType, typename... ArgTypes,
ReturnType (ObjectType::*MemberFunction)(ArgTypes...)>
class ClusterEventWrapperEvent<ReturnType (ObjectType::*)(ArgTypes...), MemberFunction>
{
static_assert(TIsDerivedFrom<ObjectType, UObject>::IsDerived, "Object needs to derive from UObject");
public:
using MemberFunctionType = decltype(MemberFunction);
ClusterEventWrapperEvent(const TCHAR* MethodName) : MethodName{MethodName} {}
void Attach(ObjectType* NewObject)
{
checkf(Object == nullptr, TEXT("The event is already attached."));
Object = NewObject;
ObjectId = Object->GetUniqueID();
EDisplayClusterOperationMode OperationMode = IDisplayCluster::Get().GetOperationMode();
if (OperationMode == EDisplayClusterOperationMode::Cluster)
{
IDisplayClusterClusterManager* ClusterManager = IDisplayCluster::Get().GetClusterMgr();
check(ClusterManager != nullptr);
check(!ClusterEventListenerDelegate.IsBound());
ClusterEventListenerDelegate = FOnClusterEventBinaryListener::CreateLambda(
[this](const FDisplayClusterClusterEventBinary& Event)
{
if (Event.EventId != CLUSTER_EVENT_WRAPPER_EVENT_ID)
{
return;
}
FMemoryReader MemoryReader(Event.EventData);
uint32 EventObjectId;
// This reads the value!
MemoryReader << EventObjectId;
if (EventObjectId != ObjectId)
{
// Event does not belong to this object.
return;
}
FString EventMethodName;
// This reads the value!
MemoryReader << EventMethodName;
if (EventMethodName != MethodName)
{
// This event does not belong to this method.
return;
}
// Create a tuple that holds all arguments. This assumes that all
// argument types are default constructible. However, all
// types that overload the FArchive "<<" operator probably are.
TTuple<typename std::remove_cv_t<typename TRemoveReference<ArgTypes>::Type>...> ArgumentTuple;
// This call will deserialze the values and fill all values in the tuple appropriately.
FillArgumentTuple<0>(&MemoryReader, &ArgumentTuple);
ArgumentTuple.ApplyBefore([this](const ArgTypes&... Arguments)
{ (Object->*MemberFunction)(Forward<const ArgTypes&>(Arguments)...); });
});
ClusterManager->AddClusterEventBinaryListener(ClusterEventListenerDelegate);
}
}
void Detach()
{
checkf(Object != nullptr, TEXT("The event was never attached."));
EDisplayClusterOperationMode OperationMode = IDisplayCluster::Get().GetOperationMode();
if (OperationMode == EDisplayClusterOperationMode::Cluster)
{
IDisplayClusterClusterManager* ClusterManager = IDisplayCluster::Get().GetClusterMgr();
check(ClusterManager != nullptr);
// check(ClusterEventListenerDelegate.IsBound());
ClusterManager->RemoveClusterEventBinaryListener(ClusterEventListenerDelegate);
}
}
void Send(ArgTypes... Arguments)
{
checkf(Object != nullptr, TEXT("The event was not attached."));
EDisplayClusterOperationMode OperationMode = IDisplayCluster::Get().GetOperationMode();
if (OperationMode != EDisplayClusterOperationMode::Cluster)
{
(Object->*MemberFunction)(Forward<ArgTypes>(Arguments)...);
}
else
{
IDisplayClusterClusterManager* ClusterManager = IDisplayCluster::Get().GetClusterMgr();
check(ClusterManager != nullptr);
FDisplayClusterClusterEventBinary ClusterEvent;
ClusterEvent.EventId = CLUSTER_EVENT_WRAPPER_EVENT_ID;
ClusterEvent.bShouldDiscardOnRepeat = false;
FMemoryWriter MemoryWriter(ClusterEvent.EventData);
MemoryWriter << ObjectId;
MemoryWriter << const_cast<FString&>(MethodName);
SerializeParameters(&MemoryWriter, Forward<ArgTypes>(Arguments)...);
ClusterManager->EmitClusterEventBinary(ClusterEvent, true);
}
}
private:
const FString MethodName;
uint32 ObjectId;
ObjectType* Object = nullptr;
FOnClusterEventBinaryListener ClusterEventListenerDelegate;
};
#define DCEW_STRINGIFY(x) #x
#define DCEW_TOSTRING(x) DCEW_STRINGIFY(x)
#define DECLARE_DISPLAY_CLUSTER_EVENT(OwningType, MethodIdentifier) \
ClusterEventWrapperEvent<decltype(&OwningType::MethodIdentifier), &OwningType::MethodIdentifier> \
MethodIdentifier##Event \
{ \
TEXT(DCEW_TOSTRING(OwningType) DCEW_TOSTRING(MethodIdentifier)) \
}
#pragma once
#include "CoreMinimal.h"
#include "Modules/ModuleManager.h"
#include "ClusterConsole/ClusterConsole.h"
class FRWTHVRClusterModule : public IModuleInterface
{
public:
virtual void StartupModule() override;
virtual void ShutdownModule() override;
private:
FClusterConsole ClusterConsole;
};
using UnrealBuildTool;
public class RWTHVRCluster : ModuleRules
{
public RWTHVRCluster(ReadOnlyTargetRules Target) : base(Target)
{
PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs;
PublicIncludePaths.AddRange(
new string[] { }
);
PrivateIncludePaths.AddRange(
new string[] { }
);
PublicDependencyModuleNames.AddRange(
new string[]
{
"Core",
"CoreUObject",
"Engine",
"DeveloperSettings",
"EnhancedInput",
"UMG",
"Slate",
"SlateCore",
"RWTHVRToolkit",
"LiveLink"
}
);
if (IsPluginEnabledForTarget("nDisplay", base.Target))
{
PublicDependencyModuleNames.AddRange(
new string[]
{
"DisplayCluster"
}
);
}
if (IsPluginEnabledForTarget("DTrackPlugin", base.Target))
{
PublicDependencyModuleNames.AddRange(
new string[]
{
"DTrackPlugin",
"DTrackInput"
}
);
}
PrivateDependencyModuleNames.AddRange(
new string[] { }
);
DynamicallyLoadedModuleNames.AddRange(
new string[] { }
);
}
private static bool IsPluginEnabledForTarget(string PluginName, ReadOnlyTargetRules Target)
{
var PL = Plugins.GetPlugin(PluginName);
return PL != null && Target.ProjectFile != null && Plugins.IsPluginEnabledForTarget(PL,
ProjectDescriptor.FromFile(Target.ProjectFile), Target.Platform, Target.Configuration, Target.Type);
}
}
\ No newline at end of file
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
#include "Interaction/Interactables/IntenSelect/IntenSelectableScoring.h" #include "Interaction/Interactables/IntenSelect/IntenSelectableScoring.h"
#include "Interaction/Interactables/IntenSelect/IntenSelectableSinglePointScoring.h" #include "Interaction/Interactables/IntenSelect/IntenSelectableSinglePointScoring.h"
#include "Kismet/KismetSystemLibrary.h" #include "Kismet/KismetSystemLibrary.h"
#include "Logging/StructuredLog.h"
#include "Misc/MessageDialog.h" #include "Misc/MessageDialog.h"
#include "Pawn/IntenSelectComponent.h" #include "Pawn/IntenSelectComponent.h"
#include "Utility/RWTHVRUtilities.h" #include "Utility/RWTHVRUtilities.h"
...@@ -46,9 +47,9 @@ void UIntenSelectable::BeginPlay() ...@@ -46,9 +47,9 @@ void UIntenSelectable::BeginPlay()
{ {
if (ScoringBehaviours.Num() == 0) if (ScoringBehaviours.Num() == 0)
{ {
URWTHVRUtilities::ShowErrorAndQuit( UE_LOGFMT(
"Please assign the Scoring Behaviour manually when using more than one IntenSelectable Component!", Toolkit, Error,
false, this); "Please assign the Scoring Behaviour manually when using more than one IntenSelectable Component!");
} }
} }
else else
......
...@@ -16,6 +16,10 @@ ...@@ -16,6 +16,10 @@
#include "Roles/LiveLinkTransformTypes.h" #include "Roles/LiveLinkTransformTypes.h"
#include "Utility/RWTHVRUtilities.h" #include "Utility/RWTHVRUtilities.h"
#if PLATFORM_SUPPORTS_CLUSTER
#include "Components/DisplayClusterSceneComponentSyncParent.h"
#endif
ARWTHVRPawn::ARWTHVRPawn(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) ARWTHVRPawn::ARWTHVRPawn(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer)
{ {
BaseEyeHeight = 160.0f; BaseEyeHeight = 160.0f;
...@@ -36,14 +40,21 @@ ARWTHVRPawn::ARWTHVRPawn(const FObjectInitializer& ObjectInitializer) : Super(Ob ...@@ -36,14 +40,21 @@ ARWTHVRPawn::ARWTHVRPawn(const FObjectInitializer& ObjectInitializer) : Super(Ob
LeftHand = CreateDefaultSubobject<UReplicatedMotionControllerComponent>(TEXT("Left Hand MCC")); LeftHand = CreateDefaultSubobject<UReplicatedMotionControllerComponent>(TEXT("Left Hand MCC"));
LeftHand->SetupAttachment(RootComponent); LeftHand->SetupAttachment(RootComponent);
}
void ARWTHVRPawn::BeginPlay()
{
Super::BeginPlay();
#if PLATFORM_SUPPORTS_CLUSTER
// Add an nDisplay Parent Sync Component. It syncs the parent's transform from master to clients. // Add an nDisplay Parent Sync Component. It syncs the parent's transform from master to clients.
// This is required because for collision based movement, it can happen that the physics engine // This is required because for collision based movement, it can happen that the physics engine
// for some reason acts different on the nodes, therefore leading to a potential desync when // for some reason acts different on the nodes, therefore leading to a potential desync when
// e.g. colliding with an object while moving. // e.g. colliding with an object while moving.
SyncComponent =
CreateDefaultSubobject<UDisplayClusterSceneComponentSyncParent>(TEXT("Parent Display Cluster Sync Component")); SyncComponent = Cast<USceneComponent>(AddComponentByClass(UDisplayClusterSceneComponentSyncParent::StaticClass(),
SyncComponent->SetupAttachment(RootComponent); false, FTransform::Identity, false));
AddInstanceComponent(SyncComponent);
#endif
} }
void ARWTHVRPawn::Tick(float DeltaSeconds) void ARWTHVRPawn::Tick(float DeltaSeconds)
......
#include "Utility/RWTHVRUtilities.h" #include "Utility/RWTHVRUtilities.h"
#if PLATFORM_SUPPORTS_NDISPLAY
#include "DisplayClusterConfigurationTypes.h"
#include "DisplayClusterRootActor.h"
#include "IDisplayCluster.h"
#include "Cluster/IDisplayClusterClusterManager.h"
#include "Components/DisplayClusterCameraComponent.h"
#include "Config/IDisplayClusterConfigManager.h"
#include "Game/IDisplayClusterGameManager.h"
#endif
#include "AudioDevice.h" #include "AudioDevice.h"
#include "IHeadMountedDisplay.h" #include "IHeadMountedDisplay.h"
#include "IXRTrackingSystem.h" #include "IXRTrackingSystem.h"
...@@ -17,20 +7,15 @@ ...@@ -17,20 +7,15 @@
#include "Engine/LocalPlayer.h" #include "Engine/LocalPlayer.h"
#include "Kismet/GameplayStatics.h" #include "Kismet/GameplayStatics.h"
#if PLATFORM_SUPPORTS_CLUSTER
#include "Utility/RWTHVRClusterUtilities.h"
#endif
DEFINE_LOG_CATEGORY(Toolkit); DEFINE_LOG_CATEGORY(Toolkit);
bool URWTHVRUtilities::IsDesktopMode() { return !IsRoomMountedMode() && !IsHeadMountedMode(); } bool URWTHVRUtilities::IsDesktopMode() { return !IsRoomMountedMode() && !IsHeadMountedMode(); }
bool URWTHVRUtilities::IsRoomMountedMode()
{
#if PLATFORM_SUPPORTS_NDISPLAY
return IDisplayCluster::Get().GetOperationMode() == EDisplayClusterOperationMode::Cluster;
#else
return false;
#endif
}
bool URWTHVRUtilities::IsHeadMountedMode() bool URWTHVRUtilities::IsHeadMountedMode()
{ {
// In editor builds: checks for EdEngine->IsVRPreviewActive() // In editor builds: checks for EdEngine->IsVRPreviewActive()
...@@ -38,62 +23,20 @@ bool URWTHVRUtilities::IsHeadMountedMode() ...@@ -38,62 +23,20 @@ bool URWTHVRUtilities::IsHeadMountedMode()
return FAudioDevice::CanUseVRAudioDevice(); return FAudioDevice::CanUseVRAudioDevice();
} }
bool URWTHVRUtilities::IsCave() bool URWTHVRUtilities::IsRoomMountedMode()
{ {
#if PLATFORM_SUPPORTS_NDISPLAY #if PLATFORM_SUPPORTS_CLUSTER
if (!IsRoomMountedMode()) URWTHVRClusterUtilities::IsRoomMountedMode();
return false;
const UDisplayClusterConfigurationData* ClusterConfig = IDisplayCluster::Get().GetConfigMgr()->GetConfig();
return ClusterConfig->CustomParameters.Contains("Hardware_Platform") &&
ClusterConfig->CustomParameters.Find("Hardware_Platform")->Equals("aixcave", ESearchCase::IgnoreCase);
#else
return false;
#endif #endif
}
bool URWTHVRUtilities::IsRolv()
{
#if PLATFORM_SUPPORTS_NDISPLAY
if (!IsRoomMountedMode())
return false; return false;
const UDisplayClusterConfigurationData* ClusterConfig = IDisplayCluster::Get().GetConfigMgr()->GetConfig();
return ClusterConfig->CustomParameters.Contains("Hardware_Platform") &&
ClusterConfig->CustomParameters.Find("Hardware_Platform")->Equals("ROLV", ESearchCase::IgnoreCase);
#else
return false;
#endif
} }
/* Return true on the Primary in cluster mode and in a normal desktop session. Otherwise false */
bool URWTHVRUtilities::IsPrimaryNode() bool URWTHVRUtilities::IsPrimaryNode()
{ {
#if PLATFORM_SUPPORTS_NDISPLAY #if PLATFORM_SUPPORTS_CLUSTER
if (!IDisplayCluster::IsAvailable()) URWTHVRClusterUtilities::IsPrimaryNode();
{
return true;
}
IDisplayClusterClusterManager* Manager = IDisplayCluster::Get().GetClusterMgr();
if (Manager == nullptr)
{
return true; // if we are not in cluster mode, we are always the primary node
}
return Manager->IsPrimary() || !Manager->IsSecondary();
#else
return true;
#endif
}
bool URWTHVRUtilities::IsSecondaryNode() { return !IsPrimaryNode(); }
FString URWTHVRUtilities::GetNodeName()
{
#if PLATFORM_SUPPORTS_NDISPLAY
return IsRoomMountedMode() ? IDisplayCluster::Get().GetClusterMgr()->GetNodeId() : FString(TEXT("Localhost"));
#else
return FString(TEXT("Localhost"));
#endif #endif
return false;
} }
float URWTHVRUtilities::GetEyeDistance() float URWTHVRUtilities::GetEyeDistance()
...@@ -102,81 +45,7 @@ float URWTHVRUtilities::GetEyeDistance() ...@@ -102,81 +45,7 @@ float URWTHVRUtilities::GetEyeDistance()
{ {
return GEngine->XRSystem->GetHMDDevice()->GetInterpupillaryDistance(); return GEngine->XRSystem->GetHMDDevice()->GetInterpupillaryDistance();
} }
else return 0;
{
#if PLATFORM_SUPPORTS_NDISPLAY
const ADisplayClusterRootActor* RootActor = IDisplayCluster::Get().GetGameMgr()->GetRootActor();
return (RootActor) ? RootActor->GetDefaultCamera()->GetInterpupillaryDistance() : 0.0f;
#else
return 0.0f;
#endif
}
}
EEyeStereoOffset URWTHVRUtilities::GetNodeEyeType()
{
#if PLATFORM_SUPPORTS_NDISPLAY
const ADisplayClusterRootActor* RootActor = IDisplayCluster::Get().GetGameMgr()->GetRootActor();
return static_cast<EEyeStereoOffset>((RootActor) ? RootActor->GetDefaultCamera()->GetStereoOffset()
: EDisplayClusterEyeStereoOffset::None);
#else
return EDisplayClusterEyeStereoOffset::None;
#endif
}
void URWTHVRUtilities::ShowErrorAndQuit(const FString& Message, bool ShouldQuit, const UObject* WorldContext)
{
UE_LOG(LogTemp, Error, TEXT("%s"), *Message)
#if WITH_EDITOR
FMessageDialog::Open(EAppMsgType::Ok, FText::FromString(Message));
#endif
if (ShouldQuit)
{
UKismetSystemLibrary::QuitGame(WorldContext, nullptr, EQuitPreference::Quit, false);
}
}
USceneComponent* URWTHVRUtilities::GetClusterComponent(const FString& Name)
{
#if PLATFORM_SUPPORTS_NDISPLAY
const ADisplayClusterRootActor* RootActor = IDisplayCluster::Get().GetGameMgr()->GetRootActor();
return (RootActor) ? RootActor->GetComponentByName<USceneComponent>(Name) : nullptr;
#else
return nullptr;
#endif
}
USceneComponent* URWTHVRUtilities::GetNamedClusterComponent(const ENamedClusterComponent& Component)
{
switch (Component)
{
case ENamedClusterComponent::NCC_CAVE_ORIGIN:
return GetClusterComponent("cave_origin");
case ENamedClusterComponent::NCC_CAVE_CENTER:
return GetClusterComponent("cave_center");
case ENamedClusterComponent::NCC_CAVE_LHT:
return GetClusterComponent("left_hand_target");
case ENamedClusterComponent::NCC_CAVE_RHT:
return GetClusterComponent("right_hand_target");
case ENamedClusterComponent::NCC_SHUTTERGLASSES:
return GetClusterComponent("shutter_glasses");
case ENamedClusterComponent::NCC_ROLV_ORIGIN:
return GetClusterComponent("rolv_origin");
case ENamedClusterComponent::NCC_FLYSTICK:
return GetClusterComponent("flystick");
case ENamedClusterComponent::NCC_CALIBRATIO:
return GetClusterComponent("calibratio");
case ENamedClusterComponent::NCC_TRACKING_ORIGIN:
USceneComponent* Result;
if ((Result = GetClusterComponent("cave_origin")))
return Result;
if ((Result = GetClusterComponent("rolv_origin")))
return Result;
if ((Result = GetClusterComponent("tdw_origin_floor")))
return Result;
return nullptr;
default:
return nullptr;
}
} }
void URWTHVRUtilities::ShowErrorAndQuit(UWorld* WorldContext, const FString& Message) void URWTHVRUtilities::ShowErrorAndQuit(UWorld* WorldContext, const FString& Message)
......
...@@ -6,8 +6,6 @@ ...@@ -6,8 +6,6 @@
#include "LiveLinkRole.h" #include "LiveLinkRole.h"
#include "Pawn/Navigation/CollisionHandlingMovement.h" #include "Pawn/Navigation/CollisionHandlingMovement.h"
#include "Components/DisplayClusterSceneComponentSyncParent.h"
#include "RWTHVRPawn.generated.h" #include "RWTHVRPawn.generated.h"
class UInputMappingContext; class UInputMappingContext;
...@@ -27,6 +25,8 @@ class RWTHVRTOOLKIT_API ARWTHVRPawn : public APawn ...@@ -27,6 +25,8 @@ class RWTHVRTOOLKIT_API ARWTHVRPawn : public APawn
public: public:
ARWTHVRPawn(const FObjectInitializer& ObjectInitializer); ARWTHVRPawn(const FObjectInitializer& ObjectInitializer);
virtual void BeginPlay() override;
virtual void Tick(float DeltaSeconds) override; virtual void Tick(float DeltaSeconds) override;
virtual void NotifyControllerChanged() override; virtual void NotifyControllerChanged() override;
...@@ -54,8 +54,8 @@ public: ...@@ -54,8 +54,8 @@ public:
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Pawn|Camera") UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Pawn|Camera")
UCameraComponent* HeadCameraComponent; UCameraComponent* HeadCameraComponent;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Pawn|Camera") UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Pawn")
UDisplayClusterSceneComponentSyncParent* SyncComponent; USceneComponent* SyncComponent;
// LiveLink functionality // LiveLink functionality
......
...@@ -2,7 +2,6 @@ ...@@ -2,7 +2,6 @@
#include "CoreMinimal.h" #include "CoreMinimal.h"
#include "Kismet/BlueprintFunctionLibrary.h" #include "Kismet/BlueprintFunctionLibrary.h"
#include "UObject/ConstructorHelpers.h"
#include "RWTHVRUtilities.generated.h" #include "RWTHVRUtilities.generated.h"
...@@ -12,75 +11,25 @@ ...@@ -12,75 +11,25 @@
*/ */
DECLARE_LOG_CATEGORY_EXTERN(Toolkit, Log, All); DECLARE_LOG_CATEGORY_EXTERN(Toolkit, Log, All);
UENUM(BlueprintType)
enum class ENamedClusterComponent : uint8
{
/* CAVE Specific */
NCC_CAVE_ORIGIN UMETA(DisplayName = "CAVE Origin"),
NCC_CAVE_CENTER UMETA(DisplayName = "CAVE Center"),
NCC_CAVE_LHT UMETA(DisplayName = "CAVE Left Hand Target"),
NCC_CAVE_RHT UMETA(DisplayName = "CAVE Right Hand Target"),
/* ROLV Specific */
NCC_ROLV_ORIGIN UMETA(DisplayName = "ROLV Origin"),
/* Non Specific */
NCC_CALIBRATIO UMETA(DisplayName = "Calibratio Motion to Photon Measurement Device"),
NCC_SHUTTERGLASSES UMETA(DisplayName = "CAVE/ROLV/TDW Shutter Glasses"),
NCC_FLYSTICK UMETA(DisplayName = "CAVE/ROLV/TDW Flystick"),
NCC_TRACKING_ORIGIN UMETA(DisplayName = "CAVE/ROLV/TDW Origin")
};
UENUM()
enum class EEyeStereoOffset
{
None,
Left,
Right
};
UCLASS() UCLASS()
class RWTHVRTOOLKIT_API URWTHVRUtilities : public UBlueprintFunctionLibrary class RWTHVRTOOLKIT_API URWTHVRUtilities : public UBlueprintFunctionLibrary
{ {
GENERATED_BODY() GENERATED_BODY()
public: public:
UFUNCTION(BlueprintPure, Category = "DisplayCluster|Platform") UFUNCTION(BlueprintPure, Category = "RWTHVRToolkit|Platform")
static bool IsDesktopMode(); static bool IsDesktopMode();
UFUNCTION(BlueprintPure, Category = "DisplayCluster|Platform") UFUNCTION(BlueprintPure, Category = "RWTHVRToolkit|Platform")
static bool IsRoomMountedMode();
UFUNCTION(BlueprintPure, Category = "DisplayCluster|Platform")
static bool IsHeadMountedMode(); static bool IsHeadMountedMode();
UFUNCTION(BlueprintPure, Category = "DisplayCluster|Platform") UFUNCTION(BlueprintPure, Category = "RWTHVRToolkit|Platform")
static bool IsCave(); static bool IsRoomMountedMode();
UFUNCTION(BlueprintPure, Category = "DisplayCluster|Platform") UFUNCTION(BlueprintPure, Category = "RWTHVRToolkit|Platform")
static bool IsRolv();
UFUNCTION(BlueprintPure, Category = "DisplayCluster")
static bool IsPrimaryNode(); static bool IsPrimaryNode();
UFUNCTION(BlueprintPure, Category = "DisplayCluster")
static bool IsSecondaryNode();
UFUNCTION(BlueprintPure, Category = "DisplayCluster")
static FString GetNodeName();
/* Distance in meters */ /* Distance in meters */
UFUNCTION(BlueprintPure, Category = "DisplayCluster") UFUNCTION(BlueprintPure, Category = "RWTHVRToolkit")
static float GetEyeDistance(); static float GetEyeDistance();
UFUNCTION(BlueprintPure, Category = "DisplayCluster")
static EEyeStereoOffset GetNodeEyeType();
static void ShowErrorAndQuit(const FString& Message, bool ShouldQuit, const UObject* WorldContext);
// Get Component of Display Cluster by it's name, which is specified in the nDisplay config
UE_DEPRECATED(5.4, "GetClusterComponent has been removed because it is obsolete.")
UFUNCTION(BlueprintPure, BlueprintCallable, Category = "DisplayCluster", meta = (DeprecatedFunction))
static USceneComponent* GetClusterComponent(const FString& Name);
UE_DEPRECATED(5.4, "GetNamedClusterComponent has been removed because it is obsolete.")
UFUNCTION(BlueprintPure, BlueprintCallable, Category = "DisplayCluster", meta = (DeprecatedFunction))
static USceneComponent* GetNamedClusterComponent(const ENamedClusterComponent& Component);
UFUNCTION(BlueprintCallable) UFUNCTION(BlueprintCallable)
static void ShowErrorAndQuit(UWorld* WorldContext, const FString& Message); static void ShowErrorAndQuit(UWorld* WorldContext, const FString& Message);
}; };
...@@ -50,14 +50,22 @@ public class RWTHVRToolkit : ModuleRules ...@@ -50,14 +50,22 @@ public class RWTHVRToolkit : ModuleRules
new string[]{} new string[]{}
); );
if(Target.Platform == UnrealTargetPlatform.Win64 || Target.Platform == UnrealTargetPlatform.Linux) if (IsPluginEnabledForTarget("RWTHVRCluster", base.Target))
{ {
PublicDependencyModuleNames.Add("DisplayCluster"); PrivateDependencyModuleNames.Add("RWTHVRCluster");
PublicDefinitions.Add("PLATFORM_SUPPORTS_NDISPLAY=1"); PrivateDependencyModuleNames.Add("DisplayCluster");
PublicDefinitions.Add("PLATFORM_SUPPORTS_CLUSTER=1");
} }
else else
{ {
PublicDefinitions.Add("PLATFORM_SUPPORTS_NDISPLAY=0"); PublicDefinitions.Add("PLATFORM_SUPPORTS_CLUSTER=0");
} }
} }
private static bool IsPluginEnabledForTarget(string PluginName, ReadOnlyTargetRules Target)
{
var PL = Plugins.GetPlugin(PluginName);
return PL != null && Target.ProjectFile != null && Plugins.IsPluginEnabledForTarget(PL,
ProjectDescriptor.FromFile(Target.ProjectFile), Target.Platform, Target.Configuration, Target.Type);
}
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment