diff --git a/Content/Blueprints/OptiXGameModeBP.uasset b/Content/Blueprints/OptiXGameModeBP.uasset
index 9d3bff61140f07f2c52f9e2c50c8369c0a35960a..4a771f118266fbe3f06f2c8ea12ad939e428ccb9 100644
Binary files a/Content/Blueprints/OptiXGameModeBP.uasset and b/Content/Blueprints/OptiXGameModeBP.uasset differ
diff --git a/Content/Blueprints/OptiXVRPawnStandaloneBP.uasset b/Content/Blueprints/OptiXVRPawnStandaloneBP.uasset
index 28b42d429448e4fdb1b05068f2922209080a6860..7f898a4ba1f46f175d2df1fb2ddd575165f8938b 100644
Binary files a/Content/Blueprints/OptiXVRPawnStandaloneBP.uasset and b/Content/Blueprints/OptiXVRPawnStandaloneBP.uasset differ
diff --git a/Content/UI/LoadingScreen.uasset b/Content/UI/LoadingScreen.uasset
index efaa7303315fe2fb61e28fb0c26925232b4b5ed6..3f7ece913c843db4f3ea80e4448d50a44daa892a 100644
Binary files a/Content/UI/LoadingScreen.uasset and b/Content/UI/LoadingScreen.uasset differ
diff --git a/Content/UI/Screen.uasset b/Content/UI/Screen.uasset
new file mode 100644
index 0000000000000000000000000000000000000000..8c271b5a86d3d21ef73a37c2de2c7ea288d89f58
Binary files /dev/null and b/Content/UI/Screen.uasset differ
diff --git a/Source/OptiX/Private/SelectableActorBase.cpp b/Source/OptiX/Private/SelectableActorBase.cpp
index 53ef56dbc8fbc441d6f3e7c80dc6c9c0f6afcf01..ad331cddddcf0a42930d2bdd8f12b801cba27a07 100644
--- a/Source/OptiX/Private/SelectableActorBase.cpp
+++ b/Source/OptiX/Private/SelectableActorBase.cpp
@@ -1,547 +1,549 @@
-// Fill out your copyright notice in the Description page of Project Settings.
-
-#include "SelectableActorBase.h"
-#include "UObject/ConstructorHelpers.h"
-#include "Runtime/Engine/Classes/Engine/StaticMesh.h"
-#include "Kismet/GameplayStatics.h"
-#include "Blueprint/UserWidget.h"
-#include "Runtime/Engine/Classes/Materials/MaterialInstanceDynamic.h"
-
-#include "OptiXVRPawn.h"
-
-ASelectableActorBase::ASelectableActorBase(const FObjectInitializer& ObjectInitializer)
-	: Super(ObjectInitializer)
-{
-
-	UE_LOG(LogTemp, Display, TEXT("OptiX ASelectableActorBase Constructor Start"));
-
-	SetMobility(EComponentMobility::Movable);
-
-	GetStaticMeshComponent()->SetGenerateOverlapEvents(true);
-	GetStaticMeshComponent()->CastShadow = 0;
-
-	UE_LOG(LogTemp, Display, TEXT("OptiX ASelectableActorBase Constructor Component Setup Start"));
-
-
-	Gizmo = CreateDefaultSubobject<USceneComponent>(TEXT("Gizmo"));
-	Gizmo->SetupAttachment(GetStaticMeshComponent());
-	Gizmo->SetHiddenInGame(true);
-	//Gizmo->SetAbsolute(false, true, true);
-
-	SupportWidget = CreateDefaultSubobject<UWidgetComponent>(TEXT("SupportWidget"));
-	SupportWidget->SetAbsolute(false, true, true);
-
-	SupportWidget->SetupAttachment(Gizmo);
-	static ConstructorHelpers::FClassFinder<UUserWidget> SupportWidgetClass(TEXT("/OptiX/UI/SupportSwapWidget2"));
-	SupportWidget->SetWidgetClass(SupportWidgetClass.Class);
-	SupportWidget->SetWorldScale3D(FVector(0.05, 0.05, 0.05));
-	SupportWidget->SetDrawSize(FVector2D(800, 2300));
-	SupportWidget->SetGenerateOverlapEvents(false);
-	SupportWidget->SetHiddenInGame(true);
-	SupportWidget->SetTwoSided(true);
-
-	UE_LOG(LogTemp, Display, TEXT("OptiX ASelectableActorBase Constructor 1/4"));
-
-
-	TranslationSupport = CreateDefaultSubobject<USceneComponent>(TEXT("TranslationSupport"));
-	TranslationSupport->SetupAttachment(Gizmo);
-
-	TranslateX = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("TranslateX"));
-	TranslateX->SetAbsolute(false, true, true);
-	TranslateX->SetupAttachment(TranslationSupport);
-	static ConstructorHelpers::FObjectFinder<UStaticMesh> TranslateXMesh(TEXT("StaticMesh'/OptiX/UI/Translator/Arrowbody.Arrowbody'"));
-	TranslateX->SetStaticMesh(TranslateXMesh.Object);
-	TranslateX->SetWorldScale3D(FVector(0.6f, 0.6f, 0.6f));
-	TranslateX->SetGenerateOverlapEvents(false);
-	TranslateX->SetHiddenInGame(true);
-
-	TranslateX->CastShadow = 0;
-	TranslateX->bVisibleInReflectionCaptures = false;
-	TranslateX->SetCanEverAffectNavigation(false);
-
-	ArrowX = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("ArrowX"));
-	ArrowX->SetAbsolute(false, false, true);
-	ArrowX->SetWorldScale3D(FVector(0.6f, 0.6f, 0.6f));
-	ArrowX->SetupAttachment(TranslateX);
-	static ConstructorHelpers::FObjectFinder<UStaticMesh> TranslateArrow(TEXT("StaticMesh'/OptiX/UI/Translator/Arrowhead.Arrowhead'"));
-	ArrowX->SetStaticMesh(TranslateArrow.Object);
-	//ArrowX->SetAbsolute(false, true, false);
-	ArrowX->SetRelativeLocation(FVector(39, 0, 0));
-	ArrowX->SetGenerateOverlapEvents(false);
-	ArrowX->SetHiddenInGame(true);
-
-	ArrowX->CastShadow = 0;
-	ArrowX->bVisibleInReflectionCaptures = false;
-	ArrowX->SetCanEverAffectNavigation(false);
-
-	TranslateWidgetX = CreateDefaultSubobject<UWidgetComponent>(TEXT("TranslateWidgetX"));
-	TranslateWidgetX->SetAbsolute(false, true, true);
-	TranslateWidgetX->SetupAttachment(ArrowX);
-	static ConstructorHelpers::FClassFinder<UUserWidget> PosWidgetClass(TEXT("/OptiX/UI/Translator/PositionCounter"));
-	TranslateWidgetX->SetWidgetClass(PosWidgetClass.Class);
-	//TranslateWidgetX->SetRelativeLocationAndRotation(FVector(0, 0, 0), FRotator(0, 90, 0));
-	//TranslateWidgetX->SetWorldRotation(FRotator());
-	TranslateWidgetX->SetRelativeScale3D(FVector(0.05, 0.05, 0.05));
-	TranslateWidgetX->SetDrawSize(FVector2D(300, 300));
-	TranslateWidgetX->SetHiddenInGame(true);
-	TranslateWidgetX->SetGenerateOverlapEvents(false);
-	//TranslateWidgetX->SetTwoSided(true);
-	// todo
-
-	TranslateY = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("TranslateY"));
-	TranslateY->SetAbsolute(false, true, true);
-
-	TranslateY->SetupAttachment(TranslationSupport);
-	TranslateY->SetStaticMesh(TranslateXMesh.Object);
-	TranslateY->SetWorldScale3D(FVector(0.6f, 0.6f, 0.6f));
-	TranslateY->SetGenerateOverlapEvents(false);
-	TranslateY->SetHiddenInGame(true);
-	TranslateY->SetWorldRotation(FRotator(0.f, 90.0f, 0.0f));
-
-	TranslateY->CastShadow = 0;
-	TranslateY->bVisibleInReflectionCaptures = false;
-	TranslateY->SetCanEverAffectNavigation(false);
-
-	ArrowY = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("ArrowY"));
-	ArrowY->SetAbsolute(false, false, true);
-
-	ArrowY->SetupAttachment(TranslateY);
-	ArrowY->SetStaticMesh(TranslateArrow.Object);
-	//ArrowY->SetAbsolute(false, true, false);
-	ArrowY->SetWorldScale3D(FVector(0.6f, 0.6f, 0.6f));
-	ArrowY->SetRelativeLocation(FVector(39, 0, 0));
-	ArrowY->SetGenerateOverlapEvents(false);
-	ArrowY->SetHiddenInGame(true);
-
-	ArrowY->CastShadow = 0;
-	ArrowY->bVisibleInReflectionCaptures = false;
-	ArrowY->SetCanEverAffectNavigation(false);
-
-	TranslateWidgetY = CreateDefaultSubobject<UWidgetComponent>(TEXT("TranslateWidgetY"));	
-	TranslateWidgetY->SetAbsolute(false, true, true);
-	TranslateWidgetY->SetupAttachment(ArrowY);
-	TranslateWidgetY->SetWidgetClass(PosWidgetClass.Class);
-	//TranslateWidgetY->SetWorldRotation(FRotator());
-	TranslateWidgetY->SetRelativeScale3D(FVector(0.05, 0.05, 0.05));
-	TranslateWidgetY->SetDrawSize(FVector2D(300, 300));
-	TranslateWidgetY->SetHiddenInGame(true);
-	TranslateWidgetY->SetGenerateOverlapEvents(false);
-	//TranslateWidgetY->SetTwoSided(true);
-
-	TranslateZ = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("TranslateZ"));
-	TranslateZ->SetAbsolute(false, true, true);
-	TranslateZ->SetupAttachment(TranslationSupport);
-	TranslateZ->SetStaticMesh(TranslateXMesh.Object);
-	TranslateZ->SetWorldScale3D(FVector(0.6f, 0.6f, 0.6f));
-	TranslateZ->SetGenerateOverlapEvents(false);
-	TranslateZ->SetHiddenInGame(true);
-	TranslateZ->SetWorldRotation(FRotator(90.f, 0.0f, 0.0f));
-	TranslateZ->SetCanEverAffectNavigation(false);
-	TranslateZ->CastShadow = 0;
-	TranslateZ->bVisibleInReflectionCaptures = false;
-
-
-	ArrowZ = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("ArrowZ"));
-	ArrowZ->SetAbsolute(false, false, true);
-	ArrowZ->SetupAttachment(TranslateZ);
-	ArrowZ->SetStaticMesh(TranslateArrow.Object);
-	//ArrowZ->SetAbsolute(false, true, false);
-	ArrowZ->SetWorldScale3D(FVector(0.6f, 0.6f, 0.6f));
-	ArrowZ->SetRelativeLocation(FVector(39, 0, 0));
-	ArrowZ->SetGenerateOverlapEvents(false);
-	ArrowZ->SetHiddenInGame(true);
-	ArrowZ->SetCanEverAffectNavigation(false);
-	ArrowZ->CastShadow = 0;
-	ArrowZ->bVisibleInReflectionCaptures = false;
-
-	TranslateWidgetZ = CreateDefaultSubobject<UWidgetComponent>(TEXT("TranslateWidgetZ"));
-	TranslateWidgetZ->SetAbsolute(false, true, true);
-	//TranslateWidgetZ->SetTwoSided(true);
-
-	TranslateWidgetZ->SetupAttachment(ArrowZ);
-	TranslateWidgetZ->SetWidgetClass(PosWidgetClass.Class);
-	//TranslateWidgetZ->SetWorldRotation(FRotator());
-	TranslateWidgetZ->SetRelativeScale3D(FVector(0.05, 0.05, 0.05));
-	TranslateWidgetZ->SetDrawSize(FVector2D(300, 300));
-	TranslateWidgetZ->SetRelativeLocation(FVector(8, 0, 0));
-
-	TranslateWidgetZ->SetHiddenInGame(true);
-	TranslateWidgetZ->SetGenerateOverlapEvents(false);
-
-	UE_LOG(LogTemp, Display, TEXT("OptiX ASelectableActorBase Constructor 2/4"));
-
-
-	RotationSupport = CreateDefaultSubobject<USceneComponent>(TEXT("RotationSupport"));
-	RotationSupport->SetupAttachment(Gizmo);
-
-	ScaleH = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("ScaleH"));
-	ScaleH->SetupAttachment(RotationSupport);
-	static ConstructorHelpers::FObjectFinder<UStaticMesh> ScaleMesh(TEXT("StaticMesh'/OptiX/UI/Rotator/scale1.scale1'"));
-	ScaleH->SetStaticMesh(ScaleMesh.Object);
-	ScaleH->SetAbsolute(false, true, false);
-	ScaleH->SetGenerateOverlapEvents(false);
-	ScaleH->SetCollisionEnabled(ECollisionEnabled::NoCollision);
-	ScaleH->SetHiddenInGame(true);
-	ScaleH->SetCanEverAffectNavigation(false);
-	ScaleH->CastShadow = 0;
-	ScaleH->bVisibleInReflectionCaptures = false;
-
-	ScaleV = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("ScaleV"));
-	ScaleV->SetupAttachment(RotationSupport);
-	ScaleV->SetStaticMesh(ScaleMesh.Object);
-	ScaleV->SetWorldRotation(FRotator(90, 0, 0));
-	ScaleV->SetAbsolute(false, true, false);
-	ScaleV->SetGenerateOverlapEvents(false);
-	ScaleV->SetCollisionEnabled(ECollisionEnabled::NoCollision);
-	ScaleV->SetHiddenInGame(true);
-	ScaleV->SetCanEverAffectNavigation(false);
-	ScaleV->CastShadow = 0;
-	ScaleV->bVisibleInReflectionCaptures = false;
-
-	SupportH = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("SupportH"));
-	SupportH->SetupAttachment(RotationSupport);
-	static ConstructorHelpers::FObjectFinder<UStaticMesh> SupportMesh(TEXT("StaticMesh'/OptiX/UI/Rotator/Cylinder_2.Cylinder_2'"));
-	SupportH->SetStaticMesh(SupportMesh.Object);
-	SupportH->SetWorldRotation(FRotator(-90, 0, 0));
-	SupportH->SetWorldScale3D(FVector(0.6, 0.6, 0.3));
-	SupportH->SetGenerateOverlapEvents(false);
-	SupportH->SetHiddenInGame(true);
-	//SupportH->SetWorldLocation(FVector(25, 0, 0));
-	SupportH->SetCanEverAffectNavigation(false);
-	SupportH->CastShadow = 0;
-	SupportH->bVisibleInReflectionCaptures = false;
-
-	SupportSphereH = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("SupportSphereH"));
-	SupportSphereH->SetupAttachment(SupportH);
-	static ConstructorHelpers::FObjectFinder<UStaticMesh> SupportSphereMesh(TEXT("StaticMesh'/OptiX/UI/Rotator/SelectorSphere.SelectorSphere'"));
-	SupportSphereH->SetStaticMesh(SupportSphereMesh.Object);
-	SupportSphereH->SetAbsolute(false, false, true);
-	SupportSphereH->SetWorldScale3D(FVector(0.03, 0.03, 0.03));
-	SupportSphereH->SetGenerateOverlapEvents(false);
-	SupportSphereH->SetHiddenInGame(true);
-	SupportSphereH->SetRelativeLocation(FVector(0, 0, 100));
-	SupportSphereH->SetCanEverAffectNavigation(false);
-	SupportSphereH->CastShadow = 0;
-	SupportSphereH->bVisibleInReflectionCaptures = false;
-
-	DegreeWidgetH = CreateDefaultSubobject<UWidgetComponent>(TEXT("DegreeWidgetH"));
-	DegreeWidgetH->SetupAttachment(SupportSphereH);
-	static ConstructorHelpers::FClassFinder<UUserWidget> DegreeWidgetClass(TEXT("/OptiX/UI/Rotator/DegreeCounter"));
-	DegreeWidgetH->SetWidgetClass(DegreeWidgetClass.Class);
-	DegreeWidgetH->SetRelativeLocationAndRotation(FVector(0, 0, -40), FRotator(0, 90, -90));
-	//DegreeWidgetH->SetRelativeScale3D(FVector(2.0, 2.0, 0.08));
-	DegreeWidgetH->SetDrawSize(FVector2D(200, 300));
-	DegreeWidgetH->SetHiddenInGame(true);
-	DegreeWidgetH->SetGenerateOverlapEvents(false);
-	//DegreeWidgetH->SetTwoSided(true);
-
-	SupportV = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("SupportV"));
-	SupportV->SetupAttachment(RotationSupport);
-	SupportV->SetStaticMesh(SupportMesh.Object);
-	SupportV->SetWorldRotation(FRotator(0.0f, 0.0f, 90.0f));
-	SupportV->SetWorldScale3D(FVector(0.6, 0.6, 0.3));
-	SupportV->SetGenerateOverlapEvents(false);
-	SupportV->SetHiddenInGame(true);
-	//SupportV->SetWorldLocation(FVector(0, 25, 0));
-	SupportV->SetCanEverAffectNavigation(false);
-	SupportV->CastShadow = 0;
-	SupportV->bVisibleInReflectionCaptures = false;
-
-	SupportSphereV = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("SupportSphereV"));
-	SupportSphereV->SetupAttachment(SupportV);
-	//static ConstructorHelpers::FObjectFinder<UStaticMesh> SupportSphereMesh(TEXT("StaticMesh'/OptiX/UI/Rotator/Sphere_2.Sphere_2'"));
-	SupportSphereV->SetStaticMesh(SupportSphereMesh.Object);
-	SupportSphereV->SetAbsolute(false, false, true);
-	SupportSphereV->SetWorldScale3D(FVector(0.03, 0.03, 0.03));
-	SupportSphereV->SetGenerateOverlapEvents(false);
-	SupportSphereV->SetHiddenInGame(true);
-	SupportSphereV->SetRelativeLocation(FVector(0, 0, 100));
-	SupportSphereV->SetCanEverAffectNavigation(false);
-	SupportSphereV->CastShadow = 0;
-	SupportSphereV->bVisibleInReflectionCaptures = false;
-
-	DegreeWidgetV = CreateDefaultSubobject<UWidgetComponent>(TEXT("DegreeWidgetV"));
-	DegreeWidgetV->SetupAttachment(SupportSphereV);
-	DegreeWidgetV->SetWidgetClass(DegreeWidgetClass.Class);
-	DegreeWidgetV->SetRelativeLocationAndRotation(FVector(0, 0, 40), FRotator(0, 0, -90));
-	//DegreeWidgetV->SetRelativeScale3D(FVector(2.0, 2.0, 0.08));
-	DegreeWidgetV->SetDrawSize(FVector2D(200, 300));
-	DegreeWidgetV->SetHiddenInGame(true);
-	DegreeWidgetV->SetGenerateOverlapEvents(false);
-	//DegreeWidgetV->SetTwoSided(true);
-
-	UE_LOG(LogTemp, Display, TEXT("OptiX ASelectableActorBase Constructor 3/4"));
-	   	 
-
-	// Rods	   	 
-
-	static ConstructorHelpers::FObjectFinder<UMaterial> MetalMaterial(TEXT("Material'/OptiX/Laser/MetalSilver.MetalSilver'"));
-	static ConstructorHelpers::FObjectFinder<UStaticMesh> SphereMesh(TEXT("StaticMesh'/Engine/BasicShapes/Sphere.Sphere'"));
-	static ConstructorHelpers::FObjectFinder<UStaticMesh> Cylinder2(TEXT("StaticMesh'/OptiX/UI/Rotator/Cylinder_2.Cylinder_2'"));
-
-	Socket = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("SocketNew"));
-	Socket->SetAbsolute(false, false, true);
-
-	Socket->SetupAttachment(GetStaticMeshComponent());
-	Socket->SetStaticMesh(SphereMesh.Object);
-	Socket->SetGenerateOverlapEvents(false);
-	Socket->SetMaterial(0, MetalMaterial.Object);
-	Socket->SetCollisionEnabled(ECollisionEnabled::NoCollision);
-	Socket->SetWorldScale3D(FVector(0.02, 0.02, 0.02));
-	//Socket->SetRelativeLocation(FVector(0, 0, 0));
-	Socket->SetCanEverAffectNavigation(false);
-	Socket->CastShadow = 0;
-	Socket->bVisibleInReflectionCaptures = false;
-
-	ConnectorV = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("ConnectorVNew"));
-	ConnectorV->SetAbsolute(false, true, true);
-
-	ConnectorV->SetupAttachment(Socket);
-	ConnectorV->SetStaticMesh(Cylinder2.Object);
-	ConnectorV->SetWorldScale3D(FVector(0.4, 0.4, -1));
-	ConnectorV->SetGenerateOverlapEvents(false);
-	ConnectorV->SetCollisionEnabled(ECollisionEnabled::NoCollision);
-	ConnectorV->SetMaterial(0, MetalMaterial.Object);
-	ConnectorV->SetMaterial(1, MetalMaterial.Object);
-	ConnectorV->SetCanEverAffectNavigation(false);
-	ConnectorV->CastShadow = 0;
-	ConnectorV->bVisibleInReflectionCaptures = false;
-
-	Sphere = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("SphereNew"));
-	Sphere->SetAbsolute(false, false, true);
-
-	Sphere->SetupAttachment(ConnectorV);
-	Sphere->SetStaticMesh(SphereMesh.Object);
-	Sphere->SetGenerateOverlapEvents(false);
-	Sphere->SetMaterial(0, MetalMaterial.Object);
-	Sphere->SetCollisionEnabled(ECollisionEnabled::NoCollision);
-	Sphere->SetWorldScale3D(FVector(0.02, 0.02, 0.02));
-	Sphere->SetRelativeLocation(FVector(0, 0, 100));
-	Sphere->SetCanEverAffectNavigation(false);
-	Sphere->CastShadow = 0;
-	Sphere->bVisibleInReflectionCaptures = false;
-
-	ConnectorH = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("ConnectorHNew"));
-	ConnectorH->SetAbsolute(false, true, true);
-	ConnectorH->SetupAttachment(ConnectorV);
-	ConnectorH->SetStaticMesh(Cylinder2.Object);
-	ConnectorH->SetGenerateOverlapEvents(false);	
-	ConnectorH->SetRelativeLocation(FVector(0, 0, 100));
-	ConnectorH->SetWorldScale3D(FVector(0.4, 0.4, 1.0));
-	ConnectorH->SetMaterial(0, MetalMaterial.Object);
-	ConnectorH->SetMaterial(1, MetalMaterial.Object);
-	ConnectorH->SetGenerateOverlapEvents(false);
-	ConnectorH->SetCollisionEnabled(ECollisionEnabled::NoCollision);
-	ConnectorH->SetCanEverAffectNavigation(false);
-	ConnectorH->CastShadow = 0;
-	ConnectorH->bVisibleInReflectionCaptures = false;
-
-	UE_LOG(LogTemp, Display, TEXT("OptiX ASelectableActorBase Constructor End 4/4"));
-
-
-}
-
-void ASelectableActorBase::BeginPlay()
-{
-	Super::BeginPlay();
-
-	ArrowX->CreateAndSetMaterialInstanceDynamicFromMaterial(0, ArrowX->GetMaterial(0));
-	ArrowX->CreateAndSetMaterialInstanceDynamicFromMaterial(1, ArrowX->GetMaterial(1));
-	ArrowY->CreateAndSetMaterialInstanceDynamicFromMaterial(0, ArrowY->GetMaterial(0));
-	ArrowY->CreateAndSetMaterialInstanceDynamicFromMaterial(1, ArrowY->GetMaterial(1));
-	ArrowZ->CreateAndSetMaterialInstanceDynamicFromMaterial(0, ArrowZ->GetMaterial(0));
-	ArrowZ->CreateAndSetMaterialInstanceDynamicFromMaterial(1, ArrowZ->GetMaterial(1));
-
-	SupportSphereH->CreateAndSetMaterialInstanceDynamicFromMaterial(0, SupportSphereH->GetMaterial(0));
-	SupportSphereV->CreateAndSetMaterialInstanceDynamicFromMaterial(0, SupportSphereV->GetMaterial(0));
-
-
-	SupportSphereH->OnComponentBeginOverlap.AddDynamic(this, &ASelectableActorBase::OnOverlapBegin);
-	SupportSphereH->OnComponentEndOverlap.AddDynamic(this, &ASelectableActorBase::OnOverlapEnd);
-
-	SupportSphereV->OnComponentBeginOverlap.AddDynamic(this, &ASelectableActorBase::OnOverlapBegin);
-	SupportSphereV->OnComponentEndOverlap.AddDynamic(this, &ASelectableActorBase::OnOverlapEnd);
-
-	ArrowX->OnComponentBeginOverlap.AddDynamic(this, &ASelectableActorBase::OnOverlapBegin);
-	ArrowX->OnComponentEndOverlap.AddDynamic(this, &ASelectableActorBase::OnOverlapEnd);
-
-	ArrowY->OnComponentBeginOverlap.AddDynamic(this, &ASelectableActorBase::OnOverlapBegin);
-	ArrowY->OnComponentEndOverlap.AddDynamic(this, &ASelectableActorBase::OnOverlapEnd);
-
-	ArrowZ->OnComponentBeginOverlap.AddDynamic(this, &ASelectableActorBase::OnOverlapBegin);
-	ArrowZ->OnComponentEndOverlap.AddDynamic(this, &ASelectableActorBase::OnOverlapEnd);
-}
-
-void ASelectableActorBase::Tick(float DeltaTime)
-{
-	Super::Tick(DeltaTime);
-	
-
-	FVector PlayerLocation = UGameplayStatics::GetPlayerPawn(GetWorld(), 0)->GetActorLocation();
-	{
-		FVector Diff = PlayerLocation - DegreeWidgetV->GetComponentTransform().GetLocation();
-		FVector Projected = FVector::VectorPlaneProject(Diff, FVector(0, 0, 1));
-		DegreeWidgetV->SetWorldRotation(FRotationMatrix::MakeFromXZ(Projected, FVector(0, 0, 1)).Rotator());
-	}
-	{
-		FVector Diff = PlayerLocation - DegreeWidgetH->GetComponentTransform().GetLocation();
-		FVector Projected = FVector::VectorPlaneProject(Diff, FVector(0, 0, 1));
-		DegreeWidgetH->SetWorldRotation(FRotationMatrix::MakeFromXZ(Projected, FVector(0, 0, 1)).Rotator());
-	}
-	{
-		FVector Diff = PlayerLocation - SupportWidget->GetComponentTransform().GetLocation();
-		FVector Projected = FVector::VectorPlaneProject(Diff, FVector(0, 0, 1));
-		SupportWidget->SetWorldRotation(FRotationMatrix::MakeFromXZ(Projected, FVector(0, 0, 1)).Rotator());
-	}
-	{
-		FVector Diff = PlayerLocation - TranslateWidgetX->GetComponentTransform().GetLocation();
-		FVector Projected = FVector::VectorPlaneProject(Diff, FVector(0, 0, 1));
-		TranslateWidgetX->SetWorldRotation(FRotationMatrix::MakeFromXZ(Projected, FVector(0, 0, 1)).Rotator());
-	} 
-	{
-		FVector Diff = PlayerLocation - TranslateWidgetY->GetComponentTransform().GetLocation();
-		FVector Projected = FVector::VectorPlaneProject(Diff, FVector(0, 0, 1));
-		TranslateWidgetY->SetWorldRotation(FRotationMatrix::MakeFromXZ(Projected, FVector(0, 0, 1)).Rotator());
-	}
-	{
-		FVector Diff = PlayerLocation - TranslateWidgetZ->GetComponentTransform().GetLocation();
-		FVector Projected = FVector::VectorPlaneProject(Diff, FVector(0, 0, 1));
-		TranslateWidgetZ->SetWorldRotation(FRotationMatrix::MakeFromXZ(Projected, FVector(0, 0, 1)).Rotator());
-	}
-
-}
-
-void ASelectableActorBase::SetScaleV(FRotator Rot)
-{
-	ScaleV->SetWorldRotation(Rot);
-}
-
-void ASelectableActorBase::SetScaleH(FRotator Rot)
-{
-	ScaleH->SetWorldRotation(Rot);
-}
-
-void ASelectableActorBase::EnableTranslation()
-{
-	TranslationSupport->SetHiddenInGame(false, true);
-	RotationSupport->SetHiddenInGame(true, true);
-
-	SupportSphereV->SetGenerateOverlapEvents(false);
-	SupportSphereH->SetGenerateOverlapEvents(false);
-	ArrowX->SetGenerateOverlapEvents(true);
-	ArrowY->SetGenerateOverlapEvents(true);
-	ArrowZ->SetGenerateOverlapEvents(true);
-
-	AOptiXVRPawn* OptiXVRPawn = Cast<AOptiXVRPawn>(UGameplayStatics::GetPlayerPawn(GetWorld(), 0));
-	if (OptiXVRPawn)
-	{
-		OptiXVRPawn->UIEventTranslation();
-	}
-
-}
-
-void ASelectableActorBase::EnableRotation()
-{
-	TranslationSupport->SetHiddenInGame(true, true);
-	RotationSupport->SetHiddenInGame(false, true);
-
-	SupportSphereV->SetGenerateOverlapEvents(true);
-	SupportSphereH->SetGenerateOverlapEvents(true);
-	ArrowX->SetGenerateOverlapEvents(false);
-	ArrowY->SetGenerateOverlapEvents(false);
-	ArrowZ->SetGenerateOverlapEvents(false);
-
-	AOptiXVRPawn* OptiXVRPawn = Cast<AOptiXVRPawn>(UGameplayStatics::GetPlayerPawn(GetWorld(), 0));
-	if (OptiXVRPawn)
-	{
-		OptiXVRPawn->UIEventRotation();
-	}
-}
-
-void ASelectableActorBase::DeselectActor()
-{
-	AOptiXVRPawn* OptiXVRPawn = Cast<AOptiXVRPawn>(UGameplayStatics::GetPlayerPawn(GetWorld(), 0));
-	if (OptiXVRPawn)
-	{
-		OptiXVRPawn->UIEventDeselect();
-	}
-	Deselect();
-}
-
-void ASelectableActorBase::DeleteActor()
-{
-	AOptiXVRPawn* OptiXVRPawn = Cast<AOptiXVRPawn>(UGameplayStatics::GetPlayerPawn(GetWorld(), 0));
-	if (OptiXVRPawn)
-	{
-		OptiXVRPawn->UIEventDelete();
-	}
-	Destroy();
-}
-
-
-void ASelectableActorBase::SetRodPosition(FVector TablePosition)
-{
-
-	// Flip socket?
-	if (Socket->GetComponentLocation().Z > GetActorLocation().Z)
-	{
-		Socket->SetRelativeLocation(-1 * Socket->RelativeLocation);
-	}
-
-
-	FVector TableZero = TablePosition + FVector(0, 0, 95); // Table Height	
-
-	// Far away from the table or below table, make it go straight down
-	if ( (Socket->GetComponentLocation().Z <= TableZero.Z) || (Socket->GetComponentLocation() - TableZero).Size() > 200) 
-	{
-		ConnectorH->SetWorldScale3D(FVector(0, 0, 0));
-		ConnectorV->SetWorldScale3D(FVector(0.4, 0.4, -10));
-		return;
-	}
-
-
-	float ScaleFactorV = FMath::Abs(ConnectorV->GetComponentLocation().Z - TableZero.Z) / 100.0f;
-	ConnectorV->SetWorldScale3D(FVector(0.4, 0.4, -ScaleFactorV));
-
-	FVector DistanceToSphere = TableZero - Sphere->GetComponentLocation();
-	float ScaleFactorH = DistanceToSphere.Size() / 100.0f;
-	ConnectorH->SetWorldScale3D(FVector(0.4, 0.4, ScaleFactorH));
-
-	ConnectorH->SetWorldRotation(FRotationMatrix::MakeFromZ(DistanceToSphere).Rotator());
-
-}
-
-// TODO Material highlighting - swap material slots?
-void ASelectableActorBase::OnOverlapBegin_Implementation(UPrimitiveComponent * OverlapComponent, AActor * OtherActor, UPrimitiveComponent * OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult & SweepResult)
-{
-
-	AOptiXVRPawn* OverlappingPawn = Cast<AOptiXVRPawn>(OtherActor);
-
-	if (OverlappingPawn != nullptr)
-	{
-		OverlappingPawn->OnOverlapBeginWithLever(OverlapComponent);
-	}
-
-	//int32 N = OverlapComponent->GetNumMaterials();
-	//for (int32 i = 0; i < N; i++)
-	//{
-	//	Cast<UMaterialInstanceDynamic>(OverlapComponent->GetMaterial(i))->SetVectorParameterValue("Color", FLinearColor(0.5, 0.5, 0.8));
-	//}
-}
-
-void ASelectableActorBase::OnOverlapEnd_Implementation(UPrimitiveComponent* OverlappedComp, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex)
-{
-
-	AOptiXVRPawn* OverlappingPawn = Cast<AOptiXVRPawn>(OtherActor);
-
-	if (OverlappingPawn != nullptr)
-	{
-		OverlappingPawn->OnOverlapEndWithLever(OverlappedComp);
-	}
-
-	//int32 N = OverlappedComp->GetNumMaterials();
-	//for (int32 i = 0; i < N; i++)
-	//{
-	//	Cast<UMaterialInstanceDynamic>(OverlappedComp->GetMaterial(i))->SetVectorParameterValue("Color", FLinearColor(0.4, 0.4, 0.4));
-	//}
-}
+// Fill out your copyright notice in the Description page of Project Settings.
+
+#include "SelectableActorBase.h"
+#include "UObject/ConstructorHelpers.h"
+#include "Runtime/Engine/Classes/Engine/StaticMesh.h"
+#include "Kismet/GameplayStatics.h"
+#include "Blueprint/UserWidget.h"
+#include "Runtime/Engine/Classes/Materials/MaterialInstanceDynamic.h"
+
+#include "OptiXVRPawn.h"
+
+ASelectableActorBase::ASelectableActorBase(const FObjectInitializer& ObjectInitializer)
+	: Super(ObjectInitializer)
+{
+
+	UE_LOG(LogTemp, Display, TEXT("OptiX ASelectableActorBase Constructor Start"));
+
+	SetMobility(EComponentMobility::Movable);
+
+	GetStaticMeshComponent()->SetGenerateOverlapEvents(true);
+	GetStaticMeshComponent()->CastShadow = 0;
+
+	UE_LOG(LogTemp, Display, TEXT("OptiX ASelectableActorBase Constructor Component Setup Start"));
+
+
+	Gizmo = CreateDefaultSubobject<USceneComponent>(TEXT("Gizmo"));
+	Gizmo->SetupAttachment(GetStaticMeshComponent());
+	Gizmo->SetHiddenInGame(true);
+	//Gizmo->SetAbsolute(false, true, true);
+
+	SupportWidget = CreateDefaultSubobject<UWidgetComponent>(TEXT("SupportWidget"));
+	SupportWidget->SetAbsolute(false, true, true);
+
+	SupportWidget->SetupAttachment(Gizmo);
+	static ConstructorHelpers::FClassFinder<UUserWidget> SupportWidgetClass(TEXT("/OptiX/UI/SupportSwapWidget2"));
+	SupportWidget->SetWidgetClass(SupportWidgetClass.Class);
+	SupportWidget->SetWorldScale3D(FVector(0.05, 0.05, 0.05));
+	SupportWidget->SetDrawSize(FVector2D(800, 2300));
+	SupportWidget->SetGenerateOverlapEvents(false);
+	SupportWidget->SetHiddenInGame(true);
+	SupportWidget->SetTwoSided(true);
+
+	UE_LOG(LogTemp, Display, TEXT("OptiX ASelectableActorBase Constructor 1/4"));
+
+
+	TranslationSupport = CreateDefaultSubobject<USceneComponent>(TEXT("TranslationSupport"));
+	TranslationSupport->SetupAttachment(Gizmo);
+
+	TranslateX = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("TranslateX"));
+	TranslateX->SetAbsolute(false, true, true);
+	TranslateX->SetupAttachment(TranslationSupport);
+	static ConstructorHelpers::FObjectFinder<UStaticMesh> TranslateXMesh(TEXT("StaticMesh'/OptiX/UI/Translator/Arrowbody.Arrowbody'"));
+	TranslateX->SetStaticMesh(TranslateXMesh.Object);
+	TranslateX->SetWorldScale3D(FVector(0.6f, 0.6f, 0.6f));
+	TranslateX->SetGenerateOverlapEvents(false);
+	TranslateX->SetHiddenInGame(true);
+
+	TranslateX->CastShadow = 0;
+	TranslateX->bVisibleInReflectionCaptures = false;
+	TranslateX->SetCanEverAffectNavigation(false);
+
+	ArrowX = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("ArrowX"));
+	ArrowX->SetAbsolute(false, false, true);
+	ArrowX->SetWorldScale3D(FVector(0.6f, 0.6f, 0.6f));
+	ArrowX->SetupAttachment(TranslateX);
+	static ConstructorHelpers::FObjectFinder<UStaticMesh> TranslateArrow(TEXT("StaticMesh'/OptiX/UI/Translator/Arrowhead.Arrowhead'"));
+	ArrowX->SetStaticMesh(TranslateArrow.Object);
+	//ArrowX->SetAbsolute(false, true, false);
+	ArrowX->SetRelativeLocation(FVector(39, 0, 0));
+	ArrowX->SetGenerateOverlapEvents(false);
+	ArrowX->SetHiddenInGame(true);
+
+	ArrowX->CastShadow = 0;
+	ArrowX->bVisibleInReflectionCaptures = false;
+	ArrowX->SetCanEverAffectNavigation(false);
+
+	TranslateY = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("TranslateY"));
+	TranslateY->SetAbsolute(false, true, true);
+
+	TranslateY->SetupAttachment(TranslationSupport);
+	TranslateY->SetStaticMesh(TranslateXMesh.Object);
+	TranslateY->SetWorldScale3D(FVector(0.6f, 0.6f, 0.6f));
+	TranslateY->SetGenerateOverlapEvents(false);
+	TranslateY->SetHiddenInGame(true);
+	TranslateY->SetWorldRotation(FRotator(0.f, 90.0f, 0.0f));
+
+	TranslateY->CastShadow = 0;
+	TranslateY->bVisibleInReflectionCaptures = false;
+	TranslateY->SetCanEverAffectNavigation(false);
+
+	ArrowY = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("ArrowY"));
+	ArrowY->SetAbsolute(false, false, true);
+
+	ArrowY->SetupAttachment(TranslateY);
+	ArrowY->SetStaticMesh(TranslateArrow.Object);
+	//ArrowY->SetAbsolute(false, true, false);
+	ArrowY->SetWorldScale3D(FVector(0.6f, 0.6f, 0.6f));
+	ArrowY->SetRelativeLocation(FVector(39, 0, 0));
+	ArrowY->SetGenerateOverlapEvents(false);
+	ArrowY->SetHiddenInGame(true);
+
+	ArrowY->CastShadow = 0;
+	ArrowY->bVisibleInReflectionCaptures = false;
+	ArrowY->SetCanEverAffectNavigation(false);	
+
+	TranslateZ = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("TranslateZ"));
+	TranslateZ->SetAbsolute(false, true, true);
+	TranslateZ->SetupAttachment(TranslationSupport);
+	TranslateZ->SetStaticMesh(TranslateXMesh.Object);
+	TranslateZ->SetWorldScale3D(FVector(0.6f, 0.6f, 0.6f));
+	TranslateZ->SetGenerateOverlapEvents(false);
+	TranslateZ->SetHiddenInGame(true);
+	TranslateZ->SetWorldRotation(FRotator(90.f, 0.0f, 0.0f));
+	TranslateZ->SetCanEverAffectNavigation(false);
+	TranslateZ->CastShadow = 0;
+	TranslateZ->bVisibleInReflectionCaptures = false;
+
+
+	ArrowZ = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("ArrowZ"));
+	ArrowZ->SetAbsolute(false, false, true);
+	ArrowZ->SetupAttachment(TranslateZ);
+	ArrowZ->SetStaticMesh(TranslateArrow.Object);
+	//ArrowZ->SetAbsolute(false, true, false);
+	ArrowZ->SetWorldScale3D(FVector(0.6f, 0.6f, 0.6f));
+	ArrowZ->SetRelativeLocation(FVector(39, 0, 0));
+	ArrowZ->SetGenerateOverlapEvents(false);
+	ArrowZ->SetHiddenInGame(true);
+	ArrowZ->SetCanEverAffectNavigation(false);
+	ArrowZ->CastShadow = 0;
+	ArrowZ->bVisibleInReflectionCaptures = false;
+
+	UE_LOG(LogTemp, Display, TEXT("OptiX ASelectableActorBase Constructor 2/4"));
+
+
+	RotationSupport = CreateDefaultSubobject<USceneComponent>(TEXT("RotationSupport"));
+	RotationSupport->SetupAttachment(Gizmo);
+
+	ScaleH = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("ScaleH"));
+	ScaleH->SetupAttachment(RotationSupport);
+	static ConstructorHelpers::FObjectFinder<UStaticMesh> ScaleMesh(TEXT("StaticMesh'/OptiX/UI/Rotator/scale1.scale1'"));
+	ScaleH->SetStaticMesh(ScaleMesh.Object);
+	ScaleH->SetAbsolute(false, true, false);
+	ScaleH->SetGenerateOverlapEvents(false);
+	ScaleH->SetCollisionEnabled(ECollisionEnabled::NoCollision);
+	ScaleH->SetHiddenInGame(true);
+	ScaleH->SetCanEverAffectNavigation(false);
+	ScaleH->CastShadow = 0;
+	ScaleH->bVisibleInReflectionCaptures = false;
+
+	ScaleV = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("ScaleV"));
+	ScaleV->SetupAttachment(RotationSupport);
+	ScaleV->SetStaticMesh(ScaleMesh.Object);
+	ScaleV->SetWorldRotation(FRotator(90, 0, 0));
+	ScaleV->SetAbsolute(false, true, false);
+	ScaleV->SetGenerateOverlapEvents(false);
+	ScaleV->SetCollisionEnabled(ECollisionEnabled::NoCollision);
+	ScaleV->SetHiddenInGame(true);
+	ScaleV->SetCanEverAffectNavigation(false);
+	ScaleV->CastShadow = 0;
+	ScaleV->bVisibleInReflectionCaptures = false;
+
+	SupportH = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("SupportH"));
+	SupportH->SetupAttachment(RotationSupport);
+	static ConstructorHelpers::FObjectFinder<UStaticMesh> SupportMesh(TEXT("StaticMesh'/OptiX/UI/Rotator/Cylinder_2.Cylinder_2'"));
+	SupportH->SetStaticMesh(SupportMesh.Object);
+	SupportH->SetWorldRotation(FRotator(-90, 0, 0));
+	SupportH->SetWorldScale3D(FVector(0.6, 0.6, 0.3));
+	SupportH->SetGenerateOverlapEvents(false);
+	SupportH->SetHiddenInGame(true);
+	//SupportH->SetWorldLocation(FVector(25, 0, 0));
+	SupportH->SetCanEverAffectNavigation(false);
+	SupportH->CastShadow = 0;
+	SupportH->bVisibleInReflectionCaptures = false;
+
+	SupportSphereH = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("SupportSphereH"));
+	SupportSphereH->SetupAttachment(SupportH);
+	static ConstructorHelpers::FObjectFinder<UStaticMesh> SupportSphereMesh(TEXT("StaticMesh'/OptiX/UI/Rotator/SelectorSphere.SelectorSphere'"));
+	SupportSphereH->SetStaticMesh(SupportSphereMesh.Object);
+	SupportSphereH->SetAbsolute(false, false, true);
+	SupportSphereH->SetWorldScale3D(FVector(0.03, 0.03, 0.03));
+	SupportSphereH->SetGenerateOverlapEvents(false);
+	SupportSphereH->SetHiddenInGame(true);
+	SupportSphereH->SetRelativeLocation(FVector(0, 0, 100));
+	SupportSphereH->SetCanEverAffectNavigation(false);
+	SupportSphereH->CastShadow = 0;
+	SupportSphereH->bVisibleInReflectionCaptures = false;
+
+	DegreeWidgetH = CreateDefaultSubobject<UWidgetComponent>(TEXT("DegreeWidgetH"));
+	DegreeWidgetH->SetupAttachment(SupportSphereH);
+	static ConstructorHelpers::FClassFinder<UUserWidget> DegreeWidgetClass(TEXT("/OptiX/UI/Rotator/DegreeCounter"));
+	DegreeWidgetH->SetWidgetClass(DegreeWidgetClass.Class);
+	DegreeWidgetH->SetRelativeLocationAndRotation(FVector(0, 0, -40), FRotator(0, 90, -90));
+	//DegreeWidgetH->SetRelativeScale3D(FVector(2.0, 2.0, 0.08));
+	DegreeWidgetH->SetDrawSize(FVector2D(200, 300));
+	DegreeWidgetH->SetHiddenInGame(true);
+	DegreeWidgetH->SetGenerateOverlapEvents(false);
+	//DegreeWidgetH->SetTwoSided(true);
+
+	SupportV = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("SupportV"));
+	SupportV->SetupAttachment(RotationSupport);
+	SupportV->SetStaticMesh(SupportMesh.Object);
+	SupportV->SetWorldRotation(FRotator(0.0f, 0.0f, 90.0f));
+	SupportV->SetWorldScale3D(FVector(0.6, 0.6, 0.3));
+	SupportV->SetGenerateOverlapEvents(false);
+	SupportV->SetHiddenInGame(true);
+	//SupportV->SetWorldLocation(FVector(0, 25, 0));
+	SupportV->SetCanEverAffectNavigation(false);
+	SupportV->CastShadow = 0;
+	SupportV->bVisibleInReflectionCaptures = false;
+
+	SupportSphereV = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("SupportSphereV"));
+	SupportSphereV->SetupAttachment(SupportV);
+	//static ConstructorHelpers::FObjectFinder<UStaticMesh> SupportSphereMesh(TEXT("StaticMesh'/OptiX/UI/Rotator/Sphere_2.Sphere_2'"));
+	SupportSphereV->SetStaticMesh(SupportSphereMesh.Object);
+	SupportSphereV->SetAbsolute(false, false, true);
+	SupportSphereV->SetWorldScale3D(FVector(0.03, 0.03, 0.03));
+	SupportSphereV->SetGenerateOverlapEvents(false);
+	SupportSphereV->SetHiddenInGame(true);
+	SupportSphereV->SetRelativeLocation(FVector(0, 0, 100));
+	SupportSphereV->SetCanEverAffectNavigation(false);
+	SupportSphereV->CastShadow = 0;
+	SupportSphereV->bVisibleInReflectionCaptures = false;
+
+	DegreeWidgetV = CreateDefaultSubobject<UWidgetComponent>(TEXT("DegreeWidgetV"));
+	DegreeWidgetV->SetupAttachment(SupportSphereV);
+	DegreeWidgetV->SetWidgetClass(DegreeWidgetClass.Class);
+	DegreeWidgetV->SetRelativeLocationAndRotation(FVector(0, 0, 40), FRotator(0, 0, -90));
+	//DegreeWidgetV->SetRelativeScale3D(FVector(2.0, 2.0, 0.08));
+	DegreeWidgetV->SetDrawSize(FVector2D(200, 300));
+	DegreeWidgetV->SetHiddenInGame(true);
+	DegreeWidgetV->SetGenerateOverlapEvents(false);
+	//DegreeWidgetV->SetTwoSided(true);
+
+	UE_LOG(LogTemp, Display, TEXT("OptiX ASelectableActorBase Constructor 3/4"));
+	   	 
+
+	// Rods	   	 
+
+	static ConstructorHelpers::FObjectFinder<UMaterial> MetalMaterial(TEXT("Material'/OptiX/Laser/MetalSilver.MetalSilver'"));
+	static ConstructorHelpers::FObjectFinder<UStaticMesh> SphereMesh(TEXT("StaticMesh'/Engine/BasicShapes/Sphere.Sphere'"));
+	static ConstructorHelpers::FObjectFinder<UStaticMesh> Cylinder2(TEXT("StaticMesh'/OptiX/UI/Rotator/Cylinder_2.Cylinder_2'"));
+
+	Socket = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("SocketNew"));
+	Socket->SetAbsolute(false, false, true);
+
+	Socket->SetupAttachment(GetStaticMeshComponent());
+	Socket->SetStaticMesh(SphereMesh.Object);
+	Socket->SetGenerateOverlapEvents(false);
+	Socket->SetMaterial(0, MetalMaterial.Object);
+	Socket->SetCollisionEnabled(ECollisionEnabled::NoCollision);
+	Socket->SetWorldScale3D(FVector(0.02, 0.02, 0.02));
+	//Socket->SetRelativeLocation(FVector(0, 0, 0));
+	Socket->SetCanEverAffectNavigation(false);
+	Socket->CastShadow = 0;
+	Socket->bVisibleInReflectionCaptures = false;
+
+	ConnectorV = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("ConnectorVNew"));
+	ConnectorV->SetAbsolute(false, true, true);
+
+	ConnectorV->SetupAttachment(Socket);
+	ConnectorV->SetStaticMesh(Cylinder2.Object);
+	ConnectorV->SetWorldScale3D(FVector(0.4, 0.4, -1));
+	ConnectorV->SetGenerateOverlapEvents(false);
+	ConnectorV->SetCollisionEnabled(ECollisionEnabled::NoCollision);
+	ConnectorV->SetMaterial(0, MetalMaterial.Object);
+	ConnectorV->SetMaterial(1, MetalMaterial.Object);
+	ConnectorV->SetCanEverAffectNavigation(false);
+	ConnectorV->CastShadow = 0;
+	ConnectorV->bVisibleInReflectionCaptures = false;
+
+	Sphere = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("SphereNew"));
+	Sphere->SetAbsolute(false, false, true);
+
+	Sphere->SetupAttachment(ConnectorV);
+	Sphere->SetStaticMesh(SphereMesh.Object);
+	Sphere->SetGenerateOverlapEvents(false);
+	Sphere->SetMaterial(0, MetalMaterial.Object);
+	Sphere->SetCollisionEnabled(ECollisionEnabled::NoCollision);
+	Sphere->SetWorldScale3D(FVector(0.02, 0.02, 0.02));
+	Sphere->SetRelativeLocation(FVector(0, 0, 100));
+	Sphere->SetCanEverAffectNavigation(false);
+	Sphere->CastShadow = 0;
+	Sphere->bVisibleInReflectionCaptures = false;
+
+	ConnectorH = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("ConnectorHNew"));
+	ConnectorH->SetAbsolute(false, true, true);
+	ConnectorH->SetupAttachment(ConnectorV);
+	ConnectorH->SetStaticMesh(Cylinder2.Object);
+	ConnectorH->SetGenerateOverlapEvents(false);	
+	ConnectorH->SetRelativeLocation(FVector(0, 0, 100));
+	ConnectorH->SetWorldScale3D(FVector(0.4, 0.4, 1.0));
+	ConnectorH->SetMaterial(0, MetalMaterial.Object);
+	ConnectorH->SetMaterial(1, MetalMaterial.Object);
+	ConnectorH->SetGenerateOverlapEvents(false);
+	ConnectorH->SetCollisionEnabled(ECollisionEnabled::NoCollision);
+	ConnectorH->SetCanEverAffectNavigation(false);
+	ConnectorH->CastShadow = 0;
+	ConnectorH->bVisibleInReflectionCaptures = false;
+
+
+	static ConstructorHelpers::FClassFinder<UUserWidget> PosWidgetClass(TEXT("/OptiX/UI/Translator/PositionCounter"));
+
+	TranslateWidgetX = CreateDefaultSubobject<UWidgetComponent>(TEXT("TranslateWidgetX"));
+	TranslateWidgetX->SetAbsolute(false, true, true);
+	TranslateWidgetX->SetupAttachment(ArrowX);
+	TranslateWidgetX->SetWidgetClass(PosWidgetClass.Class);
+	//TranslateWidgetX->SetRelativeLocationAndRotation(FVector(0, 0, 0), FRotator(0, 90, 0));
+	//TranslateWidgetX->SetWorldRotation(FRotator());
+	TranslateWidgetX->SetRelativeScale3D(FVector(0.05, 0.05, 0.05));
+	TranslateWidgetX->SetDrawSize(FVector2D(300, 300));
+	TranslateWidgetX->SetHiddenInGame(true);
+	TranslateWidgetX->SetGenerateOverlapEvents(false);
+	//TranslateWidgetX->SetTwoSided(true);
+	// todo
+
+	TranslateWidgetY = CreateDefaultSubobject<UWidgetComponent>(TEXT("TranslateWidgetY"));
+	TranslateWidgetY->SetAbsolute(false, true, true);
+	TranslateWidgetY->SetupAttachment(ArrowY);
+	TranslateWidgetY->SetWidgetClass(PosWidgetClass.Class);
+	//TranslateWidgetY->SetWorldRotation(FRotator());
+	TranslateWidgetY->SetRelativeScale3D(FVector(0.05, 0.05, 0.05));
+	TranslateWidgetY->SetDrawSize(FVector2D(300, 300));
+	TranslateWidgetY->SetHiddenInGame(true);
+	TranslateWidgetY->SetGenerateOverlapEvents(false);
+	//TranslateWidgetY->SetTwoSided(true);
+
+	TranslateWidgetZ = CreateDefaultSubobject<UWidgetComponent>(TEXT("TranslateWidgetZ"));
+	TranslateWidgetZ->SetAbsolute(false, true, true);
+	//TranslateWidgetZ->SetTwoSided(true);
+
+	TranslateWidgetZ->SetupAttachment(ArrowZ);
+	TranslateWidgetZ->SetWidgetClass(PosWidgetClass.Class);
+	//TranslateWidgetZ->SetWorldRotation(FRotator());
+	TranslateWidgetZ->SetRelativeScale3D(FVector(0.05, 0.05, 0.05));
+	TranslateWidgetZ->SetDrawSize(FVector2D(300, 300));
+	TranslateWidgetZ->SetRelativeLocation(FVector(8, 0, 0));
+
+	TranslateWidgetZ->SetHiddenInGame(true);
+	TranslateWidgetZ->SetGenerateOverlapEvents(false);
+
+	UE_LOG(LogTemp, Display, TEXT("OptiX ASelectableActorBase Constructor End 4/4"));
+
+
+}
+
+void ASelectableActorBase::BeginPlay()
+{
+	Super::BeginPlay();
+
+	ArrowX->CreateAndSetMaterialInstanceDynamicFromMaterial(0, ArrowX->GetMaterial(0));
+	ArrowX->CreateAndSetMaterialInstanceDynamicFromMaterial(1, ArrowX->GetMaterial(1));
+	ArrowY->CreateAndSetMaterialInstanceDynamicFromMaterial(0, ArrowY->GetMaterial(0));
+	ArrowY->CreateAndSetMaterialInstanceDynamicFromMaterial(1, ArrowY->GetMaterial(1));
+	ArrowZ->CreateAndSetMaterialInstanceDynamicFromMaterial(0, ArrowZ->GetMaterial(0));
+	ArrowZ->CreateAndSetMaterialInstanceDynamicFromMaterial(1, ArrowZ->GetMaterial(1));
+
+	SupportSphereH->CreateAndSetMaterialInstanceDynamicFromMaterial(0, SupportSphereH->GetMaterial(0));
+	SupportSphereV->CreateAndSetMaterialInstanceDynamicFromMaterial(0, SupportSphereV->GetMaterial(0));
+
+
+	SupportSphereH->OnComponentBeginOverlap.AddDynamic(this, &ASelectableActorBase::OnOverlapBegin);
+	SupportSphereH->OnComponentEndOverlap.AddDynamic(this, &ASelectableActorBase::OnOverlapEnd);
+
+	SupportSphereV->OnComponentBeginOverlap.AddDynamic(this, &ASelectableActorBase::OnOverlapBegin);
+	SupportSphereV->OnComponentEndOverlap.AddDynamic(this, &ASelectableActorBase::OnOverlapEnd);
+
+	ArrowX->OnComponentBeginOverlap.AddDynamic(this, &ASelectableActorBase::OnOverlapBegin);
+	ArrowX->OnComponentEndOverlap.AddDynamic(this, &ASelectableActorBase::OnOverlapEnd);
+
+	ArrowY->OnComponentBeginOverlap.AddDynamic(this, &ASelectableActorBase::OnOverlapBegin);
+	ArrowY->OnComponentEndOverlap.AddDynamic(this, &ASelectableActorBase::OnOverlapEnd);
+
+	ArrowZ->OnComponentBeginOverlap.AddDynamic(this, &ASelectableActorBase::OnOverlapBegin);
+	ArrowZ->OnComponentEndOverlap.AddDynamic(this, &ASelectableActorBase::OnOverlapEnd);
+}
+
+void ASelectableActorBase::Tick(float DeltaTime)
+{
+	Super::Tick(DeltaTime);
+	
+
+	FVector PlayerLocation = UGameplayStatics::GetPlayerPawn(GetWorld(), 0)->GetActorLocation();
+	{
+		FVector Diff = PlayerLocation - DegreeWidgetV->GetComponentTransform().GetLocation();
+		FVector Projected = FVector::VectorPlaneProject(Diff, FVector(0, 0, 1));
+		DegreeWidgetV->SetWorldRotation(FRotationMatrix::MakeFromXZ(Projected, FVector(0, 0, 1)).Rotator());
+	}
+	{
+		FVector Diff = PlayerLocation - DegreeWidgetH->GetComponentTransform().GetLocation();
+		FVector Projected = FVector::VectorPlaneProject(Diff, FVector(0, 0, 1));
+		DegreeWidgetH->SetWorldRotation(FRotationMatrix::MakeFromXZ(Projected, FVector(0, 0, 1)).Rotator());
+	}
+	{
+		FVector Diff = PlayerLocation - SupportWidget->GetComponentTransform().GetLocation();
+		FVector Projected = FVector::VectorPlaneProject(Diff, FVector(0, 0, 1));
+		SupportWidget->SetWorldRotation(FRotationMatrix::MakeFromXZ(Projected, FVector(0, 0, 1)).Rotator());
+	}
+	{
+		FVector Diff = PlayerLocation - TranslateWidgetX->GetComponentTransform().GetLocation();
+		FVector Projected = FVector::VectorPlaneProject(Diff, FVector(0, 0, 1));
+		TranslateWidgetX->SetWorldRotation(FRotationMatrix::MakeFromXZ(Projected, FVector(0, 0, 1)).Rotator());
+	} 
+	{
+		FVector Diff = PlayerLocation - TranslateWidgetY->GetComponentTransform().GetLocation();
+		FVector Projected = FVector::VectorPlaneProject(Diff, FVector(0, 0, 1));
+		TranslateWidgetY->SetWorldRotation(FRotationMatrix::MakeFromXZ(Projected, FVector(0, 0, 1)).Rotator());
+	}
+	{
+		FVector Diff = PlayerLocation - TranslateWidgetZ->GetComponentTransform().GetLocation();
+		FVector Projected = FVector::VectorPlaneProject(Diff, FVector(0, 0, 1));
+		TranslateWidgetZ->SetWorldRotation(FRotationMatrix::MakeFromXZ(Projected, FVector(0, 0, 1)).Rotator());
+	}
+
+}
+
+void ASelectableActorBase::SetScaleV(FRotator Rot)
+{
+	ScaleV->SetWorldRotation(Rot);
+}
+
+void ASelectableActorBase::SetScaleH(FRotator Rot)
+{
+	ScaleH->SetWorldRotation(Rot);
+}
+
+void ASelectableActorBase::EnableTranslation()
+{
+	TranslationSupport->SetHiddenInGame(false, true);
+	RotationSupport->SetHiddenInGame(true, true);
+
+	SupportSphereV->SetGenerateOverlapEvents(false);
+	SupportSphereH->SetGenerateOverlapEvents(false);
+	ArrowX->SetGenerateOverlapEvents(true);
+	ArrowY->SetGenerateOverlapEvents(true);
+	ArrowZ->SetGenerateOverlapEvents(true);
+
+	AOptiXVRPawn* OptiXVRPawn = Cast<AOptiXVRPawn>(UGameplayStatics::GetPlayerPawn(GetWorld(), 0));
+	if (OptiXVRPawn)
+	{
+		OptiXVRPawn->UIEventTranslation();
+	}
+
+}
+
+void ASelectableActorBase::EnableRotation()
+{
+	TranslationSupport->SetHiddenInGame(true, true);
+	RotationSupport->SetHiddenInGame(false, true);
+
+	SupportSphereV->SetGenerateOverlapEvents(true);
+	SupportSphereH->SetGenerateOverlapEvents(true);
+	ArrowX->SetGenerateOverlapEvents(false);
+	ArrowY->SetGenerateOverlapEvents(false);
+	ArrowZ->SetGenerateOverlapEvents(false);
+
+	AOptiXVRPawn* OptiXVRPawn = Cast<AOptiXVRPawn>(UGameplayStatics::GetPlayerPawn(GetWorld(), 0));
+	if (OptiXVRPawn)
+	{
+		OptiXVRPawn->UIEventRotation();
+	}
+}
+
+void ASelectableActorBase::DeselectActor()
+{
+	AOptiXVRPawn* OptiXVRPawn = Cast<AOptiXVRPawn>(UGameplayStatics::GetPlayerPawn(GetWorld(), 0));
+	if (OptiXVRPawn)
+	{
+		OptiXVRPawn->UIEventDeselect();
+	}
+	Deselect();
+}
+
+void ASelectableActorBase::DeleteActor()
+{
+	AOptiXVRPawn* OptiXVRPawn = Cast<AOptiXVRPawn>(UGameplayStatics::GetPlayerPawn(GetWorld(), 0));
+	if (OptiXVRPawn)
+	{
+		OptiXVRPawn->UIEventDelete();
+	}
+	Destroy();
+}
+
+
+void ASelectableActorBase::SetRodPosition(FVector TablePosition)
+{
+
+	// Flip socket?
+	if (Socket->GetComponentLocation().Z > GetActorLocation().Z)
+	{
+		Socket->SetRelativeLocation(-1 * Socket->RelativeLocation);
+	}
+
+
+	FVector TableZero = TablePosition + FVector(0, 0, 95); // Table Height	
+
+	// Far away from the table or below table, make it go straight down
+	if ( (Socket->GetComponentLocation().Z <= TableZero.Z) || (Socket->GetComponentLocation() - TableZero).Size() > 200) 
+	{
+		ConnectorH->SetWorldScale3D(FVector(0, 0, 0));
+		ConnectorV->SetWorldScale3D(FVector(0.4, 0.4, -10));
+		return;
+	}
+
+
+	float ScaleFactorV = FMath::Abs(ConnectorV->GetComponentLocation().Z - TableZero.Z) / 100.0f;
+	ConnectorV->SetWorldScale3D(FVector(0.4, 0.4, -ScaleFactorV));
+
+	FVector DistanceToSphere = TableZero - Sphere->GetComponentLocation();
+	float ScaleFactorH = DistanceToSphere.Size() / 100.0f;
+	ConnectorH->SetWorldScale3D(FVector(0.4, 0.4, ScaleFactorH));
+
+	ConnectorH->SetWorldRotation(FRotationMatrix::MakeFromZ(DistanceToSphere).Rotator());
+
+}
+
+// TODO Material highlighting - swap material slots?
+void ASelectableActorBase::OnOverlapBegin_Implementation(UPrimitiveComponent * OverlapComponent, AActor * OtherActor, UPrimitiveComponent * OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult & SweepResult)
+{
+
+	AOptiXVRPawn* OverlappingPawn = Cast<AOptiXVRPawn>(OtherActor);
+
+	if (OverlappingPawn != nullptr)
+	{
+		OverlappingPawn->OnOverlapBeginWithLever(OverlapComponent);
+	}
+
+	//int32 N = OverlapComponent->GetNumMaterials();
+	//for (int32 i = 0; i < N; i++)
+	//{
+	//	Cast<UMaterialInstanceDynamic>(OverlapComponent->GetMaterial(i))->SetVectorParameterValue("Color", FLinearColor(0.5, 0.5, 0.8));
+	//}
+}
+
+void ASelectableActorBase::OnOverlapEnd_Implementation(UPrimitiveComponent* OverlappedComp, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex)
+{
+
+	AOptiXVRPawn* OverlappingPawn = Cast<AOptiXVRPawn>(OtherActor);
+
+	if (OverlappingPawn != nullptr)
+	{
+		OverlappingPawn->OnOverlapEndWithLever(OverlappedComp);
+	}
+
+	//int32 N = OverlappedComp->GetNumMaterials();
+	//for (int32 i = 0; i < N; i++)
+	//{
+	//	Cast<UMaterialInstanceDynamic>(OverlappedComp->GetMaterial(i))->SetVectorParameterValue("Color", FLinearColor(0.4, 0.4, 0.4));
+	//}
+}
diff --git a/Source/OptiX/Public/OptiXContextManager.h b/Source/OptiX/Public/OptiXContextManager.h
index 822beaa36cd843d78f68a91a659a42adf83ba91a..2634494b20ae6565db5bf26fb0aa8ecd1231a31f 100644
--- a/Source/OptiX/Public/OptiXContextManager.h
+++ b/Source/OptiX/Public/OptiXContextManager.h
@@ -1,797 +1,799 @@
-#pragma once
-
-#include "CoreMinimal.h"
-#include "EngineUtils.h"
-
-#include "Runtime/Engine/Public/SceneViewExtension.h"
-
-#include "Runtime/Engine/Classes/Engine/Texture2D.h"
-
-#include "MaterialShared.h"
-#include "Materials/MaterialInstance.h"
-#include "Delegates/Delegate.h"
-
-#include "OptiXContext.h"
-#include "OptiXObjectComponent.h"
-#include "OptiXLaserComponent.h"
-#include "OptiXLaserActor.h"
-#include "OptiXCameraActor.h"
-
-
-
-// Let's try some events!
-
-DECLARE_EVENT(FOptiXContextManager, FLaserTraceFinishedEvent)
-DECLARE_EVENT_OneParam(FOptiXContextManager, FWavelengthChangedEvent, const float)
-DECLARE_MULTICAST_DELEGATE(FOnSceneChangedDelegate);
-
-// DX
-
-#if PLATFORM_WINDOWS
-#include "AllowWindowsPlatformTypes.h"
-#endif
-#include <d3d11.h>
-#if PLATFORM_WINDOWS
-#include "HideWindowsPlatformTypes.h"
-#endif
-
-// print cuda error helper:
-
-inline void PrintLastCudaError(FString Msg)
-{
-	cudaError_t Err = cudaGetLastError();
-	if (cudaSuccess != Err) {
-		UE_LOG(LogTemp, Fatal, TEXT("Cuda Error: %s. "), *Msg, static_cast<int>(Err), cudaGetErrorString(Err));
-	}
-}
-
-
-class OPTIX_API FOptiXContextManager : public FSceneViewExtensionBase
-{
-
-public:
-
-	// The auto register thing is used to make sure this constructor is only called via the NewExtension function
-	FOptiXContextManager(const FAutoRegister& AutoRegister);
-
-	~FOptiXContextManager() 
-	{
-		if (bIsInitialized)
-		{
-			cudaGraphicsUnregisterResource(CudaResourceDepthLeft);
-			cudaGraphicsUnregisterResource(CudaResourceDepthRight);
-			cudaGraphicsUnregisterResource(CudaResourceColorLeft);
-			cudaGraphicsUnregisterResource(CudaResourceColorRight);
-			cudaGraphicsUnregisterResource(CudaResourceIntersections);
-			cudaGraphicsUnregisterResource(CudaResourceColorOrtho);
-			cudaGraphicsUnregisterResource(CudaResourceDepthOrtho);
-
-			PrintLastCudaError("cudaGraphicsUnregisterResource");
-			cudaFree(CudaLinearMemoryDepth);
-			cudaFree(CudaLinearMemoryColor);
-			cudaFree(CudaLinearMemoryIntersections);
-			PrintLastCudaError("cudaFree");
-		}
-
-		AccelerationsToDeleteQueue.Empty();
-		BuffersToDeleteQueue.Empty();
-		GeometriesToDeleteQueue.Empty();
-		GeometryGroupToDeleteQueue.Empty();
-		GeometryInstancesToDeleteQueue.Empty();
-		GroupsToDeleteQueue.Empty();
-		MaterialsToDeleteQueue.Empty();
-		ProgramToDeleteQueue.Empty();
-		TextureSamplersToDeleteQueue.Empty();
-		TransformsToDeleteQueue.Empty();
-
-		GroupChildrenToRemoveQueue.Empty();
-		GeometryGroupChildrenToRemoveQueue.Empty();
-
-		ComponentsToInitializeQueue.Empty();
-		ComponentsToUpdateQueue.Empty();
-		CubemapComponentsToUpdateQueue.Empty();
-
-		LaserActor.Reset();
-		CameraActor.Reset();
-	}
-
-	// ISceneViewExtension interface start, called by the render thread:
-public:
-	virtual void SetupViewFamily(FSceneViewFamily& InViewFamily) override;
-	virtual void SetupView(FSceneViewFamily& InViewFamily, FSceneView& InView) override;
-	virtual void BeginRenderViewFamily(FSceneViewFamily& InViewFamily) override;
-	virtual void PreRenderView_RenderThread(FRHICommandListImmediate& RHICmdList, FSceneView& InView) override;
-	virtual void PreRenderViewFamily_RenderThread(FRHICommandListImmediate& RHICmdList, FSceneViewFamily& InViewFamily) override;
-	virtual void PostRenderViewFamily_RenderThread(FRHICommandListImmediate& RHICmdList, FSceneViewFamily& InViewFamily) override;
-	virtual bool IsActiveThisFrame(class FViewport* InViewport) const override;
-	virtual void PostRenderView_RenderThread(FRHICommandListImmediate& RHICmdList, FSceneView& InView) override;
-	// ISceneViewExtension interface end
-
-
-	void RenderOrthoPass();
-	
-	// Initialization methods, called by the GAME thread	
-	void Init();
-
-	void EndPlay()
-	{
-		//CleanupOptiXOnEnd();
-		//bCleanup.AtomicSet(true);
-		//bStartTracing.AtomicSet(false);
-		//bCleanup.AtomicSet(false);
-		//bEndPlay.AtomicSet(true);
-	}
-
-	UOptiXContext* GetOptiXContext()
-	{
-		return OptiXContext.Get();
-	}
-
-	UMaterialInstanceDynamic* GetOptiXMID() // Used to set up the post process
-	{
-		return DynamicMaterial.Get();
-	}
-
-	UMaterialInstanceDynamic* GetOptiXMIDOrtho() // Used to set up the post process
-	{
-		return DynamicMaterialOrtho.Get();
-	}
-
-	void SceneChangedCallback();
-
-	// The OptiX context is not thread-safe, so any changes to variables/properties on the game thread 
-	// while a trace is running will lead to errors. Game thread objects push their requested updates into several queues,
-	// which then get updated just before the trace runs on the render thread.
-	// TQueue is guaranteed to be thread-safe.
-	// There is probably a better and faster way of doing this.
-
-	void RegisterOptiXComponent(IOptiXComponentInterface* Component)
-	{
-		ComponentsToInitializeQueue.Enqueue(Component);
-	}
-
-	void QueueComponentUpdate(IOptiXComponentInterface* Component)
-	{
-		ComponentsToUpdateQueue.Enqueue(Component);
-	}
-
-	void RequestCubemapUpdate(UOptiXCubemapComponent* Component)
-	{
-		CubemapComponentsToUpdateQueue.Enqueue(Component);
-	}
-
-	void SetActiveLaserActor(AOptiXLaserActor* Laser)
-	{
-		LaserActor = Laser;
-		if (LaserMaterialDynamic.IsValid())
-		{
-			LaserActor->SetLaserMaterial(LaserMaterialDynamic.Get());
-		}
-		else
-		{
-			UE_LOG(LogTemp, Error, TEXT("LaserMaterialDynamic is invalid!"));
-		}
-	}
-
-	void SetActiveCameraActor(AOptiXPlayerCameraManager* Cam)
-	{
-		CameraActor = Cam;
-	}
-
-	FIntRect GetViewRectanglePerEye()
-	{
-		return FIntRect(0, 0, Width, Height);
-	}
-
-	int32 RequestCubemapId();
-
-	void DeleteCubemapId(int32 Id);
-
-	void AddCubemapToBuffer(int32 CubemapId, int32 SamplerId);
-
-	void BroadcastWavelengthChange(float WL)
-	{
-		WavelengthChangedEvent.Broadcast(WL);
-	}
-
-
-public:
-	
-	FThreadSafeBool bStartTracing = false;
-	//FThreadSafeBool bEndPlay = false;
-	FThreadSafeBool bIsInitialized = false;
-	FThreadSafeBool bLaserIsInitialized = false;
-	FThreadSafeBool bSceneChanged = true;
-	FThreadSafeBool bIsTracing = false;
-	FThreadSafeBool bClearToLaunch = true;
-	FThreadSafeBool bCleanup = false;
-	FThreadSafeBool bValidCubemap = false;
-	FThreadSafeBool bRequestOrthoPass = false;
-
-	FLaserTraceFinishedEvent LaserTraceFinishedEvent;
-	FWavelengthChangedEvent WavelengthChangedEvent;
-	FOnSceneChangedDelegate OnSceneChangedDelegate;
-
-
-public:
-
-	// This is so ugly but the optix api structure doesn't really allow anything more abstract.
-	TQueue<optix::Acceleration>			AccelerationsToDeleteQueue;
-	TQueue<optix::Buffer>				BuffersToDeleteQueue;
-	TQueue<optix::Geometry>				GeometriesToDeleteQueue;
-	TQueue<optix::GeometryGroup>		GeometryGroupToDeleteQueue;
-	TQueue<optix::GeometryInstance>		GeometryInstancesToDeleteQueue;
-	TQueue<optix::Group>				GroupsToDeleteQueue;
-	TQueue<optix::Material>				MaterialsToDeleteQueue;
-	TQueue<optix::Program>				ProgramToDeleteQueue;
-	TQueue<optix::TextureSampler>		TextureSamplersToDeleteQueue;
-	TQueue<optix::Transform>			TransformsToDeleteQueue;
-
-	TQueue<TPair<optix::Group, uint32>> GroupChildrenToRemoveQueue;
-	TQueue<TPair<optix::GeometryGroup, uint32>> GeometryGroupChildrenToRemoveQueue;
-
-	FMatrix OrthoMatrix;
-
-private:
-	void InitContext();
-	void InitRendering();
-	void InitBuffers();
-	void InitPrograms();
-	void InitLaser();
-
-	void LaunchLaser();
-
-	void InitCubemap();
-
-	void InitOptiXComponents(FRHICommandListImmediate & RHICmdList)
-	{
-		// Possibly dangerous? Use limited for instead of while in case something goes wrong and we deadlock
-		for (uint32 i = 0; i < 100 && !ComponentsToInitializeQueue.IsEmpty(); i++)
-		{
-			IOptiXComponentInterface* Component;
-			if (ComponentsToInitializeQueue.Dequeue(Component))
-			{
-				Component->InitOptiXComponent(RHICmdList);				
-			}
-		}
-	}
-
-	void UpdateOptiXComponentVariables()
-	{
-		for (uint32 i = 0; i < 100 && !ComponentsToUpdateQueue.IsEmpty(); i++)
-		{
-			IOptiXComponentInterface* Component;
-			if (ComponentsToUpdateQueue.Dequeue(Component))
-			{
-				if (Component != nullptr)
-				{
-					Component->UpdateOptiXComponentVariables();
-					Component->SetUpdateQueued(false);//   bUpdateQueued.AtomicSet(false);
-				}
-			}
-		}
-	}
-
-	void RemovePendingChildrenFromGroups()
-	{
-		for (uint32 i = 0; i < 100 && !GroupChildrenToRemoveQueue.IsEmpty(); i++)
-		{
-			TPair<optix::Group, uint32> Pair;
-			if (GroupChildrenToRemoveQueue.Dequeue(Pair))
-			{
-				if (Pair.Key != NULL)
-				{
-					Pair.Key->removeChild(Pair.Value); // TODO do we need to do anything else here?
-				}
-				else
-				{
-					UE_LOG(LogTemp, Error, TEXT("Error while trying to remove optix child in queue: Object was NULL"));
-				}
-			}
-		}
-		for (uint32 i = 0; i < 100 && !GeometryGroupChildrenToRemoveQueue.IsEmpty(); i++)
-		{
-			TPair<optix::GeometryGroup, uint32> Pair;
-			if (GeometryGroupChildrenToRemoveQueue.Dequeue(Pair))
-			{
-				if (Pair.Key != NULL)
-				{
-					Pair.Key->removeChild(Pair.Value); // TODO do we need to do anything else here?
-				}
-				else
-				{
-					UE_LOG(LogTemp, Error, TEXT("Error while trying to remove optix child in queue: Object was NULL"));
-				}
-			}
-		}
-	}
-
-	void DestroyOptiXObjects()
-	{
-		for (uint32 i = 0; i < 100 && !AccelerationsToDeleteQueue.IsEmpty(); i++)
-		{
-			optix::Acceleration NativeObj;
-			if (AccelerationsToDeleteQueue.Dequeue(NativeObj))
-			{
-				if (NativeObj != NULL)
-				{
-					if(NativeObj->getContext() != NULL)
-						NativeObj->destroy(); // TODO do we need to do anything else here?
-					else
-					{
-						UE_LOG(LogTemp, Warning, TEXT("Context already destroyed but somehow this buffer handle is still valid"));
-					}
-				}
-				else
-				{
-					UE_LOG(LogTemp, Error, TEXT("Error while trying to destroy optix object in queue: Object was NULL"));
-				}
-			}			
-		}
-		for (uint32 i = 0; i < 100 && !BuffersToDeleteQueue.IsEmpty(); i++)
-		{
-			optix::Buffer NativeObj;
-			if (BuffersToDeleteQueue.Dequeue(NativeObj))
-			{
-				if (NativeObj != NULL)
-				{
-					try
-					{
-						NativeObj->destroy(); // TODO do we need to do anything else here?
-					}
-					catch (optix::Exception& E)
-					{
-						FString Message = FString(E.getErrorString().c_str());
-						UE_LOG(LogTemp, Error, TEXT("Trying to remove buffer: OptiX Error: %s"), *Message);
-						GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-					}
-				}
-				else
-				{
-					UE_LOG(LogTemp, Error, TEXT("Error while trying to destroy optix object in queue: Object was NULL"));
-				}
-			}
-		}
-		for (uint32 i = 0; i < 100 && !GeometriesToDeleteQueue.IsEmpty(); i++)
-		{
-			optix::Geometry NativeObj;
-			if (GeometriesToDeleteQueue.Dequeue(NativeObj))
-			{
-				if (NativeObj != NULL)
-				{
-					NativeObj->destroy(); // TODO do we need to do anything else here?
-				}
-				else
-				{
-					UE_LOG(LogTemp, Error, TEXT("Error while trying to destroy optix object in queue: Object was NULL"));
-				}
-			}
-		}
-		for (uint32 i = 0; i < 100 && !GeometryInstancesToDeleteQueue.IsEmpty(); i++)
-		{
-			optix::GeometryInstance NativeObj;
-			if (GeometryInstancesToDeleteQueue.Dequeue(NativeObj))
-			{
-				if (NativeObj != NULL)
-				{
-					NativeObj->destroy(); // TODO do we need to do anything else here?
-				}
-				else
-				{
-					UE_LOG(LogTemp, Error, TEXT("Error while trying to destroy optix object in queue: Object was NULL"));
-				}
-			}
-		}
-		for (uint32 i = 0; i < 100 && !GeometryGroupToDeleteQueue.IsEmpty(); i++)
-		{
-			optix::GeometryGroup NativeObj;
-			if (GeometryGroupToDeleteQueue.Dequeue(NativeObj))
-			{
-				if (NativeObj != NULL)
-				{
-					NativeObj->destroy(); // TODO do we need to do anything else here?
-				}
-				else
-				{
-					UE_LOG(LogTemp, Error, TEXT("Error while trying to destroy optix object in queue: Object was NULL"));
-				}
-			}
-		}
-		for (uint32 i = 0; i < 100 && !GroupsToDeleteQueue.IsEmpty(); i++)
-		{
-			optix::Group NativeObj;
-			if (GroupsToDeleteQueue.Dequeue(NativeObj))
-			{
-				if (NativeObj != NULL)
-				{
-					NativeObj->destroy(); // TODO do we need to do anything else here?
-				}
-				else
-				{
-					UE_LOG(LogTemp, Error, TEXT("Error while trying to destroy optix object in queue: Object was NULL"));
-				}
-			}
-		}
-		for (uint32 i = 0; i < 100 && !MaterialsToDeleteQueue.IsEmpty(); i++)
-		{
-			optix::Material NativeObj;
-			if (MaterialsToDeleteQueue.Dequeue(NativeObj))
-			{
-				if (NativeObj != NULL)
-				{
-					NativeObj->destroy(); // TODO do we need to do anything else here?
-				}
-				else
-				{
-					UE_LOG(LogTemp, Error, TEXT("Error while trying to destroy optix object in queue: Object was NULL"));
-				}
-			}
-		}
-		for (uint32 i = 0; i < 100 && !ProgramToDeleteQueue.IsEmpty(); i++)
-		{
-			optix::Program NativeObj;
-			if (ProgramToDeleteQueue.Dequeue(NativeObj))
-			{
-				if (NativeObj != NULL)
-				{
-					NativeObj->destroy(); // TODO do we need to do anything else here?
-				}
-				else
-				{
-					UE_LOG(LogTemp, Error, TEXT("Error while trying to destroy optix object in queue: Object was NULL"));
-				}
-			}
-		}
-		for (uint32 i = 0; i < 100 && !TextureSamplersToDeleteQueue.IsEmpty(); i++)
-		{
-			optix::TextureSampler NativeObj;
-			if (TextureSamplersToDeleteQueue.Dequeue(NativeObj))
-			{
-				if (NativeObj != NULL)
-				{
-					try
-					{
-						NativeObj->destroy(); // TODO do we need to do anything else here?
-					}
-					catch (optix::Exception& E)
-					{
-						FString Message = FString(E.getErrorString().c_str());
-						UE_LOG(LogTemp, Error, TEXT("Trying to remove texture sampler: OptiX Error: %s"), *Message);
-						GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-					}
-				}
-				else
-				{
-					UE_LOG(LogTemp, Error, TEXT("Error while trying to destroy optix object in queue: Object was NULL"));
-				}
-			}
-		}
-		for (uint32 i = 0; i < 100 && !TransformsToDeleteQueue.IsEmpty(); i++)
-		{
-			optix::Transform NativeObj;
-			if (TransformsToDeleteQueue.Dequeue(NativeObj))
-			{
-				if (NativeObj != NULL)
-				{
-					NativeObj->destroy(); // TODO do we need to do anything else here?
-				}
-				else
-				{
-					UE_LOG(LogTemp, Error, TEXT("Error while trying to destroy optix object in queue: Object was NULL"));
-				}
-			}
-		}
-	}
-
-	void UpdateRequestedCubemaps(FRHICommandListImmediate & RHICmdList)
-	{
-		// update only the first for now, shouldn't be more than 1 in queue anyway:
-
-		if (!CubemapComponentsToUpdateQueue.IsEmpty())
-		{
-			UOptiXCubemapComponent* Comp;
-			if (CubemapComponentsToUpdateQueue.Dequeue(Comp))
-			{
-				Comp->UpdateCubemap(RHICmdList);
-			}
-		}
-	}
-
-	void UpdateCubemapBuffer(FRHICommandListImmediate & RHICmdList);
-
-	void CleanupOptiXOnEnd()
-	{
-
-		UE_LOG(LogTemp, Display, TEXT("Starting Cleanup in Context Manager"));
-
-
-		if (bIsInitialized)
-		{
-			if(CudaResourceDepthLeft != NULL)
-				cudaGraphicsUnregisterResource(CudaResourceDepthLeft);
-			if (CudaResourceDepthRight != NULL)
-				cudaGraphicsUnregisterResource(CudaResourceDepthRight);
-			if (CudaResourceColorLeft != NULL)
-				cudaGraphicsUnregisterResource(CudaResourceColorLeft);
-			if(CudaResourceColorRight != NULL)
-				cudaGraphicsUnregisterResource(CudaResourceColorRight);
-			if(CudaResourceIntersections != NULL)
-				cudaGraphicsUnregisterResource(CudaResourceIntersections);
-			if (CudaResourceDepthOrtho != NULL)
-				cudaGraphicsUnregisterResource(CudaResourceDepthOrtho);
-			if (CudaResourceColorOrtho != NULL)
-				cudaGraphicsUnregisterResource(CudaResourceColorOrtho);
-			PrintLastCudaError("cudaGraphicsUnregisterResource");
-			if(CudaLinearMemoryDepth != NULL)
-				cudaFree(CudaLinearMemoryDepth);
-
-			if (CudaLinearMemoryColor != NULL)
-				cudaFree(CudaLinearMemoryColor);
-
-			if (CudaLinearMemoryIntersections != NULL)
-				cudaFree(CudaLinearMemoryIntersections);
-
-			PrintLastCudaError("cudaFree");
-		}
-
-
-
-		//check(IsInRenderingThread());
-		bStartTracing.AtomicSet(false);
-		//bEndPlay.AtomicSet(false);
-		bIsInitialized.AtomicSet(false);
-		bLaserIsInitialized.AtomicSet(false);
-		bSceneChanged.AtomicSet(true);
-		bIsTracing.AtomicSet(false);
-		bClearToLaunch.AtomicSet(true);
-		bCleanup.AtomicSet(false);
-		bValidCubemap.AtomicSet(false);
-
-		// Clear the queue
-		DestroyOptiXObjects();
-
-		if (OptiXContext.IsValid())
-		{
-			OptiXContext->RemoveFromRoot();
-		}
-		if (LaserOutputBuffer.IsValid())
-		{
-			LaserOutputBuffer->RemoveFromRoot();
-		}
-		if (OutputTexture.IsValid())
-		{
-			OutputTexture->RemoveFromRoot();
-		}
-		if (OutputTexture2.IsValid())
-		{
-			OutputTexture2->RemoveFromRoot();
-		}
-		if (DepthTexture.IsValid())
-		{
-			DepthTexture->RemoveFromRoot();
-		}
-		if (DepthTexture2.IsValid())
-		{
-			DepthTexture2->RemoveFromRoot();
-		}
-		if (CubemapSampler.IsValid())
-		{
-			CubemapSampler->RemoveFromRoot();
-		}
-		if (CubemapBuffer.IsValid())
-		{
-			CubemapBuffer->RemoveFromRoot();
-		}
-
-		OutputBuffer.Reset();
-		OutputDepthBuffer.Reset();
-
-		OutputTexture.Reset();
-		DepthTexture.Reset();
-		OutputTexture2.Reset();
-		DepthTexture2.Reset();
-		LaserIntersectionTexture.Reset();
-
-		DynamicMaterial.Reset();
-		DynamicMaterialOrtho.Reset();
-		RegularMaterial.Reset();
-		VRMaterial.Reset();
-		LaserMaterial.Reset();
-
-		LaserMaterialDynamic.Reset();		
-
-		LaserActor.Reset();
-
-		TopObject.Reset();
-		TopAcceleration.Reset();
-		OptiXContext.Reset();
-
-		if (NativeContext != NULL)
-		{
-			NativeContext->destroy();
-			NativeContext = NULL;
-		}
-
-		/*{
-			
-			OptiXContext->RemoveFromRoot();
-			LaserOutputBuffer->RemoveFromRoot();
-			OutputTexture->RemoveFromRoot();
-			OutputTexture2->RemoveFromRoot();
-			DepthTexture->RemoveFromRoot();
-			DepthTexture2->RemoveFromRoot();
-
-		
-
-			OutputBuffer.Reset();
-			OutputDepthBuffer.Reset();
-
-			OutputTexture.Reset();
-			DepthTexture.Reset();
-			OutputTexture2.Reset();
-			DepthTexture2.Reset();
-
-			DynamicMaterial.Reset();
-			RegularMaterial.Reset();
-			VRMaterial.Reset();
-
-
-			TopObject.Reset();
-			TopAcceleration.Reset();
-			OptiXContext.Reset();
-
-			if (NativeContext != NULL)
-			{
-				NativeContext->destroy();
-			}
-		}*/
-	}
-
-	
-private:
-	// OptiX Part
-
-	// Todo: refactor this to delegates maybe?
-	TQueue<IOptiXComponentInterface*> ComponentsToInitializeQueue;
-	TQueue<IOptiXComponentInterface*> ComponentsToUpdateQueue;
-	TQueue<UOptiXCubemapComponent*> CubemapComponentsToUpdateQueue;
-
-	TWeakObjectPtr<AOptiXLaserActor> LaserActor;
-
-	TWeakObjectPtr<AOptiXPlayerCameraManager> CameraActor;
-
-	// OptiX Objects to be kept in the context manager, TODO triple check that the GC doesn't nab them.
-	// Those are always required, but some should also be changeable! TODO make custom setters for them later.
-	TWeakObjectPtr<UOptiXContext> OptiXContext;
-	TWeakObjectPtr<UOptiXProgram> RayGenerationProgram;
-	TWeakObjectPtr<UOptiXProgram> MissProgram;
-	TWeakObjectPtr<UOptiXProgram> ExceptionProgram;
-
-	TWeakObjectPtr<UOptiXGroup> TopObject;
-	TWeakObjectPtr<UOptiXAcceleration> TopAcceleration;
-
-	TWeakObjectPtr<UOptiXBuffer> OutputBuffer;
-	TWeakObjectPtr<UOptiXBuffer> OutputDepthBuffer;
-
-	TWeakObjectPtr<UOptiXTextureSampler> CubemapSampler;
-	TWeakObjectPtr<UOptiXBuffer> CubemapBuffer;
-	TWeakObjectPtr<UOptiXBuffer> CubemapsInputBuffer;
-
-	TQueue<int32> UnallocatedCubemapIds;
-
-	TArray<TArray<FColor>> SurfaceDataCube;
-
-	optix::Context NativeContext;
-
-
-	// Laser Part
-	TWeakObjectPtr<UOptiXBuffer> LaserOutputBuffer;
-	TWeakObjectPtr<UOptiXProgram> LaserRayGenerationProgram;
-	TWeakObjectPtr<UOptiXProgram> LaserMissProgram;
-	TWeakObjectPtr<UOptiXProgram> LaserExceptionProgram;
-
-
-
-	// Rendering Part
-
-	//FUpdateTextureRegion2D TextureRegion;
-
-	//UTextureCube* TextureCube;
-
-	int32 Width;
-	int32 Height;
-
-	FTexture2DRHIRef OutputTextureColorRightRef;
-	FTexture2DRHIRef OutputTextureColorLeftRef;
-	FTexture2DRHIRef OutputTextureDepthRightRef;
-	FTexture2DRHIRef OutputTextureDepthLeftRef;
-	
-	FTexture2DRHIRef OutputTextureColorOrthoRef;
-	FTexture2DRHIRef OutputTextureDepthOrthoRef;
-
-	TWeakObjectPtr<UTexture2D> OutputTexture;
-	TWeakObjectPtr<UTexture2D> DepthTexture;
-	TWeakObjectPtr<UTexture2D> OutputTexture2;
-	TWeakObjectPtr<UTexture2D> DepthTexture2;
-
-	TWeakObjectPtr<UTexture2D> OutputTextureOrtho;
-	TWeakObjectPtr<UTexture2D> DepthTextureOrtho;
-
-	TWeakObjectPtr<UMaterialInstanceDynamic> DynamicMaterial;
-	TWeakObjectPtr<UMaterialInstanceDynamic> DynamicMaterialOrtho;
-	TWeakObjectPtr<UMaterial> RegularMaterial;
-	TWeakObjectPtr<UMaterial> VRMaterial;
-	bool bWithHMD;
-
-
-	// ---------------------------------------------------------------------------------------------------
-	// Laser stuff
-	// ---------------------------------------------------------------------------------------------------
-
-	FTexture2DRHIRef LaserIntersectionTextureRef;
-
-	TWeakObjectPtr<UTexture2D> LaserIntersectionTexture;
-	TWeakObjectPtr<UMaterial> LaserMaterial;
-	TWeakObjectPtr<UMaterialInstanceDynamic> LaserMaterialDynamic;
-
-
-public:
-
-	TQueue<TPair<uint32, TArray<FVector>>> LaserIntersectionQueue;
-
-	TArray<TArray<FVector>> PreviousLaserResults;
-
-
-private:
-
-	TArray<FVector4> IntersectionData;
-	TArray<FVector4> OldIntersectionData;
-
-	FThreadSafeBool bTracingLaser;
-
-	FCriticalSection CriticalSection;
-
-	int32 LaserMaxDepth;
-	int32 LaserEntryPoint;
-	int32 LaserBufferSize;
-
-	int32 LaserBufferWidth;
-	int32 LaserBufferHeight;
-
-
-	// ---------------------------------------------------------------------------------------------------
-	// DX <-> CUDA stuff
-	// ---------------------------------------------------------------------------------------------------
-
-
-public:
-	// I'm not sure which ones I actually need
-	IDXGIAdapter			*CudaCapableAdapter = NULL;		// Adapter to use
-	ID3D11Device			*D3DDevice = NULL;				// Rendering device
-	ID3D11DeviceContext		*D3DDeviceContext = NULL;
-
-	// RTX mode
-	int RTXOn = 1;
-
-
-private:
-
-	void InitCUDADX();
-
-
-	//ID3D11Texture2D* D3D11Texture;
-	cudaGraphicsResource* CudaResourceDepthLeft;
-	cudaGraphicsResource* CudaResourceDepthRight;
-	cudaGraphicsResource* CudaResourceColorLeft;
-	cudaGraphicsResource* CudaResourceColorRight;
-	cudaGraphicsResource* CudaResourceIntersections;
-	cudaGraphicsResource* CudaResourceColorOrtho;
-	cudaGraphicsResource* CudaResourceDepthOrtho;
-	void* CudaLinearMemoryDepth;
-	void* CudaLinearMemoryColor;
-	void* CudaLinearMemoryIntersections;
-	size_t Pitch; // fix me
-	size_t PitchLaser;
-
-	cudaGraphicsResource *Resources[7];
+#pragma once
+
+#include "CoreMinimal.h"
+#include "EngineUtils.h"
+
+#include "Runtime/Engine/Public/SceneViewExtension.h"
+
+#include "Runtime/Engine/Classes/Engine/Texture2D.h"
+
+#include "MaterialShared.h"
+#include "Materials/MaterialInstance.h"
+#include "Delegates/Delegate.h"
+
+#include "OptiXContext.h"
+#include "OptiXObjectComponent.h"
+#include "OptiXLaserComponent.h"
+#include "OptiXLaserActor.h"
+#include "OptiXCameraActor.h"
+
+
+
+// Let's try some events!
+
+DECLARE_EVENT(FOptiXContextManager, FLaserTraceFinishedEvent)
+DECLARE_EVENT_OneParam(FOptiXContextManager, FWavelengthChangedEvent, const float)
+DECLARE_MULTICAST_DELEGATE(FOnSceneChangedDelegate);
+
+// DX
+
+#if PLATFORM_WINDOWS
+#include "AllowWindowsPlatformTypes.h"
+#endif
+#include <d3d11.h>
+#if PLATFORM_WINDOWS
+#include "HideWindowsPlatformTypes.h"
+#endif
+
+// print cuda error helper:
+
+inline void PrintLastCudaError(FString Msg)
+{
+	cudaError_t Err = cudaGetLastError();
+	if (cudaSuccess != Err) {
+		UE_LOG(LogTemp, Fatal, TEXT("Cuda Error: %s. "), *Msg, static_cast<int>(Err), cudaGetErrorString(Err));
+	}
+}
+
+
+class OPTIX_API FOptiXContextManager : public FSceneViewExtensionBase
+{
+
+public:
+
+	// The auto register thing is used to make sure this constructor is only called via the NewExtension function
+	FOptiXContextManager(const FAutoRegister& AutoRegister);
+
+	~FOptiXContextManager() 
+	{
+		if (bIsInitialized)
+		{
+			cudaGraphicsUnregisterResource(CudaResourceDepthLeft);
+			cudaGraphicsUnregisterResource(CudaResourceDepthRight);
+			cudaGraphicsUnregisterResource(CudaResourceColorLeft);
+			cudaGraphicsUnregisterResource(CudaResourceColorRight);
+			cudaGraphicsUnregisterResource(CudaResourceIntersections);
+			cudaGraphicsUnregisterResource(CudaResourceColorOrtho);
+			cudaGraphicsUnregisterResource(CudaResourceDepthOrtho);
+
+			PrintLastCudaError("cudaGraphicsUnregisterResource");
+			cudaFree(CudaLinearMemoryDepth);
+			cudaFree(CudaLinearMemoryColor);
+			cudaFree(CudaLinearMemoryIntersections);
+			PrintLastCudaError("cudaFree");
+		}
+
+		AccelerationsToDeleteQueue.Empty();
+		BuffersToDeleteQueue.Empty();
+		GeometriesToDeleteQueue.Empty();
+		GeometryGroupToDeleteQueue.Empty();
+		GeometryInstancesToDeleteQueue.Empty();
+		GroupsToDeleteQueue.Empty();
+		MaterialsToDeleteQueue.Empty();
+		ProgramToDeleteQueue.Empty();
+		TextureSamplersToDeleteQueue.Empty();
+		TransformsToDeleteQueue.Empty();
+
+		GroupChildrenToRemoveQueue.Empty();
+		GeometryGroupChildrenToRemoveQueue.Empty();
+
+		ComponentsToInitializeQueue.Empty();
+		ComponentsToUpdateQueue.Empty();
+		CubemapComponentsToUpdateQueue.Empty();
+
+		LaserActor.Reset();
+		CameraActor.Reset();
+	}
+
+	// ISceneViewExtension interface start, called by the render thread:
+public:
+	virtual void SetupViewFamily(FSceneViewFamily& InViewFamily) override;
+	virtual void SetupView(FSceneViewFamily& InViewFamily, FSceneView& InView) override;
+	virtual void BeginRenderViewFamily(FSceneViewFamily& InViewFamily) override;
+	virtual void PreRenderView_RenderThread(FRHICommandListImmediate& RHICmdList, FSceneView& InView) override;
+	virtual void PreRenderViewFamily_RenderThread(FRHICommandListImmediate& RHICmdList, FSceneViewFamily& InViewFamily) override;
+	virtual void PostRenderViewFamily_RenderThread(FRHICommandListImmediate& RHICmdList, FSceneViewFamily& InViewFamily) override;
+	virtual bool IsActiveThisFrame(class FViewport* InViewport) const override;
+	virtual void PostRenderView_RenderThread(FRHICommandListImmediate& RHICmdList, FSceneView& InView) override;
+	// ISceneViewExtension interface end
+
+
+	void RenderOrthoPass();
+	
+	// Initialization methods, called by the GAME thread	
+	void Init();
+
+	void EndPlay()
+	{
+		//CleanupOptiXOnEnd();
+		//bCleanup.AtomicSet(true);
+		//bStartTracing.AtomicSet(false);
+		//bCleanup.AtomicSet(false);
+		//bEndPlay.AtomicSet(true);
+	}
+
+	UOptiXContext* GetOptiXContext()
+	{
+		return OptiXContext.Get();
+	}
+
+	UMaterialInstanceDynamic* GetOptiXMID() // Used to set up the post process
+	{
+		return DynamicMaterial.Get();
+	}
+
+	UMaterialInstanceDynamic* GetOptiXMIDOrtho() // Used to set up the post process
+	{
+		return DynamicMaterialOrtho.Get();
+	}
+
+	void SceneChangedCallback();
+
+	// The OptiX context is not thread-safe, so any changes to variables/properties on the game thread 
+	// while a trace is running will lead to errors. Game thread objects push their requested updates into several queues,
+	// which then get updated just before the trace runs on the render thread.
+	// TQueue is guaranteed to be thread-safe.
+	// There is probably a better and faster way of doing this.
+
+	void RegisterOptiXComponent(IOptiXComponentInterface* Component)
+	{
+		ComponentsToInitializeQueue.Enqueue(Component);
+	}
+
+	void QueueComponentUpdate(IOptiXComponentInterface* Component)
+	{
+		ComponentsToUpdateQueue.Enqueue(Component);
+	}
+
+	void RequestCubemapUpdate(UOptiXCubemapComponent* Component)
+	{
+		CubemapComponentsToUpdateQueue.Enqueue(Component);
+	}
+
+	void SetActiveLaserActor(AOptiXLaserActor* Laser)
+	{
+		LaserActor = Laser;
+		if (LaserMaterialDynamic.IsValid())
+		{
+			LaserActor->SetLaserMaterial(LaserMaterialDynamic.Get());
+		}
+		else
+		{
+			UE_LOG(LogTemp, Error, TEXT("LaserMaterialDynamic is invalid!"));
+		}
+	}
+
+	void SetActiveCameraActor(AOptiXPlayerCameraManager* Cam)
+	{
+		CameraActor = Cam;
+	}
+
+	FIntRect GetViewRectanglePerEye()
+	{
+		return FIntRect(0, 0, Width, Height);
+	}
+
+	int32 RequestCubemapId();
+
+	void DeleteCubemapId(int32 Id);
+
+	void AddCubemapToBuffer(int32 CubemapId, int32 SamplerId);
+
+	void BroadcastWavelengthChange(float WL)
+	{
+		WavelengthChangedEvent.Broadcast(WL);
+		//UE_LOG(LogTemp, Error, TEXT("LaserMaterialDynamic is invalid!"));
+
+	}
+
+
+public:
+	
+	FThreadSafeBool bStartTracing = false;
+	FThreadSafeBool bIsInitialized = false;
+	FThreadSafeBool bLaserIsInitialized = false;
+	FThreadSafeBool bSceneChanged = true;
+	FThreadSafeBool bIsTracing = false;
+	FThreadSafeBool bClearToLaunch = true;
+	FThreadSafeBool bCleanup = false;
+	FThreadSafeBool bValidCubemap = false;
+	FThreadSafeBool bRequestOrthoPass = false;
+	//FThreadSafeBool bEndPlay = false;
+
+	FLaserTraceFinishedEvent LaserTraceFinishedEvent;
+	FWavelengthChangedEvent WavelengthChangedEvent;
+	FOnSceneChangedDelegate OnSceneChangedDelegate;
+
+
+public:
+
+	// This is so ugly but the optix api structure doesn't really allow anything more abstract.
+	TQueue<optix::Acceleration>			AccelerationsToDeleteQueue;
+	TQueue<optix::Buffer>				BuffersToDeleteQueue;
+	TQueue<optix::Geometry>				GeometriesToDeleteQueue;
+	TQueue<optix::GeometryGroup>		GeometryGroupToDeleteQueue;
+	TQueue<optix::GeometryInstance>		GeometryInstancesToDeleteQueue;
+	TQueue<optix::Group>				GroupsToDeleteQueue;
+	TQueue<optix::Material>				MaterialsToDeleteQueue;
+	TQueue<optix::Program>				ProgramToDeleteQueue;
+	TQueue<optix::TextureSampler>		TextureSamplersToDeleteQueue;
+	TQueue<optix::Transform>			TransformsToDeleteQueue;
+
+	TQueue<TPair<optix::Group, uint32>> GroupChildrenToRemoveQueue;
+	TQueue<TPair<optix::GeometryGroup, uint32>> GeometryGroupChildrenToRemoveQueue;
+
+	FMatrix OrthoMatrix;
+
+private:
+	void InitContext();
+	void InitRendering();
+	void InitBuffers();
+	void InitPrograms();
+	void InitLaser();
+
+	void LaunchLaser();
+
+	void InitCubemap();
+
+	void InitOptiXComponents(FRHICommandListImmediate & RHICmdList)
+	{
+		// Possibly dangerous? Use limited for instead of while in case something goes wrong and we deadlock
+		for (uint32 i = 0; i < 100 && !ComponentsToInitializeQueue.IsEmpty(); i++)
+		{
+			IOptiXComponentInterface* Component;
+			if (ComponentsToInitializeQueue.Dequeue(Component))
+			{
+				Component->InitOptiXComponent(RHICmdList);				
+			}
+		}
+	}
+
+	void UpdateOptiXComponentVariables()
+	{
+		for (uint32 i = 0; i < 100 && !ComponentsToUpdateQueue.IsEmpty(); i++)
+		{
+			IOptiXComponentInterface* Component;
+			if (ComponentsToUpdateQueue.Dequeue(Component))
+			{
+				if (Component != nullptr)
+				{
+					Component->UpdateOptiXComponentVariables();
+					Component->SetUpdateQueued(false);//   bUpdateQueued.AtomicSet(false);
+				}
+			}
+		}
+	}
+
+	void RemovePendingChildrenFromGroups()
+	{
+		for (uint32 i = 0; i < 100 && !GroupChildrenToRemoveQueue.IsEmpty(); i++)
+		{
+			TPair<optix::Group, uint32> Pair;
+			if (GroupChildrenToRemoveQueue.Dequeue(Pair))
+			{
+				if (Pair.Key != NULL)
+				{
+					Pair.Key->removeChild(Pair.Value); // TODO do we need to do anything else here?
+				}
+				else
+				{
+					UE_LOG(LogTemp, Error, TEXT("Error while trying to remove optix child in queue: Object was NULL"));
+				}
+			}
+		}
+		for (uint32 i = 0; i < 100 && !GeometryGroupChildrenToRemoveQueue.IsEmpty(); i++)
+		{
+			TPair<optix::GeometryGroup, uint32> Pair;
+			if (GeometryGroupChildrenToRemoveQueue.Dequeue(Pair))
+			{
+				if (Pair.Key != NULL)
+				{
+					Pair.Key->removeChild(Pair.Value); // TODO do we need to do anything else here?
+				}
+				else
+				{
+					UE_LOG(LogTemp, Error, TEXT("Error while trying to remove optix child in queue: Object was NULL"));
+				}
+			}
+		}
+	}
+
+	void DestroyOptiXObjects()
+	{
+		for (uint32 i = 0; i < 100 && !AccelerationsToDeleteQueue.IsEmpty(); i++)
+		{
+			optix::Acceleration NativeObj;
+			if (AccelerationsToDeleteQueue.Dequeue(NativeObj))
+			{
+				if (NativeObj != NULL)
+				{
+					if(NativeObj->getContext() != NULL)
+						NativeObj->destroy(); // TODO do we need to do anything else here?
+					else
+					{
+						UE_LOG(LogTemp, Warning, TEXT("Context already destroyed but somehow this buffer handle is still valid"));
+					}
+				}
+				else
+				{
+					UE_LOG(LogTemp, Error, TEXT("Error while trying to destroy optix object in queue: Object was NULL"));
+				}
+			}			
+		}
+		for (uint32 i = 0; i < 100 && !BuffersToDeleteQueue.IsEmpty(); i++)
+		{
+			optix::Buffer NativeObj;
+			if (BuffersToDeleteQueue.Dequeue(NativeObj))
+			{
+				if (NativeObj != NULL)
+				{
+					try
+					{
+						NativeObj->destroy(); // TODO do we need to do anything else here?
+					}
+					catch (optix::Exception& E)
+					{
+						FString Message = FString(E.getErrorString().c_str());
+						UE_LOG(LogTemp, Error, TEXT("Trying to remove buffer: OptiX Error: %s"), *Message);
+						GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+					}
+				}
+				else
+				{
+					UE_LOG(LogTemp, Error, TEXT("Error while trying to destroy optix object in queue: Object was NULL"));
+				}
+			}
+		}
+		for (uint32 i = 0; i < 100 && !GeometriesToDeleteQueue.IsEmpty(); i++)
+		{
+			optix::Geometry NativeObj;
+			if (GeometriesToDeleteQueue.Dequeue(NativeObj))
+			{
+				if (NativeObj != NULL)
+				{
+					NativeObj->destroy(); // TODO do we need to do anything else here?
+				}
+				else
+				{
+					UE_LOG(LogTemp, Error, TEXT("Error while trying to destroy optix object in queue: Object was NULL"));
+				}
+			}
+		}
+		for (uint32 i = 0; i < 100 && !GeometryInstancesToDeleteQueue.IsEmpty(); i++)
+		{
+			optix::GeometryInstance NativeObj;
+			if (GeometryInstancesToDeleteQueue.Dequeue(NativeObj))
+			{
+				if (NativeObj != NULL)
+				{
+					NativeObj->destroy(); // TODO do we need to do anything else here?
+				}
+				else
+				{
+					UE_LOG(LogTemp, Error, TEXT("Error while trying to destroy optix object in queue: Object was NULL"));
+				}
+			}
+		}
+		for (uint32 i = 0; i < 100 && !GeometryGroupToDeleteQueue.IsEmpty(); i++)
+		{
+			optix::GeometryGroup NativeObj;
+			if (GeometryGroupToDeleteQueue.Dequeue(NativeObj))
+			{
+				if (NativeObj != NULL)
+				{
+					NativeObj->destroy(); // TODO do we need to do anything else here?
+				}
+				else
+				{
+					UE_LOG(LogTemp, Error, TEXT("Error while trying to destroy optix object in queue: Object was NULL"));
+				}
+			}
+		}
+		for (uint32 i = 0; i < 100 && !GroupsToDeleteQueue.IsEmpty(); i++)
+		{
+			optix::Group NativeObj;
+			if (GroupsToDeleteQueue.Dequeue(NativeObj))
+			{
+				if (NativeObj != NULL)
+				{
+					NativeObj->destroy(); // TODO do we need to do anything else here?
+				}
+				else
+				{
+					UE_LOG(LogTemp, Error, TEXT("Error while trying to destroy optix object in queue: Object was NULL"));
+				}
+			}
+		}
+		for (uint32 i = 0; i < 100 && !MaterialsToDeleteQueue.IsEmpty(); i++)
+		{
+			optix::Material NativeObj;
+			if (MaterialsToDeleteQueue.Dequeue(NativeObj))
+			{
+				if (NativeObj != NULL)
+				{
+					NativeObj->destroy(); // TODO do we need to do anything else here?
+				}
+				else
+				{
+					UE_LOG(LogTemp, Error, TEXT("Error while trying to destroy optix object in queue: Object was NULL"));
+				}
+			}
+		}
+		for (uint32 i = 0; i < 100 && !ProgramToDeleteQueue.IsEmpty(); i++)
+		{
+			optix::Program NativeObj;
+			if (ProgramToDeleteQueue.Dequeue(NativeObj))
+			{
+				if (NativeObj != NULL)
+				{
+					NativeObj->destroy(); // TODO do we need to do anything else here?
+				}
+				else
+				{
+					UE_LOG(LogTemp, Error, TEXT("Error while trying to destroy optix object in queue: Object was NULL"));
+				}
+			}
+		}
+		for (uint32 i = 0; i < 100 && !TextureSamplersToDeleteQueue.IsEmpty(); i++)
+		{
+			optix::TextureSampler NativeObj;
+			if (TextureSamplersToDeleteQueue.Dequeue(NativeObj))
+			{
+				if (NativeObj != NULL)
+				{
+					try
+					{
+						NativeObj->destroy(); // TODO do we need to do anything else here?
+					}
+					catch (optix::Exception& E)
+					{
+						FString Message = FString(E.getErrorString().c_str());
+						UE_LOG(LogTemp, Error, TEXT("Trying to remove texture sampler: OptiX Error: %s"), *Message);
+						GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+					}
+				}
+				else
+				{
+					UE_LOG(LogTemp, Error, TEXT("Error while trying to destroy optix object in queue: Object was NULL"));
+				}
+			}
+		}
+		for (uint32 i = 0; i < 100 && !TransformsToDeleteQueue.IsEmpty(); i++)
+		{
+			optix::Transform NativeObj;
+			if (TransformsToDeleteQueue.Dequeue(NativeObj))
+			{
+				if (NativeObj != NULL)
+				{
+					NativeObj->destroy(); // TODO do we need to do anything else here?
+				}
+				else
+				{
+					UE_LOG(LogTemp, Error, TEXT("Error while trying to destroy optix object in queue: Object was NULL"));
+				}
+			}
+		}
+	}
+
+	void UpdateRequestedCubemaps(FRHICommandListImmediate & RHICmdList)
+	{
+		// update only the first for now, shouldn't be more than 1 in queue anyway:
+
+		if (!CubemapComponentsToUpdateQueue.IsEmpty())
+		{
+			UOptiXCubemapComponent* Comp;
+			if (CubemapComponentsToUpdateQueue.Dequeue(Comp))
+			{
+				Comp->UpdateCubemap(RHICmdList);
+			}
+		}
+	}
+
+	void UpdateCubemapBuffer(FRHICommandListImmediate & RHICmdList);
+
+	void CleanupOptiXOnEnd()
+	{
+
+		UE_LOG(LogTemp, Display, TEXT("Starting Cleanup in Context Manager"));
+
+
+		if (bIsInitialized)
+		{
+			if(CudaResourceDepthLeft != NULL)
+				cudaGraphicsUnregisterResource(CudaResourceDepthLeft);
+			if (CudaResourceDepthRight != NULL)
+				cudaGraphicsUnregisterResource(CudaResourceDepthRight);
+			if (CudaResourceColorLeft != NULL)
+				cudaGraphicsUnregisterResource(CudaResourceColorLeft);
+			if(CudaResourceColorRight != NULL)
+				cudaGraphicsUnregisterResource(CudaResourceColorRight);
+			if(CudaResourceIntersections != NULL)
+				cudaGraphicsUnregisterResource(CudaResourceIntersections);
+			if (CudaResourceDepthOrtho != NULL)
+				cudaGraphicsUnregisterResource(CudaResourceDepthOrtho);
+			if (CudaResourceColorOrtho != NULL)
+				cudaGraphicsUnregisterResource(CudaResourceColorOrtho);
+			PrintLastCudaError("cudaGraphicsUnregisterResource");
+			if(CudaLinearMemoryDepth != NULL)
+				cudaFree(CudaLinearMemoryDepth);
+
+			if (CudaLinearMemoryColor != NULL)
+				cudaFree(CudaLinearMemoryColor);
+
+			if (CudaLinearMemoryIntersections != NULL)
+				cudaFree(CudaLinearMemoryIntersections);
+
+			PrintLastCudaError("cudaFree");
+		}
+
+
+
+		//check(IsInRenderingThread());
+		bStartTracing.AtomicSet(false);
+		//bEndPlay.AtomicSet(false);
+		bIsInitialized.AtomicSet(false);
+		bLaserIsInitialized.AtomicSet(false);
+		bSceneChanged.AtomicSet(true);
+		bIsTracing.AtomicSet(false);
+		bClearToLaunch.AtomicSet(true);
+		bCleanup.AtomicSet(false);
+		bValidCubemap.AtomicSet(false);
+
+		// Clear the queue
+		DestroyOptiXObjects();
+
+		if (OptiXContext.IsValid())
+		{
+			OptiXContext->RemoveFromRoot();
+		}
+		if (LaserOutputBuffer.IsValid())
+		{
+			LaserOutputBuffer->RemoveFromRoot();
+		}
+		if (OutputTexture.IsValid())
+		{
+			OutputTexture->RemoveFromRoot();
+		}
+		if (OutputTexture2.IsValid())
+		{
+			OutputTexture2->RemoveFromRoot();
+		}
+		if (DepthTexture.IsValid())
+		{
+			DepthTexture->RemoveFromRoot();
+		}
+		if (DepthTexture2.IsValid())
+		{
+			DepthTexture2->RemoveFromRoot();
+		}
+		if (CubemapSampler.IsValid())
+		{
+			CubemapSampler->RemoveFromRoot();
+		}
+		if (CubemapBuffer.IsValid())
+		{
+			CubemapBuffer->RemoveFromRoot();
+		}
+
+		OutputBuffer.Reset();
+		OutputDepthBuffer.Reset();
+
+		OutputTexture.Reset();
+		DepthTexture.Reset();
+		OutputTexture2.Reset();
+		DepthTexture2.Reset();
+		LaserIntersectionTexture.Reset();
+
+		DynamicMaterial.Reset();
+		DynamicMaterialOrtho.Reset();
+		RegularMaterial.Reset();
+		VRMaterial.Reset();
+		LaserMaterial.Reset();
+
+		LaserMaterialDynamic.Reset();		
+
+		LaserActor.Reset();
+
+		TopObject.Reset();
+		TopAcceleration.Reset();
+		OptiXContext.Reset();
+
+		if (NativeContext != NULL)
+		{
+			NativeContext->destroy();
+			NativeContext = NULL;
+		}
+
+		/*{
+			
+			OptiXContext->RemoveFromRoot();
+			LaserOutputBuffer->RemoveFromRoot();
+			OutputTexture->RemoveFromRoot();
+			OutputTexture2->RemoveFromRoot();
+			DepthTexture->RemoveFromRoot();
+			DepthTexture2->RemoveFromRoot();
+
+		
+
+			OutputBuffer.Reset();
+			OutputDepthBuffer.Reset();
+
+			OutputTexture.Reset();
+			DepthTexture.Reset();
+			OutputTexture2.Reset();
+			DepthTexture2.Reset();
+
+			DynamicMaterial.Reset();
+			RegularMaterial.Reset();
+			VRMaterial.Reset();
+
+
+			TopObject.Reset();
+			TopAcceleration.Reset();
+			OptiXContext.Reset();
+
+			if (NativeContext != NULL)
+			{
+				NativeContext->destroy();
+			}
+		}*/
+	}
+
+	
+private:
+	// OptiX Part
+
+	// Todo: refactor this to delegates maybe?
+	TQueue<IOptiXComponentInterface*> ComponentsToInitializeQueue;
+	TQueue<IOptiXComponentInterface*> ComponentsToUpdateQueue;
+	TQueue<UOptiXCubemapComponent*> CubemapComponentsToUpdateQueue;
+
+	TWeakObjectPtr<AOptiXLaserActor> LaserActor;
+
+	TWeakObjectPtr<AOptiXPlayerCameraManager> CameraActor;
+
+	// OptiX Objects to be kept in the context manager, TODO triple check that the GC doesn't nab them.
+	// Those are always required, but some should also be changeable! TODO make custom setters for them later.
+	TWeakObjectPtr<UOptiXContext> OptiXContext;
+	TWeakObjectPtr<UOptiXProgram> RayGenerationProgram;
+	TWeakObjectPtr<UOptiXProgram> MissProgram;
+	TWeakObjectPtr<UOptiXProgram> ExceptionProgram;
+
+	TWeakObjectPtr<UOptiXGroup> TopObject;
+	TWeakObjectPtr<UOptiXAcceleration> TopAcceleration;
+
+	TWeakObjectPtr<UOptiXBuffer> OutputBuffer;
+	TWeakObjectPtr<UOptiXBuffer> OutputDepthBuffer;
+
+	TWeakObjectPtr<UOptiXTextureSampler> CubemapSampler;
+	TWeakObjectPtr<UOptiXBuffer> CubemapBuffer;
+	TWeakObjectPtr<UOptiXBuffer> CubemapsInputBuffer;
+
+	TQueue<int32> UnallocatedCubemapIds;
+
+	TArray<TArray<FColor>> SurfaceDataCube;
+
+	optix::Context NativeContext;
+
+
+	// Laser Part
+	TWeakObjectPtr<UOptiXBuffer> LaserOutputBuffer;
+	TWeakObjectPtr<UOptiXProgram> LaserRayGenerationProgram;
+	TWeakObjectPtr<UOptiXProgram> LaserMissProgram;
+	TWeakObjectPtr<UOptiXProgram> LaserExceptionProgram;
+
+
+
+	// Rendering Part
+
+	//FUpdateTextureRegion2D TextureRegion;
+
+	//UTextureCube* TextureCube;
+
+	int32 Width;
+	int32 Height;
+
+	FTexture2DRHIRef OutputTextureColorRightRef;
+	FTexture2DRHIRef OutputTextureColorLeftRef;
+	FTexture2DRHIRef OutputTextureDepthRightRef;
+	FTexture2DRHIRef OutputTextureDepthLeftRef;
+	
+	FTexture2DRHIRef OutputTextureColorOrthoRef;
+	FTexture2DRHIRef OutputTextureDepthOrthoRef;
+
+	TWeakObjectPtr<UTexture2D> OutputTexture;
+	TWeakObjectPtr<UTexture2D> DepthTexture;
+	TWeakObjectPtr<UTexture2D> OutputTexture2;
+	TWeakObjectPtr<UTexture2D> DepthTexture2;
+
+	TWeakObjectPtr<UTexture2D> OutputTextureOrtho;
+	TWeakObjectPtr<UTexture2D> DepthTextureOrtho;
+
+	TWeakObjectPtr<UMaterialInstanceDynamic> DynamicMaterial;
+	TWeakObjectPtr<UMaterialInstanceDynamic> DynamicMaterialOrtho;
+	TWeakObjectPtr<UMaterial> RegularMaterial;
+	TWeakObjectPtr<UMaterial> VRMaterial;
+	bool bWithHMD;
+
+
+	// ---------------------------------------------------------------------------------------------------
+	// Laser stuff
+	// ---------------------------------------------------------------------------------------------------
+
+	FTexture2DRHIRef LaserIntersectionTextureRef;
+
+	TWeakObjectPtr<UTexture2D> LaserIntersectionTexture;
+	TWeakObjectPtr<UMaterial> LaserMaterial;
+	TWeakObjectPtr<UMaterialInstanceDynamic> LaserMaterialDynamic;
+
+
+public:
+
+	TQueue<TPair<uint32, TArray<FVector>>> LaserIntersectionQueue;
+
+	TArray<TArray<FVector>> PreviousLaserResults;
+
+
+private:
+
+	TArray<FVector4> IntersectionData;
+	TArray<FVector4> OldIntersectionData;
+
+	FThreadSafeBool bTracingLaser;
+
+	FCriticalSection CriticalSection;
+
+	int32 LaserMaxDepth;
+	int32 LaserEntryPoint;
+	int32 LaserBufferSize;
+
+	int32 LaserBufferWidth;
+	int32 LaserBufferHeight;
+
+
+	// ---------------------------------------------------------------------------------------------------
+	// DX <-> CUDA stuff
+	// ---------------------------------------------------------------------------------------------------
+
+
+public:
+	// I'm not sure which ones I actually need
+	IDXGIAdapter			*CudaCapableAdapter = NULL;		// Adapter to use
+	ID3D11Device			*D3DDevice = NULL;				// Rendering device
+	ID3D11DeviceContext		*D3DDeviceContext = NULL;
+
+	// RTX mode
+	int RTXOn = 1;
+
+
+private:
+
+	void InitCUDADX();
+
+
+	//ID3D11Texture2D* D3D11Texture;
+	cudaGraphicsResource* CudaResourceDepthLeft;
+	cudaGraphicsResource* CudaResourceDepthRight;
+	cudaGraphicsResource* CudaResourceColorLeft;
+	cudaGraphicsResource* CudaResourceColorRight;
+	cudaGraphicsResource* CudaResourceIntersections;
+	cudaGraphicsResource* CudaResourceColorOrtho;
+	cudaGraphicsResource* CudaResourceDepthOrtho;
+	void* CudaLinearMemoryDepth;
+	void* CudaLinearMemoryColor;
+	void* CudaLinearMemoryIntersections;
+	size_t Pitch; // fix me
+	size_t PitchLaser;
+
+	cudaGraphicsResource *Resources[7];
 };
\ No newline at end of file