diff --git a/Content/CalibratioMaterial.uasset b/Content/CalibratioMaterial.uasset index c1ff5f0bd9e92786b74edd76e5ca51ee81db1413..2e55c4426b31579da3d6554eaf715d7b7ebaaed1 100644 Binary files a/Content/CalibratioMaterial.uasset and b/Content/CalibratioMaterial.uasset differ diff --git a/Content/CalibratioOldHud.uasset b/Content/CalibratioOldHud.uasset new file mode 100644 index 0000000000000000000000000000000000000000..ebda68e6f63df4a147f3ae9671626c94f247671c Binary files /dev/null and b/Content/CalibratioOldHud.uasset differ diff --git a/Source/Calibratio/Private/Calibratio.cpp b/Source/Calibratio/Private/Calibratio.cpp index 1360332ccfe01cef30d9fb1c1f7c2bbe0e968d67..43821ad5346344c7e9084160b0fbf6de0181fab9 100644 --- a/Source/Calibratio/Private/Calibratio.cpp +++ b/Source/Calibratio/Private/Calibratio.cpp @@ -1,7 +1,11 @@ #include "Calibratio.h" + +#include "CalibratioOldActor.h" +#include "FlickerTester.h" #include "Kismet/GameplayStatics.h" #include "IDisplayCluster.h" #include "Cluster/DisplayClusterClusterEvent.h" +#include <Misc/DefaultValueHelper.h> #define LOCTEXT_NAMESPACE "FCalibratioModule" @@ -75,8 +79,8 @@ CurrentViewMode FCalibratioModule::GetCurrentViewMode(const APlayerController *P void FCalibratioModule::StartupModule () { - /* Registering console command */ - CalibratioConsoleCommand = IConsoleManager::Get().RegisterConsoleCommand(TEXT("Calibratio"), TEXT("Spawn an instance of calibratio"), + /* Registering console commands */ + CalibratioConsoleCommand = IConsoleManager::Get().RegisterConsoleCommand(TEXT("Calibratio"), TEXT("Spawn an instance of Calibratio V2"), FConsoleCommandWithArgsDelegate::CreateLambda([](const TArray< FString >&) { if(IsRoomMountedMode()){ @@ -89,6 +93,36 @@ void FCalibratioModule::StartupModule () SpawnCalibratio(); } })); + CalibratioConsoleCommand = IConsoleManager::Get().RegisterConsoleCommand(TEXT("CalibratioOld"), TEXT("Spawn an instance of Calibratio V1"), + FConsoleCommandWithArgsDelegate::CreateLambda([](const TArray< FString >&) + { + if(IsRoomMountedMode()){ + /* Emitting cluster event to spawn on all nodes in sync*/ + FDisplayClusterClusterEventJson ClusterEvent; + ClusterEvent.Name = "CalibratioOldSpawn"; + ClusterEvent.Category = "CalibratioSpawner"; + IDisplayCluster::Get().GetClusterMgr()->EmitClusterEventJson(ClusterEvent, false); + } else { + SpawnCalibratioOld(); + } + })); + FlickerTestConsoleCommand = IConsoleManager::Get().RegisterConsoleCommand(TEXT("FlickerTester"), TEXT("Spawn an instance of the ScreenFlickerTester with X Y Z offset"), + FConsoleCommandWithArgsDelegate::CreateLambda([](const TArray< FString >& param) + { + if(param.Num() != 3) return; + if(IsRoomMountedMode()){ + /* Emitting cluster event to spawn on all nodes in sync*/ + FDisplayClusterClusterEventJson ClusterEvent; + ClusterEvent.Name = "FlickerTester"; + ClusterEvent.Category = "CalibratioSpawner"; + ClusterEvent.Parameters.Add("X", param[0]); + ClusterEvent.Parameters.Add("Y", param[1]); + ClusterEvent.Parameters.Add("Z", param[2]); + IDisplayCluster::Get().GetClusterMgr()->EmitClusterEventJson(ClusterEvent, false); + } else { + SpawnFlickerTest({FCString::Atof(*param[0]), FCString::Atof(*param[1]), FCString::Atof(*param[2])}); + } + })); /* Register cluster event listening */ @@ -97,10 +131,19 @@ void FCalibratioModule::StartupModule () { ClusterEventListenerDelegate = FOnClusterEventJsonListener::CreateLambda([](const FDisplayClusterClusterEventJson& Event) { - if (Event.Category.Equals("CalibratioSpawner") && Event.Name.Equals("CalibratioSpawn")) + if(!Event.Category.Equals("CalibratioSpawner")) return; + if (Event.Name.Equals("CalibratioSpawn")) { SpawnCalibratio(); } + else if (Event.Name.Equals("CalibratioOldSpawn")) + { + SpawnCalibratioOld(); + } + else if (Event.Name.Equals("FlickerTester") && Event.Parameters.Contains("X") && Event.Parameters.Contains("Y") && Event.Parameters.Contains("Z")) + { + SpawnFlickerTest({FCString::Atof(*Event.Parameters["X"]), FCString::Atof(*Event.Parameters["Y"]), FCString::Atof(*Event.Parameters["Z"])}); + } }); DisplayCluster->GetClusterMgr()->AddClusterEventJsonListener(ClusterEventListenerDelegate); } @@ -117,6 +160,23 @@ void FCalibratioModule::SpawnCalibratio() GEngine->GetCurrentPlayWorld()->SpawnActor<ACalibratioActor>(); } +void FCalibratioModule::SpawnCalibratioOld() +{ + if (UGameplayStatics::GetActorOfClass(GEngine->GetCurrentPlayWorld(), ACalibratioOldActor::StaticClass()) != nullptr) return; + GEngine->GetCurrentPlayWorld()->SpawnActor<ACalibratioOldActor>(); +} + +void FCalibratioModule::SpawnFlickerTest(FVector pos) +{ + AActor* found = UGameplayStatics::GetActorOfClass(GEngine->GetCurrentPlayWorld(), AFlickerTester::StaticClass()); + if (found != nullptr){ + found->SetActorLocation(pos); + }else + { + GEngine->GetCurrentPlayWorld()->SpawnActor<AFlickerTester>(pos, FRotator::ZeroRotator); + } +} + #undef LOCTEXT_NAMESPACE IMPLEMENT_MODULE(FCalibratioModule, Calibratio) \ No newline at end of file diff --git a/Source/Calibratio/Private/CalibratioActor.cpp b/Source/Calibratio/Private/CalibratioActor.cpp index e41ed7162a024846980f07857fb729c435707e37..384e094695faef327c52cba8988dabc14d0d4486 100644 --- a/Source/Calibratio/Private/CalibratioActor.cpp +++ b/Source/Calibratio/Private/CalibratioActor.cpp @@ -26,10 +26,11 @@ ACalibratioActor::ACalibratioActor() /* Create Mesh component and initialize */ Mesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Mesh")); - Mesh->SetupAttachment(RootComponent); Mesh->SetStaticMesh(CylinderMesh); Mesh->SetRelativeScale3D(FVector(1.0f,1.0f,0.1f)); //Make it a Disk Mesh->SetupAttachment(MotionSource); + + SetActorEnableCollision(false); //Prevent Stepping on the Disc etc. } // Called when the game starts or when spawned @@ -132,15 +133,18 @@ void ACalibratioActor::LocalReset() void ACalibratioActor::ClusterDespawn() { - if (!FCalibratioModule::IsRoomMountedMode()) return; - - IDisplayClusterClusterManager* const Manager = IDisplayCluster::Get().GetClusterMgr(); - if (!Manager) return; - - FDisplayClusterClusterEventJson ClusterEvent; - ClusterEvent.Name = EventDespawn; - ClusterEvent.Category = EventCategory; - Manager->EmitClusterEventJson(ClusterEvent, true); + if (FCalibratioModule::IsRoomMountedMode()){ + IDisplayClusterClusterManager* const Manager = IDisplayCluster::Get().GetClusterMgr(); + if (!Manager) return; + + FDisplayClusterClusterEventJson ClusterEvent; + ClusterEvent.Name = EventDespawn; + ClusterEvent.Category = EventCategory; + Manager->EmitClusterEventJson(ClusterEvent, true); + } else + { + LocalDespawn(); + } } void ACalibratioActor::LocalDespawn() { diff --git a/Source/Calibratio/Private/CalibratioOldActor.cpp b/Source/Calibratio/Private/CalibratioOldActor.cpp new file mode 100644 index 0000000000000000000000000000000000000000..214ccbcf9a9a6aae75dbc245c9c06494e80f7a5d --- /dev/null +++ b/Source/Calibratio/Private/CalibratioOldActor.cpp @@ -0,0 +1,332 @@ +#include "CalibratioOldActor.h" + +#include "Components/StaticMeshComponent.h" +#include "Cluster/DisplayClusterClusterEvent.h" +#include "IDisplayCluster.h" +#include "TimerManager.h" +#include "CalibratioOverlay.h" +#include "GameFramework/InputSettings.h" +#include "Kismet/GameplayStatics.h" + +ACalibratioOldActor::ACalibratioOldActor() +{ + PrimaryActorTick.bCanEverTick = true; + AutoReceiveInput = EAutoReceiveInput::Player0; + + /* Loads needed Assets */ + UStaticMesh* CylinderMesh = nullptr; + + FCalibratioModule::LoadClass("WidgetBlueprint'/Calibratio/CalibratioOldHud'", Overlay_Class); + FCalibratioModule::LoadAsset("StaticMesh'/Calibratio/Cylinder'", CylinderMesh); + FCalibratioModule::LoadAsset("Material'/Calibratio/CalibratioMaterial'", BaseMaterial); + +/* LiveLink Data Source */ + MotionSource = CreateDefaultSubobject<UMotionControllerComponent>("MotionSource"); + MotionSource->SetTrackingMotionSource(MotionSourceName); + SetRootComponent(MotionSource); + + /* Create Mesh component and initialize */ + Mesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Mesh")); + Mesh->SetStaticMesh(CylinderMesh); + Mesh->SetRelativeScale3D(FVector(1.0f,1.0f,0.1f)); //Make it a Disk + Mesh->SetupAttachment(MotionSource); + + SetActorEnableCollision(false); //Prevent Stepping on the Disc etc. +} + +// Called when the game starts or when spawned +void ACalibratioOldActor::BeginPlay() +{ + Super::BeginPlay(); + + // Register cluster event listener + IDisplayClusterClusterManager* ClusterManager = IDisplayCluster::Get().GetClusterMgr(); + if (ClusterManager && !ClusterEventListenerDelegate.IsBound()) + { + ClusterEventListenerDelegate = FOnClusterEventJsonListener::CreateUObject(this, &ACalibratioOldActor::HandleClusterEvent); + ClusterManager->AddClusterEventJsonListener(ClusterEventListenerDelegate); + } + + // Create Overlay + Overlay = CreateWidget<UCalibratioOldOverlay>(GetWorld()->GetFirstPlayerController(), Overlay_Class); + Overlay->AddToViewport(0); + Overlay->SetThresholds(MinRotation, MaxRotation, Threshold); + Overlay->SetOwner(this); + + // Bind Buttons + Overlay->ResettingButton->OnClicked.AddDynamic(this, &ACalibratioOldActor::ClusterReset); + Overlay->IncreaseThresholdButton->OnClicked.AddDynamic(this, &ACalibratioOldActor::ClusterIncreaseThreshold); + Overlay->DecreaseThresholdButton->OnClicked.AddDynamic(this, &ACalibratioOldActor::ClusterDecreaseThreshold); + + // Hide this overlay on all clients + if (!FCalibratioModule::IsMaster()) + { + Overlay->SetVisibility(ESlateVisibility::Hidden); + } + + // Attach to CAVE-Root + APawn* Pawn = UGameplayStatics::GetPlayerPawn(GetWorld(), 0); + AttachToActor(Pawn, FAttachmentTransformRules::KeepRelativeTransform); + SetOwner(Pawn); + + //Cache input mode + APlayerController* PlayerController = UGameplayStatics::GetPlayerController(GetWorld(), 0); + PreviousInputMode = FCalibratioModule::GetCurrentViewMode(PlayerController); + PlayerController->SetInputMode(FInputModeUIOnly()); +} + +void ACalibratioOldActor::PostInitializeComponents() +{ + Super::PostInitializeComponents(); + + /* Create dynamic materials at runtime (Not constructor) */ + DynamicMaterial = UMaterialInstanceDynamic::Create(BaseMaterial, RootComponent); + DynamicMaterial->SetVectorParameterValue("Color", FColor::Red); + Mesh->SetMaterial(0, DynamicMaterial); +} + +void ACalibratioOldActor::EndPlay(const EEndPlayReason::Type EndPlayReason) +{ + /* Remove from Cluster events */ + IDisplayClusterClusterManager* ClusterManager = IDisplayCluster::Get().GetClusterMgr(); + if (ClusterManager && ClusterEventListenerDelegate.IsBound()) + { + ClusterManager->RemoveClusterEventJsonListener(ClusterEventListenerDelegate); + } + + Super::EndPlay(EndPlayReason); + + /* Remove components */ + GetWorld()->GetTimerManager().ClearTimer(ResetTimerHandle); + if(Overlay->IsInViewport()) Overlay->RemoveFromViewport(); +} + +void ACalibratioOldActor::HandleClusterEvent(const FDisplayClusterClusterEventJson& Event) +{ + if(!Event.Category.Equals(EventCategory)) return; //Not our Business + + if (Event.Name == EventReset) + { + LocalReset(); + } + else if (Event.Name == EventThreshold && Event.Parameters.Contains(EventParamNewThreshold)) + { + LocalSetThreshold(FCString::Atof(*Event.Parameters[EventParamNewThreshold])); + } + else if (Event.Name == EventArmAndSet && Event.Parameters.Contains(EventParamNewMin) && Event.Parameters.Contains(EventParamNewMax)) + { + LocalArmAndSetCalibration(FCString::Atof(*Event.Parameters[EventParamNewMin]), FCString::Atof(*Event.Parameters[EventParamNewMax])); + } + else if (Event.Name == EventDespawn) + { + LocalDespawn(); + } +} + +void ACalibratioOldActor::ClusterReset() +{ + if(!FCalibratioModule::IsRoomMountedMode()) return; + + IDisplayClusterClusterManager* const Manager = IDisplayCluster::Get().GetClusterMgr(); + if (!Manager) return; + + FDisplayClusterClusterEventJson ClusterEvent; + ClusterEvent.Name = EventReset; + ClusterEvent.Category = EventCategory; + Manager->EmitClusterEventJson(ClusterEvent, true); +} + +void ACalibratioOldActor::LocalReset() +{ + DynamicMaterial->SetVectorParameterValue("Color", FColor::Red); + CurrentCalibrationRuns = 0; + MaxRotation = -FLT_MAX; + MinRotation = FLT_MAX; + LastRotations.Empty(); + LastRotations.Reserve(MaxCalibrationRuns); +} + +void ACalibratioOldActor::ClusterIncreaseThreshold() +{ + ClusterChangeThreshold(FMath::DegreesToRadians(0.1f)); +} + +void ACalibratioOldActor::ClusterDecreaseThreshold() +{ + ClusterChangeThreshold(-FMath::DegreesToRadians(0.1f)); +} + +void ACalibratioOldActor::ClusterChangeThreshold(float Value) +{ + const float NewThreshold = Threshold + Value; + + if (!FCalibratioModule::IsRoomMountedMode()) return; + + IDisplayClusterClusterManager* const Manager = IDisplayCluster::Get().GetClusterMgr(); + if (!Manager) return; + + FDisplayClusterClusterEventJson ClusterEvent; + ClusterEvent.Name = EventThreshold; + ClusterEvent.Category = EventCategory; + ClusterEvent.Parameters.Add(EventParamNewThreshold,FString::SanitizeFloat(NewThreshold)); + Manager->EmitClusterEventJson(ClusterEvent, true); +} + +void ACalibratioOldActor::LocalSetThreshold(float NewValue) +{ + Threshold = NewValue; + Overlay->SetThresholds(MinRotation, MaxRotation, Threshold); +} + +void ACalibratioOldActor::ClusterArmAndSetCalibration(float MinAngle, float MaxAngle) +{ + if (!FCalibratioModule::IsRoomMountedMode()) return; + + IDisplayClusterClusterManager* const Manager = IDisplayCluster::Get().GetClusterMgr(); + if (!Manager) return; + + FDisplayClusterClusterEventJson ClusterEvent; + ClusterEvent.Name = EventArmAndSet; + ClusterEvent.Category = EventCategory; + ClusterEvent.Parameters.Add(EventParamNewMin,FString::SanitizeFloat(MinAngle)); + ClusterEvent.Parameters.Add(EventParamNewMax,FString::SanitizeFloat(MaxAngle)); + Manager->EmitClusterEventJson(ClusterEvent, true); +} + +void ACalibratioOldActor::LocalArmAndSetCalibration(float NewMin, float NewMax) +{ + MinRotation = NewMin; + MaxRotation = NewMax; + Overlay->SetStatus(Waiting); + DynamicMaterial->SetVectorParameterValue("Color", FColor::Black); + CurrentCalibrationRuns = MaxCalibrationRuns + 1; //Arm +} + +void ACalibratioOldActor::ClusterDespawn() +{ + if (FCalibratioModule::IsRoomMountedMode()){ + IDisplayClusterClusterManager* const Manager = IDisplayCluster::Get().GetClusterMgr(); + if (!Manager) return; + + FDisplayClusterClusterEventJson ClusterEvent; + ClusterEvent.Name = EventDespawn; + ClusterEvent.Category = EventCategory; + Manager->EmitClusterEventJson(ClusterEvent, true); + }else + { + LocalDespawn(); + } +} +void ACalibratioOldActor::LocalDespawn() +{ + // Set input mode to previous one + APlayerController* playerController = UGameplayStatics::GetPlayerController(GetWorld(), 0); + switch(PreviousInputMode){ + case CurrentViewMode::GameAndUI: + playerController->SetInputMode(FInputModeGameAndUI()); + break; + case CurrentViewMode::UIOnly: + playerController->SetInputMode(FInputModeUIOnly()); + break; + case CurrentViewMode::GameOnly: + playerController->SetInputMode(FInputModeGameOnly()); + break; + case CurrentViewMode::Invalid: + default: ; + } + + GetWorld()->DestroyActor(this); // Destroy ourself +} + +void ACalibratioOldActor::Tick(const float DeltaSeconds) +{ + Super::Tick(DeltaSeconds); + + const FVector NewPos = MotionSource->GetRelativeLocation(); + if(NewPos != LastVisiblePosition) + { + if(FirstPositionSet) LastTimeVisible = FDateTime::Now(); //Every tick after the first one + + LastVisiblePosition = NewPos; + FirstPositionSet = true; + } + + if (!IsTrackerCurrentlyVisible() || !MotionSource) + { + Overlay->SetPhysicalStatus(NotFound); + Overlay->SetStatus(Waiting); + return; + } + + /* Tracker is visible */ + const float Rotation = MotionSource->GetRelativeRotation().Yaw; + + /* First run, place mesh */ + if (CurrentCalibrationRuns == 0) + { + Mesh->SetRelativeLocation(MotionSource->GetRelativeLocation()); + } + /* More calibration runs to go */ + if (CurrentCalibrationRuns < MaxCalibrationRuns) + { + Overlay->SetStatus(Calibrating); + if (IsDeviceMoving(Rotation)) + { + Overlay->SetPhysicalStatus(Moving); + LocalReset(); + } + else + { + Overlay->SetPhysicalStatus(Found); + CalibrationRun(Rotation); + } + } + /* Calibration finished */ + else if (CurrentCalibrationRuns == MaxCalibrationRuns) + { + ClusterArmAndSetCalibration(MinRotation, MaxRotation); /* Sync to other nodes */ + } + /* Actual Measuring */ + else if (Rotation < MinRotation - Threshold || Rotation > MaxRotation + Threshold) + { + if (!GetWorld()->GetTimerManager().IsTimerActive(ResetTimerHandle)) + { + DynamicMaterial->SetVectorParameterValue("Color", FColor::White); + Overlay->SetStatus(Triggered); + GetWorld()->GetTimerManager().SetTimer(ResetTimerHandle, this, &ACalibratioOldActor::ClusterReset, ResetTime, false); + } + } +} + +/* Checks if last 10 calls to this function handed in roughly the same Angle */ +bool ACalibratioOldActor::IsDeviceMoving(float Angle) +{ + LastRotations.Add(Angle); /* Push into back */ + if (LastRotations.Num() > 10) LastRotations.RemoveAt(0); /* Remove first one */ + + float Sum = 0.0f; + for (float& CurrentAngle : LastRotations) + { + Sum += CurrentAngle; + } + const float Average = Sum / LastRotations.Num(); + + return FMath::Abs(Average - Angle) > 5 * Threshold && LastRotations.Num() >= 10; +} + +/* Adjusts min and max rotation values */ +void ACalibratioOldActor::CalibrationRun(float Angle) +{ + if(!FCalibratioModule::IsMaster()) return; //Not our Business + + MinRotation = FMath::Min(MinRotation, Angle); + MaxRotation = FMath::Max(MaxRotation, Angle); + Overlay->SetThresholds(MinRotation, MaxRotation, Threshold); + + CurrentCalibrationRuns++; +} + +bool ACalibratioOldActor::IsTrackerCurrentlyVisible() +{ + return (FDateTime::Now() - LastTimeVisible).GetTotalMilliseconds() <= AcceptedAbscenceTime; +} diff --git a/Source/Calibratio/Private/CalibratioOldOverlay.cpp b/Source/Calibratio/Private/CalibratioOldOverlay.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a0984a8a49b31378fbd1cbb36b9a9b8f872c4198 --- /dev/null +++ b/Source/Calibratio/Private/CalibratioOldOverlay.cpp @@ -0,0 +1,60 @@ +#include "CalibratioOldOverlay.h" + +bool UCalibratioOldOverlay::Initialize() +{ + const bool Result = Super::Initialize(); + DismissButton->OnClicked.AddDynamic(this, &UCalibratioOldOverlay::Dismiss); + return Result; +} + +void UCalibratioOldOverlay::SetStatus(const ECalibratioProtocolStatus Status) +{ + if(CurrentStatus == Status) return; + switch(Status) + { + case Calibrating: + StatusProtocol->SetText(FText::FromString(TEXT("Calibrating"))); + break; + case Waiting: + StatusProtocol->SetText(FText::FromString(TEXT("Waiting"))); + break; + case Triggered: + StatusProtocol->SetText(FText::FromString(TEXT("Triggered"))); + break; + } + CurrentStatus = Status; +} + +void UCalibratioOldOverlay::SetThresholds(const float Min, const float Max, const float Threshold) +{ + MinAngle->SetText(FText::FromString(FString::Printf(TEXT("%.2f\u00B0"), FMath::Fmod(FMath::RadiansToDegrees(Min), 360)))); + MaxAngle->SetText(FText::FromString(FString::Printf(TEXT("%.2f\u00B0"), FMath::Fmod(FMath::RadiansToDegrees(Max), 360)))); + CurrentThreshold->SetText(FText::FromString(FString::Printf(TEXT("+-%.2f\u00B0s"), FMath::Fmod(FMath::RadiansToDegrees(Threshold), 360)))); +} + +void UCalibratioOldOverlay::SetPhysicalStatus(const ECalibratioPhysicalStatus Status) +{ + if(CurrentPhysicalStatus == Status) return; + switch(Status) + { + case Found: + StatusCalibratio->SetText(FText::FromString(TEXT("Found"))); + StatusCalibratio->SetColorAndOpacity(FSlateColor(FLinearColor::Green)); + break; + case Unknown: + case NotFound: + StatusCalibratio->SetText(FText::FromString(TEXT("Not Found"))); + StatusCalibratio->SetColorAndOpacity(FSlateColor(FLinearColor::Red)); + break; + case Moving: + StatusCalibratio->SetText(FText::FromString(TEXT("Moving"))); + StatusCalibratio->SetColorAndOpacity(FSlateColor(FLinearColor::Yellow)); + break; + } + CurrentPhysicalStatus = Status; +} + +void UCalibratioOldOverlay::Dismiss() +{ + Owner->ClusterDespawn(); +} diff --git a/Source/Calibratio/Private/FlickerTester.cpp b/Source/Calibratio/Private/FlickerTester.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c67af9dec04faed37eb840ae23273afa2ce6c453 --- /dev/null +++ b/Source/Calibratio/Private/FlickerTester.cpp @@ -0,0 +1,52 @@ +// Fill out your copyright notice in the Description page of Project Settings. + + +#include "FlickerTester.h" + +#include "Calibratio.h" + +// Sets default values +AFlickerTester::AFlickerTester() +{ + // Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it. + PrimaryActorTick.bCanEverTick = true; + + /* Loads needed Assets */ + UStaticMesh* CylinderMesh = nullptr; + FCalibratioModule::LoadAsset("StaticMesh'/Calibratio/Cylinder'", CylinderMesh); + FCalibratioModule::LoadAsset("Material'/Calibratio/CalibratioMaterial'", BaseMaterial); + + /* Create Mesh component and initialize */ + Mesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Mesh")); + Mesh->SetStaticMesh(CylinderMesh); + Mesh->SetRelativeScale3D(FVector(1.0f,1.0f,0.1f)); //Make it a Disk + + SetRootComponent(Mesh); +} + +// Called when the game starts or when spawned +void AFlickerTester::BeginPlay() +{ + Super::BeginPlay(); +} + +void AFlickerTester::PostInitializeComponents() +{ + Super::PostInitializeComponents(); + + /* Create dynamic materials at runtime (Not constructor) */ + DynamicMaterial = UMaterialInstanceDynamic::Create(BaseMaterial, RootComponent); + DynamicMaterial->SetVectorParameterValue("Color", FColor::Black); + Mesh->SetMaterial(0, DynamicMaterial); +} + +// Called every frame +void AFlickerTester::Tick(float DeltaTime) +{ + Super::Tick(DeltaTime); + + //Flip every tick + flipped = !flipped; + DynamicMaterial->SetVectorParameterValue("Color", (flipped)?FColor::Black : FColor::White); +} + diff --git a/Source/Calibratio/Public/Calibratio.h b/Source/Calibratio/Public/Calibratio.h index e242d645169e5f98074177538de15afd35db2ff0..d153bfb50136e514794d0ef44e89b2647c5d3590 100644 --- a/Source/Calibratio/Public/Calibratio.h +++ b/Source/Calibratio/Public/Calibratio.h @@ -27,8 +27,12 @@ public: virtual void ShutdownModule() override; static void SpawnCalibratio(); + static void SpawnCalibratioOld(); + static void SpawnFlickerTest(FVector pos); private: IConsoleCommand* CalibratioConsoleCommand = nullptr; + IConsoleCommand* CalibratioOldConsoleCommand = nullptr; + IConsoleCommand* FlickerTestConsoleCommand = nullptr; FOnClusterEventJsonListener ClusterEventListenerDelegate; }; diff --git a/Source/Calibratio/Public/CalibratioOldActor.h b/Source/Calibratio/Public/CalibratioOldActor.h new file mode 100644 index 0000000000000000000000000000000000000000..bdf51b58cdc0958e1e4d7d8ccea699e7aa55fa9e --- /dev/null +++ b/Source/Calibratio/Public/CalibratioOldActor.h @@ -0,0 +1,84 @@ +#pragma once + +#include "CoreMinimal.h" +#include "Materials/MaterialInstanceDynamic.h" +#include "Cluster/IDisplayClusterClusterManager.h" + +#include "GameFramework/Actor.h" +#include "MotionControllerComponent.h" +#include "CalibratioOldOverlay.h" +#include "Calibratio.h" +#include "CalibratioOldActor.generated.h" + +UCLASS() +class CALIBRATIO_API ACalibratioOldActor : public AActor +{ + GENERATED_BODY() + +public: + ACalibratioOldActor(); + +protected: + virtual void BeginPlay() override; + virtual void PostInitializeComponents() override; + virtual void Tick(float DeltaSeconds) override; + virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override; + +public: + UPROPERTY(VisibleAnywhere) UStaticMeshComponent* Mesh; + UPROPERTY(EditAnywhere) UMaterialInterface* BaseMaterial; + UPROPERTY(VisibleAnywhere) UMotionControllerComponent* MotionSource; + UPROPERTY(BlueprintReadWrite) float Threshold = FMath::DegreesToRadians(1.7f); + UPROPERTY(BlueprintReadWrite) float ResetTime = 0.5f; + UFUNCTION(Blueprintcallable) void ClusterDespawn(); + +private: + DECLARE_DELEGATE_OneParam(FThresholdDelegate, float); + FOnClusterEventJsonListener ClusterEventListenerDelegate; + + void CalibrationRun(float Angle); + bool IsTrackerCurrentlyVisible(); + void LocalSetThreshold(float NewValue); + void LocalArmAndSetCalibration(float NewMin, float NewMax); + void LocalDespawn(); + bool IsDeviceMoving(float Angle); + void LocalReset(); + + // Handling Cluster events + UFUNCTION() void ClusterReset(); + UFUNCTION() void ClusterIncreaseThreshold(); + UFUNCTION() void ClusterDecreaseThreshold(); + void ClusterChangeThreshold(float Value); + void ClusterArmAndSetCalibration(float MinAngle, float MaxAngle); + void HandleClusterEvent(const FDisplayClusterClusterEventJson& Event); + + float MinRotation{0}; + float MaxRotation{0}; + int CurrentCalibrationRuns{0}; + int MaxCalibrationRuns{60}; + FTimerHandle ResetTimerHandle; + TArray<float> LastRotations; + + UPROPERTY() UMaterialInstanceDynamic* DynamicMaterial = nullptr; + + FDateTime LastTimeVisible = FDateTime::MinValue(); + FVector LastVisiblePosition = FVector(NAN, NAN, NAN); + bool FirstPositionSet = false; + uint32 AcceptedAbscenceTime = 500u; // in Milliseconds + + //Overlay + TSubclassOf<class UCalibratioOldOverlay> Overlay_Class; + UPROPERTY() UCalibratioOldOverlay* Overlay; + + const FName MotionSourceName = FName("Unknown-DTrack-Body-09"); + CurrentViewMode PreviousInputMode = CurrentViewMode::Invalid; + + const FString EventCategory = "CalibratioOld"; + const FString EventDespawn = "CalibratioDespawn"; + const FString EventReset = "CalibratioReset"; + const FString EventThreshold = "CalibratioSetThreshold"; + const FString EventArmAndSet = "CalibratioArmAndSetCalibration"; + const FString EventParamNewThreshold = "NewThreshold"; + const FString EventParamNewMin = "NewMin"; + const FString EventParamNewMax = "NewMax"; +}; diff --git a/Source/Calibratio/Public/CalibratioOldOverlay.h b/Source/Calibratio/Public/CalibratioOldOverlay.h new file mode 100644 index 0000000000000000000000000000000000000000..0f320e9b2186fe5db149c9531b3ad2e500e0258c --- /dev/null +++ b/Source/Calibratio/Public/CalibratioOldOverlay.h @@ -0,0 +1,79 @@ +#pragma once + +#include "CoreMinimal.h" + +#include "Blueprint/UserWidget.h" +#include "Components/TextBlock.h" +#include "Components/Button.h" + +#include "CalibratioOldOverlay.generated.h" + + +class ACalibratioOldActor; + +UENUM(BlueprintType) +enum ECalibratioProtocolStatus +{ + Calibrating, + Waiting, + Triggered +}; + +UENUM(BlueprintType) +enum ECalibratioPhysicalStatus +{ + Moving, + Found, + NotFound, + Unknown +}; + +/** + * This is the parent class for the Overlay that is used on the master. + * All declarations in it are magically bound to the UMG child class if they are named the same (see "meta = (BindWidget)") + */ +UCLASS() +class CALIBRATIO_API UCalibratioOldOverlay : public UUserWidget +{ + GENERATED_BODY() + +virtual bool Initialize() override; +public: + /* Public Buttons */ + UPROPERTY(BlueprintReadWrite, meta = (BindWidget)) + UButton* ResettingButton; + UPROPERTY(BlueprintReadWrite, meta = (BindWidget)) + UButton* IncreaseThresholdButton; + UPROPERTY(BlueprintReadWrite, meta = (BindWidget)) + UButton* DecreaseThresholdButton; + +protected: + UPROPERTY(BlueprintReadWrite, meta = (BindWidget)) + UButton* DismissButton; + + /* Numbers: */ + UPROPERTY(BlueprintReadWrite, meta = (BindWidget)) + UTextBlock* CurrentThreshold; + UPROPERTY(BlueprintReadWrite, meta = (BindWidget)) + UTextBlock* MinAngle; + UPROPERTY(BlueprintReadWrite, meta = (BindWidget)) + UTextBlock* MaxAngle; + + /* Status: */ + UPROPERTY(BlueprintReadWrite, meta = (BindWidget)) + UTextBlock* StatusProtocol; + UPROPERTY(BlueprintReadWrite, meta = (BindWidget)) + UTextBlock* StatusCalibratio; + +public: + UFUNCTION() void SetStatus(ECalibratioProtocolStatus Status); + UFUNCTION() void SetThresholds(float Min, float Max, float Threshold); + UFUNCTION() void SetPhysicalStatus(ECalibratioPhysicalStatus Status); + void SetOwner(ACalibratioOldActor* InOwner) {Owner = InOwner;} + UFUNCTION() void Dismiss(); + +private: + ECalibratioPhysicalStatus CurrentPhysicalStatus = Unknown; + ECalibratioProtocolStatus CurrentStatus = Calibrating; + UPROPERTY() ACalibratioOldActor* Owner; +}; diff --git a/Source/Calibratio/Public/FlickerTester.h b/Source/Calibratio/Public/FlickerTester.h new file mode 100644 index 0000000000000000000000000000000000000000..adb1c104fc5d419eca8694211a16b9dbd44a73f0 --- /dev/null +++ b/Source/Calibratio/Public/FlickerTester.h @@ -0,0 +1,32 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once + +#include "CoreMinimal.h" +#include "GameFramework/Actor.h" +#include "FlickerTester.generated.h" + +UCLASS() +class CALIBRATIO_API AFlickerTester : public AActor +{ + GENERATED_BODY() + +public: + // Sets default values for this actor's properties + AFlickerTester(); + UPROPERTY(VisibleAnywhere) UStaticMeshComponent* Mesh; + UPROPERTY(EditAnywhere) UMaterialInterface* BaseMaterial; + +protected: + // Called when the game starts or when spawned + virtual void BeginPlay() override; + virtual void PostInitializeComponents() override; + +public: + // Called every frame + virtual void Tick(float DeltaTime) override; + +private: + bool flipped = false; + UPROPERTY() UMaterialInstanceDynamic* DynamicMaterial = nullptr; +};