Skip to content
Snippets Groups Projects
Commit b0060790 authored by Simon Oehrl's avatar Simon Oehrl
Browse files

Merge branch 'release/4.22.2'

parents 13607574 b4e2c84e
Branches
Tags
No related merge requests found
Showing
with 1177 additions and 50 deletions
// Fill out your copyright notice in the Description page of Project Settings.
#include "Clickable.h"
UClickable::UClickable(const FObjectInitializer& ObjectInitializer)
:Super(ObjectInitializer)
{}
// Fill out your copyright notice in the Description page of Project Settings.
#include "Grabable.h"
// to avoid some bugs
UGrabable::UGrabable(const FObjectInitializer& ObjectInitializer)
:Super(ObjectInitializer)
{}
// Fill out your copyright notice in the Description page of Project Settings.
#include "GrabbingBehaviorComponent.h"
// Sets default values for this component's properties
UGrabbingBehaviorComponent::UGrabbingBehaviorComponent()
{
// Set this component to be initialized when the game starts, and to be ticked every frame. You can turn these features
// off to improve performance if you don't need them.
PrimaryComponentTick.bCanEverTick = true;
// ...
}
// Called when the game starts
void UGrabbingBehaviorComponent::BeginPlay()
{
Super::BeginPlay();
// ...
}
// Called every frame
void UGrabbingBehaviorComponent::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
{
Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
// ...
}
// Fill out your copyright notice in the Description page of Project Settings.
#include "GrabbingBehaviorOnLineComponent.h"
// Sets default values for this component's properties
UGrabbingBehaviorOnLineComponent::UGrabbingBehaviorOnLineComponent()
{
// Set this component to be initialized when the game starts, and to be ticked every frame. You can turn these features
// off to improve performance if you don't need them.
PrimaryComponentTick.bCanEverTick = true;
bAbsoluteLocation = true;
bAbsoluteRotation = true;
bAbsoluteScale = true;
this->Distance = 0;
}
void UGrabbingBehaviorOnLineComponent::SetDistance(float Dist)
{
check(Dist > 0 && "max distance has to be greater than 0");
this->Distance = Dist;
}
float UGrabbingBehaviorOnLineComponent::GetDistance() const
{
return this->Distance;
}
void UGrabbingBehaviorOnLineComponent::HandleNewPositionAndDirection(FVector Position, FQuat Orientation)
{
FVector AttachmentPoint = this->RelativeLocation;
FVector ConstraintAxis = this->GetComponentQuat().GetUpVector();
FVector Direction = Orientation.GetForwardVector();
FVector FromHandToMe = -Position + AttachmentPoint;
// Vector perpendicular to both points
FVector Temp = FVector::CrossProduct(FromHandToMe, ConstraintAxis);
Temp.Normalize();
FVector PlaneNormal = FVector::CrossProduct(ConstraintAxis,Temp);
// get intersection point defined by plane
FVector Intersection = FMath::LinePlaneIntersection(Position, Position + Direction, AttachmentPoint, PlaneNormal);
FVector FromOriginToIntersection = Intersection - AttachmentPoint;
// point along the constraint axis with length of the projection from intersection point onto the axis
FVector NewPosition = FVector::DotProduct(FromOriginToIntersection, ConstraintAxis)* ConstraintAxis;
NewPosition = NewPosition.GetClampedToMaxSize(Distance);
NewPosition += AttachmentPoint;
// transform the targeted actor which is owner of this component with calculated quaternion and posiition
// here rotation is not changed
GetOwner()->SetActorLocation(NewPosition);
}
// Called when the game starts
void UGrabbingBehaviorOnLineComponent::BeginPlay()
{
Super::BeginPlay();
// ...
}
// Called every frame
void UGrabbingBehaviorOnLineComponent::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
{
Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
}
// Fill out your copyright notice in the Description page of Project Settings.
//TODO rename distance to maxDistance
#include "GrabbingBehaviorOnPlaneComponent.h"
// Sets default values for this component's properties
UGrabbingBehaviorOnPlaneComponent::UGrabbingBehaviorOnPlaneComponent()
{
// Set this component to be initialized when the game starts, and to be ticked every frame. You can turn these features
// off to improve performance if you don't need them.
PrimaryComponentTick.bCanEverTick = true;
bAbsoluteLocation = true;
bAbsoluteRotation = true;
bAbsoluteScale = true;
// ...
}
void UGrabbingBehaviorOnPlaneComponent::SetDistance(float Dist)
{
check(Dist > 0 && "max distance has to be greater than 0");
this->Distance = Dist;
}
float UGrabbingBehaviorOnPlaneComponent::GetDistance() const
{
return this->Distance;
}
void UGrabbingBehaviorOnPlaneComponent::HandleNewPositionAndDirection(FVector Position, FQuat Orientation)
{
FVector AttachmentPoint = this->RelativeLocation;
FVector PlaneNormal = this->GetComponentQuat().GetUpVector();
FVector Direction = Orientation.GetForwardVector();
// calculate point on plane which is pointed to by hand ray
FVector Intersection = FMath::LinePlaneIntersection(Position, Position + Direction, AttachmentPoint, PlaneNormal);
FVector NewPosition = -AttachmentPoint + Intersection;
// clamp size by maxDistance
NewPosition = NewPosition.GetClampedToMaxSize(Distance);
// after this NewPoint is in world position
NewPosition += AttachmentPoint;
// set new position and orientation using calculated quaternion and position
// here rotation is not changed
GetOwner()->SetActorLocation(NewPosition);
}
// Called when the game starts
void UGrabbingBehaviorOnPlaneComponent::BeginPlay()
{
Super::BeginPlay();
// ...
}
// Called every frame
void UGrabbingBehaviorOnPlaneComponent::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
{
Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
// ...
}
......@@ -20,6 +20,20 @@ bool UVirtualRealityUtilities::IsHeadMountedMode()
return GEngine->XRSystem.IsValid() && GEngine->XRSystem->IsHeadTrackingAllowed();
}
bool UVirtualRealityUtilities::IsMaster()
{
IDisplayClusterClusterManager* manager = IDisplayCluster::Get().GetClusterMgr();
if (manager == nullptr) // no manager means we are not in clustermode and therefore master
return true;
return manager->IsMaster();
}
bool UVirtualRealityUtilities::IsSlave()
{
return !IsMaster();
}
FString UVirtualRealityUtilities::GetNodeName()
{
return IsRoomMountedMode() ? IDisplayCluster::Get().GetClusterMgr()->GetNodeId() : FString(TEXT("Localhost"));
......
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Object.h"
#include "UObject/Interface.h"
#include "Clickable.generated.h"
UINTERFACE(BlueprintType)
class DISPLAYCLUSTEREXTENSIONS_API UClickable : public UInterface
{
// has to be empty, this is Unreals syntax to make it visible in blueprints
GENERATED_UINTERFACE_BODY()
};
class IClickable
{
GENERATED_IINTERFACE_BODY()
public:
// function that will be called when clickable actor got clicked, and passed the world pos of the click
UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = Gameplay)
void OnClicked(FVector WorldPositionOfClick);
};
#pragma once
#include "Serialization/MemoryReader.h"
#include "Serialization/MemoryWriter.h"
// Helper function to put the arguments into a string map. It uses template substitution to choose the correct specialization.
template <typename... Values>
struct FillParameterMapImpl;
// This specialization is chosen when there no argument left to serialize.
template <>
struct FillParameterMapImpl<>
{
template <int ArgumentIndex>
static inline void Invoke(TMap<FString, FString>*)
{
// There is nothing left to do here.
}
};
// This specialization is chosen when there is at least one argument left to serialize.
template <typename CurrentValueType, typename... RemainingValueTypes>
struct FillParameterMapImpl<CurrentValueType, RemainingValueTypes...>
{
template <int ArgumentIndex>
static inline void Invoke(
TMap<FString, FString>* ParameterMap, const CurrentValueType& CurrentValue, RemainingValueTypes&&... RemainingValues)
{
// If this assertion fails: implement the workaround described below!
static_assert(sizeof(TCHAR) > sizeof(uint8), "TCHAR needs to have extra room!");
TArray<uint8> SerializedValue;
// TODO: maybe it is a good idea to guess the amount of bytes the serialized value will have. This would probably reduce the
// number of reallocations in the serialization process. However, I don't know if this is already taken care of in the
// FArchive class. Also it is hard to implement correctly, so we have to see whether it is worth it.
FMemoryWriter writer(SerializedValue);
// Const cast is necessary here because the "<<" operator is used for reading and writing and thus does not take a const
// argument. However, it should be fine as, hopefully, the "<<" operator doesn't modify the value in "reading mode".
auto NonConstCurrentValue = const_cast<CurrentValueType&>(CurrentValue);
writer << NonConstCurrentValue;
// We have an array of bytes. Now we need to convert them to a string.
FString SerializedDataString;
SerializedDataString.Empty(SerializedValue.Num()); // Preallocate memory to avoid reallocations.
for (const uint8 Byte : SerializedValue)
{
// This is potentially dangerous:
// We treat the individual bytes as characters in a string. The character with the value 0 is normally used to mark the
// end of the string. Because of this, FString will not add zero values to the underlying data array. To avoid this I
// add 1 to every value. This only works, because the TCHAR is usually more than one byte long. However, this is not
// guaranteed. Currently I enforce it with a static_assert above. If this is not the case we would need to split each
// byte into two characters. Another option would be to access the underlying TCHAR array directly. However I don't know
// if they are transported correctly using the cluster events.
SerializedDataString += static_cast<TCHAR>(static_cast<TCHAR>(Byte) + 1);
}
ParameterMap->Add(FString::FromInt(ArgumentIndex), SerializedDataString);
// Recursive call for the remaining values.
FillParameterMapImpl<RemainingValueTypes...>::template Invoke<ArgumentIndex + 1>(
ParameterMap, Forward<RemainingValueTypes>(RemainingValues)...);
}
};
// This function creates a string map with the arguments it gets passed. The resulting map will contain an entry for every argument.
// The first argument will have the key "0", the second "1" and so on.
template <typename... ArgTypes>
inline TMap<FString, FString> CreateParameterMap(ArgTypes&&... Arguments)
{
TMap<FString, FString> ParameterMap;
ParameterMap.Empty(sizeof...(ArgTypes)); // Preallocate to avoid allocations.
FillParameterMapImpl<ArgTypes...>::template Invoke<0>(&ParameterMap, Forward<ArgTypes>(Arguments)...);
return ParameterMap;
}
// 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(
TTuple<ArgTypes...>* ArgumentTuple, const TMap<FString, FString>& Parameters)
{
const FString& SerializedDataString = Parameters[FString::FromInt(CurrentIndex)];
TArray<uint8> SerializedData;
// Preallocate to avoid reallocation
SerializedData.Empty(SerializedDataString.Len());
// Reconstruct the original bytes. I.e., reversing the addition by one.
for (const auto Character : SerializedDataString)
{
SerializedData.Add(static_cast<uint8>(Character - 1));
}
FMemoryReader Reader(SerializedData);
// 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.
Reader << ArgumentTuple->template Get<CurrentIndex>();
// Recursive call for the remaining attributes.
FillArgumentTuple<CurrentIndex + 1>(
Forward<TTuple<ArgTypes...>*>(ArgumentTuple), Forward<const TMap<FString, FString>&>(Parameters));
}
// 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(
TTuple<ArgTypes...>* ArgumentTuple, const TMap<FString, FString>& Parameters)
{
}
template <typename RetType, typename... ArgTypes>
inline RetType CallDelegateWithParameterMap(
const TBaseDelegate<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 TRemoveCV<typename TRemoveReference<ArgTypes>::Type>::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 "IDisplayClusterClusterManager.h"
#include "Cluster/DisplayClusterClusterEvent.h"
#include "DisplayClusterEventParameterHelper.h"
#include "Templates/IsInvocable.h"
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, AActor>::IsDerived, "Object needs to derive from AActor");
public:
using MemberFunctionType = decltype(MemberFunction);
ClusterEventWrapperEvent(const TCHAR* EventTypeName) : EventTypeName{EventTypeName}
{
}
void Attach(ObjectType* NewObject)
{
IDisplayClusterClusterManager* ClusterManager = IDisplayCluster::Get().GetClusterMgr();
check(ClusterManager != nullptr);
checkf(Object == nullptr, TEXT("The event is already attached."));
Object = NewObject;
ObjectName = AActor::GetDebugName(Object);
if (!ClusterManager->IsStandalone())
{
check(!ClusterEventListenerDelegate.IsBound());
ClusterEventListenerDelegate = FOnClusterEventListener::CreateLambda([this](const FDisplayClusterClusterEvent& Event) {
if (Event.Type == EventTypeName && Event.Name == ObjectName)
{
// 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 TRemoveCV<typename TRemoveReference<ArgTypes>::Type>::Type...> ArgumentTuple;
// This call will parse the string map and fill all values in the
// tuple appropriately.
FillArgumentTuple<0>(&ArgumentTuple, Event.Parameters);
ArgumentTuple.ApplyBefore([this](const ArgTypes&... Arguments) {
(Object->*MemberFunction)(Forward<const ArgTypes&>(Arguments)...);
});
}
});
ClusterManager->AddClusterEventListener(ClusterEventListenerDelegate);
}
}
void Detach()
{
checkf(Object != nullptr, TEXT("The event was never attached."));
IDisplayClusterClusterManager* ClusterManager = IDisplayCluster::Get().GetClusterMgr();
check(ClusterManager != nullptr);
if (!ClusterManager->IsStandalone())
{
// check(ClusterEventListenerDelegate.IsBound());
ClusterManager->RemoveClusterEventListener(ClusterEventListenerDelegate);
}
}
void Send(ArgTypes&&... Arguments)
{
IDisplayClusterClusterManager* ClusterManager = IDisplayCluster::Get().GetClusterMgr();
check(ClusterManager != nullptr);
checkf(Object != nullptr, TEXT("The event was not attached."));
if (ClusterManager->IsStandalone())
{
(Object->*MemberFunction)(Forward<ArgTypes>(Arguments)...);
}
else
{
FDisplayClusterClusterEvent ClusterEvent;
ClusterEvent.Category = "DisplayClusterEventWrapper";
ClusterEvent.Type = EventTypeName;
ClusterEvent.Name = ObjectName;
ClusterEvent.Parameters = CreateParameterMap(Forward<ArgTypes>(Arguments)...);
ClusterManager->EmitClusterEvent(ClusterEvent, true);
}
}
private:
const TCHAR* EventTypeName;
ObjectType* Object = nullptr;
FString ObjectName;
FOnClusterEventListener 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)) \
}
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Object.h"
#include "UObject/Interface.h"
#include "Grabable.generated.h"
UINTERFACE(BlueprintType)
class DISPLAYCLUSTEREXTENSIONS_API UGrabable : public UInterface
{
// has to be empty, this is Unreals syntax to make it visible in blueprints
GENERATED_UINTERFACE_BODY()
};
class IGrabable
{
GENERATED_IINTERFACE_BODY()
public:
// function that will be called when grabbed by a pawn
UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = Gameplay)
void OnGrabbed();
// called when pawn released the object
UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = Gameplay)
void OnReleased();
};
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Components/SceneComponent.h"
#include "GrabbingBehaviorComponent.generated.h"
UCLASS(Abstract, ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
class DISPLAYCLUSTEREXTENSIONS_API UGrabbingBehaviorComponent : public USceneComponent
{
GENERATED_BODY()
public:
// Sets default values for this component's properties
UGrabbingBehaviorComponent();
// takes the hand ray and moves the parent actor to a new possible position, also might change rotation
virtual void HandleNewPositionAndDirection(FVector position, FQuat orientation) PURE_VIRTUAL(UGrabbingBehaviorComponent::GeneratePossiblePosition,);
protected:
// Called when the game starts
virtual void BeginPlay() override;
public:
// Called every frame
virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;
};
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "GrabbingBehaviorComponent.h"
#include "GrabbingBehaviorOnLineComponent.generated.h"
UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
class DISPLAYCLUSTEREXTENSIONS_API UGrabbingBehaviorOnLineComponent : public UGrabbingBehaviorComponent
{
GENERATED_BODY()
public:
// Sets default values for this component's properties
UGrabbingBehaviorOnLineComponent();
// defining a constraint line with these 3 parameters
UFUNCTION(BlueprintCallable) void SetDistance(float Dist);
UFUNCTION(BlueprintCallable) float GetDistance() const;
virtual void HandleNewPositionAndDirection(FVector position, FQuat orientation) override;
protected:
// Called when the game starts
virtual void BeginPlay() override;
public:
// Called every frame
virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;
private:
UPROPERTY(EditAnywhere) float Distance; // distance the object can be moved from the center
};
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "GrabbingBehaviorComponent.h"
#include "GrabbingBehaviorOnPlaneComponent.generated.h"
UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
class DISPLAYCLUSTEREXTENSIONS_API UGrabbingBehaviorOnPlaneComponent : public UGrabbingBehaviorComponent
{
GENERATED_BODY()
public:
// Sets default values for this component's properties
UGrabbingBehaviorOnPlaneComponent();
// defining the constraint plane with these 3 parameters
UFUNCTION(BlueprintCallable) void SetDistance(float Dist);
UFUNCTION(BlueprintCallable) float GetDistance() const;
virtual void HandleNewPositionAndDirection(FVector position, FQuat orientation) override;
protected:
// Called when the game starts
virtual void BeginPlay() override;
public:
// Called every frame
virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;
private:
UPROPERTY(EditAnywhere) float Distance; // distance the object can be moved from the center
};
......@@ -5,9 +5,11 @@
#include "Cluster/IDisplayClusterClusterManager.h"
#include "DisplayClusterPawn.h"
#include "DisplayClusterSceneComponent.h"
#include "Components/CapsuleComponent.h"
#include "GameFramework/FloatingPawnMovement.h"
#include "GameFramework/PawnMovementComponent.h"
#include "GameFramework/RotatingMovementComponent.h"
#include "MotionControllerComponent.h"
#include "VirtualRealityPawn.generated.h"
......@@ -15,6 +17,7 @@ UENUM(BlueprintType)
enum class EVRNavigationModes : uint8
{
nav_mode_none UMETA(DisplayName = "Navigation Mode None"),
nav_mode_walk UMETA(DisplayName = "Navigation Mode Walk"),
nav_mode_fly UMETA(DisplayName = "Navigation Mode Fly")
};
......@@ -36,8 +39,8 @@ public:
UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "Pawn") void OnRight(float Value);
UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "Pawn") void OnTurnRate(float Rate);
UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "Pawn") void OnLookUpRate(float Rate);
UFUNCTION(BlueprintNativeEvent, BlueprintCallable, BlueprintCallable, Category = "Pawn") void OnFire(bool Pressed);
UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "Pawn") void OnAction(bool Pressed, int32 Index);
UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "Pawn") void OnBeginFire();
UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "Pawn") void OnEndFire();
UFUNCTION(Category = "Pawn") float GetBaseTurnRate() const;
UFUNCTION(Category = "Pawn") void SetBaseTurnRate(float Value);
......@@ -50,29 +53,32 @@ public:
UFUNCTION(Category = "Pawn") UDisplayClusterSceneComponent* GetLeftHandtargetComponent();
UFUNCTION(Category = "Pawn") UMotionControllerComponent* GetHmdLeftMotionControllerComponent();
UFUNCTION(Category = "Pawn") UMotionControllerComponent* GetHmdRightMotionControllerComponent();
UFUNCTION(Category = "Pawn") UMotionControllerComponent* GetHmdTracker1MotionControllerComponent();
UFUNCTION(Category = "Pawn") UMotionControllerComponent* GetHmdTracker2MotionControllerComponent();
UFUNCTION(Category = "Pawn") USceneComponent* GetHeadComponent();
UFUNCTION(Category = "Pawn") USceneComponent* GetLeftHandComponent();
UFUNCTION(Category = "Pawn") USceneComponent* GetRightHandComponent();
UFUNCTION(Category = "Pawn") USceneComponent* GetTrackingOriginComponent();
private:
UFUNCTION(Category = "Pawn") USceneComponent* GetCaveCenterComponent();
UFUNCTION(Category = "Pawn") USceneComponent* GetShutterGlassesComponent();
UFUNCTION(Category = "Pawn") FTwoVectors GetHandRay(float Distance);
UFUNCTION(Category = "Pawn") void HandlePhysicsAndAttachActor(AActor* HitActor);
public:
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Pawn") EVRNavigationModes NavigationMode = EVRNavigationModes::nav_mode_fly;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Pawn") float MaxStepHeight = 40.0f;
//Execute specified console command on all nDisplayCluster Nodes
UFUNCTION(Exec, BlueprintCallable, Category = "DisplayCluster") static void ClusterExecute(const FString& Command);
private:
FOnClusterEventListener ClusterEventListenerDelegate;
UFUNCTION() void HandleClusterEvent(const FDisplayClusterClusterEvent& Event);
protected:
DECLARE_DELEGATE_OneParam(FFireDelegate, bool);
DECLARE_DELEGATE_TwoParams(FActionDelegate, bool, int32);
virtual void BeginPlay() override;
virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
......@@ -92,9 +98,13 @@ protected:
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Pawn", meta = (AllowPrivateAccess = "true")) UDisplayClusterSceneComponent* LeftHandTarget = nullptr;
// Use only when handling cross-device (PC, HMD, CAVE/ROLV) compatibility manually. HMD left motion controller.
UMotionControllerComponent* HmdLeftMotionController = nullptr;
UPROPERTY() UMotionControllerComponent* HmdLeftMotionController = nullptr;
// Use only when handling cross-device (PC, HMD, CAVE/ROLV) compatibility manually. HMD right motion controller.
UMotionControllerComponent* HmdRightMotionController = nullptr;
UPROPERTY() UMotionControllerComponent* HmdRightMotionController = nullptr;
// used only for HMDs, tested with the additional Vive Trackers
UPROPERTY() UMotionControllerComponent* HmdTracker1 = nullptr;
UPROPERTY() UMotionControllerComponent* HmdTracker2 = nullptr;
// PC: Camera, HMD: Camera, CAVE/ROLV: Shutter glasses.
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Pawn", meta = (AllowPrivateAccess = "true")) USceneComponent* Head = nullptr;
......@@ -110,10 +120,33 @@ protected:
// Holding the Shutter Glasses Component that is attached to this Pawn
UPROPERTY() USceneComponent* ShutterGlasses = nullptr;
// Holding a reference to the actor that is currently being grabbed
UPROPERTY() AActor* GrabbedActor;
// indicates if the grabbed actor was simulating physics before we grabbed it
UPROPERTY() bool bDidSimulatePhysics;
UPROPERTY(EditAnywhere) float MaxGrabDistance = 50;
UPROPERTY(EditAnywhere) float MaxClickDistance = 500;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Pawn") bool ShowHMDControllers = true;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Pawn") EAttachementType AttachRightHandInCAVE = EAttachementType::AT_FLYSTICK;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Pawn") EAttachementType AttachLeftHandInCAVE = EAttachementType::AT_NONE;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Pawn", meta = (AllowPrivateAccess = "true")) UCapsuleComponent* CapsuleColliderComponent = nullptr;
private:
float DeltaTime = 0.0f;
float VerticalSpeed = 0.0f;
UPROPERTY() float GravityAcceleration = 981.0f;
UPROPERTY() float UpSteppingAcceleration = 500.0f;
FVector LastCameraPosition;
FHitResult CreateLineTrace(FVector Direction, const FVector Start, bool Visibility);
FHitResult CreateMultiLineTrace(FVector Direction, const FVector Start, float Radius, bool Visibility);
void SetCapsuleColliderCharacterSizeVR();
void CheckForPhysWalkingCollision();
void HandleMovementInput(float Value, FVector Direction);
void VRWalkingMode(float Value, FVector Direction);
void VRFlyingMode(float Value, FVector Direction);
void MoveByGravityOrStepUp(float DeltaSeconds);
void ShiftVertically(float DiffernceDistance, float Acceleration, float DeltaSeconds, int Direction);//(direction = Down = -1), (direction = Up = 1)
void InitRoomMountedComponentReferences();
};
......@@ -23,6 +23,9 @@ public:
UFUNCTION(BlueprintPure, Category = "DisplayCluster") static bool IsRoomMountedMode();
UFUNCTION(BlueprintPure, Category = "DisplayCluster") static bool IsHeadMountedMode();
UFUNCTION(BlueprintPure, Category = "DisplayCluster") static bool IsMaster();
UFUNCTION(BlueprintPure, Category = "DisplayCluster") static bool IsSlave();
UFUNCTION(BlueprintPure, Category = "DisplayCluster") static FString GetNodeName();
UFUNCTION(BlueprintPure, Category = "DisplayCluster") static float GetEyeDistance();
......
using UnrealBuildTool;
public class DisplayClusterExtensionsEditor : ModuleRules
{
public DisplayClusterExtensionsEditor(ReadOnlyTargetRules Target) : base(Target)
{
PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
PublicDependencyModuleNames.AddRange(
new string[]
{
"Core",
"CoreUObject",
"DisplayCluster",
"Engine",
"UnrealEd",
"ComponentVisualizers",
"HeadMountedDisplay",
"InputCore",
"DisplayClusterExtensions"
// ... add public dependencies that you statically link with here ...
}
);
PrivateDependencyModuleNames.AddRange(
new string[]
{
// ... add private dependencies that you statically link with here ...
}
);
PublicIncludePaths.AddRange(
new string[]
{
// ... add private dependencies that you statically link with here ...
}
);
PrivateIncludePaths.AddRange(
new string[]
{
// ... add private dependencies that you statically link with here ...
}
);
}
}
\ No newline at end of file
#include "DisplayClusterExtensionsEditor.h"
#include "ComponentVisualizers.h"
#include "GrabbingBehaviorOnLineVisualizer.h"
#include "GrabbingBehaviorPlaneVisualizer.h"
#include "GrabbingBehaviorOnPlaneComponent.h"
#include "GrabbingBehaviorOnLineComponent.h"
#include "UnrealEdGlobals.h"
#include "Editor/UnrealEdEngine.h"
IMPLEMENT_GAME_MODULE(FDisplayClusterExtensionsEditorModule, DisplayClusterExtensionsEditor);
#define LOCTEXT_NAMESPACE "DisplayClusterExtensionsEdito"
void FDisplayClusterExtensionsEditorModule::StartupModule()
{
if (GUnrealEd != NULL)
{
TSharedPtr<FComponentVisualizer> LineVisualizer = MakeShareable(new FGrabbingBehaviorOnLineVisualizer());
if (LineVisualizer.IsValid())
{
GUnrealEd->RegisterComponentVisualizer(UGrabbingBehaviorOnLineComponent::StaticClass()->GetFName(), LineVisualizer);
LineVisualizer->OnRegister();
}
TSharedPtr<FComponentVisualizer> PlaneVisualizer = MakeShareable(new FGrabbingBehaviorPlaneVisualizer());
if (PlaneVisualizer.IsValid())
{
GUnrealEd->RegisterComponentVisualizer(UGrabbingBehaviorOnPlaneComponent::StaticClass()->GetFName(), PlaneVisualizer);
PlaneVisualizer->OnRegister();
}
}
}
void FDisplayClusterExtensionsEditorModule::ShutdownModule()
{
if (GUnrealEd != NULL)
{
GUnrealEd->UnregisterComponentVisualizer(UGrabbingBehaviorOnLineComponent::StaticClass()->GetFName());
GUnrealEd->UnregisterComponentVisualizer(UGrabbingBehaviorOnPlaneComponent::StaticClass()->GetFName());
}
}
#undef LOCTEXT_NAMESPACE
\ No newline at end of file
// Fill out your copyright notice in the Description page of Project Settings.
#include "GrabbingBehaviorOnLineVisualizer.h"
#include "GrabbingBehaviorOnLineComponent.h"
#include "SceneManagement.h"
FGrabbingBehaviorOnLineVisualizer::FGrabbingBehaviorOnLineVisualizer()
{
}
FGrabbingBehaviorOnLineVisualizer::~FGrabbingBehaviorOnLineVisualizer()
{
}
// Fill out your copyright notice in the Description page of Project Settings.
void FGrabbingBehaviorOnLineVisualizer::DrawVisualization(const UActorComponent* Component, const FSceneView* View, FPrimitiveDrawInterface* PDI) {
const UGrabbingBehaviorOnLineComponent* LineBehavior = Cast<const UGrabbingBehaviorOnLineComponent>(Component);
if (LineBehavior != nullptr)
{
FVector Attachment = LineBehavior->GetComponentLocation();
FVector Forward = LineBehavior->GetComponentQuat().GetUpVector();
float Distance = LineBehavior->GetDistance();
PDI->DrawLine(Attachment + Forward * Distance, Attachment - Forward * Distance, FColor::Blue, SDPG_World);
}
}
// Fill out your copyright notice in the Description page of Project Settings.
#include "GrabbingBehaviorPlaneVisualizer.h"
#include "GrabbingBehaviorOnPlaneComponent.h"
#include "SceneManagement.h"
FGrabbingBehaviorPlaneVisualizer::FGrabbingBehaviorPlaneVisualizer()
{
}
FGrabbingBehaviorPlaneVisualizer::~FGrabbingBehaviorPlaneVisualizer()
{
}
void FGrabbingBehaviorPlaneVisualizer::DrawVisualization(const UActorComponent* Component, const FSceneView* View, FPrimitiveDrawInterface* PDI) {
const UGrabbingBehaviorOnPlaneComponent* PlaneBehavior = Cast<const UGrabbingBehaviorOnPlaneComponent>(Component);
if (PlaneBehavior != nullptr)
{
FVector Attachment = PlaneBehavior->GetComponentLocation();
FVector Forward = PlaneBehavior->GetComponentQuat().GetUpVector();
FVector Right = PlaneBehavior->GetComponentQuat().GetRightVector();
FVector Next;
Right.Normalize();
float Distance = PlaneBehavior->GetDistance();
int Segments = 60;
check(360% Segments == 0 && "circle cannot be divided equally");
for (int i = 1; i < Segments + 1; i++) // draw circle using lines
{
Next = Right.RotateAngleAxis(360/Segments, Forward);
PDI->DrawLine(Attachment + Right*Distance,Attachment + Next*Distance, FColor::Blue, SDPG_World);
Right = Next;
}
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment