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
No related branches found
No related tags found
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