diff --git a/Content/Blueprints/OptiXObjects/OptiXLaserActor_Pickup.uasset b/Content/Blueprints/OptiXObjects/OptiXLaserActor_Pickup.uasset
index 12e540eef2fa3ceb787d12e1491618a67f2bad5b..bda89e7f0673e5561b9d30d59805127e5928f1b5 100644
Binary files a/Content/Blueprints/OptiXObjects/OptiXLaserActor_Pickup.uasset and b/Content/Blueprints/OptiXObjects/OptiXLaserActor_Pickup.uasset differ
diff --git a/Content/Blueprints/OptiXObjects/OptiXLaserDetectorActor_Pickup.uasset b/Content/Blueprints/OptiXObjects/OptiXLaserDetectorActor_Pickup.uasset
index a2d0660d67225d78b2702f67c5f202a894846d0c..54e742360289761721c0d1bb9fc3a704abcea8f6 100644
Binary files a/Content/Blueprints/OptiXObjects/OptiXLaserDetectorActor_Pickup.uasset and b/Content/Blueprints/OptiXObjects/OptiXLaserDetectorActor_Pickup.uasset differ
diff --git a/Content/Blueprints/OptiXObjects/SelectableLensBP.uasset b/Content/Blueprints/OptiXObjects/SelectableLensBP.uasset
index 2219bf152d8d981b2609c024b043a7270385df52..993b1c6e6d8e6d8420053a0dc187cc56afeb31bf 100644
Binary files a/Content/Blueprints/OptiXObjects/SelectableLensBP.uasset and b/Content/Blueprints/OptiXObjects/SelectableLensBP.uasset differ
diff --git a/Content/Blueprints/OptiXObjects/SelectableTargetBP.uasset b/Content/Blueprints/OptiXObjects/SelectableTargetBP.uasset
index ca8efd9f57d53b33eb388bb3380d7bd77a881a84..7fbd9144e1ed44edb69a93bd1f622704c861219c 100644
Binary files a/Content/Blueprints/OptiXObjects/SelectableTargetBP.uasset and b/Content/Blueprints/OptiXObjects/SelectableTargetBP.uasset differ
diff --git a/Content/Blueprints/OptiXObjects/SelectableTargetBP_Black.uasset b/Content/Blueprints/OptiXObjects/SelectableTargetBP_Black.uasset
index 245ee109dc3b1a1533dcdd5f95add0da2b550423..ce401748dbb1154b011686dcf96df8c8d5b6b707 100644
Binary files a/Content/Blueprints/OptiXObjects/SelectableTargetBP_Black.uasset and b/Content/Blueprints/OptiXObjects/SelectableTargetBP_Black.uasset differ
diff --git a/Content/Blueprints/OptiXObjects/SelectableTargetBP_Circles.uasset b/Content/Blueprints/OptiXObjects/SelectableTargetBP_Circles.uasset
index 899237562f89f3fa4a2cc89865401128ea6f2b13..fcaf433f5a4003061cd585d6a42c53f8e5d73d85 100644
Binary files a/Content/Blueprints/OptiXObjects/SelectableTargetBP_Circles.uasset and b/Content/Blueprints/OptiXObjects/SelectableTargetBP_Circles.uasset differ
diff --git a/Content/Blueprints/OptiXObjects/SelectableTargetPB_Grid.uasset b/Content/Blueprints/OptiXObjects/SelectableTargetPB_Grid.uasset
index e96c064eabb076d54c6ea06525dfff815f4aec14..c7557cc81c6b50af692badcc083530d7db75ad7c 100644
Binary files a/Content/Blueprints/OptiXObjects/SelectableTargetPB_Grid.uasset and b/Content/Blueprints/OptiXObjects/SelectableTargetPB_Grid.uasset differ
diff --git a/Content/Blueprints/OptiXVRPawnStandaloneBP.uasset b/Content/Blueprints/OptiXVRPawnStandaloneBP.uasset
index ae3b9477e3e1166137063662e02e1335b141003a..f86b8771f30f9e0a41ad0e7df4635f0edf526757 100644
Binary files a/Content/Blueprints/OptiXVRPawnStandaloneBP.uasset and b/Content/Blueprints/OptiXVRPawnStandaloneBP.uasset differ
diff --git a/Content/Blueprints/OpticalTable.uasset b/Content/Blueprints/OpticalTable.uasset
index e06b89d09ec376b8d987a4ccb60a5a4821d63d37..9348b485a24b5ec3f01e5343b7da6063d7fc4ee8 100644
Binary files a/Content/Blueprints/OpticalTable.uasset and b/Content/Blueprints/OpticalTable.uasset differ
diff --git a/Content/Blueprints/Screen_Blueprint.uasset b/Content/Blueprints/Screen_Blueprint.uasset
index 11c260a7dbdc192a74ba44df0cf001ac98268663..d2a798a192f59ad6e8435b53126edd368fa3a519 100644
Binary files a/Content/Blueprints/Screen_Blueprint.uasset and b/Content/Blueprints/Screen_Blueprint.uasset differ
diff --git a/Content/Blueprints/SelectableActorBP.uasset b/Content/Blueprints/SelectableActorBP.uasset
index 6b00d06444f545c931663189370d7108bcd20657..c636fd59e526a6458743512f421b5516ae1e2b51 100644
Binary files a/Content/Blueprints/SelectableActorBP.uasset and b/Content/Blueprints/SelectableActorBP.uasset differ
diff --git a/Content/Blueprints/TabletBP.uasset b/Content/Blueprints/TabletBP.uasset
index 3c2fc8f021c61b63a83d956eada5b026dbed197a..43e2defb777f2b5f7cb38b29e86389a59530aa1a 100644
Binary files a/Content/Blueprints/TabletBP.uasset and b/Content/Blueprints/TabletBP.uasset differ
diff --git a/Content/Blueprints/TeleportControllerBP.uasset b/Content/Blueprints/TeleportControllerBP.uasset
index a2296b49b8034c87edd3151b99b69ce104b8bbca..23d4ab65036e26647dc965465088b2d1d3ceac62 100644
Binary files a/Content/Blueprints/TeleportControllerBP.uasset and b/Content/Blueprints/TeleportControllerBP.uasset differ
diff --git a/Content/Laser/LaserMaterial.uasset b/Content/Laser/LaserMaterial.uasset
index 7bbae78aba86b9f1d4469fff70af595638138cd5..2de346cc4854bc27bb5ebcb66d865d147a9395ce 100644
Binary files a/Content/Laser/LaserMaterial.uasset and b/Content/Laser/LaserMaterial.uasset differ
diff --git a/Content/PPMaterials/Outlines.uasset b/Content/PPMaterials/Outlines.uasset
new file mode 100644
index 0000000000000000000000000000000000000000..6cb8c2a7989c45b20ba50755c324898df5ee8e4e
Binary files /dev/null and b/Content/PPMaterials/Outlines.uasset differ
diff --git a/Content/PPMaterials/TextureMaterialVR.uasset b/Content/PPMaterials/TextureMaterialVR.uasset
index 9ecd3c4d36e382ab28692683a948638a3dfcd3c1..6ddea184752139117cd0fb78c22c0dfecedd5453 100644
Binary files a/Content/PPMaterials/TextureMaterialVR.uasset and b/Content/PPMaterials/TextureMaterialVR.uasset differ
diff --git a/Content/UI/PointerMaterial.uasset b/Content/UI/PointerMaterial.uasset
index 7f08be0f11c46a82058aaa0bbe016ba6987a332b..5fcc736df29ee497022ec490c62552e06f669b01 100644
Binary files a/Content/UI/PointerMaterial.uasset and b/Content/UI/PointerMaterial.uasset differ
diff --git a/Content/UI/Tablet/LaserMenuWidget.uasset b/Content/UI/Tablet/LaserMenuWidget.uasset
index 06bf7dad0d02208db6d2e0c641e2362918262028..4e687e6105eb12a155898ebed81c1a23ab6857fd 100644
Binary files a/Content/UI/Tablet/LaserMenuWidget.uasset and b/Content/UI/Tablet/LaserMenuWidget.uasset differ
diff --git a/Content/UI/Tablet/LensMenuWidget.uasset b/Content/UI/Tablet/LensMenuWidget.uasset
index e00a2c46770840021e040c9396a6aa987d1c998e..72d3e17a0d0468c0c6105e199087bffc23abbfba 100644
Binary files a/Content/UI/Tablet/LensMenuWidget.uasset and b/Content/UI/Tablet/LensMenuWidget.uasset differ
diff --git a/Source/OptiX/Private/OptiXAcceleration.cpp b/Deprecated/Private/OptiXAcceleration.cpp
similarity index 96%
rename from Source/OptiX/Private/OptiXAcceleration.cpp
rename to Deprecated/Private/OptiXAcceleration.cpp
index cb6f815ff2fff2724682b3a2ae6950e4ae85b320..707a0311c20d12bf2c3bd71437379fa13ba7f66d 100644
--- a/Source/OptiX/Private/OptiXAcceleration.cpp
+++ b/Deprecated/Private/OptiXAcceleration.cpp
@@ -1,218 +1,218 @@
-#include "OptiXAcceleration.h"
-
-#include "CoreMinimal.h"
-#include "UObject/ObjectMacros.h"
-#include "Engine/EngineTypes.h"
-
-// Needed for debugging
-#include <EngineGlobals.h>
-#include <Runtime/Engine/Classes/Engine/Engine.h>
-
-#include "OptiXModule.h"
-
-DEFINE_LOG_CATEGORY(OptiXPluginAcceleration);
-
-void UOptiXAcceleration::BeginDestroy()
-{
-	Super::BeginDestroy();
-	DestroyOptiXObject();
-}
-
-void UOptiXAcceleration::DestroyOptiXObject()
-{
-	if (NativeAcceleration != NULL)
-	{
-		//NativeAcceleration->destroy();
-		FOptiXModule::Get().GetOptiXContextManager()->AccelerationsToDeleteQueue.Enqueue(NativeAcceleration);
-	}
-	NativeAcceleration = NULL;
-}
-
-void UOptiXAcceleration::Validate()
-{
-	try
-	{
-		NativeAcceleration->validate();
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginAcceleration, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-}
-
-void UOptiXAcceleration::MarkDirty()
-{
-	try
-	{
-		NativeAcceleration->markDirty();
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginAcceleration, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-}
-
-bool UOptiXAcceleration::IsDirty()
-{
-	bool B = false;
-	try
-	{
-		B = NativeAcceleration->isDirty();
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginAcceleration, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-	return B;
-}
-
-void UOptiXAcceleration::SetProperty(FString Name, FString Value)
-{
-	try
-	{
-		std::string N = std::string(TCHAR_TO_ANSI(*Name));
-		std::string V = std::string(TCHAR_TO_ANSI(*Value));
-
-		NativeAcceleration->setProperty(N, V);
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginAcceleration, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-}
-
-FString UOptiXAcceleration::GetProperty(FString Name)
-{
-	FString Property;
-	try
-	{
-		std::string N = std::string(TCHAR_TO_ANSI(*Name));
-		std::string V = NativeAcceleration->getProperty(N);
-		Property = FString(V.c_str());
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginAcceleration, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-	return Property;
-}
-
-void UOptiXAcceleration::SetBuilder(FString Builder)
-{
-	try
-	{
-		std::string N = std::string(TCHAR_TO_ANSI(*Builder));
-
-		NativeAcceleration->setBuilder(N);
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginAcceleration, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-}
-
-FString UOptiXAcceleration::GetBuilder()
-{
-	FString Property;
-	try
-	{
-		std::string V = NativeAcceleration->getBuilder();
-		Property = FString(V.c_str());
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginAcceleration, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-	return Property;
-}
-
-void UOptiXAcceleration::SetTraverser(FString Traverser)
-{
-	try
-	{
-		std::string N = std::string(TCHAR_TO_ANSI(*Traverser));
-
-		NativeAcceleration->setTraverser(N);
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginAcceleration, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-}
-
-FString UOptiXAcceleration::GetTraverser()
-{
-	FString Property;
-	try
-	{
-		std::string V = NativeAcceleration->getTraverser();
-		Property = FString(V.c_str());
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginAcceleration, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-	return Property;
-}
-
-RTsize UOptiXAcceleration::GetDataSize()
-{
-	RTsize Size = 0;
-	try
-	{
-		Size = NativeAcceleration->getDataSize();
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginAcceleration, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-	return Size;
-}
-
-void UOptiXAcceleration::GetData(void * Data)
-{
-	try
-	{
-		NativeAcceleration->getData(Data);
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginAcceleration, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-}
-
-void UOptiXAcceleration::SetData(void * Data, RTsize Size)
-{
-	try
-	{
-		NativeAcceleration->setData(Data, Size);
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginAcceleration, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-}
+#include "OptiXAcceleration.h"
+
+#include "CoreMinimal.h"
+#include "UObject/ObjectMacros.h"
+#include "Engine/EngineTypes.h"
+
+// Needed for debugging
+#include <EngineGlobals.h>
+#include <Runtime/Engine/Classes/Engine/Engine.h>
+
+#include "OptiXModule.h"
+
+DEFINE_LOG_CATEGORY(OptiXPluginAcceleration);
+
+void UOptiXAcceleration::BeginDestroy()
+{
+	Super::BeginDestroy();
+	DestroyOptiXObject();
+}
+
+void UOptiXAcceleration::DestroyOptiXObject()
+{
+	if (NativeAcceleration != NULL)
+	{
+		//NativeAcceleration->destroy();
+		FOptiXModule::Get().GetOptiXContextManager()->AccelerationsToDeleteQueue.Enqueue(NativeAcceleration);
+	}
+	NativeAcceleration = NULL;
+}
+
+void UOptiXAcceleration::Validate()
+{
+	try
+	{
+		NativeAcceleration->validate();
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginAcceleration, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+void UOptiXAcceleration::MarkDirty()
+{
+	try
+	{
+		NativeAcceleration->markDirty();
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginAcceleration, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+bool UOptiXAcceleration::IsDirty()
+{
+	bool B = false;
+	try
+	{
+		B = NativeAcceleration->isDirty();
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginAcceleration, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return B;
+}
+
+void UOptiXAcceleration::SetProperty(FString Name, FString Value)
+{
+	try
+	{
+		std::string N = std::string(TCHAR_TO_ANSI(*Name));
+		std::string V = std::string(TCHAR_TO_ANSI(*Value));
+
+		NativeAcceleration->setProperty(N, V);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginAcceleration, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+FString UOptiXAcceleration::GetProperty(FString Name)
+{
+	FString Property;
+	try
+	{
+		std::string N = std::string(TCHAR_TO_ANSI(*Name));
+		std::string V = NativeAcceleration->getProperty(N);
+		Property = FString(V.c_str());
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginAcceleration, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return Property;
+}
+
+void UOptiXAcceleration::SetBuilder(FString Builder)
+{
+	try
+	{
+		std::string N = std::string(TCHAR_TO_ANSI(*Builder));
+
+		NativeAcceleration->setBuilder(N);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginAcceleration, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+FString UOptiXAcceleration::GetBuilder()
+{
+	FString Property;
+	try
+	{
+		std::string V = NativeAcceleration->getBuilder();
+		Property = FString(V.c_str());
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginAcceleration, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return Property;
+}
+
+void UOptiXAcceleration::SetTraverser(FString Traverser)
+{
+	try
+	{
+		std::string N = std::string(TCHAR_TO_ANSI(*Traverser));
+
+		NativeAcceleration->setTraverser(N);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginAcceleration, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+FString UOptiXAcceleration::GetTraverser()
+{
+	FString Property;
+	try
+	{
+		std::string V = NativeAcceleration->getTraverser();
+		Property = FString(V.c_str());
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginAcceleration, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return Property;
+}
+
+RTsize UOptiXAcceleration::GetDataSize()
+{
+	RTsize Size = 0;
+	try
+	{
+		Size = NativeAcceleration->getDataSize();
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginAcceleration, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return Size;
+}
+
+void UOptiXAcceleration::GetData(void * Data)
+{
+	try
+	{
+		NativeAcceleration->getData(Data);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginAcceleration, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+void UOptiXAcceleration::SetData(void * Data, RTsize Size)
+{
+	try
+	{
+		NativeAcceleration->setData(Data, Size);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginAcceleration, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
diff --git a/Source/OptiX/Private/OptiXBuffer.cpp b/Deprecated/Private/OptiXBuffer.cpp
similarity index 96%
rename from Source/OptiX/Private/OptiXBuffer.cpp
rename to Deprecated/Private/OptiXBuffer.cpp
index 524ae72f911f3b81bc799a9a71553a3186ff3889..a8ed97dfb2300020db2c32b0f010c6f7621bca87 100644
--- a/Source/OptiX/Private/OptiXBuffer.cpp
+++ b/Deprecated/Private/OptiXBuffer.cpp
@@ -1,700 +1,700 @@
-#include "OptiXBuffer.h"
-
-#include "CoreMinimal.h"
-#include "UObject/ObjectMacros.h"
-#include "Engine/EngineTypes.h"
-
-//#include "OptiXModule.h"
-
-// Needed for debugging
-#include <EngineGlobals.h>
-#include <Runtime/Engine/Classes/Engine/Engine.h>
-
-#include "OptiXModule.h"
-
-DEFINE_LOG_CATEGORY(OptiXPluginBuffer);
-
-void UOptiXBuffer::BeginDestroy()
-{
-	UE_LOG(LogTemp, Warning, TEXT("OptiX Buffer BeginDestroy"));
-	DestroyOptiXObject();
-	Super::BeginDestroy();
-}
-
-void UOptiXBuffer::DestroyOptiXObject()
-{
-	if (NativeBuffer != NULL)
-	{
-		UE_LOG(LogTemp, Display, TEXT("Buffer Name: %s!"), *Name);
-		try
-		{
-			//NativeBuffer->destroy();
-			FOptiXModule::Get().GetOptiXContextManager()->BuffersToDeleteQueue.Enqueue(NativeBuffer);
-		}
-		catch (optix::Exception& E)
-		{
-			FString Message = FString(E.getErrorString().c_str());
-			UE_LOG(OptiXPluginBuffer, Fatal, TEXT("OptiX Error: %s"), *Message);
-			GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-		}
-	}
-
-	NativeBuffer = NULL;
-}
-
-void UOptiXBuffer::Validate()
-{
-	try
-	{
-		NativeBuffer->validate();
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-}
-
-void UOptiXBuffer::SetFormat(RTformat Format)
-{
-	try
-	{
-		NativeBuffer->setFormat(Format);
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-}
-
-RTformat UOptiXBuffer::GetFormat()
-{
-	return NativeBuffer->getFormat();
-}
-
-void UOptiXBuffer::SetElementSize(int32 Size)
-{
-	try
-	{
-		NativeBuffer->setElementSize(Size);
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-}
-
-void UOptiXBuffer::SetElementSizeNative(RTsize Size)
-{
-	try
-	{
-		NativeBuffer->setElementSize(Size);
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-}
-
-
-RTsize UOptiXBuffer::GetElementSizeNative()
-{
-	RTsize S = 0;
-	try
-	{
-		S = NativeBuffer->getElementSize();
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-	return S;
-}
-
-int32 UOptiXBuffer::GetElementSize()
-{
-	int32 S = 0;
-	try
-	{
-		S = NativeBuffer->getElementSize();
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-	return S;
-}
-
-void UOptiXBuffer::MarkDirty()
-{
-	try
-	{
-		NativeBuffer->markDirty();
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-}
-
-void UOptiXBuffer::SetSize1D(int32 Width)
-{
-	try
-	{
-		NativeBuffer->setSize(Width);
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-}
-
-void UOptiXBuffer::SetSize1DNative(RTsize Width)
-{
-	try
-	{
-		NativeBuffer->setSize(Width);
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-}
-
-RTsize UOptiXBuffer::GetSize1DNative()
-{
-	RTsize Width;
-	try
-	{
-		NativeBuffer->getSize(Width);
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-	return Width;
-}
-
-int32 UOptiXBuffer::GetSize1D()
-{
-	RTsize Width;
-	try
-	{
-		NativeBuffer->getSize(Width);
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-	return static_cast<int32>(Width);
-}
-
-RTsize UOptiXBuffer::GetMipLevelSize1DNative(uint8 Level)
-{
-	RTsize Width;
-	try
-	{
-		NativeBuffer->getMipLevelSize(Level, Width);
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-	return Width;
-}
-
-int32 UOptiXBuffer::GetMipLevelSize1D(uint8 Level)
-{
-	RTsize Width;
-	try
-	{
-		NativeBuffer->getMipLevelSize(Level, Width);
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-	return static_cast<int32>(Width);
-}
-
-void UOptiXBuffer::SetSize2D(int32 Width, int32 Height)
-{
-	try
-	{
-		NativeBuffer->setSize(Width, Height);
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-}
-
-void UOptiXBuffer::SetSize2DNative(RTsize Width, RTsize Height)
-{
-	try
-	{
-		NativeBuffer->setSize(Width, Height);
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-}
-
-RTsize2 UOptiXBuffer::GetSize2DNative()
-{
-	RTsize2 S;
-	RTsize A;
-	RTsize B;
-	NativeBuffer->getSize(A, B);
-	S.X = A;
-	S.Y = B;
-	return S;
-}
-
-FIntPoint UOptiXBuffer::GetSize2D()
-{
-	FIntPoint S;
-	RTsize A;
-	RTsize B;
-	try
-	{
-		NativeBuffer->getSize(A, B);
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-	S.X = A;
-	S.Y = B;
-	return S;
-}
-
-FIntPoint UOptiXBuffer::GetMipLevelSize2D(uint8 Level)
-{
-	FIntPoint S;
-	RTsize A = 0;
-	RTsize B = 0;
-	try
-	{
-		NativeBuffer->getMipLevelSize(A, B);
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}	
-	S.X = A;
-	S.Y = B;
-	return S;
-}
-
-RTsize2 UOptiXBuffer::GetMipLevelSize2DNative(uint8 Level)
-{
-	RTsize2 S;
-	RTsize A = 0;
-	RTsize B = 0;
-	try
-	{
-		NativeBuffer->getMipLevelSize(A, B);
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}	
-	S.X = A;
-	S.Y = B;
-	return S;
-}
-
-void UOptiXBuffer::SetSize3DNative(RTsize Width, RTsize Height, RTsize Depth)
-{
-	try
-	{
-		NativeBuffer->setSize(Width, Height, Depth);
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-}
-
-void UOptiXBuffer::SetSize3D(int32 Width, int32 Height, int32 Depth)
-{
-	try
-	{
-		NativeBuffer->setSize(Width, Height, Depth);
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-}
-
-FIntVector UOptiXBuffer::GetSize3D()
-{
-	FIntVector S;
-	RTsize A;
-	RTsize B;
-	RTsize C;
-	try
-	{
-		NativeBuffer->getSize(A, B, C);
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-	S.X = A;
-	S.Y = B;	
-	S.Z = C;
-	return S;
-}
-
-
-RTsize3 UOptiXBuffer::GetSize3DNative()
-{
-	RTsize3 S;
-	RTsize A;
-	RTsize B;
-	RTsize C;
-	try
-	{
-		NativeBuffer->getSize(A, B, C);
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-	S.X = A;
-	S.Y = B;
-	S.Z = C;
-	return S;
-}
-
-FIntVector UOptiXBuffer::GetMipLevelSize3D(uint8 Level)
-{
-	FIntVector S;
-	RTsize A = 0;
-	RTsize B = 0;
-	RTsize C = 0;
-	try
-	{
-		NativeBuffer->getMipLevelSize(A, B, C);
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-	S.X = A;
-	S.Y = B;
-	S.Z = C;
-	return S;
-}
-
-RTsize3 UOptiXBuffer::GetMipLevelSize3DNative(uint8 Level)
-{
-	RTsize3 S;
-	RTsize A = 0;
-	RTsize B = 0;
-	RTsize C = 0;
-	try
-	{
-		NativeBuffer->getMipLevelSize(A, B, C);
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-	S.X = A;
-	S.Y = B;
-	S.Z = C;
-	return S;
-}
-
-void UOptiXBuffer::SetMipLevelCount(uint8 Count)
-{
-	try
-	{
-		NativeBuffer->setMipLevelCount(Count);
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-}
-
-uint8 UOptiXBuffer::GetMipLevelCount()
-{
-	uint8 Count = 0;
-	try
-	{
-		Count = NativeBuffer->getMipLevelCount();
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-	return Count;
-}
-
-int UOptiXBuffer::GetId()
-{
-	int Id = 0;
-	try
-	{
-		Id = NativeBuffer->getId();
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-	return Id;
-}
-
-void UOptiXBuffer::Map(uint8 Level, uint8 MapFlags)
-{
-	try
-	{
-		NativeBuffer->map(Level, MapFlags);
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-}
-
-
-void * UOptiXBuffer::MapNative(uint8 Level, uint8 MapFlags, void * UserOwned)
-{
-	void * Ptr = nullptr;
-	try
-	{
-		Ptr = NativeBuffer->map(Level, MapFlags, UserOwned);
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-	return Ptr;
-}
-
-void UOptiXBuffer::Unmap(uint8 Level)
-{
-	try
-	{
-		NativeBuffer->unmap(Level);
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-}
-
-// TODO: Wrap those a bit better
-
-void UOptiXBuffer::BindProgressiveStream(UOptiXBuffer * Source)
-{
-	try
-	{
-		NativeBuffer->bindProgressiveStream(Source->GetNativeBuffer());
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-}
-
-void UOptiXBuffer::GetProgressiveUpdateReady(int * Ready, unsigned int * SubframeCount, unsigned int * MaxSubframes)
-{
-	try
-	{
-		NativeBuffer->getProgressiveUpdateReady(Ready, SubframeCount, MaxSubframes);
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-}
-
-bool UOptiXBuffer::GetProgressiveUpdateReady()
-{
-	bool Ready = false;
-	try
-	{
-		Ready = NativeBuffer->getProgressiveUpdateReady();
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-	return Ready;
-}
-
-void UOptiXBuffer::GetDevicePointer(int32 OptiXDeviceOrdinal, void ** DevicePointer)
-{
-	try
-	{
-		NativeBuffer->getDevicePointer(OptiXDeviceOrdinal, DevicePointer);
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-}
-
-void * UOptiXBuffer::GetDevicePointer(int32 OptiXDeviceOrdinal)
-{
-	void* Ptr = nullptr;
-	try
-	{
-		Ptr = NativeBuffer->getDevicePointer(OptiXDeviceOrdinal);
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-	return Ptr;
-}
-
-void UOptiXBuffer::SetDevicePointer(int32 OptiXDeviceOrdinal, void * DevicePointer)
-{
-	try
-	{
-		NativeBuffer->setDevicePointer(OptiXDeviceOrdinal, DevicePointer);
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-}
-
-bool UOptiXBuffer::GetProgressiveUpdateReady(unsigned int & SubframeCount)
-{
-	bool Ready = false;
-	try
-	{
-		Ready = NativeBuffer->getProgressiveUpdateReady(SubframeCount);
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-	return Ready;
-}
-
-bool UOptiXBuffer::GetProgressiveUpdateReady(unsigned int & SubframeCount, unsigned int & MaxSubframes)
-{
-	bool Ready = false;
-	try
-	{
-		Ready = NativeBuffer->getProgressiveUpdateReady(SubframeCount, MaxSubframes);
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-	return Ready;
-}
-
-void UOptiXBuffer::SetAttribute(RTbufferattribute Attrib, RTsize Size, void * P)
-{
-	try
-	{
-		NativeBuffer->setAttribute(Attrib, Size, P);
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-}
-
-void UOptiXBuffer::GetAttribute(RTbufferattribute Attrib, RTsize Size, void * P)
-{
-	try
-	{
-		NativeBuffer->getAttribute(Attrib, Size, P);
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
+#include "OptiXBuffer.h"
+
+#include "CoreMinimal.h"
+#include "UObject/ObjectMacros.h"
+#include "Engine/EngineTypes.h"
+
+//#include "OptiXModule.h"
+
+// Needed for debugging
+#include <EngineGlobals.h>
+#include <Runtime/Engine/Classes/Engine/Engine.h>
+
+#include "OptiXModule.h"
+
+DEFINE_LOG_CATEGORY(OptiXPluginBuffer);
+
+void UOptiXBuffer::BeginDestroy()
+{
+	UE_LOG(LogTemp, Warning, TEXT("OptiX Buffer BeginDestroy"));
+	DestroyOptiXObject();
+	Super::BeginDestroy();
+}
+
+void UOptiXBuffer::DestroyOptiXObject()
+{
+	if (NativeBuffer != NULL)
+	{
+		UE_LOG(LogTemp, Display, TEXT("Buffer Name: %s!"), *Name);
+		try
+		{
+			//NativeBuffer->destroy();
+			FOptiXModule::Get().GetOptiXContextManager()->BuffersToDeleteQueue.Enqueue(NativeBuffer);
+		}
+		catch (optix::Exception& E)
+		{
+			FString Message = FString(E.getErrorString().c_str());
+			UE_LOG(OptiXPluginBuffer, Fatal, TEXT("OptiX Error: %s"), *Message);
+			GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+		}
+	}
+
+	NativeBuffer = NULL;
+}
+
+void UOptiXBuffer::Validate()
+{
+	try
+	{
+		NativeBuffer->validate();
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+void UOptiXBuffer::SetFormat(RTformat Format)
+{
+	try
+	{
+		NativeBuffer->setFormat(Format);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+RTformat UOptiXBuffer::GetFormat()
+{
+	return NativeBuffer->getFormat();
+}
+
+void UOptiXBuffer::SetElementSize(int32 Size)
+{
+	try
+	{
+		NativeBuffer->setElementSize(Size);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+void UOptiXBuffer::SetElementSizeNative(RTsize Size)
+{
+	try
+	{
+		NativeBuffer->setElementSize(Size);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+
+RTsize UOptiXBuffer::GetElementSizeNative()
+{
+	RTsize S = 0;
+	try
+	{
+		S = NativeBuffer->getElementSize();
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return S;
+}
+
+int32 UOptiXBuffer::GetElementSize()
+{
+	int32 S = 0;
+	try
+	{
+		S = NativeBuffer->getElementSize();
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return S;
+}
+
+void UOptiXBuffer::MarkDirty()
+{
+	try
+	{
+		NativeBuffer->markDirty();
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+void UOptiXBuffer::SetSize1D(int32 Width)
+{
+	try
+	{
+		NativeBuffer->setSize(Width);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+void UOptiXBuffer::SetSize1DNative(RTsize Width)
+{
+	try
+	{
+		NativeBuffer->setSize(Width);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+RTsize UOptiXBuffer::GetSize1DNative()
+{
+	RTsize Width;
+	try
+	{
+		NativeBuffer->getSize(Width);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return Width;
+}
+
+int32 UOptiXBuffer::GetSize1D()
+{
+	RTsize Width;
+	try
+	{
+		NativeBuffer->getSize(Width);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return static_cast<int32>(Width);
+}
+
+RTsize UOptiXBuffer::GetMipLevelSize1DNative(uint8 Level)
+{
+	RTsize Width;
+	try
+	{
+		NativeBuffer->getMipLevelSize(Level, Width);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return Width;
+}
+
+int32 UOptiXBuffer::GetMipLevelSize1D(uint8 Level)
+{
+	RTsize Width;
+	try
+	{
+		NativeBuffer->getMipLevelSize(Level, Width);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return static_cast<int32>(Width);
+}
+
+void UOptiXBuffer::SetSize2D(int32 Width, int32 Height)
+{
+	try
+	{
+		NativeBuffer->setSize(Width, Height);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+void UOptiXBuffer::SetSize2DNative(RTsize Width, RTsize Height)
+{
+	try
+	{
+		NativeBuffer->setSize(Width, Height);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+RTsize2 UOptiXBuffer::GetSize2DNative()
+{
+	RTsize2 S;
+	RTsize A;
+	RTsize B;
+	NativeBuffer->getSize(A, B);
+	S.X = A;
+	S.Y = B;
+	return S;
+}
+
+FIntPoint UOptiXBuffer::GetSize2D()
+{
+	FIntPoint S;
+	RTsize A;
+	RTsize B;
+	try
+	{
+		NativeBuffer->getSize(A, B);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	S.X = A;
+	S.Y = B;
+	return S;
+}
+
+FIntPoint UOptiXBuffer::GetMipLevelSize2D(uint8 Level)
+{
+	FIntPoint S;
+	RTsize A = 0;
+	RTsize B = 0;
+	try
+	{
+		NativeBuffer->getMipLevelSize(A, B);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}	
+	S.X = A;
+	S.Y = B;
+	return S;
+}
+
+RTsize2 UOptiXBuffer::GetMipLevelSize2DNative(uint8 Level)
+{
+	RTsize2 S;
+	RTsize A = 0;
+	RTsize B = 0;
+	try
+	{
+		NativeBuffer->getMipLevelSize(A, B);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}	
+	S.X = A;
+	S.Y = B;
+	return S;
+}
+
+void UOptiXBuffer::SetSize3DNative(RTsize Width, RTsize Height, RTsize Depth)
+{
+	try
+	{
+		NativeBuffer->setSize(Width, Height, Depth);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+void UOptiXBuffer::SetSize3D(int32 Width, int32 Height, int32 Depth)
+{
+	try
+	{
+		NativeBuffer->setSize(Width, Height, Depth);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+FIntVector UOptiXBuffer::GetSize3D()
+{
+	FIntVector S;
+	RTsize A;
+	RTsize B;
+	RTsize C;
+	try
+	{
+		NativeBuffer->getSize(A, B, C);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	S.X = A;
+	S.Y = B;	
+	S.Z = C;
+	return S;
+}
+
+
+RTsize3 UOptiXBuffer::GetSize3DNative()
+{
+	RTsize3 S;
+	RTsize A;
+	RTsize B;
+	RTsize C;
+	try
+	{
+		NativeBuffer->getSize(A, B, C);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	S.X = A;
+	S.Y = B;
+	S.Z = C;
+	return S;
+}
+
+FIntVector UOptiXBuffer::GetMipLevelSize3D(uint8 Level)
+{
+	FIntVector S;
+	RTsize A = 0;
+	RTsize B = 0;
+	RTsize C = 0;
+	try
+	{
+		NativeBuffer->getMipLevelSize(A, B, C);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	S.X = A;
+	S.Y = B;
+	S.Z = C;
+	return S;
+}
+
+RTsize3 UOptiXBuffer::GetMipLevelSize3DNative(uint8 Level)
+{
+	RTsize3 S;
+	RTsize A = 0;
+	RTsize B = 0;
+	RTsize C = 0;
+	try
+	{
+		NativeBuffer->getMipLevelSize(A, B, C);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	S.X = A;
+	S.Y = B;
+	S.Z = C;
+	return S;
+}
+
+void UOptiXBuffer::SetMipLevelCount(uint8 Count)
+{
+	try
+	{
+		NativeBuffer->setMipLevelCount(Count);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+uint8 UOptiXBuffer::GetMipLevelCount()
+{
+	uint8 Count = 0;
+	try
+	{
+		Count = NativeBuffer->getMipLevelCount();
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return Count;
+}
+
+int UOptiXBuffer::GetId()
+{
+	int Id = 0;
+	try
+	{
+		Id = NativeBuffer->getId();
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return Id;
+}
+
+void UOptiXBuffer::Map(uint8 Level, uint8 MapFlags)
+{
+	try
+	{
+		NativeBuffer->map(Level, MapFlags);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+
+void * UOptiXBuffer::MapNative(uint8 Level, uint8 MapFlags, void * UserOwned)
+{
+	void * Ptr = nullptr;
+	try
+	{
+		Ptr = NativeBuffer->map(Level, MapFlags, UserOwned);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return Ptr;
+}
+
+void UOptiXBuffer::Unmap(uint8 Level)
+{
+	try
+	{
+		NativeBuffer->unmap(Level);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+// TODO: Wrap those a bit better
+
+void UOptiXBuffer::BindProgressiveStream(UOptiXBuffer * Source)
+{
+	try
+	{
+		NativeBuffer->bindProgressiveStream(Source->GetNativeBuffer());
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+void UOptiXBuffer::GetProgressiveUpdateReady(int * Ready, unsigned int * SubframeCount, unsigned int * MaxSubframes)
+{
+	try
+	{
+		NativeBuffer->getProgressiveUpdateReady(Ready, SubframeCount, MaxSubframes);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+bool UOptiXBuffer::GetProgressiveUpdateReady()
+{
+	bool Ready = false;
+	try
+	{
+		Ready = NativeBuffer->getProgressiveUpdateReady();
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return Ready;
+}
+
+void UOptiXBuffer::GetDevicePointer(int32 OptiXDeviceOrdinal, void ** DevicePointer)
+{
+	try
+	{
+		NativeBuffer->getDevicePointer(OptiXDeviceOrdinal, DevicePointer);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+void * UOptiXBuffer::GetDevicePointer(int32 OptiXDeviceOrdinal)
+{
+	void* Ptr = nullptr;
+	try
+	{
+		Ptr = NativeBuffer->getDevicePointer(OptiXDeviceOrdinal);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return Ptr;
+}
+
+void UOptiXBuffer::SetDevicePointer(int32 OptiXDeviceOrdinal, void * DevicePointer)
+{
+	try
+	{
+		NativeBuffer->setDevicePointer(OptiXDeviceOrdinal, DevicePointer);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+bool UOptiXBuffer::GetProgressiveUpdateReady(unsigned int & SubframeCount)
+{
+	bool Ready = false;
+	try
+	{
+		Ready = NativeBuffer->getProgressiveUpdateReady(SubframeCount);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return Ready;
+}
+
+bool UOptiXBuffer::GetProgressiveUpdateReady(unsigned int & SubframeCount, unsigned int & MaxSubframes)
+{
+	bool Ready = false;
+	try
+	{
+		Ready = NativeBuffer->getProgressiveUpdateReady(SubframeCount, MaxSubframes);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return Ready;
+}
+
+void UOptiXBuffer::SetAttribute(RTbufferattribute Attrib, RTsize Size, void * P)
+{
+	try
+	{
+		NativeBuffer->setAttribute(Attrib, Size, P);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+void UOptiXBuffer::GetAttribute(RTbufferattribute Attrib, RTsize Size, void * P)
+{
+	try
+	{
+		NativeBuffer->getAttribute(Attrib, Size, P);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginBuffer, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
 }
\ No newline at end of file
diff --git a/Source/OptiX/Private/OptiXContext.cpp b/Deprecated/Private/OptiXContext.cpp
similarity index 96%
rename from Source/OptiX/Private/OptiXContext.cpp
rename to Deprecated/Private/OptiXContext.cpp
index 92b7a3a423b62c86b25c8e22b9d1622ec1920e1e..620f79ebcd7e25e2ef437719f8847ad577e5a36a 100644
--- a/Source/OptiX/Private/OptiXContext.cpp
+++ b/Deprecated/Private/OptiXContext.cpp
@@ -1,1428 +1,1427 @@
-#include "OptiXContext.h"
-
-#include "CoreMinimal.h"
-#include "UObject/ObjectMacros.h"
-#include "Engine/EngineTypes.h"
-
-// Needed for debugging
-#include <EngineGlobals.h>
-#include <Runtime/Engine/Classes/Engine/Engine.h>
-
-#include "StatsDefines.h"
-
-
-DEFINE_LOG_CATEGORY(OptiXPluginContext);
-
-
-UOptiXContext::UOptiXContext(const FObjectInitializer& ObjectInitializer)
-	: Super(ObjectInitializer)
-{
-}
-
-optix::Context UOptiXContext::Init()
-{
-	UOptiXGeometryGroup* Group = NewObject<UOptiXGeometryGroup>(this, UOptiXGeometryGroup::StaticClass());
-	try
-	{
-		NativeContext = optix::Context::create();
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginContext, Fatal, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-	UE_LOG(LogTemp, Warning, TEXT("OptiX Context Init"));
-	return NativeContext;
-}
-
-void UOptiXContext::UpdateVariables()
-{
-	TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("UOptiXContext::UpdateVariables"))
-
-	check(IsInRenderingThread());
-
-	for (UOptiXTransform* T : TransformMap)
-	{
-		T->UpdateTransform();
-	}
-
-	for (TPair<FString, FVector>& V : VectorCache)
-	{
-		SetFloat3DVector(V.Key, V.Value);
-	}
-	VectorCache.Empty();
-	for (TPair<FString, FMatrix>& M : MatrixCache)
-	{
-		SetMatrix(M.Key, M.Value);
-	}
-	VectorCache.Empty();
-}
-
-void UOptiXContext::BeginDestroy()
-{
-	// Tell optix to clean up
-	UE_LOG(LogTemp, Warning, TEXT("OptiX Context BeginDestroy"));
-	
-	Reset();
-
-	if (NativeContext != NULL)
-	{
-		// To make sure the context will be destroyed LAST, after the UObject is gone, the Context Manager needs to make sure 
-		// it actually saves a ptr to the optix::Context and destroys that manually!
-		//NativeContext->destroy();
-
-	}
-	Super::BeginDestroy();
-
-}
-
-/*
-Creator functions. Those functions are used to create the wrapper object and the respective wrapped 
-optix:: object. The UObjects will *not* be saved, so the caller of those functions is responsible
-to keep them from getting eaten by the garbage collection. They can be registered by using the 
-SetObject functions below, which will keep them referenced in the context instance.
-*/
-
-void UOptiXContext::Reset()
-{
-	BufferMap.Empty();
-	MaterialMap.Empty();
-	GeometryMap.Empty();
-	GeometryInstanceMap.Empty();
-	GeometryGroupMap.Empty();
-	GroupMap.Empty();
-	TextureSamplerMap.Empty();
-	RayGenerationPrograms.Empty();
-	ExceptionPrograms.Empty();
-	MissPrograms.Empty();
-	TransformMap.Empty();
-}
-
-UOptiXGeometry* UOptiXContext::CreateGeometry()
-{
-	// Create the object - maybe move outer to the caller of CreateGeometry so the actor actually owns the Geometry? TODO
-	UOptiXGeometry* Geometry = NewObject<UOptiXGeometry>(this, UOptiXGeometry::StaticClass());
-	Geometry->SetGeometry(NativeContext->createGeometry());
-	return Geometry;
-}
-
-UOptiXMaterial * UOptiXContext::CreateMaterial()
-{
-	// Create the object - maybe move outer to the caller of CreateGeometry so the actor actually owns the Geometry? TODO
-	UOptiXMaterial* Material = NewObject<UOptiXMaterial>(this, UOptiXMaterial::StaticClass());
-	Material->SetMaterial(NativeContext->createMaterial());
-	return Material;
-}
-
-UOptiXGeometryInstance * UOptiXContext::CreateGeometryInstance(UOptiXGeometry* Geometry, TArray<UOptiXMaterial*> Materials)
-{
-	// Create the object - maybe move outer to the caller of CreateGeometry so the actor actually owns the Geometry? TODO
-	UOptiXGeometryInstance* Instance = NewObject<UOptiXGeometryInstance>(this, UOptiXGeometryInstance::StaticClass());
-	optix::GeometryInstance NativeInstance = NativeContext->createGeometryInstance();
-	Instance->SetNativeInstance(NativeInstance);
-	Instance->SetGeometry(Geometry);
-	for (UOptiXMaterial* Mat : Materials)
-	{
-		Instance->AddMaterial(Mat);
-	}
-	return Instance;
-}
-
-UOptiXGeometryInstance * UOptiXContext::CreateGeometryInstance(UOptiXGeometry* Geometry, UOptiXMaterial* Material)
-{
-	// Create the object - maybe move outer to the caller of CreateGeometry so the actor actually owns the Geometry? TODO
-	UOptiXGeometryInstance* Instance = NewObject<UOptiXGeometryInstance>(this, UOptiXGeometryInstance::StaticClass());
-	optix::GeometryInstance NativeInstance = NativeContext->createGeometryInstance();
-	Instance->SetNativeInstance(NativeInstance);
-	Instance->SetGeometry(Geometry);
-
-	Instance->AddMaterial(Material);
-	return Instance;
-}
-
-UOptiXGeometryGroup * UOptiXContext::CreateGeometryGroup()
-{
-	UOptiXGeometryGroup* Group = NewObject<UOptiXGeometryGroup>(this, UOptiXGeometryGroup::StaticClass());
-	try
-	{
-		Group->SetNativeGroup(NativeContext->createGeometryGroup());
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginContext, Fatal, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}	
-	return Group;
-}
-
-UOptiXGroup * UOptiXContext::CreateGroup()
-{
-	UOptiXGroup* Group = NewObject<UOptiXGroup>(this, UOptiXGroup::StaticClass());
-	try
-	{
-		Group->SetNativeGroup(NativeContext->createGroup());
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginContext, Fatal, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-	return Group;
-}
-
-UOptiXTransform * UOptiXContext::CreateTransform()
-{
-	UOptiXTransform* Transform = NewObject<UOptiXTransform>(this, UOptiXTransform::StaticClass());
-	Transform->SetNativeGroup(NativeContext->createTransform());
-	TransformMap.Add(Transform); // TODO Fix me 
-	return Transform;
-}
-
-UOptiXAcceleration * UOptiXContext::CreateAcceleration(FString Builder)
-{
-	std::string B = std::string(TCHAR_TO_ANSI(*Builder));
-
-	UOptiXAcceleration* Accel = NewObject<UOptiXAcceleration>(this, UOptiXAcceleration::StaticClass());
-	Accel->SetNativeAcceleration(NativeContext->createAcceleration(B));
-	return Accel;
-}
-
-/*
-Various setter and getter methods to manipulate the current context and pass variables to the shaders.
-*/
-
-void UOptiXContext::SetFloat(FString string, float Var)
-{
-	try 
-	{
-		NativeContext[std::string(TCHAR_TO_ANSI(*string))]->setFloat(Var);
-	} 
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-}
-
-void UOptiXContext::SetFloat2D(FString string, float Var1, float Var2)
-{
-	try
-	{
-		NativeContext[std::string(TCHAR_TO_ANSI(*string))]->setFloat(Var1, Var2);
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-
-}
-
-void UOptiXContext::SetFloat3DVector(FString string, FVector Var)
-{
-	try
-	{
-		NativeContext[std::string(TCHAR_TO_ANSI(*string))]->setFloat(Var.X, Var.Y, Var.Z);
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-}
-
-void UOptiXContext::SetFloat3D(FString string, float Var1, float Var2, float Var3)
-{
-	try
-	{
-		NativeContext[std::string(TCHAR_TO_ANSI(*string))]->setFloat(Var1, Var2, Var3);
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-
-}
-
-void UOptiXContext::SetFloat4DVector(FString string, FVector4 Var)
-{
-	try
-	{
-		NativeContext[std::string(TCHAR_TO_ANSI(*string))]->setFloat(Var.X, Var.Y, Var.Z, Var.W);
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-}
-
-void UOptiXContext::SetFloat4D(FString string, float Var1, float Var2, float Var3, float Var4)
-{
-	try
-	{
-		NativeContext[std::string(TCHAR_TO_ANSI(*string))]->setFloat(Var1, Var2, Var3, Var4);
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-}
-
-void UOptiXContext::SetInt(FString string, int32 Var)
-{
-	try
-	{
-		NativeContext[std::string(TCHAR_TO_ANSI(*string))]->setInt(Var);
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-}
-
-void UOptiXContext::SetInt2D(FString string, int32 Var1, int32 Var2)
-{
-	try
-	{
-		NativeContext[std::string(TCHAR_TO_ANSI(*string))]->setInt(Var1, Var2);
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-}
-
-void UOptiXContext::SetInt3DVector(FString string, FIntVector Var)
-{
-	try
-	{
-		NativeContext[std::string(TCHAR_TO_ANSI(*string))]->setInt(Var.X, Var.Y, Var.Z);
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-}
-
-void UOptiXContext::SetInt3D(FString string, int32 Var1, int32 Var2, int32 Var3)
-{
-	try
-	{
-		NativeContext[std::string(TCHAR_TO_ANSI(*string))]->setInt(Var1, Var2, Var3);
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-}
-
-//void UOptiXContext::SetInt4DVector(FString string, FIntVector4 Var)
-//{
-//	NativeContext[std::string(TCHAR_TO_ANSI(*string))]->setInt(Var.X, Var.Y, Var.Z, Var.W);
-//
-//}
-
-void UOptiXContext::SetInt4D(FString string, int32 Var1, int32 Var2, int32 Var3, int32 Var4)
-{
-	try
-	{
-		NativeContext[std::string(TCHAR_TO_ANSI(*string))]->setInt(Var1, Var2, Var3, Var4);
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-}
-
-void UOptiXContext::SetUint(FString string, uint8 Var)
-{
-	try
-	{
-		NativeContext[std::string(TCHAR_TO_ANSI(*string))]->setUint(Var);
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-}
-
-void UOptiXContext::SetUint2D(FString string, uint8 Var1, uint8 Var2)
-{
-	try
-	{
-		NativeContext[std::string(TCHAR_TO_ANSI(*string))]->setUint(Var1, Var2);
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-}
-
-void UOptiXContext::SetUint3D(FString string, uint8 Var1, uint8 Var2, uint8 Var3)
-{
-	try
-	{
-		NativeContext[std::string(TCHAR_TO_ANSI(*string))]->setUint(Var1, Var2, Var3);
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-}
-
-void UOptiXContext::SetUint4D(FString string, uint8 Var1, uint8 Var2, uint8 Var3, uint8 Var4)
-{
-	try
-	{
-		NativeContext[std::string(TCHAR_TO_ANSI(*string))]->setUint(Var1, Var2, Var3, Var4);
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-}
-
-void UOptiXContext::SetMatrix(FString string, FMatrix Matrix)
-{
-	try
-	{
-		// According to the optix doc false == row major
-		NativeContext[std::string(TCHAR_TO_ANSI(*string))]->setMatrix4x4fv(true, &Matrix.M[0][0]); // TODO - find out if false or true is column or row major
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-}
-
-float UOptiXContext::GetFloat(FString string)
-{
-	float F = 0;
-	try
-	{
-		F = NativeContext[std::string(TCHAR_TO_ANSI(*string))]->getFloat();
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-	return F;
-}
-
-// TODO: COMPLETE ERROR HANDLING
-
-FVector2D UOptiXContext::GetFloat2D(FString string)
-{
-	optix::float2 V = optix::make_float2(0, 0);
-	try
-	{
-		V = NativeContext[std::string(TCHAR_TO_ANSI(*string))]->getFloat2();
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-
-	return FVector2D(V.x, V.y);
-}
-
-FVector UOptiXContext::GetFloat3D(FString string)
-{
-	optix::float3 V = optix::make_float3(0, 0, 0);;
-	try
-	{
-		V = NativeContext[std::string(TCHAR_TO_ANSI(*string))]->getFloat3();
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-	return FVector(V.x, V.y, V.z);
-}
-
-FVector4 UOptiXContext::GetFloat4D(FString string)
-{
-	optix::float4 V = optix::make_float4(0, 0, 0, 0);
-	try
-	{
-		V = NativeContext[std::string(TCHAR_TO_ANSI(*string))]->getFloat4();
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-	return FVector4(V.x, V.y, V.z, V.w);
-}
-
-int32 UOptiXContext::GetInt(FString string)
-{
-	int32 Result = 0;
-	try
-	{
-		Result = NativeContext[std::string(TCHAR_TO_ANSI(*string))]->getInt();
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-	return Result;
-}
-
-FIntPoint UOptiXContext::GetInt2D(FString string)
-{
-	optix::int2 V = optix::make_int2(0, 0);
-	try
-	{
-		V = NativeContext[std::string(TCHAR_TO_ANSI(*string))]->getInt2();
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-	return FIntPoint(V.x, V.y);
-}
-
-FIntVector UOptiXContext::GetInt3D(FString string)
-{
-	optix::int3 V = optix::make_int3(0, 0, 0);
-	try
-	{
-		V = NativeContext[std::string(TCHAR_TO_ANSI(*string))]->getInt3();
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-	return FIntVector(V.x, V.y, V.z);
-}
-
-
-void UOptiXContext::Validate()
-{
-	try
-	{
-		NativeContext->validate();
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-}
-
-uint32 UOptiXContext::GetDeviceCount()
-{
-	uint32 DeviceCount = 0;
-	try
-	{
-		DeviceCount = NativeContext->getDeviceCount();
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-	return DeviceCount;
-}
-
-FString UOptiXContext::GetDeviceName(int32 Ordinal)
-{
-	FString DeviceName = "";
-	try
-	{
-		DeviceName = FString(NativeContext->getDeviceName(Ordinal).c_str());
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-	return DeviceName;
-}
-
-void UOptiXContext::SetStackSize(int32 StackSize)
-{
-	if (StackSize < 0)
-	{
-		FString Message = "Trying to set negative stack size!";
-		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
-		return; // TODO Throw error
-	}
-	try
-	{
-		NativeContext->setStackSize(static_cast<uint32>(StackSize));
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-}
-
-int32 UOptiXContext::GetStackSize()
-{
-	// Casting a uint32 into an int32 is a bit dangerous here...
-	// TODO Check precision
-	int32 Size = 0;
-	try
-	{
-		Size = static_cast<int32>(NativeContext->getStackSize());
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-	return Size;
-}
-
-void UOptiXContext::SetStackSize64(uint64 StackSize)
-{
-	try
-	{
-		NativeContext->setStackSize(StackSize);
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-}
-
-uint64 UOptiXContext::GetStackSize64()
-{
-	uint64 Size = 0;
-	try
-	{
-		Size = NativeContext->getStackSize();
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-	return Size;
-}
-
-void UOptiXContext::SetEntryPointCount(int32 NumEntryPoints)
-{
-	int32 Diff = NumEntryPoints - GetEntryPointCount();
-	if (Diff > 0)
-	{
-		RayGenerationPrograms.SetNum(NumEntryPoints);
-		ExceptionPrograms.SetNum(NumEntryPoints);
-	}
-	// TODO delete if diff < 0
-	else
-	{
-		for (int32 i = NumEntryPoints; i < GetEntryPointCount(); i++)
-		{
-			RayGenerationPrograms.RemoveAt(i);
-			ExceptionPrograms.RemoveAt(i);
-		}
-		RayGenerationPrograms.SetNum(NumEntryPoints);
-		ExceptionPrograms.SetNum(NumEntryPoints);
-
-		FString Message = FString("Shrinking Entry Point Count!");
-		UE_LOG(OptiXPluginContext, Warning, TEXT("Error: %s"), *Message);
-	}
-	try
-	{
-		NativeContext->setEntryPointCount(static_cast<uint32>(NumEntryPoints));
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-}
-
-int32 UOptiXContext::GetEntryPointCount()
-{
-	int32 EntryPointCount = 0;
-	try
-	{
-		EntryPointCount = static_cast<int32>(NativeContext->getEntryPointCount());
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-	return EntryPointCount;
-}
-
-
-void UOptiXContext::SetRayGenerationProgram(int32 EntryPointIndex, UOptiXProgram* Program)
-{
-	if (!RayGenerationPrograms.IsValidIndex(EntryPointIndex))
-	{
-		UE_LOG(LogTemp, Error, TEXT("OptiXContext: Trying to insert program in non-existing place! \n"));
-		return;
-	}
-	try
-	{
-		NativeContext->setRayGenerationProgram(EntryPointIndex, Program->GetNativeProgram());
-		RayGenerationPrograms.Insert(Program, EntryPointIndex);
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-
-}
-
-UOptiXProgram* UOptiXContext::GetRayGenerationProgram(int32 EntryPointIndex)
-{
-	UOptiXProgram* Program = nullptr;
-	if (!RayGenerationPrograms.IsValidIndex(EntryPointIndex))
-	{
-		UE_LOG(LogTemp, Error, TEXT("OptiXContext: Trying to get ray generation program from non-existing place! \n"));
-	}
-	try
-	{
-		NativeContext->getRayGenerationProgram(EntryPointIndex);
-		Program = RayGenerationPrograms[EntryPointIndex];
-		// Todo: this could use some sweet little love
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-	return Program;
-}
-
-void UOptiXContext::SetExceptionProgram(int32 EntryPointIndex, UOptiXProgram* Program)
-{
-	if (!ExceptionPrograms.IsValidIndex(EntryPointIndex))
-	{
-		UE_LOG(LogTemp, Error, TEXT("OptiXContext: Trying to insert program in non-existing place! \n"));
-		return;
-	}
-	try
-	{
-		NativeContext->setExceptionProgram(EntryPointIndex, Program->GetNativeProgram());
-		ExceptionPrograms.Insert(Program, EntryPointIndex);
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-
-}
-
-UOptiXProgram* UOptiXContext::GetExceptionProgram(int32 EntryPointIndex)
-{
-	UOptiXProgram* Program = nullptr;
-	if (!ExceptionPrograms.IsValidIndex(EntryPointIndex))
-	{
-		UE_LOG(LogTemp, Error, TEXT("OptiXContext: Trying to get ray exception program from non-existing place! \n"));
-	}
-	try
-	{
-		NativeContext->getExceptionProgram(EntryPointIndex);
-		Program = ExceptionPrograms[EntryPointIndex];
-		// Todo: this could use some sweet little love
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-	return Program;
-}
-
-void UOptiXContext::SetExceptionEnabled(RTexception Exception, bool Enabled)
-{
-	try
-	{
-		NativeContext->setExceptionEnabled(Exception, Enabled);
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-}
-
-bool UOptiXContext::GetExceptionEnabled(RTexception Exception)
-{
-	bool V = false; // TODO Look at all those shitty default values
-	try
-	{
-		V = NativeContext->getExceptionEnabled(Exception);
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-	return V;
-}
-
-// Uh oh
-
-void UOptiXContext::SetRayTypeCount(int32 NumRayTypes)
-{
-	int32 Diff = NumRayTypes - GetRayTypeCount();
-	if (Diff > 0)
-	{
-		MissPrograms.SetNum(NumRayTypes);
-	}
-	// TODO delete if diff < 0
-	try
-	{
-		NativeContext->setRayTypeCount(static_cast<uint32>(NumRayTypes));
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-}
-
-int32 UOptiXContext::GetRayTypeCount()
-{
-	// TODO CAST
-	int32 RTC = 0; static_cast<int32>(NativeContext->getRayTypeCount());
-	try
-	{
-		RTC = static_cast<int32>(NativeContext->getRayTypeCount());
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-	return RTC;
-}
-
-
-void UOptiXContext::SetMissProgram(int32 RayTypeIndex, UOptiXProgram* Program)
-{
-	if (!MissPrograms.IsValidIndex(RayTypeIndex))
-	{
-		UE_LOG(LogTemp, Error, TEXT("UOptiXContext: Trying to insert program in non-existing place! \n"));
-		return;
-	}
-	try
-	{
-		NativeContext->setMissProgram(RayTypeIndex, Program->GetNativeProgram());
-		MissPrograms.Insert(Program, RayTypeIndex);
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-}
-
-UOptiXProgram* UOptiXContext::GetMissProgram(int32 RayTypeIndex)
-{
-	UOptiXProgram* Program = nullptr;
-	if (!MissPrograms.IsValidIndex(RayTypeIndex))
-	{
-		UE_LOG(LogTemp, Error, TEXT("OptiXContext: Trying to get ray miss program from non-existing place! \n"));
-	}
-	try
-	{
-		NativeContext->getMissProgram(RayTypeIndex);
-		Program = MissPrograms[RayTypeIndex];
-		// Todo: this could use some sweet little love
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-	return Program;
-}
-
-void UOptiXContext::Launch(int32 EntryPointIndex, uint64 ImageWidth)
-{
-	TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("UOptiXContext::Launch1D"))
-
-	try
-	{
-		NativeContext->launch(EntryPointIndex, ImageWidth);
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-}
-
-void UOptiXContext::Launch(int32 EntryPointIndex, uint64 ImageWidth, uint64 ImageHeight)
-{
-	//UE_LOG(OptiXPluginContext, Warning, TEXT("Child count: %i"), GeometryGroupMap["top_object"]->GetChildCount());
-	TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("UOptiXContext::Launch2D"))
-
-	try
-	{
-		NativeContext->launch(EntryPointIndex, ImageWidth, ImageHeight);
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-}
-
-void UOptiXContext::Launch(int32 EntryPointIndex, uint64 ImageWidth, uint64 ImageHeight, uint64 ImageDepth)
-{
-	TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("UOptiXContext::Launch3D"))
-
-	try
-	{
-		NativeContext->launch(EntryPointIndex, ImageWidth, ImageHeight, ImageDepth);
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-}
-
-void UOptiXContext::SetBuffer(FString Name, UOptiXBuffer * Buffer)
-{
-	try
-	{
-		std::string N = std::string(TCHAR_TO_ANSI(*Name));
-		NativeContext[N]->set(Buffer->GetNativeBuffer());
-		Buffer->Name = Name;
-		BufferMap.Add(Name, Buffer);
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-}
-
-void UOptiXContext::SetGeometryGroup(FString Name, UOptiXGeometryGroup * GeoGroup)
-{
-	try
-	{
-		std::string N = std::string(TCHAR_TO_ANSI(*Name));
-		NativeContext[N]->set(GeoGroup->GetNativeGroup());
-		GeometryGroupMap.Add(Name, GeoGroup);
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-}
-
-void UOptiXContext::SetGroup(FString Name, UOptiXGroup * Group)
-{
-	try
-	{
-		std::string N = std::string(TCHAR_TO_ANSI(*Name));
-		NativeContext[N]->set(Group->GetNativeGroup());
-		GroupMap.Add(Name, Group);
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-}
-
-UOptiXProgram * UOptiXContext::CreateProgramFromPTXFile(FString Path, FString Name)
-{
-	UOptiXProgram* ProgramPtr = nullptr;
-	try
-	{
-		ProgramPtr = NewObject<UOptiXProgram>(this, UOptiXProgram::StaticClass());
-		std::string P = std::string(TCHAR_TO_ANSI(*Path));
-		std::string N = std::string(TCHAR_TO_ANSI(*Name));
-		optix::Program Prog = NativeContext->createProgramFromPTXFile(P, N);
-		ProgramPtr->SetProgram(Prog);
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-	return ProgramPtr;
-}
-
-UOptiXBuffer * UOptiXContext::CreateBuffer(uint8 Type, RTformat Format, RTsize Width)
-{
-	UOptiXBuffer* BufferPtr = nullptr;
-	try
-	{
-		BufferPtr = NewObject<UOptiXBuffer>(this, UOptiXBuffer::StaticClass());
-		BufferPtr->SetBuffer(NativeContext->createBuffer(Type, Format, Width));
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-	return BufferPtr;
-}
-
-UOptiXBuffer * UOptiXContext::CreateBuffer(uint8 Type, RTformat Format, RTsize Width, RTsize Height)
-{
-	UOptiXBuffer* BufferPtr = nullptr;
-	try
-	{
-		BufferPtr = NewObject<UOptiXBuffer>(this, UOptiXBuffer::StaticClass());
-		BufferPtr->SetBuffer(NativeContext->createBuffer(Type, Format, Width, Height));
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-	return BufferPtr;
-}
-
-UOptiXBuffer * UOptiXContext::CreateBuffer(uint8 Type, RTformat Format, RTsize Width, RTsize Height, RTsize Depth)
-{
-	UOptiXBuffer* BufferPtr = nullptr;
-	try
-	{
-		BufferPtr = NewObject<UOptiXBuffer>(this, UOptiXBuffer::StaticClass());
-		BufferPtr->SetBuffer(NativeContext->createBuffer(Type, Format, Width, Height, Depth));
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-	return BufferPtr;
-}
-
-UOptiXBuffer * UOptiXContext::CreateBufferSimple(uint8 Type)
-{
-	UOptiXBuffer* BufferPtr = nullptr;
-	try
-	{
-		BufferPtr = NewObject<UOptiXBuffer>(this, UOptiXBuffer::StaticClass());
-		BufferPtr->SetBuffer(NativeContext->createBuffer(Type));
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-	return BufferPtr;
-}
-
-UOptiXBuffer * UOptiXContext::CreateBufferUByte(uint8 Type)
-{
-	UOptiXBuffer* BufferPtr = nullptr;
-	try
-	{
-		BufferPtr = NewObject<UOptiXBuffer>(this, UOptiXBuffer::StaticClass());
-		BufferPtr->SetBuffer(NativeContext->createBuffer(Type, RT_FORMAT_UNSIGNED_BYTE4));
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-	return BufferPtr;
-}
-
-UOptiXBuffer * UOptiXContext::CreateBufferUByte1D(uint8 Type, int32 Width)
-{
-	UOptiXBuffer* BufferPtr = nullptr;
-	try
-	{
-		BufferPtr = NewObject<UOptiXBuffer>(this, UOptiXBuffer::StaticClass());
-		BufferPtr->SetBuffer(NativeContext->createBuffer(Type, RT_FORMAT_UNSIGNED_BYTE4, Width));
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-	return BufferPtr;
-}
-
-UOptiXBuffer * UOptiXContext::CreateBufferUByte2D(uint8 Type, int32 Width, int32 Height)
-{
-	UOptiXBuffer* BufferPtr = nullptr;
-	try
-	{
-		BufferPtr = NewObject<UOptiXBuffer>(this, UOptiXBuffer::StaticClass());
-		BufferPtr->SetBuffer(NativeContext->createBuffer(Type, RT_FORMAT_UNSIGNED_BYTE4, Width, Height));
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-	return BufferPtr;
-}
-
-UOptiXBuffer * UOptiXContext::CreateBufferUByte3D(uint8 Type, int32 Width, int32 Height, int32 Depth)
-{
-	UOptiXBuffer* BufferPtr = nullptr;
-	try
-	{
-		BufferPtr = NewObject<UOptiXBuffer>(this, UOptiXBuffer::StaticClass());
-		BufferPtr->SetBuffer(NativeContext->createBuffer(Type, RT_FORMAT_UNSIGNED_BYTE4, Width, Height, Depth));
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-	return BufferPtr;
-}
-
-UOptiXBuffer * UOptiXContext::CreateOutputBufferIntersections(int32 Width, int32 Height)
-{
-	UOptiXBuffer* BufferPtr = nullptr;
-	try
-	{
-		BufferPtr = NewObject<UOptiXBuffer>(this, UOptiXBuffer::StaticClass());
-		BufferPtr->SetBuffer(NativeContext->createBufferForCUDA(RT_BUFFER_INPUT_OUTPUT | RT_BUFFER_GPU_LOCAL, RT_FORMAT_FLOAT4, Width, Height));
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-	return BufferPtr;
-}
-
-
-UOptiXBuffer * UOptiXContext::CreateOutputBufferColor(int32 Width, int32 Height)
-{
-	UOptiXBuffer* BufferPtr = nullptr;
-	try
-	{
-		BufferPtr = NewObject<UOptiXBuffer>(this, UOptiXBuffer::StaticClass());
-		BufferPtr->SetBuffer(NativeContext->createBufferForCUDA(RT_BUFFER_INPUT_OUTPUT | RT_BUFFER_GPU_LOCAL, RT_FORMAT_FLOAT4, Width, Height));
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-	return BufferPtr;
-}
-
-UOptiXBuffer * UOptiXContext::CreateOutputBufferUByte3D(int32 Width, int32 Height, int32 Depth)
-{
-	UOptiXBuffer* BufferPtr = nullptr;
-	try
-	{
-		BufferPtr = NewObject<UOptiXBuffer>(this, UOptiXBuffer::StaticClass());
-		BufferPtr->SetBuffer(NativeContext->createBuffer(RT_BUFFER_OUTPUT, RT_FORMAT_UNSIGNED_BYTE4, Width, Height, Depth));
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-	return BufferPtr;
-}
-
-UOptiXBuffer* UOptiXContext::CreateOutputBufferDepth(int32 Width, int32 Height)
-{
-	UOptiXBuffer* BufferPtr = nullptr;
-	try
-	{
-		BufferPtr = NewObject<UOptiXBuffer>(this, UOptiXBuffer::StaticClass());
-		//BufferPtr->SetBuffer(NativeContext->createBuffer(RT_BUFFER_INPUT_OUTPUT | RT_BUFFER_GPU_LOCAL, RT_FORMAT_FLOAT, Width, Height));
-		BufferPtr->SetBuffer(NativeContext->createBufferForCUDA(RT_BUFFER_INPUT_OUTPUT | RT_BUFFER_GPU_LOCAL, RT_FORMAT_FLOAT, Width, Height));
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-	return BufferPtr;
-}
-
-UOptiXBuffer * UOptiXContext::CreateInputBufferFloat(int32 Width)
-{
-	UOptiXBuffer* BufferPtr = nullptr;
-	try
-	{
-		BufferPtr = NewObject<UOptiXBuffer>(this, UOptiXBuffer::StaticClass());
-		BufferPtr->SetBuffer(NativeContext->createBuffer(RT_BUFFER_INPUT, RT_FORMAT_FLOAT, Width));
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-	return BufferPtr;
-}
-
-UOptiXBuffer * UOptiXContext::CreateInputBufferFloat2D(int32 Width, int32 Height)
-{
-	UOptiXBuffer* BufferPtr = nullptr;
-	try
-	{
-		BufferPtr = NewObject<UOptiXBuffer>(this, UOptiXBuffer::StaticClass());
-		BufferPtr->SetBuffer(NativeContext->createBuffer(RT_BUFFER_INPUT, RT_FORMAT_FLOAT, Width, Height));
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-	return BufferPtr;
-}
-
-UOptiXBuffer * UOptiXContext::CreateInputBufferFloat3D(int32 Width, int32 Height, int32 Depth)
-{
-	UOptiXBuffer* BufferPtr = nullptr;
-	try
-	{
-		BufferPtr = NewObject<UOptiXBuffer>(this, UOptiXBuffer::StaticClass());
-		BufferPtr->SetBuffer(NativeContext->createBuffer(RT_BUFFER_INPUT, RT_FORMAT_FLOAT, Width, Height, Depth));
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-	return BufferPtr;
-}
-
-UOptiXBuffer * UOptiXContext::CreateCubemapBuffer(int32 Width, int32 Height)
-{
-	UOptiXBuffer* BufferPtr = nullptr;
-	try
-	{
-		// https://github.com/nvpro-samples/optix_advanced_samples/blob/master/src/optixIntroduction/optixIntro_07/src/Texture.cpp
-		BufferPtr = NewObject<UOptiXBuffer>(this, UOptiXBuffer::StaticClass());
-		BufferPtr->SetBuffer(NativeContext->createBuffer(RT_BUFFER_INPUT | RT_BUFFER_CUBEMAP, RT_FORMAT_UNSIGNED_BYTE4, Width, Height, 6)); // 6 slices
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-	return BufferPtr;
-}
-
-void UOptiXContext::SetMaxTraceDepth(int32 Depth)
-{
-	try
-	{
-		NativeContext->setMaxTraceDepth(static_cast<unsigned int>(Depth));
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-}
-
-int32 UOptiXContext::GetMaxTraceDepth()
-{
-	int32 Depth = 0;
-	try
-	{
-		Depth = static_cast<int32>(NativeContext->getMaxTraceDepth()); // Loss of precision but won't happen ever anyway
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-	return Depth;
-}
-
-void UOptiXContext::SetFloat3DVectorThreadsafe(FString string, FVector Var)
-{
-	VectorCache.Add(string, Var);
-}
-
-void UOptiXContext::SetMatrixThreadsafe(FString string, FMatrix Matrix)
-{
-	MatrixCache.Add(string, Matrix);
-}
-
-UOptiXTextureSampler * UOptiXContext::CreateTextureSampler()
-{
-	UOptiXTextureSampler* SamplerPtr = nullptr;
-	try
-	{
-		SamplerPtr = NewObject<UOptiXTextureSampler>(this, UOptiXTextureSampler::StaticClass());
-		SamplerPtr->SetTextureSampler(NativeContext->createTextureSampler());
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-	return SamplerPtr;
-}
-
-void UOptiXContext::SetTextureSampler(FString Name, UOptiXTextureSampler * Sampler)
-{
-	try
-	{
-		std::string N = std::string(TCHAR_TO_ANSI(*Name));
-		NativeContext[N]->set(Sampler->GetNativeTextureSampler());
-		TextureSamplerMap.Add(Name, Sampler);
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-}
-
-void UOptiXContext::SetSkybox(FString Name, UOptiXTextureSampler * Sampler)
-{
-	SetInt(Name, Sampler->GetId());
-	TextureSamplerMap.Add(Name, Sampler);
-}
-
-UOptiXBuffer * UOptiXContext::GetBuffer(FString Name)
-{
-	if (BufferMap.Contains(Name))
-	{
-		return BufferMap[Name];
-	}
-	else
-	{
-		FString Message = "Buffer doesn't exist!";
-		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-		return nullptr;
-	}
-}
-
-UOptiXGeometryGroup * UOptiXContext::GetGeometryGroup(FString Name)
-{
-	if (GeometryGroupMap.Contains(Name))
-	{
-		// Todo - check if that's actually the correct one! (GetNative etc)
-		return GeometryGroupMap[Name];
-	}
-	else
-	{
-		FString Message = "Geometry Group doesn't exist!";
-		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-		return nullptr;
-	}
-}
-
-UOptiXGroup * UOptiXContext::GetGroup(FString Name)
-{
-	if (GroupMap.Contains(Name))
-	{
-		// Todo - check if that's actually the correct one! (GetNative etc)
-		return GroupMap[Name];
-	}
-	else
-	{
-		FString Message = "Group doesn't exist!";
-		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-		return nullptr;
-	}
-}
-
-// Copy Paste too strong, could have shortened that quite a bit 
+#include "OptiXContext.h"
+
+#include "CoreMinimal.h"
+#include "UObject/ObjectMacros.h"
+#include "Engine/EngineTypes.h"
+
+// Needed for debugging
+#include <EngineGlobals.h>
+#include <Runtime/Engine/Classes/Engine/Engine.h>
+
+#include "StatsDefines.h"
+
+
+DEFINE_LOG_CATEGORY(OptiXPluginContext);
+
+
+UOptiXContext::UOptiXContext(const FObjectInitializer& ObjectInitializer)
+	: Super(ObjectInitializer)
+{
+}
+
+optix::Context UOptiXContext::Init()
+{
+	try
+	{
+		NativeContext = optix::Context::create();
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Fatal, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	UE_LOG(LogTemp, Warning, TEXT("OptiX Context Init"));
+	return NativeContext;
+}
+
+void UOptiXContext::UpdateVariables()
+{
+	TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("UOptiXContext::UpdateVariables"))
+
+	check(IsInRenderingThread());
+
+	for (UOptiXTransform* T : TransformMap)
+	{
+		T->UpdateTransform();
+	}
+
+	for (TPair<FString, FVector>& V : VectorCache)
+	{
+		SetFloat3DVector(V.Key, V.Value);
+	}
+	VectorCache.Empty();
+	for (TPair<FString, FMatrix>& M : MatrixCache)
+	{
+		SetMatrix(M.Key, M.Value);
+	}
+	VectorCache.Empty();
+}
+
+void UOptiXContext::BeginDestroy()
+{
+	// Tell optix to clean up
+	UE_LOG(LogTemp, Warning, TEXT("OptiX Context BeginDestroy"));
+	
+	Reset();
+
+	if (NativeContext != NULL)
+	{
+		// To make sure the context will be destroyed LAST, after the UObject is gone, the Context Manager needs to make sure 
+		// it actually saves a ptr to the optix::Context and destroys that manually!
+		//NativeContext->destroy();
+
+	}
+	Super::BeginDestroy();
+
+}
+
+/*
+Creator functions. Those functions are used to create the wrapper object and the respective wrapped 
+optix:: object. The UObjects will *not* be saved, so the caller of those functions is responsible
+to keep them from getting eaten by the garbage collection. They can be registered by using the 
+SetObject functions below, which will keep them referenced in the context instance.
+*/
+
+void UOptiXContext::Reset()
+{
+	BufferMap.Empty();
+	MaterialMap.Empty();
+	GeometryMap.Empty();
+	GeometryInstanceMap.Empty();
+	GeometryGroupMap.Empty();
+	GroupMap.Empty();
+	TextureSamplerMap.Empty();
+	RayGenerationPrograms.Empty();
+	ExceptionPrograms.Empty();
+	MissPrograms.Empty();
+	TransformMap.Empty();
+}
+
+UOptiXGeometry* UOptiXContext::CreateGeometry()
+{
+	// Create the object - maybe move outer to the caller of CreateGeometry so the actor actually owns the Geometry? TODO
+	UOptiXGeometry* Geometry = NewObject<UOptiXGeometry>(this, UOptiXGeometry::StaticClass());
+	Geometry->SetGeometry(NativeContext->createGeometry());
+	return Geometry;
+}
+
+UOptiXMaterial * UOptiXContext::CreateMaterial()
+{
+	// Create the object - maybe move outer to the caller of CreateGeometry so the actor actually owns the Geometry? TODO
+	UOptiXMaterial* Material = NewObject<UOptiXMaterial>(this, UOptiXMaterial::StaticClass());
+	Material->SetMaterial(NativeContext->createMaterial());
+	return Material;
+}
+
+UOptiXGeometryInstance * UOptiXContext::CreateGeometryInstance(UOptiXGeometry* Geometry, TArray<UOptiXMaterial*> Materials)
+{
+	// Create the object - maybe move outer to the caller of CreateGeometry so the actor actually owns the Geometry? TODO
+	UOptiXGeometryInstance* Instance = NewObject<UOptiXGeometryInstance>(this, UOptiXGeometryInstance::StaticClass());
+	optix::GeometryInstance NativeInstance = NativeContext->createGeometryInstance();
+	Instance->SetNativeInstance(NativeInstance);
+	Instance->SetGeometry(Geometry);
+	for (UOptiXMaterial* Mat : Materials)
+	{
+		Instance->AddMaterial(Mat);
+	}
+	return Instance;
+}
+
+UOptiXGeometryInstance * UOptiXContext::CreateGeometryInstance(UOptiXGeometry* Geometry, UOptiXMaterial* Material)
+{
+	// Create the object - maybe move outer to the caller of CreateGeometry so the actor actually owns the Geometry? TODO
+	UOptiXGeometryInstance* Instance = NewObject<UOptiXGeometryInstance>(this, UOptiXGeometryInstance::StaticClass());
+	optix::GeometryInstance NativeInstance = NativeContext->createGeometryInstance();
+	Instance->SetNativeInstance(NativeInstance);
+	Instance->SetGeometry(Geometry);
+
+	Instance->AddMaterial(Material);
+	return Instance;
+}
+
+UOptiXGeometryGroup * UOptiXContext::CreateGeometryGroup()
+{
+	UOptiXGeometryGroup* Group = NewObject<UOptiXGeometryGroup>(this, UOptiXGeometryGroup::StaticClass());
+	try
+	{
+		Group->SetNativeGroup(NativeContext->createGeometryGroup());
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Fatal, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}	
+	return Group;
+}
+
+UOptiXGroup * UOptiXContext::CreateGroup()
+{
+	UOptiXGroup* Group = NewObject<UOptiXGroup>(this, UOptiXGroup::StaticClass());
+	try
+	{
+		Group->SetNativeGroup(NativeContext->createGroup());
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Fatal, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return Group;
+}
+
+UOptiXTransform * UOptiXContext::CreateTransform()
+{
+	UOptiXTransform* Transform = NewObject<UOptiXTransform>(this, UOptiXTransform::StaticClass());
+	Transform->SetNativeGroup(NativeContext->createTransform());
+	TransformMap.Add(Transform); // TODO Fix me 
+	return Transform;
+}
+
+UOptiXAcceleration * UOptiXContext::CreateAcceleration(FString Builder)
+{
+	std::string B = std::string(TCHAR_TO_ANSI(*Builder));
+
+	UOptiXAcceleration* Accel = NewObject<UOptiXAcceleration>(this, UOptiXAcceleration::StaticClass());
+	Accel->SetNativeAcceleration(NativeContext->createAcceleration(B));
+	return Accel;
+}
+
+/*
+Various setter and getter methods to manipulate the current context and pass variables to the shaders.
+*/
+
+void UOptiXContext::SetFloat(FString string, float Var)
+{
+	try 
+	{
+		NativeContext[std::string(TCHAR_TO_ANSI(*string))]->setFloat(Var);
+	} 
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+void UOptiXContext::SetFloat2D(FString string, float Var1, float Var2)
+{
+	try
+	{
+		NativeContext[std::string(TCHAR_TO_ANSI(*string))]->setFloat(Var1, Var2);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+
+}
+
+void UOptiXContext::SetFloat3DVector(FString string, FVector Var)
+{
+	try
+	{
+		NativeContext[std::string(TCHAR_TO_ANSI(*string))]->setFloat(Var.X, Var.Y, Var.Z);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+void UOptiXContext::SetFloat3D(FString string, float Var1, float Var2, float Var3)
+{
+	try
+	{
+		NativeContext[std::string(TCHAR_TO_ANSI(*string))]->setFloat(Var1, Var2, Var3);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+
+}
+
+void UOptiXContext::SetFloat4DVector(FString string, FVector4 Var)
+{
+	try
+	{
+		NativeContext[std::string(TCHAR_TO_ANSI(*string))]->setFloat(Var.X, Var.Y, Var.Z, Var.W);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+void UOptiXContext::SetFloat4D(FString string, float Var1, float Var2, float Var3, float Var4)
+{
+	try
+	{
+		NativeContext[std::string(TCHAR_TO_ANSI(*string))]->setFloat(Var1, Var2, Var3, Var4);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+void UOptiXContext::SetInt(FString string, int32 Var)
+{
+	try
+	{
+		NativeContext[std::string(TCHAR_TO_ANSI(*string))]->setInt(Var);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+void UOptiXContext::SetInt2D(FString string, int32 Var1, int32 Var2)
+{
+	try
+	{
+		NativeContext[std::string(TCHAR_TO_ANSI(*string))]->setInt(Var1, Var2);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+void UOptiXContext::SetInt3DVector(FString string, FIntVector Var)
+{
+	try
+	{
+		NativeContext[std::string(TCHAR_TO_ANSI(*string))]->setInt(Var.X, Var.Y, Var.Z);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+void UOptiXContext::SetInt3D(FString string, int32 Var1, int32 Var2, int32 Var3)
+{
+	try
+	{
+		NativeContext[std::string(TCHAR_TO_ANSI(*string))]->setInt(Var1, Var2, Var3);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+//void UOptiXContext::SetInt4DVector(FString string, FIntVector4 Var)
+//{
+//	NativeContext[std::string(TCHAR_TO_ANSI(*string))]->setInt(Var.X, Var.Y, Var.Z, Var.W);
+//
+//}
+
+void UOptiXContext::SetInt4D(FString string, int32 Var1, int32 Var2, int32 Var3, int32 Var4)
+{
+	try
+	{
+		NativeContext[std::string(TCHAR_TO_ANSI(*string))]->setInt(Var1, Var2, Var3, Var4);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+void UOptiXContext::SetUint(FString string, uint8 Var)
+{
+	try
+	{
+		NativeContext[std::string(TCHAR_TO_ANSI(*string))]->setUint(Var);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+void UOptiXContext::SetUint2D(FString string, uint8 Var1, uint8 Var2)
+{
+	try
+	{
+		NativeContext[std::string(TCHAR_TO_ANSI(*string))]->setUint(Var1, Var2);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+void UOptiXContext::SetUint3D(FString string, uint8 Var1, uint8 Var2, uint8 Var3)
+{
+	try
+	{
+		NativeContext[std::string(TCHAR_TO_ANSI(*string))]->setUint(Var1, Var2, Var3);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+void UOptiXContext::SetUint4D(FString string, uint8 Var1, uint8 Var2, uint8 Var3, uint8 Var4)
+{
+	try
+	{
+		NativeContext[std::string(TCHAR_TO_ANSI(*string))]->setUint(Var1, Var2, Var3, Var4);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+void UOptiXContext::SetMatrix(FString string, FMatrix Matrix)
+{
+	try
+	{
+		// According to the optix doc false == row major
+		NativeContext[std::string(TCHAR_TO_ANSI(*string))]->setMatrix4x4fv(true, &Matrix.M[0][0]); // TODO - find out if false or true is column or row major
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+float UOptiXContext::GetFloat(FString string)
+{
+	float F = 0;
+	try
+	{
+		F = NativeContext[std::string(TCHAR_TO_ANSI(*string))]->getFloat();
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return F;
+}
+
+// TODO: COMPLETE ERROR HANDLING
+
+FVector2D UOptiXContext::GetFloat2D(FString string)
+{
+	optix::float2 V = optix::make_float2(0, 0);
+	try
+	{
+		V = NativeContext[std::string(TCHAR_TO_ANSI(*string))]->getFloat2();
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+
+	return FVector2D(V.x, V.y);
+}
+
+FVector UOptiXContext::GetFloat3D(FString string)
+{
+	optix::float3 V = optix::make_float3(0, 0, 0);;
+	try
+	{
+		V = NativeContext[std::string(TCHAR_TO_ANSI(*string))]->getFloat3();
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return FVector(V.x, V.y, V.z);
+}
+
+FVector4 UOptiXContext::GetFloat4D(FString string)
+{
+	optix::float4 V = optix::make_float4(0, 0, 0, 0);
+	try
+	{
+		V = NativeContext[std::string(TCHAR_TO_ANSI(*string))]->getFloat4();
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return FVector4(V.x, V.y, V.z, V.w);
+}
+
+int32 UOptiXContext::GetInt(FString string)
+{
+	int32 Result = 0;
+	try
+	{
+		Result = NativeContext[std::string(TCHAR_TO_ANSI(*string))]->getInt();
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return Result;
+}
+
+FIntPoint UOptiXContext::GetInt2D(FString string)
+{
+	optix::int2 V = optix::make_int2(0, 0);
+	try
+	{
+		V = NativeContext[std::string(TCHAR_TO_ANSI(*string))]->getInt2();
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return FIntPoint(V.x, V.y);
+}
+
+FIntVector UOptiXContext::GetInt3D(FString string)
+{
+	optix::int3 V = optix::make_int3(0, 0, 0);
+	try
+	{
+		V = NativeContext[std::string(TCHAR_TO_ANSI(*string))]->getInt3();
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return FIntVector(V.x, V.y, V.z);
+}
+
+
+void UOptiXContext::Validate()
+{
+	try
+	{
+		NativeContext->validate();
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+uint32 UOptiXContext::GetDeviceCount()
+{
+	uint32 DeviceCount = 0;
+	try
+	{
+		DeviceCount = NativeContext->getDeviceCount();
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return DeviceCount;
+}
+
+FString UOptiXContext::GetDeviceName(int32 Ordinal)
+{
+	FString DeviceName = "";
+	try
+	{
+		DeviceName = FString(NativeContext->getDeviceName(Ordinal).c_str());
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return DeviceName;
+}
+
+void UOptiXContext::SetStackSize(int32 StackSize)
+{
+	if (StackSize < 0)
+	{
+		FString Message = "Trying to set negative stack size!";
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		return; // TODO Throw error
+	}
+	try
+	{
+		NativeContext->setStackSize(static_cast<uint32>(StackSize));
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+int32 UOptiXContext::GetStackSize()
+{
+	// Casting a uint32 into an int32 is a bit dangerous here...
+	// TODO Check precision
+	int32 Size = 0;
+	try
+	{
+		Size = static_cast<int32>(NativeContext->getStackSize());
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return Size;
+}
+
+void UOptiXContext::SetStackSize64(uint64 StackSize)
+{
+	try
+	{
+		NativeContext->setStackSize(StackSize);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+uint64 UOptiXContext::GetStackSize64()
+{
+	uint64 Size = 0;
+	try
+	{
+		Size = NativeContext->getStackSize();
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return Size;
+}
+
+void UOptiXContext::SetEntryPointCount(int32 NumEntryPoints)
+{
+	int32 Diff = NumEntryPoints - GetEntryPointCount();
+	if (Diff > 0)
+	{
+		RayGenerationPrograms.SetNum(NumEntryPoints);
+		ExceptionPrograms.SetNum(NumEntryPoints);
+	}
+	// TODO delete if diff < 0
+	else
+	{
+		for (int32 i = NumEntryPoints; i < GetEntryPointCount(); i++)
+		{
+			RayGenerationPrograms.RemoveAt(i);
+			ExceptionPrograms.RemoveAt(i);
+		}
+		RayGenerationPrograms.SetNum(NumEntryPoints);
+		ExceptionPrograms.SetNum(NumEntryPoints);
+
+		FString Message = FString("Shrinking Entry Point Count!");
+		UE_LOG(OptiXPluginContext, Warning, TEXT("Error: %s"), *Message);
+	}
+	try
+	{
+		NativeContext->setEntryPointCount(static_cast<uint32>(NumEntryPoints));
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+int32 UOptiXContext::GetEntryPointCount()
+{
+	int32 EntryPointCount = 0;
+	try
+	{
+		EntryPointCount = static_cast<int32>(NativeContext->getEntryPointCount());
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return EntryPointCount;
+}
+
+
+void UOptiXContext::SetRayGenerationProgram(int32 EntryPointIndex, UOptiXProgram* Program)
+{
+	if (!RayGenerationPrograms.IsValidIndex(EntryPointIndex))
+	{
+		UE_LOG(LogTemp, Error, TEXT("OptiXContext: Trying to insert program in non-existing place! \n"));
+		return;
+	}
+	try
+	{
+		NativeContext->setRayGenerationProgram(EntryPointIndex, Program->GetNativeProgram());
+		RayGenerationPrograms.Insert(Program, EntryPointIndex);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+
+}
+
+UOptiXProgram* UOptiXContext::GetRayGenerationProgram(int32 EntryPointIndex)
+{
+	UOptiXProgram* Program = nullptr;
+	if (!RayGenerationPrograms.IsValidIndex(EntryPointIndex))
+	{
+		UE_LOG(LogTemp, Error, TEXT("OptiXContext: Trying to get ray generation program from non-existing place! \n"));
+	}
+	try
+	{
+		NativeContext->getRayGenerationProgram(EntryPointIndex);
+		Program = RayGenerationPrograms[EntryPointIndex];
+		// Todo: this could use some sweet little love
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return Program;
+}
+
+void UOptiXContext::SetExceptionProgram(int32 EntryPointIndex, UOptiXProgram* Program)
+{
+	if (!ExceptionPrograms.IsValidIndex(EntryPointIndex))
+	{
+		UE_LOG(LogTemp, Error, TEXT("OptiXContext: Trying to insert program in non-existing place! \n"));
+		return;
+	}
+	try
+	{
+		NativeContext->setExceptionProgram(EntryPointIndex, Program->GetNativeProgram());
+		ExceptionPrograms.Insert(Program, EntryPointIndex);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+
+}
+
+UOptiXProgram* UOptiXContext::GetExceptionProgram(int32 EntryPointIndex)
+{
+	UOptiXProgram* Program = nullptr;
+	if (!ExceptionPrograms.IsValidIndex(EntryPointIndex))
+	{
+		UE_LOG(LogTemp, Error, TEXT("OptiXContext: Trying to get ray exception program from non-existing place! \n"));
+	}
+	try
+	{
+		NativeContext->getExceptionProgram(EntryPointIndex);
+		Program = ExceptionPrograms[EntryPointIndex];
+		// Todo: this could use some sweet little love
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return Program;
+}
+
+void UOptiXContext::SetExceptionEnabled(RTexception Exception, bool Enabled)
+{
+	try
+	{
+		NativeContext->setExceptionEnabled(Exception, Enabled);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+bool UOptiXContext::GetExceptionEnabled(RTexception Exception)
+{
+	bool V = false; // TODO Look at all those shitty default values
+	try
+	{
+		V = NativeContext->getExceptionEnabled(Exception);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return V;
+}
+
+// Uh oh
+
+void UOptiXContext::SetRayTypeCount(int32 NumRayTypes)
+{
+	int32 Diff = NumRayTypes - GetRayTypeCount();
+	if (Diff > 0)
+	{
+		MissPrograms.SetNum(NumRayTypes);
+	}
+	// TODO delete if diff < 0
+	try
+	{
+		NativeContext->setRayTypeCount(static_cast<uint32>(NumRayTypes));
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+int32 UOptiXContext::GetRayTypeCount()
+{
+	// TODO CAST
+	int32 RTC = 0; static_cast<int32>(NativeContext->getRayTypeCount());
+	try
+	{
+		RTC = static_cast<int32>(NativeContext->getRayTypeCount());
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return RTC;
+}
+
+
+void UOptiXContext::SetMissProgram(int32 RayTypeIndex, UOptiXProgram* Program)
+{
+	if (!MissPrograms.IsValidIndex(RayTypeIndex))
+	{
+		UE_LOG(LogTemp, Error, TEXT("UOptiXContext: Trying to insert program in non-existing place! \n"));
+		return;
+	}
+	try
+	{
+		NativeContext->setMissProgram(RayTypeIndex, Program->GetNativeProgram());
+		MissPrograms.Insert(Program, RayTypeIndex);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+UOptiXProgram* UOptiXContext::GetMissProgram(int32 RayTypeIndex)
+{
+	UOptiXProgram* Program = nullptr;
+	if (!MissPrograms.IsValidIndex(RayTypeIndex))
+	{
+		UE_LOG(LogTemp, Error, TEXT("OptiXContext: Trying to get ray miss program from non-existing place! \n"));
+	}
+	try
+	{
+		NativeContext->getMissProgram(RayTypeIndex);
+		Program = MissPrograms[RayTypeIndex];
+		// Todo: this could use some sweet little love
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return Program;
+}
+
+void UOptiXContext::Launch(int32 EntryPointIndex, uint64 ImageWidth)
+{
+	TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("UOptiXContext::Launch1D"))
+
+	try
+	{
+		NativeContext->launch(EntryPointIndex, ImageWidth);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+void UOptiXContext::Launch(int32 EntryPointIndex, uint64 ImageWidth, uint64 ImageHeight)
+{
+	//UE_LOG(OptiXPluginContext, Warning, TEXT("Child count: %i"), GeometryGroupMap["top_object"]->GetChildCount());
+	TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("UOptiXContext::Launch2D"))
+
+	try
+	{
+		NativeContext->launch(EntryPointIndex, ImageWidth, ImageHeight);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+void UOptiXContext::Launch(int32 EntryPointIndex, uint64 ImageWidth, uint64 ImageHeight, uint64 ImageDepth)
+{
+	TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("UOptiXContext::Launch3D"))
+
+	try
+	{
+		NativeContext->launch(EntryPointIndex, ImageWidth, ImageHeight, ImageDepth);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+void UOptiXContext::SetBuffer(FString Name, UOptiXBuffer * Buffer)
+{
+	try
+	{
+		std::string N = std::string(TCHAR_TO_ANSI(*Name));
+		NativeContext[N]->set(Buffer->GetNativeBuffer());
+		Buffer->Name = Name;
+		BufferMap.Add(Name, Buffer);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+void UOptiXContext::SetGeometryGroup(FString Name, UOptiXGeometryGroup * GeoGroup)
+{
+	try
+	{
+		std::string N = std::string(TCHAR_TO_ANSI(*Name));
+		NativeContext[N]->set(GeoGroup->GetNativeGroup());
+		GeometryGroupMap.Add(Name, GeoGroup);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+void UOptiXContext::SetGroup(FString Name, UOptiXGroup * Group)
+{
+	try
+	{
+		std::string N = std::string(TCHAR_TO_ANSI(*Name));
+		NativeContext[N]->set(Group->GetNativeGroup());
+		GroupMap.Add(Name, Group);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+UOptiXProgram * UOptiXContext::CreateProgramFromPTXFile(FString Path, FString Name)
+{
+	UOptiXProgram* ProgramPtr = nullptr;
+	try
+	{
+		ProgramPtr = NewObject<UOptiXProgram>(this, UOptiXProgram::StaticClass());
+		std::string P = std::string(TCHAR_TO_ANSI(*Path));
+		std::string N = std::string(TCHAR_TO_ANSI(*Name));
+		optix::Program Prog = NativeContext->createProgramFromPTXFile(P, N);
+		ProgramPtr->SetProgram(Prog);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return ProgramPtr;
+}
+
+UOptiXBuffer * UOptiXContext::CreateBuffer(uint8 Type, RTformat Format, RTsize Width)
+{
+	UOptiXBuffer* BufferPtr = nullptr;
+	try
+	{
+		BufferPtr = NewObject<UOptiXBuffer>(this, UOptiXBuffer::StaticClass());
+		BufferPtr->SetBuffer(NativeContext->createBuffer(Type, Format, Width));
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return BufferPtr;
+}
+
+UOptiXBuffer * UOptiXContext::CreateBuffer(uint8 Type, RTformat Format, RTsize Width, RTsize Height)
+{
+	UOptiXBuffer* BufferPtr = nullptr;
+	try
+	{
+		BufferPtr = NewObject<UOptiXBuffer>(this, UOptiXBuffer::StaticClass());
+		BufferPtr->SetBuffer(NativeContext->createBuffer(Type, Format, Width, Height));
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return BufferPtr;
+}
+
+UOptiXBuffer * UOptiXContext::CreateBuffer(uint8 Type, RTformat Format, RTsize Width, RTsize Height, RTsize Depth)
+{
+	UOptiXBuffer* BufferPtr = nullptr;
+	try
+	{
+		BufferPtr = NewObject<UOptiXBuffer>(this, UOptiXBuffer::StaticClass());
+		BufferPtr->SetBuffer(NativeContext->createBuffer(Type, Format, Width, Height, Depth));
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return BufferPtr;
+}
+
+UOptiXBuffer * UOptiXContext::CreateBufferSimple(uint8 Type)
+{
+	UOptiXBuffer* BufferPtr = nullptr;
+	try
+	{
+		BufferPtr = NewObject<UOptiXBuffer>(this, UOptiXBuffer::StaticClass());
+		BufferPtr->SetBuffer(NativeContext->createBuffer(Type));
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return BufferPtr;
+}
+
+UOptiXBuffer * UOptiXContext::CreateBufferUByte(uint8 Type)
+{
+	UOptiXBuffer* BufferPtr = nullptr;
+	try
+	{
+		BufferPtr = NewObject<UOptiXBuffer>(this, UOptiXBuffer::StaticClass());
+		BufferPtr->SetBuffer(NativeContext->createBuffer(Type, RT_FORMAT_UNSIGNED_BYTE4));
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return BufferPtr;
+}
+
+UOptiXBuffer * UOptiXContext::CreateBufferUByte1D(uint8 Type, int32 Width)
+{
+	UOptiXBuffer* BufferPtr = nullptr;
+	try
+	{
+		BufferPtr = NewObject<UOptiXBuffer>(this, UOptiXBuffer::StaticClass());
+		BufferPtr->SetBuffer(NativeContext->createBuffer(Type, RT_FORMAT_UNSIGNED_BYTE4, Width));
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return BufferPtr;
+}
+
+UOptiXBuffer * UOptiXContext::CreateBufferUByte2D(uint8 Type, int32 Width, int32 Height)
+{
+	UOptiXBuffer* BufferPtr = nullptr;
+	try
+	{
+		BufferPtr = NewObject<UOptiXBuffer>(this, UOptiXBuffer::StaticClass());
+		BufferPtr->SetBuffer(NativeContext->createBuffer(Type, RT_FORMAT_UNSIGNED_BYTE4, Width, Height));
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return BufferPtr;
+}
+
+UOptiXBuffer * UOptiXContext::CreateBufferUByte3D(uint8 Type, int32 Width, int32 Height, int32 Depth)
+{
+	UOptiXBuffer* BufferPtr = nullptr;
+	try
+	{
+		BufferPtr = NewObject<UOptiXBuffer>(this, UOptiXBuffer::StaticClass());
+		BufferPtr->SetBuffer(NativeContext->createBuffer(Type, RT_FORMAT_UNSIGNED_BYTE4, Width, Height, Depth));
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return BufferPtr;
+}
+
+UOptiXBuffer * UOptiXContext::CreateOutputBufferIntersections(int32 Width, int32 Height)
+{
+	UOptiXBuffer* BufferPtr = nullptr;
+	try
+	{
+		BufferPtr = NewObject<UOptiXBuffer>(this, UOptiXBuffer::StaticClass());
+		BufferPtr->SetBuffer(NativeContext->createBufferForCUDA(RT_BUFFER_INPUT_OUTPUT | RT_BUFFER_GPU_LOCAL, RT_FORMAT_FLOAT4, Width, Height));
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return BufferPtr;
+}
+
+
+UOptiXBuffer * UOptiXContext::CreateOutputBufferColor(int32 Width, int32 Height)
+{
+	UOptiXBuffer* BufferPtr = nullptr;
+	try
+	{
+		BufferPtr = NewObject<UOptiXBuffer>(this, UOptiXBuffer::StaticClass());
+		BufferPtr->SetBuffer(NativeContext->createBufferForCUDA(RT_BUFFER_INPUT_OUTPUT | RT_BUFFER_GPU_LOCAL, RT_FORMAT_FLOAT4, Width, Height));
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return BufferPtr;
+}
+
+UOptiXBuffer * UOptiXContext::CreateOutputBufferUByte3D(int32 Width, int32 Height, int32 Depth)
+{
+	UOptiXBuffer* BufferPtr = nullptr;
+	try
+	{
+		BufferPtr = NewObject<UOptiXBuffer>(this, UOptiXBuffer::StaticClass());
+		BufferPtr->SetBuffer(NativeContext->createBuffer(RT_BUFFER_OUTPUT, RT_FORMAT_UNSIGNED_BYTE4, Width, Height, Depth));
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return BufferPtr;
+}
+
+UOptiXBuffer* UOptiXContext::CreateOutputBufferDepth(int32 Width, int32 Height)
+{
+	UOptiXBuffer* BufferPtr = nullptr;
+	try
+	{
+		BufferPtr = NewObject<UOptiXBuffer>(this, UOptiXBuffer::StaticClass());
+		//BufferPtr->SetBuffer(NativeContext->createBuffer(RT_BUFFER_INPUT_OUTPUT | RT_BUFFER_GPU_LOCAL, RT_FORMAT_FLOAT, Width, Height));
+		BufferPtr->SetBuffer(NativeContext->createBufferForCUDA(RT_BUFFER_INPUT_OUTPUT | RT_BUFFER_GPU_LOCAL, RT_FORMAT_FLOAT, Width, Height));
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return BufferPtr;
+}
+
+UOptiXBuffer * UOptiXContext::CreateInputBufferFloat(int32 Width)
+{
+	UOptiXBuffer* BufferPtr = nullptr;
+	try
+	{
+		BufferPtr = NewObject<UOptiXBuffer>(this, UOptiXBuffer::StaticClass());
+		BufferPtr->SetBuffer(NativeContext->createBuffer(RT_BUFFER_INPUT, RT_FORMAT_FLOAT, Width));
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return BufferPtr;
+}
+
+UOptiXBuffer * UOptiXContext::CreateInputBufferFloat2D(int32 Width, int32 Height)
+{
+	UOptiXBuffer* BufferPtr = nullptr;
+	try
+	{
+		BufferPtr = NewObject<UOptiXBuffer>(this, UOptiXBuffer::StaticClass());
+		BufferPtr->SetBuffer(NativeContext->createBuffer(RT_BUFFER_INPUT, RT_FORMAT_FLOAT, Width, Height));
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return BufferPtr;
+}
+
+UOptiXBuffer * UOptiXContext::CreateInputBufferFloat3D(int32 Width, int32 Height, int32 Depth)
+{
+	UOptiXBuffer* BufferPtr = nullptr;
+	try
+	{
+		BufferPtr = NewObject<UOptiXBuffer>(this, UOptiXBuffer::StaticClass());
+		BufferPtr->SetBuffer(NativeContext->createBuffer(RT_BUFFER_INPUT, RT_FORMAT_FLOAT, Width, Height, Depth));
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return BufferPtr;
+}
+
+UOptiXBuffer * UOptiXContext::CreateCubemapBuffer(int32 Width, int32 Height)
+{
+	UOptiXBuffer* BufferPtr = nullptr;
+	try
+	{
+		// https://github.com/nvpro-samples/optix_advanced_samples/blob/master/src/optixIntroduction/optixIntro_07/src/Texture.cpp
+		BufferPtr = NewObject<UOptiXBuffer>(this, UOptiXBuffer::StaticClass());
+		BufferPtr->SetBuffer(NativeContext->createBuffer(RT_BUFFER_INPUT | RT_BUFFER_CUBEMAP, RT_FORMAT_UNSIGNED_BYTE4, Width, Height, 6)); // 6 slices
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return BufferPtr;
+}
+
+void UOptiXContext::SetMaxTraceDepth(int32 Depth)
+{
+	try
+	{
+		NativeContext->setMaxTraceDepth(static_cast<unsigned int>(Depth));
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+int32 UOptiXContext::GetMaxTraceDepth()
+{
+	int32 Depth = 0;
+	try
+	{
+		Depth = static_cast<int32>(NativeContext->getMaxTraceDepth()); // Loss of precision but won't happen ever anyway
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return Depth;
+}
+
+void UOptiXContext::SetFloat3DVectorThreadsafe(FString string, FVector Var)
+{
+	VectorCache.Add(string, Var);
+}
+
+void UOptiXContext::SetMatrixThreadsafe(FString string, FMatrix Matrix)
+{
+	MatrixCache.Add(string, Matrix);
+}
+
+UOptiXTextureSampler * UOptiXContext::CreateTextureSampler()
+{
+	UOptiXTextureSampler* SamplerPtr = nullptr;
+	try
+	{
+		SamplerPtr = NewObject<UOptiXTextureSampler>(this, UOptiXTextureSampler::StaticClass());
+		SamplerPtr->SetTextureSampler(NativeContext->createTextureSampler());
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return SamplerPtr;
+}
+
+void UOptiXContext::SetTextureSampler(FString Name, UOptiXTextureSampler * Sampler)
+{
+	try
+	{
+		std::string N = std::string(TCHAR_TO_ANSI(*Name));
+		NativeContext[N]->set(Sampler->GetNativeTextureSampler());
+		TextureSamplerMap.Add(Name, Sampler);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+void UOptiXContext::SetSkybox(FString Name, UOptiXTextureSampler * Sampler)
+{
+	SetInt(Name, Sampler->GetId());
+	TextureSamplerMap.Add(Name, Sampler);
+}
+
+UOptiXBuffer * UOptiXContext::GetBuffer(FString Name)
+{
+	if (BufferMap.Contains(Name))
+	{
+		return BufferMap[Name];
+	}
+	else
+	{
+		FString Message = "Buffer doesn't exist!";
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+		return nullptr;
+	}
+}
+
+UOptiXGeometryGroup * UOptiXContext::GetGeometryGroup(FString Name)
+{
+	if (GeometryGroupMap.Contains(Name))
+	{
+		// Todo - check if that's actually the correct one! (GetNative etc)
+		return GeometryGroupMap[Name];
+	}
+	else
+	{
+		FString Message = "Geometry Group doesn't exist!";
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+		return nullptr;
+	}
+}
+
+UOptiXGroup * UOptiXContext::GetGroup(FString Name)
+{
+	if (GroupMap.Contains(Name))
+	{
+		// Todo - check if that's actually the correct one! (GetNative etc)
+		return GroupMap[Name];
+	}
+	else
+	{
+		FString Message = "Group doesn't exist!";
+		UE_LOG(OptiXPluginContext, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+		return nullptr;
+	}
+}
+
+// Copy Paste too strong, could have shortened that quite a bit 
diff --git a/Source/OptiX/Private/OptiXGeometry.cpp b/Deprecated/Private/OptiXGeometry.cpp
similarity index 96%
rename from Source/OptiX/Private/OptiXGeometry.cpp
rename to Deprecated/Private/OptiXGeometry.cpp
index bd9e0b259308d41c192066d85672290f0fd753d3..89178593396d3d47dfe6e895c2bfa4a91f30e866 100644
--- a/Source/OptiX/Private/OptiXGeometry.cpp
+++ b/Deprecated/Private/OptiXGeometry.cpp
@@ -1,598 +1,598 @@
-#include "OptiXGeometry.h"
-
-#include "CoreMinimal.h"
-#include "UObject/ObjectMacros.h"
-#include "Engine/EngineTypes.h"
-
-#include "OptiXGeometry.h"
-#include "OptiXModule.h"
-
-// Needed for debugging
-#include <EngineGlobals.h>
-#include <Runtime/Engine/Classes/Engine/Engine.h>
-
-DEFINE_LOG_CATEGORY(OptiXPluginGeometry);
-
-void UOptiXGeometry::BeginDestroy()
-{
-	// Tell optix to clean up
-	UE_LOG(LogTemp, Display, TEXT("OptiX Geometry BeginDestroy"));
-	// Remove all the children:
-	DestroyOptiXObject();
-	Super::BeginDestroy();
-}
-
-void UOptiXGeometry::DestroyOptiXObject()
-{
-	if (NativeGeometry != NULL)
-	{
-		//NativeGeometry->destroy();
-		FOptiXModule::Get().GetOptiXContextManager()->GeometriesToDeleteQueue.Enqueue(NativeGeometry);
-
-	}
-
-	BufferMap.Empty();
-	IntersectionProgram = nullptr;
-	BoundingBoxProgram = nullptr;
-	NativeGeometry = NULL;
-}
-
-void UOptiXGeometry::SetFloat(FString string, float Var)
-{
-	try
-	{
-		NativeGeometry[std::string(TCHAR_TO_ANSI(*string))]->setFloat(Var);
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginGeometry, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-}
-
-void UOptiXGeometry::SetFloat2D(FString string, float Var1, float Var2)
-{
-	try
-	{
-		NativeGeometry[std::string(TCHAR_TO_ANSI(*string))]->setFloat(Var1, Var2);
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginGeometry, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-}
-
-void UOptiXGeometry::SetFloat3DVector(FString string, FVector Var)
-{
-	try
-	{
-		NativeGeometry[std::string(TCHAR_TO_ANSI(*string))]->setFloat(Var.X, Var.Y, Var.Z);
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginGeometry, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-}
-
-void UOptiXGeometry::SetFloat3D(FString string, float Var1, float Var2, float Var3)
-{
-	try
-	{
-		NativeGeometry[std::string(TCHAR_TO_ANSI(*string))]->setFloat(Var1, Var2, Var3);
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginGeometry, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-}
-
-void UOptiXGeometry::SetFloat4DVector(FString string, FVector4 Var)
-{
-	try
-	{
-		NativeGeometry[std::string(TCHAR_TO_ANSI(*string))]->setFloat(Var.X, Var.Y, Var.Z, Var.W);
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginGeometry, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-}
-
-void UOptiXGeometry::SetFloat4D(FString string, float Var1, float Var2, float Var3, float Var4)
-{
-	try
-	{
-		NativeGeometry[std::string(TCHAR_TO_ANSI(*string))]->setFloat(Var1, Var2, Var3, Var4);
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginGeometry, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-}
-
-void UOptiXGeometry::SetInt(FString string, int32 Var)
-{
-	try
-	{
-		NativeGeometry[std::string(TCHAR_TO_ANSI(*string))]->setInt(Var);
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginGeometry, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-}
-
-void UOptiXGeometry::SetInt2D(FString string, int32 Var1, int32 Var2)
-{
-	try
-	{
-		NativeGeometry[std::string(TCHAR_TO_ANSI(*string))]->setInt(Var1, Var2);
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginGeometry, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-}
-
-void UOptiXGeometry::SetInt3DVector(FString string, FIntVector Var)
-{
-	try
-	{
-		NativeGeometry[std::string(TCHAR_TO_ANSI(*string))]->setInt(Var.X, Var.Y, Var.Z);
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginGeometry, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-}
-
-void UOptiXGeometry::SetInt3D(FString string, int32 Var1, int32 Var2, int32 Var3)
-{
-	try
-	{
-		NativeGeometry[std::string(TCHAR_TO_ANSI(*string))]->setInt(Var1, Var2, Var3);
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginGeometry, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-}
-
-//void UOptiXGeometry::SetInt4DVector(FString string, FIntVector4 Var)
-//{
-//	NativeGeometry[std::string(TCHAR_TO_ANSI(*string))]->setInt(Var.X, Var.Y, Var.Z, Var.W);
-//
-//}
-
-void UOptiXGeometry::SetInt4D(FString string, int32 Var1, int32 Var2, int32 Var3, int32 Var4)
-{
-	try
-	{
-		NativeGeometry[std::string(TCHAR_TO_ANSI(*string))]->setInt(Var1, Var2, Var3, Var4);
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginGeometry, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-}
-
-void UOptiXGeometry::SetUint(FString string, uint8 Var)
-{
-	try
-	{
-		NativeGeometry[std::string(TCHAR_TO_ANSI(*string))]->setUint(Var);
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginGeometry, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-}
-
-void UOptiXGeometry::SetUint2D(FString string, uint8 Var1, uint8 Var2)
-{
-	try
-	{
-		NativeGeometry[std::string(TCHAR_TO_ANSI(*string))]->setUint(Var1, Var2);
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginGeometry, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-}
-
-void UOptiXGeometry::SetUint3D(FString string, uint8 Var1, uint8 Var2, uint8 Var3)
-{
-	try
-	{
-		NativeGeometry[std::string(TCHAR_TO_ANSI(*string))]->setUint(Var1, Var2, Var3);
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginGeometry, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-}
-
-void UOptiXGeometry::SetUint4D(FString string, uint8 Var1, uint8 Var2, uint8 Var3, uint8 Var4)
-{
-	try
-	{
-		NativeGeometry[std::string(TCHAR_TO_ANSI(*string))]->setUint(Var1, Var2, Var3, Var4);
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginGeometry, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-}
-
-// Todo: try-catch stuff for getters. Pretty low prio all in all
-
-float UOptiXGeometry::GetFloat(FString string)
-{
-	return NativeGeometry[std::string(TCHAR_TO_ANSI(*string))]->getFloat();
-}
-
-FVector2D UOptiXGeometry::GetFloat2D(FString string)
-{
-	optix::float2 V = NativeGeometry[std::string(TCHAR_TO_ANSI(*string))]->getFloat2();
-	return FVector2D(V.x, V.y);
-}
-
-FVector UOptiXGeometry::GetFloat3D(FString string)
-{
-	optix::float3 V = NativeGeometry[std::string(TCHAR_TO_ANSI(*string))]->getFloat3();
-	return FVector(V.x, V.y, V.z);
-}
-
-FVector4 UOptiXGeometry::GetFloat4D(FString string)
-{
-	optix::float4 V = NativeGeometry[std::string(TCHAR_TO_ANSI(*string))]->getFloat4();
-	return FVector4(V.x, V.y, V.z, V.w);
-}
-
-int32 UOptiXGeometry::GetInt(FString string)
-{
-	return NativeGeometry[std::string(TCHAR_TO_ANSI(*string))]->getInt();
-}
-
-FIntPoint UOptiXGeometry::GetInt2D(FString string)
-{
-	optix::int2 V = NativeGeometry[std::string(TCHAR_TO_ANSI(*string))]->getInt2();
-	return FIntPoint(V.x, V.y);
-}
-
-FIntVector UOptiXGeometry::GetInt3D(FString string)
-{
-	optix::int3 V = NativeGeometry[std::string(TCHAR_TO_ANSI(*string))]->getInt3();
-	return FIntVector(V.x, V.y, V.z);
-}
-
-//FIntVector4 UOptiXGeometry::GetInt4D(FString string)
-//{
-//	optix::int4 V = NativeGeometry[std::string(TCHAR_TO_ANSI(*string))]->getInt4();
-//	return FIntVector4(V.x, V.y, V.z, V.w);
-//}
-
-//uint8 UOptiXGeometry::GetUint(FString string)
-//{
-//	return static_cast<uint8>(NativeGeometry[std::string(TCHAR_TO_ANSI(*string))]->getUint());
-//}
-//
-//void UOptiXGeometry::GetUint2D(FString & string, uint8 & Var1, uint8 & Var2)
-//{
-//	NativeGeometry[std::string(TCHAR_TO_ANSI(*string))]->getUint(Var1, Var2);
-//
-//}
-//
-//void UOptiXGeometry::GetUint3D(FString string, uint8 & Var1, uint8 & Var2, uint8 & Var3)
-//{
-//	NativeGeometry[std::string(TCHAR_TO_ANSI(*string))]->getUint(Var1, Var2, Var3);
-//}
-//
-//FUintVector4 UOptiXGeometry::GetUint4D(FString string)
-//{
-//	optix::uint4 V = NativeGeometry[std::string(TCHAR_TO_ANSI(*string))]->getUint4();
-//	return FUintVector4(V.x, V.y, V.z, V.w);
-//}
-
-
-optix::Geometry UOptiXGeometry::GetNativeGeometry()
-{
-	return NativeGeometry;
-}
-
-void UOptiXGeometry::SetPrimitiveCount(int32 NumPrimitives)
-{
-	if (NumPrimitives < 0)
-	{
-		UE_LOG(OptiXPluginGeometry, Error, TEXT("Trying to set negative primitive count in geometry: %s"));
-		return;
-	}
-	try
-	{
-		NativeGeometry->setPrimitiveCount(static_cast<uint32>(NumPrimitives));
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginGeometry, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-}
-
-int32 UOptiXGeometry::GetPrimitiveCount()
-{
-	int32 PrimitiveCount = 0;
-	try
-	{
-		PrimitiveCount = static_cast<int32>(NativeGeometry->getPrimitiveCount());
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginGeometry, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-	return PrimitiveCount;
-}
-
-void UOptiXGeometry::SetPrimitiveIndexOffset(int32 IndexOffsets)
-{
-	if (IndexOffsets < 0)
-	{
-		UE_LOG(OptiXPluginGeometry, Error, TEXT("Trying to set negative primitive index offset in geometry!"));
-		return; // TODO Throw error
-	}
-	try
-	{
-		NativeGeometry->setPrimitiveIndexOffset(static_cast<uint32>(IndexOffsets));
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginGeometry, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-}
-
-int32 UOptiXGeometry::GetPrimitiveIndexOffset()
-{
-	int32 PrimitiveIndexOffset = 0;
-	try
-	{
-		PrimitiveIndexOffset = static_cast<int32>(NativeGeometry->getPrimitiveIndexOffset());
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginGeometry, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-	return PrimitiveIndexOffset;
-}
-
-void UOptiXGeometry::SetPrimitiveCountUint(uint32 NumPrimitives)
-{
-	try
-	{
-		NativeGeometry->setPrimitiveCount(NumPrimitives);
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginGeometry, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-}
-
-uint32 UOptiXGeometry::GetPrimitiveCountUint()
-{
-	uint32 PrimitiveCount = 0;
-	try
-	{
-		PrimitiveCount = NativeGeometry->getPrimitiveCount();
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginGeometry, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-	return PrimitiveCount;
-}
-
-void UOptiXGeometry::SetPrimitiveIndexOffsetUint(uint32 IndexOffsets)
-{
-	try
-	{
-		NativeGeometry->setPrimitiveIndexOffset(IndexOffsets);
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginGeometry, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-}
-
-uint32 UOptiXGeometry::GetPrimitiveIndexOffsetUint()
-{
-	uint32 PrimitiveIndexOffset = 0;
-	try
-	{
-		PrimitiveIndexOffset = NativeGeometry->getPrimitiveIndexOffset();
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginGeometry, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-	return PrimitiveIndexOffset;
-}
-
-void UOptiXGeometry::SetMotionRange(float TimeBegin, float TimeEnd)
-{
-	try
-	{
-		NativeGeometry->setMotionRange(TimeBegin, TimeEnd);
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginGeometry, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-}
-
-// Todo: Add try-catch stuff, but the motion range things are fairly low prio as well for now.
-
-FVector2D UOptiXGeometry::GetMotionRange()
-{
-	float f1, f2;
-	NativeGeometry->getMotionRange(f1, f2);
-	return FVector2D(f1, f2);
-}
-
-void UOptiXGeometry::SetMotionBorderMode(RTmotionbordermode BeginMode, RTmotionbordermode EndMode)
-{
-	NativeGeometry->setMotionBorderMode(BeginMode, EndMode);
-}
-
-void UOptiXGeometry::GetMotionBorderMode(RTmotionbordermode & BeginMode, RTmotionbordermode & EndMode)
-{
-	NativeGeometry->getMotionBorderMode(BeginMode, EndMode);
-}
-
-void UOptiXGeometry::SetMotionSteps(int32 N)
-{
-	if (N < 0)
-	{
-		return; // TODO Throw error
-	}
-	NativeGeometry->setMotionSteps(static_cast<uint32>(N));
-}
-
-int32 UOptiXGeometry::GetMotionSteps()
-{
-	return static_cast<int32>(NativeGeometry->getMotionSteps());
-}
-
-void UOptiXGeometry::SetMotionStepsUint(uint32 N)
-{
-	NativeGeometry->setMotionSteps(N);
-}
-
-uint32 UOptiXGeometry::GetMotionStepsUint()
-{
-	return NativeGeometry->getMotionSteps();
-}
-
-void UOptiXGeometry::SetBoundingBoxProgram(UOptiXProgram* Program)
-{
-	try
-	{
-		BoundingBoxProgram = Program;
-		NativeGeometry->setBoundingBoxProgram(Program->GetNativeProgram());	
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginGeometry, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-}
-
-UOptiXProgram* UOptiXGeometry::GetBoundingBoxProgram()
-{
-	// Done to see if the optix bb prog is actually valid.
-	UOptiXProgram* Prog = nullptr;
-	try
-	{
-		NativeGeometry->getBoundingBoxProgram(); // todo: comparison check
-		Prog = BoundingBoxProgram;
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginGeometry, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-	return Prog;
-}
-
-void UOptiXGeometry::SetIntersectionProgram(UOptiXProgram* Program)
-{
-	try
-	{
-		IntersectionProgram = Program;
-		NativeGeometry->setIntersectionProgram(Program->GetNativeProgram());
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginGeometry, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-}
-
-UOptiXProgram* UOptiXGeometry::GetIntersectionProgram()
-{
-	UOptiXProgram* Prog = nullptr;
-	try
-	{
-		NativeGeometry->getIntersectionProgram(); // todo: comparison check
-		Prog = IntersectionProgram;
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginGeometry, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-	return Prog;
-}
-
-void UOptiXGeometry::SetBuffer(FString Name, UOptiXBuffer* Buffer)
-{
-	try
-	{
-		std::string N = std::string(TCHAR_TO_ANSI(*Name));
-		NativeGeometry[N]->setBuffer(Buffer->GetNativeBuffer());
-		BufferMap.Add(Name, Buffer);
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginGeometry, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-}
+#include "OptiXGeometry.h"
+
+#include "CoreMinimal.h"
+#include "UObject/ObjectMacros.h"
+#include "Engine/EngineTypes.h"
+
+#include "OptiXGeometry.h"
+#include "OptiXModule.h"
+
+// Needed for debugging
+#include <EngineGlobals.h>
+#include <Runtime/Engine/Classes/Engine/Engine.h>
+
+DEFINE_LOG_CATEGORY(OptiXPluginGeometry);
+
+void UOptiXGeometry::BeginDestroy()
+{
+	// Tell optix to clean up
+	UE_LOG(LogTemp, Display, TEXT("OptiX Geometry BeginDestroy"));
+	// Remove all the children:
+	DestroyOptiXObject();
+	Super::BeginDestroy();
+}
+
+void UOptiXGeometry::DestroyOptiXObject()
+{
+	if (NativeGeometry != NULL)
+	{
+		//NativeGeometry->destroy();
+		FOptiXModule::Get().GetOptiXContextManager()->GeometriesToDeleteQueue.Enqueue(NativeGeometry);
+
+	}
+
+	BufferMap.Empty();
+	IntersectionProgram = nullptr;
+	BoundingBoxProgram = nullptr;
+	NativeGeometry = NULL;
+}
+
+void UOptiXGeometry::SetFloat(FString string, float Var)
+{
+	try
+	{
+		NativeGeometry[std::string(TCHAR_TO_ANSI(*string))]->setFloat(Var);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginGeometry, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+void UOptiXGeometry::SetFloat2D(FString string, float Var1, float Var2)
+{
+	try
+	{
+		NativeGeometry[std::string(TCHAR_TO_ANSI(*string))]->setFloat(Var1, Var2);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginGeometry, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+void UOptiXGeometry::SetFloat3DVector(FString string, FVector Var)
+{
+	try
+	{
+		NativeGeometry[std::string(TCHAR_TO_ANSI(*string))]->setFloat(Var.X, Var.Y, Var.Z);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginGeometry, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+void UOptiXGeometry::SetFloat3D(FString string, float Var1, float Var2, float Var3)
+{
+	try
+	{
+		NativeGeometry[std::string(TCHAR_TO_ANSI(*string))]->setFloat(Var1, Var2, Var3);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginGeometry, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+void UOptiXGeometry::SetFloat4DVector(FString string, FVector4 Var)
+{
+	try
+	{
+		NativeGeometry[std::string(TCHAR_TO_ANSI(*string))]->setFloat(Var.X, Var.Y, Var.Z, Var.W);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginGeometry, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+void UOptiXGeometry::SetFloat4D(FString string, float Var1, float Var2, float Var3, float Var4)
+{
+	try
+	{
+		NativeGeometry[std::string(TCHAR_TO_ANSI(*string))]->setFloat(Var1, Var2, Var3, Var4);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginGeometry, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+void UOptiXGeometry::SetInt(FString string, int32 Var)
+{
+	try
+	{
+		NativeGeometry[std::string(TCHAR_TO_ANSI(*string))]->setInt(Var);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginGeometry, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+void UOptiXGeometry::SetInt2D(FString string, int32 Var1, int32 Var2)
+{
+	try
+	{
+		NativeGeometry[std::string(TCHAR_TO_ANSI(*string))]->setInt(Var1, Var2);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginGeometry, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+void UOptiXGeometry::SetInt3DVector(FString string, FIntVector Var)
+{
+	try
+	{
+		NativeGeometry[std::string(TCHAR_TO_ANSI(*string))]->setInt(Var.X, Var.Y, Var.Z);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginGeometry, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+void UOptiXGeometry::SetInt3D(FString string, int32 Var1, int32 Var2, int32 Var3)
+{
+	try
+	{
+		NativeGeometry[std::string(TCHAR_TO_ANSI(*string))]->setInt(Var1, Var2, Var3);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginGeometry, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+//void UOptiXGeometry::SetInt4DVector(FString string, FIntVector4 Var)
+//{
+//	NativeGeometry[std::string(TCHAR_TO_ANSI(*string))]->setInt(Var.X, Var.Y, Var.Z, Var.W);
+//
+//}
+
+void UOptiXGeometry::SetInt4D(FString string, int32 Var1, int32 Var2, int32 Var3, int32 Var4)
+{
+	try
+	{
+		NativeGeometry[std::string(TCHAR_TO_ANSI(*string))]->setInt(Var1, Var2, Var3, Var4);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginGeometry, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+void UOptiXGeometry::SetUint(FString string, uint8 Var)
+{
+	try
+	{
+		NativeGeometry[std::string(TCHAR_TO_ANSI(*string))]->setUint(Var);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginGeometry, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+void UOptiXGeometry::SetUint2D(FString string, uint8 Var1, uint8 Var2)
+{
+	try
+	{
+		NativeGeometry[std::string(TCHAR_TO_ANSI(*string))]->setUint(Var1, Var2);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginGeometry, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+void UOptiXGeometry::SetUint3D(FString string, uint8 Var1, uint8 Var2, uint8 Var3)
+{
+	try
+	{
+		NativeGeometry[std::string(TCHAR_TO_ANSI(*string))]->setUint(Var1, Var2, Var3);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginGeometry, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+void UOptiXGeometry::SetUint4D(FString string, uint8 Var1, uint8 Var2, uint8 Var3, uint8 Var4)
+{
+	try
+	{
+		NativeGeometry[std::string(TCHAR_TO_ANSI(*string))]->setUint(Var1, Var2, Var3, Var4);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginGeometry, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+// Todo: try-catch stuff for getters. Pretty low prio all in all
+
+float UOptiXGeometry::GetFloat(FString string)
+{
+	return NativeGeometry[std::string(TCHAR_TO_ANSI(*string))]->getFloat();
+}
+
+FVector2D UOptiXGeometry::GetFloat2D(FString string)
+{
+	optix::float2 V = NativeGeometry[std::string(TCHAR_TO_ANSI(*string))]->getFloat2();
+	return FVector2D(V.x, V.y);
+}
+
+FVector UOptiXGeometry::GetFloat3D(FString string)
+{
+	optix::float3 V = NativeGeometry[std::string(TCHAR_TO_ANSI(*string))]->getFloat3();
+	return FVector(V.x, V.y, V.z);
+}
+
+FVector4 UOptiXGeometry::GetFloat4D(FString string)
+{
+	optix::float4 V = NativeGeometry[std::string(TCHAR_TO_ANSI(*string))]->getFloat4();
+	return FVector4(V.x, V.y, V.z, V.w);
+}
+
+int32 UOptiXGeometry::GetInt(FString string)
+{
+	return NativeGeometry[std::string(TCHAR_TO_ANSI(*string))]->getInt();
+}
+
+FIntPoint UOptiXGeometry::GetInt2D(FString string)
+{
+	optix::int2 V = NativeGeometry[std::string(TCHAR_TO_ANSI(*string))]->getInt2();
+	return FIntPoint(V.x, V.y);
+}
+
+FIntVector UOptiXGeometry::GetInt3D(FString string)
+{
+	optix::int3 V = NativeGeometry[std::string(TCHAR_TO_ANSI(*string))]->getInt3();
+	return FIntVector(V.x, V.y, V.z);
+}
+
+//FIntVector4 UOptiXGeometry::GetInt4D(FString string)
+//{
+//	optix::int4 V = NativeGeometry[std::string(TCHAR_TO_ANSI(*string))]->getInt4();
+//	return FIntVector4(V.x, V.y, V.z, V.w);
+//}
+
+//uint8 UOptiXGeometry::GetUint(FString string)
+//{
+//	return static_cast<uint8>(NativeGeometry[std::string(TCHAR_TO_ANSI(*string))]->getUint());
+//}
+//
+//void UOptiXGeometry::GetUint2D(FString & string, uint8 & Var1, uint8 & Var2)
+//{
+//	NativeGeometry[std::string(TCHAR_TO_ANSI(*string))]->getUint(Var1, Var2);
+//
+//}
+//
+//void UOptiXGeometry::GetUint3D(FString string, uint8 & Var1, uint8 & Var2, uint8 & Var3)
+//{
+//	NativeGeometry[std::string(TCHAR_TO_ANSI(*string))]->getUint(Var1, Var2, Var3);
+//}
+//
+//FUintVector4 UOptiXGeometry::GetUint4D(FString string)
+//{
+//	optix::uint4 V = NativeGeometry[std::string(TCHAR_TO_ANSI(*string))]->getUint4();
+//	return FUintVector4(V.x, V.y, V.z, V.w);
+//}
+
+
+optix::Geometry UOptiXGeometry::GetNativeGeometry()
+{
+	return NativeGeometry;
+}
+
+void UOptiXGeometry::SetPrimitiveCount(int32 NumPrimitives)
+{
+	if (NumPrimitives < 0)
+	{
+		UE_LOG(OptiXPluginGeometry, Error, TEXT("Trying to set negative primitive count in geometry: %s"));
+		return;
+	}
+	try
+	{
+		NativeGeometry->setPrimitiveCount(static_cast<uint32>(NumPrimitives));
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginGeometry, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+int32 UOptiXGeometry::GetPrimitiveCount()
+{
+	int32 PrimitiveCount = 0;
+	try
+	{
+		PrimitiveCount = static_cast<int32>(NativeGeometry->getPrimitiveCount());
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginGeometry, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return PrimitiveCount;
+}
+
+void UOptiXGeometry::SetPrimitiveIndexOffset(int32 IndexOffsets)
+{
+	if (IndexOffsets < 0)
+	{
+		UE_LOG(OptiXPluginGeometry, Error, TEXT("Trying to set negative primitive index offset in geometry!"));
+		return; // TODO Throw error
+	}
+	try
+	{
+		NativeGeometry->setPrimitiveIndexOffset(static_cast<uint32>(IndexOffsets));
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginGeometry, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+int32 UOptiXGeometry::GetPrimitiveIndexOffset()
+{
+	int32 PrimitiveIndexOffset = 0;
+	try
+	{
+		PrimitiveIndexOffset = static_cast<int32>(NativeGeometry->getPrimitiveIndexOffset());
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginGeometry, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return PrimitiveIndexOffset;
+}
+
+void UOptiXGeometry::SetPrimitiveCountUint(uint32 NumPrimitives)
+{
+	try
+	{
+		NativeGeometry->setPrimitiveCount(NumPrimitives);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginGeometry, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+uint32 UOptiXGeometry::GetPrimitiveCountUint()
+{
+	uint32 PrimitiveCount = 0;
+	try
+	{
+		PrimitiveCount = NativeGeometry->getPrimitiveCount();
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginGeometry, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return PrimitiveCount;
+}
+
+void UOptiXGeometry::SetPrimitiveIndexOffsetUint(uint32 IndexOffsets)
+{
+	try
+	{
+		NativeGeometry->setPrimitiveIndexOffset(IndexOffsets);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginGeometry, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+uint32 UOptiXGeometry::GetPrimitiveIndexOffsetUint()
+{
+	uint32 PrimitiveIndexOffset = 0;
+	try
+	{
+		PrimitiveIndexOffset = NativeGeometry->getPrimitiveIndexOffset();
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginGeometry, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return PrimitiveIndexOffset;
+}
+
+void UOptiXGeometry::SetMotionRange(float TimeBegin, float TimeEnd)
+{
+	try
+	{
+		NativeGeometry->setMotionRange(TimeBegin, TimeEnd);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginGeometry, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+// Todo: Add try-catch stuff, but the motion range things are fairly low prio as well for now.
+
+FVector2D UOptiXGeometry::GetMotionRange()
+{
+	float f1, f2;
+	NativeGeometry->getMotionRange(f1, f2);
+	return FVector2D(f1, f2);
+}
+
+void UOptiXGeometry::SetMotionBorderMode(RTmotionbordermode BeginMode, RTmotionbordermode EndMode)
+{
+	NativeGeometry->setMotionBorderMode(BeginMode, EndMode);
+}
+
+void UOptiXGeometry::GetMotionBorderMode(RTmotionbordermode & BeginMode, RTmotionbordermode & EndMode)
+{
+	NativeGeometry->getMotionBorderMode(BeginMode, EndMode);
+}
+
+void UOptiXGeometry::SetMotionSteps(int32 N)
+{
+	if (N < 0)
+	{
+		return; // TODO Throw error
+	}
+	NativeGeometry->setMotionSteps(static_cast<uint32>(N));
+}
+
+int32 UOptiXGeometry::GetMotionSteps()
+{
+	return static_cast<int32>(NativeGeometry->getMotionSteps());
+}
+
+void UOptiXGeometry::SetMotionStepsUint(uint32 N)
+{
+	NativeGeometry->setMotionSteps(N);
+}
+
+uint32 UOptiXGeometry::GetMotionStepsUint()
+{
+	return NativeGeometry->getMotionSteps();
+}
+
+void UOptiXGeometry::SetBoundingBoxProgram(UOptiXProgram* Program)
+{
+	try
+	{
+		BoundingBoxProgram = Program;
+		NativeGeometry->setBoundingBoxProgram(Program->GetNativeProgram());	
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginGeometry, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+UOptiXProgram* UOptiXGeometry::GetBoundingBoxProgram()
+{
+	// Done to see if the optix bb prog is actually valid.
+	UOptiXProgram* Prog = nullptr;
+	try
+	{
+		NativeGeometry->getBoundingBoxProgram(); // todo: comparison check
+		Prog = BoundingBoxProgram;
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginGeometry, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return Prog;
+}
+
+void UOptiXGeometry::SetIntersectionProgram(UOptiXProgram* Program)
+{
+	try
+	{
+		IntersectionProgram = Program;
+		NativeGeometry->setIntersectionProgram(Program->GetNativeProgram());
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginGeometry, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+UOptiXProgram* UOptiXGeometry::GetIntersectionProgram()
+{
+	UOptiXProgram* Prog = nullptr;
+	try
+	{
+		NativeGeometry->getIntersectionProgram(); // todo: comparison check
+		Prog = IntersectionProgram;
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginGeometry, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return Prog;
+}
+
+void UOptiXGeometry::SetBuffer(FString Name, UOptiXBuffer* Buffer)
+{
+	try
+	{
+		std::string N = std::string(TCHAR_TO_ANSI(*Name));
+		NativeGeometry[N]->setBuffer(Buffer->GetNativeBuffer());
+		BufferMap.Add(Name, Buffer);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginGeometry, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
diff --git a/Source/OptiX/Private/OptiXGeometryGroup.cpp b/Deprecated/Private/OptiXGeometryGroup.cpp
similarity index 96%
rename from Source/OptiX/Private/OptiXGeometryGroup.cpp
rename to Deprecated/Private/OptiXGeometryGroup.cpp
index 240c8458ecdabea18d7729c40591e61ddae06144..1ccca358508a273e0b847e581fae24c554717faa 100644
--- a/Source/OptiX/Private/OptiXGeometryGroup.cpp
+++ b/Deprecated/Private/OptiXGeometryGroup.cpp
@@ -1,205 +1,205 @@
-#include "OptiXGeometryGroup.h"
-
-#include "CoreMinimal.h"
-#include "UObject/ObjectMacros.h"
-#include "Engine/EngineTypes.h"
-
-#include "OptiXGeometryGroup.h"
-#include "OptiXModule.h"
-
-// Needed for debugging
-#include <EngineGlobals.h>
-#include <Runtime/Engine/Classes/Engine/Engine.h>
-
-DEFINE_LOG_CATEGORY(OptiXPluginGeometryGroup);
-
-// TODO LOOK INTO CONSTRUCTORS
-
-void UOptiXGeometryGroup::BeginDestroy()
-{
-	Super::BeginDestroy();
-
-	// Tell optix to clean up
-	UE_LOG(LogTemp, Warning, TEXT("OptiX Geometry Group BeginDestroy"));
-	// Remove all the children:
-	DestroyOptiXObject();
-	UE_LOG(LogTemp, Warning, TEXT("OptiX Geometry Group Finished BeginDestroy"));
-
-}
-
-void UOptiXGeometryGroup::DestroyOptiXObject()
-{
-	for (UOptiXGeometryInstance* I : OptiXGeometryInstances)
-	{
-		//RemoveChild(I);
-		// For some godforsaken reason this crashes optix...
-	}
-
-	if (NativeGeometryGroup != NULL)
-	{
-		//NativeGeometryGroup->destroy();
-		FOptiXModule::Get().GetOptiXContextManager()->GeometryGroupToDeleteQueue.Enqueue(NativeGeometryGroup);
-
-	}
-
-	OptiXGeometryInstances.Empty();
-	NativeGeometryGroup = NULL;
-}
-
-void UOptiXGeometryGroup::SetAcceleration(UOptiXAcceleration* Accel)
-{
-	try
-	{
-		NativeGeometryGroup->setAcceleration(Accel->GetNativeAcceleration());
-		Acceleration = Accel;
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginGeometryGroup, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-}
-
-UOptiXAcceleration* UOptiXGeometryGroup::GetAcceleration()
-{
-	UOptiXAcceleration* Ptr = nullptr;
-	try
-	{
-		optix::Acceleration Native = NativeGeometryGroup->getAcceleration();
-
-		if (Native != Acceleration->GetNativeAcceleration())
-		{
-			FString Message = "Acceleration Mismatch in Geometry Group!";
-			UE_LOG(OptiXPluginGeometryGroup, Error, TEXT("OptiX Error: %s"), *Message);
-			GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-		}
-
-		Ptr = Acceleration;
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginGeometryGroup, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-	return Ptr;
-}
-
-void UOptiXGeometryGroup::SetChildCount(uint8 Count)
-{
-	NativeGeometryGroup->setChildCount(Count);
-	ChildCount = Count;
-
-	int32 Diff = Count - OptiXGeometryInstances.Num();
-
-	if (Diff > 0)
-	{
-		OptiXGeometryInstances.SetNum(Count);
-	}
-	else if (Diff < 0)
-	{
-		// Theoretically remove children but don't do this for now! TODOOOO
-	}
-}
-
-uint8 UOptiXGeometryGroup::GetChildCount()
-{
-	// Check if our count is the same
-	uint8 OptiXCount = NativeGeometryGroup->getChildCount();
-	if (OptiXCount != ChildCount)
-	{
-		UE_LOG(LogTemp, Error, TEXT("OptiXGeometryGroup Child Counts are mismatched: Native: %i - %i UObject \n"), OptiXCount, ChildCount);
-	}
-	return OptiXCount;
-}
-
-void UOptiXGeometryGroup::SetChild(uint8 Index, UOptiXGeometryInstance * Child)
-{
-	// This will probably mess with child counts but shouldn't.
-
-	if (!OptiXGeometryInstances.IsValidIndex(Index))
-	{
-		UE_LOG(LogTemp, Error, TEXT("OptiXGeometryGroup: Trying to insert child in non-existing place! \n"));
-		return;
-	}
-	NativeGeometryGroup->setChild(Index, Child->GetNativeInstance());
-	OptiXGeometryInstances.Insert(Child, Index);
-}
-
-UOptiXGeometryInstance * UOptiXGeometryGroup::GetChild(uint8 Index)
-{
-	if (!OptiXGeometryInstances.IsValidIndex(Index))
-	{
-		UE_LOG(LogTemp, Error, TEXT("OptiXGeometryGroup: Child does not exist! \n"));
-	}
-
-	return OptiXGeometryInstances[Index];
-}
-
-uint8 UOptiXGeometryGroup::AddChild(UOptiXGeometryInstance * Child)
-{
-	ChildCount++;
-	uint8 NativeIndex = static_cast<uint8>(NativeGeometryGroup->addChild(Child->GetNativeInstance()));
-	uint8 Index = OptiXGeometryInstances.Add(Child);
-	if (NativeIndex != Index)
-	{
-		UE_LOG(LogTemp, Error, TEXT("OptiXGeometryGroup: Index Mismatch while adding! \n"));
-	}
-	return Index;
-}
-
-uint8 UOptiXGeometryGroup::RemoveChild(UOptiXGeometryInstance * Child)
-{
-	uint8 Index = GetChildIndex(Child);
-	RemoveChildByIndex(Index);
-	return Index;
-}
-
-void UOptiXGeometryGroup::RemoveChildByIndex(uint8 Index)
-{
-	if (!OptiXGeometryInstances.IsValidIndex(Index))
-	{
-		UE_LOG(LogTemp, Error, TEXT("OptiXGeometryGroup: Index Mismatch while removing!"));
-		return;
-	}
-
-	UE_LOG(LogTemp, Display, TEXT("OptiXGeometryGroup: Removing optix child!"));
-	UE_LOG(LogTemp, Display, TEXT("Child Count: %i "), GetChildCount());
-	UE_LOG(LogTemp, Display, TEXT("Index to remove: %i "), Index);
-	UE_LOG(LogTemp, Display, TEXT("Size of TArray: %i "), OptiXGeometryInstances.Num());
-
-
-	try
-	{
-		if (IsInGameThread())
-		{
-			FOptiXModule::Get().GetOptiXContextManager()->GeometryGroupChildrenToRemoveQueue.Enqueue(TPair<optix::GeometryGroup, uint32>(NativeGeometryGroup, Index));
-		}
-		else
-		{
-			NativeGeometryGroup->removeChild(static_cast<unsigned int>(Index));
-		}
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginGeometryGroup, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-	ChildCount--; // Not sure if OptiX internally resizes the array or if the child count stays the same?
-
-	UE_LOG(LogTemp, Display, TEXT("Done Removing Native"), OptiXGeometryInstances.Num());
-	UE_LOG(LogTemp, Display, TEXT("Child Count After remove native: %i "), GetChildCount());
-	FName Name = OptiXGeometryInstances[Index]->GetFName();
-	UE_LOG(LogTemp, Display, TEXT("Name of child to remove: %s"), *Name.ToString());
-
-	OptiXGeometryInstances.RemoveAt(Index); // Will shuffle the remaining indices correctly - hopefully.
-	UE_LOG(LogTemp, Display, TEXT("Finished Removing \n"));
-
-}
-
-uint8 UOptiXGeometryGroup::GetChildIndex(UOptiXGeometryInstance * Child)
-{
-	return OptiXGeometryInstances.Find(Child);
-}
+#include "OptiXGeometryGroup.h"
+
+#include "CoreMinimal.h"
+#include "UObject/ObjectMacros.h"
+#include "Engine/EngineTypes.h"
+
+#include "OptiXGeometryGroup.h"
+#include "OptiXModule.h"
+
+// Needed for debugging
+#include <EngineGlobals.h>
+#include <Runtime/Engine/Classes/Engine/Engine.h>
+
+DEFINE_LOG_CATEGORY(OptiXPluginGeometryGroup);
+
+// TODO LOOK INTO CONSTRUCTORS
+
+void UOptiXGeometryGroup::BeginDestroy()
+{
+	Super::BeginDestroy();
+
+	// Tell optix to clean up
+	UE_LOG(LogTemp, Warning, TEXT("OptiX Geometry Group BeginDestroy"));
+	// Remove all the children:
+	DestroyOptiXObject();
+	UE_LOG(LogTemp, Warning, TEXT("OptiX Geometry Group Finished BeginDestroy"));
+
+}
+
+void UOptiXGeometryGroup::DestroyOptiXObject()
+{
+	for (UOptiXGeometryInstance* I : OptiXGeometryInstances)
+	{
+		//RemoveChild(I);
+		// For some godforsaken reason this crashes optix...
+	}
+
+	if (NativeGeometryGroup != NULL)
+	{
+		//NativeGeometryGroup->destroy();
+		FOptiXModule::Get().GetOptiXContextManager()->GeometryGroupToDeleteQueue.Enqueue(NativeGeometryGroup);
+
+	}
+
+	OptiXGeometryInstances.Empty();
+	NativeGeometryGroup = NULL;
+}
+
+void UOptiXGeometryGroup::SetAcceleration(UOptiXAcceleration* Accel)
+{
+	try
+	{
+		NativeGeometryGroup->setAcceleration(Accel->GetNativeAcceleration());
+		Acceleration = Accel;
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginGeometryGroup, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+UOptiXAcceleration* UOptiXGeometryGroup::GetAcceleration()
+{
+	UOptiXAcceleration* Ptr = nullptr;
+	try
+	{
+		optix::Acceleration Native = NativeGeometryGroup->getAcceleration();
+
+		if (Native != Acceleration->GetNativeAcceleration())
+		{
+			FString Message = "Acceleration Mismatch in Geometry Group!";
+			UE_LOG(OptiXPluginGeometryGroup, Error, TEXT("OptiX Error: %s"), *Message);
+			GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+		}
+
+		Ptr = Acceleration;
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginGeometryGroup, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return Ptr;
+}
+
+void UOptiXGeometryGroup::SetChildCount(uint8 Count)
+{
+	NativeGeometryGroup->setChildCount(Count);
+	ChildCount = Count;
+
+	int32 Diff = Count - OptiXGeometryInstances.Num();
+
+	if (Diff > 0)
+	{
+		OptiXGeometryInstances.SetNum(Count);
+	}
+	else if (Diff < 0)
+	{
+		// Theoretically remove children but don't do this for now! TODOOOO
+	}
+}
+
+uint8 UOptiXGeometryGroup::GetChildCount()
+{
+	// Check if our count is the same
+	uint8 OptiXCount = NativeGeometryGroup->getChildCount();
+	if (OptiXCount != ChildCount)
+	{
+		UE_LOG(LogTemp, Error, TEXT("OptiXGeometryGroup Child Counts are mismatched: Native: %i - %i UObject \n"), OptiXCount, ChildCount);
+	}
+	return OptiXCount;
+}
+
+void UOptiXGeometryGroup::SetChild(uint8 Index, UOptiXGeometryInstance * Child)
+{
+	// This will probably mess with child counts but shouldn't.
+
+	if (!OptiXGeometryInstances.IsValidIndex(Index))
+	{
+		UE_LOG(LogTemp, Error, TEXT("OptiXGeometryGroup: Trying to insert child in non-existing place! \n"));
+		return;
+	}
+	NativeGeometryGroup->setChild(Index, Child->GetNativeInstance());
+	OptiXGeometryInstances.Insert(Child, Index);
+}
+
+UOptiXGeometryInstance * UOptiXGeometryGroup::GetChild(uint8 Index)
+{
+	if (!OptiXGeometryInstances.IsValidIndex(Index))
+	{
+		UE_LOG(LogTemp, Error, TEXT("OptiXGeometryGroup: Child does not exist! \n"));
+	}
+
+	return OptiXGeometryInstances[Index];
+}
+
+uint8 UOptiXGeometryGroup::AddChild(UOptiXGeometryInstance * Child)
+{
+	ChildCount++;
+	uint8 NativeIndex = static_cast<uint8>(NativeGeometryGroup->addChild(Child->GetNativeInstance()));
+	uint8 Index = OptiXGeometryInstances.Add(Child);
+	if (NativeIndex != Index)
+	{
+		UE_LOG(LogTemp, Error, TEXT("OptiXGeometryGroup: Index Mismatch while adding! \n"));
+	}
+	return Index;
+}
+
+uint8 UOptiXGeometryGroup::RemoveChild(UOptiXGeometryInstance * Child)
+{
+	uint8 Index = GetChildIndex(Child);
+	RemoveChildByIndex(Index);
+	return Index;
+}
+
+void UOptiXGeometryGroup::RemoveChildByIndex(uint8 Index)
+{
+	if (!OptiXGeometryInstances.IsValidIndex(Index))
+	{
+		UE_LOG(LogTemp, Error, TEXT("OptiXGeometryGroup: Index Mismatch while removing!"));
+		return;
+	}
+
+	UE_LOG(LogTemp, Display, TEXT("OptiXGeometryGroup: Removing optix child!"));
+	UE_LOG(LogTemp, Display, TEXT("Child Count: %i "), GetChildCount());
+	UE_LOG(LogTemp, Display, TEXT("Index to remove: %i "), Index);
+	UE_LOG(LogTemp, Display, TEXT("Size of TArray: %i "), OptiXGeometryInstances.Num());
+
+
+	try
+	{
+		if (IsInGameThread())
+		{
+			FOptiXModule::Get().GetOptiXContextManager()->GeometryGroupChildrenToRemoveQueue.Enqueue(TPair<optix::GeometryGroup, uint32>(NativeGeometryGroup, Index));
+		}
+		else
+		{
+			NativeGeometryGroup->removeChild(static_cast<unsigned int>(Index));
+		}
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginGeometryGroup, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	ChildCount--; // Not sure if OptiX internally resizes the array or if the child count stays the same?
+
+	UE_LOG(LogTemp, Display, TEXT("Done Removing Native"), OptiXGeometryInstances.Num());
+	UE_LOG(LogTemp, Display, TEXT("Child Count After remove native: %i "), GetChildCount());
+	FName Name = OptiXGeometryInstances[Index]->GetFName();
+	UE_LOG(LogTemp, Display, TEXT("Name of child to remove: %s"), *Name.ToString());
+
+	OptiXGeometryInstances.RemoveAt(Index); // Will shuffle the remaining indices correctly - hopefully.
+	UE_LOG(LogTemp, Display, TEXT("Finished Removing \n"));
+
+}
+
+uint8 UOptiXGeometryGroup::GetChildIndex(UOptiXGeometryInstance * Child)
+{
+	return OptiXGeometryInstances.Find(Child);
+}
diff --git a/Source/OptiX/Private/OptiXGeometryInstance.cpp b/Deprecated/Private/OptiXGeometryInstance.cpp
similarity index 96%
rename from Source/OptiX/Private/OptiXGeometryInstance.cpp
rename to Deprecated/Private/OptiXGeometryInstance.cpp
index 1c594a09c8312d5a66d0ab1c6dc41de504c9d494..1f4dd0d4dd6ecad33c611d98ef5cf0daae596637 100644
--- a/Source/OptiX/Private/OptiXGeometryInstance.cpp
+++ b/Deprecated/Private/OptiXGeometryInstance.cpp
@@ -1,174 +1,174 @@
-#include "OptiXGeometryInstance.h"
-
-#include "CoreMinimal.h"
-#include "UObject/ObjectMacros.h"
-#include "Engine/EngineTypes.h"
-
-#include "OptiXModule.h"
-
-#include "OptiXGeometryInstance.h"
-
-// TODO LOOK INTO CONSTRUCTORS
-
-void UOptiXGeometryInstance::BeginDestroy()
-{
-	// Tell optix to clean up
-	UE_LOG(LogTemp, Warning, TEXT("OptiX Geometry Instance BeginDestroy"));
-	// This should also remove the optix::geometry if nowhere referenced
-	DestroyOptiXObject();
-	Super::BeginDestroy();
-}
-
-void UOptiXGeometryInstance::DestroyOptiXObject()
-{
-	if (NativeGeometryInstance != NULL)
-	{
-		//NativeGeometryInstance->destroy();
-		FOptiXModule::Get().GetOptiXContextManager()->GeometryInstancesToDeleteQueue.Enqueue(NativeGeometryInstance);
-	}
-
-	BufferMap.Empty();
-	OptiXMaterials.Empty();
-	TextureSamplerMap.Empty();
-	NativeGeometryInstance = NULL;
-}
-
-void UOptiXGeometryInstance::SetGeometry(UOptiXGeometry * OptiXGeometryPtr)
-{
-	OptiXGeometry = OptiXGeometryPtr;
-	NativeGeometryInstance->setGeometry(OptiXGeometryPtr->GetNativeGeometry()); // I hate passing the native geometry around here
-}
-
-UOptiXGeometry * UOptiXGeometryInstance::GetGeometry()
-{
-	return OptiXGeometry;
-}
-
-void UOptiXGeometryInstance::SetMaterialCount(uint8 Count)
-{
-	NativeGeometryInstance->setMaterialCount(Count);
-}
-
-uint8 UOptiXGeometryInstance::GetMaterialCount()
-{
-	return static_cast<uint8>(NativeGeometryInstance->getMaterialCount());
-}
-
-void UOptiXGeometryInstance::SetMaterial(uint8 Idx, UOptiXMaterial * Material)
-{
-	if (!OptiXMaterials.IsValidIndex(Idx))
-	{
-		UE_LOG(LogTemp, Error, TEXT("OptiXGeometryInstance: Trying to insert Material in non-existing place! \n"));
-		return;
-	}
-	NativeGeometryInstance->setMaterial(Idx, Material->GetNativeMaterial());
-	OptiXMaterials.Insert(Material, Idx);
-}
-
-UOptiXMaterial * UOptiXGeometryInstance::GetMaterial(uint8 Idx)
-{
-	if (!OptiXMaterials.IsValidIndex(Idx))
-	{
-		UE_LOG(LogTemp, Error, TEXT("OptiXGeometryInstance: Trying to get Material in non-existing place! \n"));
-		return nullptr;
-	}
-	return OptiXMaterials[Idx];
-}
-
-uint8 UOptiXGeometryInstance::AddMaterial(UOptiXMaterial * OptiXMaterialPtr)
-{
-	NativeGeometryInstance->addMaterial(OptiXMaterialPtr->GetNativeMaterial());
-	return OptiXMaterials.Add(OptiXMaterialPtr);
-}
-
-
-// Setters - ugh
-
-void UOptiXGeometryInstance::SetFloat(FString string, float Var)
-{
-	NativeGeometryInstance[std::string(TCHAR_TO_ANSI(*string))]->setFloat(Var);
-}
-
-void UOptiXGeometryInstance::SetFloat2D(FString string, float Var1, float Var2)
-{
-	NativeGeometryInstance[std::string(TCHAR_TO_ANSI(*string))]->setFloat(Var1, Var2);
-
-}
-
-void UOptiXGeometryInstance::SetFloat3DVector(FString string, FVector Var)
-{
-	NativeGeometryInstance[std::string(TCHAR_TO_ANSI(*string))]->setFloat(Var.X, Var.Y, Var.Z);
-
-}
-
-void UOptiXGeometryInstance::SetFloat3D(FString string, float Var1, float Var2, float Var3)
-{
-	NativeGeometryInstance[std::string(TCHAR_TO_ANSI(*string))]->setFloat(Var1, Var2, Var3);
-
-}
-
-void UOptiXGeometryInstance::SetFloat4DVector(FString string, FVector4 Var)
-{
-	NativeGeometryInstance[std::string(TCHAR_TO_ANSI(*string))]->setFloat(Var.X, Var.Y, Var.Z, Var.W);
-
-}
-
-void UOptiXGeometryInstance::SetFloat4D(FString string, float Var1, float Var2, float Var3, float Var4)
-{
-	NativeGeometryInstance[std::string(TCHAR_TO_ANSI(*string))]->setFloat(Var1, Var2, Var3, Var4);
-
-}
-
-void UOptiXGeometryInstance::SetInt(FString string, int32 Var)
-{
-	NativeGeometryInstance[std::string(TCHAR_TO_ANSI(*string))]->setInt(Var);
-
-}
-
-void UOptiXGeometryInstance::SetInt2D(FString string, int32 Var1, int32 Var2)
-{
-	NativeGeometryInstance[std::string(TCHAR_TO_ANSI(*string))]->setInt(Var1, Var2);
-
-}
-
-void UOptiXGeometryInstance::SetInt3DVector(FString string, FIntVector Var)
-{
-	NativeGeometryInstance[std::string(TCHAR_TO_ANSI(*string))]->setInt(Var.X, Var.Y, Var.Z);
-
-}
-
-void UOptiXGeometryInstance::SetInt3D(FString string, int32 Var1, int32 Var2, int32 Var3)
-{
-	NativeGeometryInstance[std::string(TCHAR_TO_ANSI(*string))]->setInt(Var1, Var2, Var3);
-
-}
-
-void UOptiXGeometryInstance::SetTextureSampler(FString Name, UOptiXTextureSampler * Sampler)
-{
-	try
-	{
-		std::string N = std::string(TCHAR_TO_ANSI(*Name));
-		NativeGeometryInstance[N]->set(Sampler->GetNativeTextureSampler());
-		TextureSamplerMap.Add(Name, Sampler);
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(LogTemp, Error, TEXT("OptiX Error: %s"), *Message);
-	}
-}
-
-void UOptiXGeometryInstance::SetBuffer(FString Name, UOptiXBuffer* Buffer)
-{
-	try
-	{
-		std::string N = std::string(TCHAR_TO_ANSI(*Name));
-		NativeGeometryInstance[N]->setBuffer(Buffer->GetNativeBuffer());
-		BufferMap.Add(Name, Buffer);
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(LogTemp, Error, TEXT("OptiX Error: %s"), *Message);
-	}
-}
+#include "OptiXGeometryInstance.h"
+
+#include "CoreMinimal.h"
+#include "UObject/ObjectMacros.h"
+#include "Engine/EngineTypes.h"
+
+#include "OptiXModule.h"
+
+#include "OptiXGeometryInstance.h"
+
+// TODO LOOK INTO CONSTRUCTORS
+
+void UOptiXGeometryInstance::BeginDestroy()
+{
+	// Tell optix to clean up
+	UE_LOG(LogTemp, Warning, TEXT("OptiX Geometry Instance BeginDestroy"));
+	// This should also remove the optix::geometry if nowhere referenced
+	DestroyOptiXObject();
+	Super::BeginDestroy();
+}
+
+void UOptiXGeometryInstance::DestroyOptiXObject()
+{
+	if (NativeGeometryInstance != NULL)
+	{
+		//NativeGeometryInstance->destroy();
+		FOptiXModule::Get().GetOptiXContextManager()->GeometryInstancesToDeleteQueue.Enqueue(NativeGeometryInstance);
+	}
+
+	BufferMap.Empty();
+	OptiXMaterials.Empty();
+	TextureSamplerMap.Empty();
+	NativeGeometryInstance = NULL;
+}
+
+void UOptiXGeometryInstance::SetGeometry(UOptiXGeometry * OptiXGeometryPtr)
+{
+	OptiXGeometry = OptiXGeometryPtr;
+	NativeGeometryInstance->setGeometry(OptiXGeometryPtr->GetNativeGeometry()); // I hate passing the native geometry around here
+}
+
+UOptiXGeometry * UOptiXGeometryInstance::GetGeometry()
+{
+	return OptiXGeometry;
+}
+
+void UOptiXGeometryInstance::SetMaterialCount(uint8 Count)
+{
+	NativeGeometryInstance->setMaterialCount(Count);
+}
+
+uint8 UOptiXGeometryInstance::GetMaterialCount()
+{
+	return static_cast<uint8>(NativeGeometryInstance->getMaterialCount());
+}
+
+void UOptiXGeometryInstance::SetMaterial(uint8 Idx, UOptiXMaterial * Material)
+{
+	if (!OptiXMaterials.IsValidIndex(Idx))
+	{
+		UE_LOG(LogTemp, Error, TEXT("OptiXGeometryInstance: Trying to insert Material in non-existing place! \n"));
+		return;
+	}
+	NativeGeometryInstance->setMaterial(Idx, Material->GetNativeMaterial());
+	OptiXMaterials.Insert(Material, Idx);
+}
+
+UOptiXMaterial * UOptiXGeometryInstance::GetMaterial(uint8 Idx)
+{
+	if (!OptiXMaterials.IsValidIndex(Idx))
+	{
+		UE_LOG(LogTemp, Error, TEXT("OptiXGeometryInstance: Trying to get Material in non-existing place! \n"));
+		return nullptr;
+	}
+	return OptiXMaterials[Idx];
+}
+
+uint8 UOptiXGeometryInstance::AddMaterial(UOptiXMaterial * OptiXMaterialPtr)
+{
+	NativeGeometryInstance->addMaterial(OptiXMaterialPtr->GetNativeMaterial());
+	return OptiXMaterials.Add(OptiXMaterialPtr);
+}
+
+
+// Setters - ugh
+
+void UOptiXGeometryInstance::SetFloat(FString string, float Var)
+{
+	NativeGeometryInstance[std::string(TCHAR_TO_ANSI(*string))]->setFloat(Var);
+}
+
+void UOptiXGeometryInstance::SetFloat2D(FString string, float Var1, float Var2)
+{
+	NativeGeometryInstance[std::string(TCHAR_TO_ANSI(*string))]->setFloat(Var1, Var2);
+
+}
+
+void UOptiXGeometryInstance::SetFloat3DVector(FString string, FVector Var)
+{
+	NativeGeometryInstance[std::string(TCHAR_TO_ANSI(*string))]->setFloat(Var.X, Var.Y, Var.Z);
+
+}
+
+void UOptiXGeometryInstance::SetFloat3D(FString string, float Var1, float Var2, float Var3)
+{
+	NativeGeometryInstance[std::string(TCHAR_TO_ANSI(*string))]->setFloat(Var1, Var2, Var3);
+
+}
+
+void UOptiXGeometryInstance::SetFloat4DVector(FString string, FVector4 Var)
+{
+	NativeGeometryInstance[std::string(TCHAR_TO_ANSI(*string))]->setFloat(Var.X, Var.Y, Var.Z, Var.W);
+
+}
+
+void UOptiXGeometryInstance::SetFloat4D(FString string, float Var1, float Var2, float Var3, float Var4)
+{
+	NativeGeometryInstance[std::string(TCHAR_TO_ANSI(*string))]->setFloat(Var1, Var2, Var3, Var4);
+
+}
+
+void UOptiXGeometryInstance::SetInt(FString string, int32 Var)
+{
+	NativeGeometryInstance[std::string(TCHAR_TO_ANSI(*string))]->setInt(Var);
+
+}
+
+void UOptiXGeometryInstance::SetInt2D(FString string, int32 Var1, int32 Var2)
+{
+	NativeGeometryInstance[std::string(TCHAR_TO_ANSI(*string))]->setInt(Var1, Var2);
+
+}
+
+void UOptiXGeometryInstance::SetInt3DVector(FString string, FIntVector Var)
+{
+	NativeGeometryInstance[std::string(TCHAR_TO_ANSI(*string))]->setInt(Var.X, Var.Y, Var.Z);
+
+}
+
+void UOptiXGeometryInstance::SetInt3D(FString string, int32 Var1, int32 Var2, int32 Var3)
+{
+	NativeGeometryInstance[std::string(TCHAR_TO_ANSI(*string))]->setInt(Var1, Var2, Var3);
+
+}
+
+void UOptiXGeometryInstance::SetTextureSampler(FString Name, UOptiXTextureSampler * Sampler)
+{
+	try
+	{
+		std::string N = std::string(TCHAR_TO_ANSI(*Name));
+		NativeGeometryInstance[N]->set(Sampler->GetNativeTextureSampler());
+		TextureSamplerMap.Add(Name, Sampler);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(LogTemp, Error, TEXT("OptiX Error: %s"), *Message);
+	}
+}
+
+void UOptiXGeometryInstance::SetBuffer(FString Name, UOptiXBuffer* Buffer)
+{
+	try
+	{
+		std::string N = std::string(TCHAR_TO_ANSI(*Name));
+		NativeGeometryInstance[N]->setBuffer(Buffer->GetNativeBuffer());
+		BufferMap.Add(Name, Buffer);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(LogTemp, Error, TEXT("OptiX Error: %s"), *Message);
+	}
+}
diff --git a/Source/OptiX/Private/OptiXGroup.cpp b/Deprecated/Private/OptiXGroup.cpp
similarity index 96%
rename from Source/OptiX/Private/OptiXGroup.cpp
rename to Deprecated/Private/OptiXGroup.cpp
index 2fa1e2a4c544a71dc1e82913e2dcbf6593424a45..f020d84a11ecbe34c394cc336ac3b74295154d7d 100644
--- a/Source/OptiX/Private/OptiXGroup.cpp
+++ b/Deprecated/Private/OptiXGroup.cpp
@@ -1,238 +1,238 @@
-#include "OptiXGroup.h"
-
-#include "CoreMinimal.h"
-#include "UObject/ObjectMacros.h"
-#include "Engine/EngineTypes.h"
-
-#include "OptiXModule.h"
-
-// Needed for debugging
-#include <EngineGlobals.h>
-#include <Runtime/Engine/Classes/Engine/Engine.h>
-
-DEFINE_LOG_CATEGORY(OptiXPluginGroup);
-
-// TODO LOOK INTO CONSTRUCTORS
-
-void UOptiXGroup::BeginDestroy()
-{
-	// Tell optix to clean up
-	UE_LOG(LogTemp, Warning, TEXT("OptiX Group BeginDestroy"));
-
-	DestroyOptiXObject();
-
-	Super::BeginDestroy();
-}
-
-
-void UOptiXGroup::DestroyOptiXObject()
-{
-	for (UObject* I : Children)
-	{
-		//RemoveChild(I);
-	}
-
-	if (NativeGroup != NULL)
-	{
-		//NativeGroup->destroy();
-		FOptiXModule::Get().GetOptiXContextManager()->GroupsToDeleteQueue.Enqueue(NativeGroup);
-	}
-
-	Children.Empty();
-	NativeGroup = NULL;
-}
-
-void UOptiXGroup::SetAcceleration(UOptiXAcceleration * Accel)
-{
-	try
-	{
-		NativeGroup->setAcceleration(Accel->GetNativeAcceleration());
-		Acceleration = Accel;
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginGroup, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-}
-
-UOptiXAcceleration * UOptiXGroup::GetAcceleration()
-{
-	UOptiXAcceleration* Ptr = nullptr;
-	try
-	{
-		optix::Acceleration Native = NativeGroup->getAcceleration();
-
-		if (Native != Acceleration->GetNativeAcceleration())
-		{
-			FString Message = "Acceleration Mismatch in Group!";
-			UE_LOG(OptiXPluginGroup, Error, TEXT("OptiX Error: %s"), *Message);
-			GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-		}
-
-		Ptr = Acceleration;
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginGroup, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-	return Ptr;
-}
-
-void UOptiXGroup::SetChildCount(uint8 Count)
-{
-	NativeGroup->setChildCount(Count);
-	ChildCount = Count;
-
-	int32 Diff = Count - Children.Num();
-
-	if (Diff > 0)
-	{
-		Children.SetNum(Count);
-	}
-	else if (Diff < 0)
-	{
-		// Theoretically remove children but don't do this for now! TODOOOO
-	}
-}
-
-uint8 UOptiXGroup::GetChildCount()
-{
-	// Check if our count is the same
-	uint8 OptiXCount = NativeGroup->getChildCount();
-	if (OptiXCount != ChildCount)
-	{
-		UE_LOG(LogTemp, Error, TEXT("OptiXGroup Child Counts are mismatched! \n"));
-	}
-	return OptiXCount;
-}
-
-void UOptiXGroup::SetChild(uint8 Index, UObject * Child)
-{
-	// This will probably mess with child counts but shouldn't.
-
-	if (!Children.IsValidIndex(Index))
-	{
-		UE_LOG(LogTemp, Error, TEXT("OptiXGroup: Trying to insert child in non-existing place! \n"));
-		return;
-	}
-
-	// Check the different child types - don't do all for now just add the code when needed
-	// Doing GeometryGroup, GeometryInstance and Transform for now
-
-	if (UOptiXGeometryGroup* GeomGroup = Cast<UOptiXGeometryGroup>(Child))
-	{
-		NativeGroup->setChild(Index, GeomGroup->GetNativeGroup());
-		Children.Insert(Child, Index);
-	}
-	else if (UOptiXGeometryInstance* GeomInstance = Cast<UOptiXGeometryInstance>(Child))
-	{
-		NativeGroup->setChild(Index, GeomInstance->GetNativeInstance());
-		Children.Insert(Child, Index);
-	}
-	else if (UOptiXTransform* Transform = Cast<UOptiXTransform>(Child))
-	{
-		NativeGroup->setChild(Index, Transform->GetNativeTransform());
-		Children.Insert(Child, Index);
-	}
-}
-
-RTobjecttype UOptiXGroup::GetChildType(uint8 Index)
-{
-	RTobjecttype Type = RT_OBJECTTYPE_UNKNOWN;
-	if (!Children.IsValidIndex(Index))
-	{
-		UE_LOG(LogTemp, Error, TEXT("OptiXGroup: Trying to get child type in non-existing place! \n"));
-		return Type;
-	}
-	
-	return NativeGroup->getChildType(Index);
-}
-
-UObject * UOptiXGroup::GetChild(uint8 Index)
-{
-	if (!Children.IsValidIndex(Index))
-	{
-		UE_LOG(LogTemp, Error, TEXT("OptiXGroup: Child does not exist! \n"));
-	}
-
-	return Children[Index];
-}
-
-uint8 UOptiXGroup::AddChild(UObject * Child)
-{
-	if (UOptiXGeometryGroup* GeomGroup = Cast<UOptiXGeometryGroup>(Child))
-	{
-		uint8 NativeIndex = static_cast<uint8>(NativeGroup->addChild(GeomGroup->GetNativeGroup()));
-		uint8 Index = Children.Add(Child);
-		if (NativeIndex != Index)
-		{
-			UE_LOG(LogTemp, Error, TEXT("OptiXGroup: Index Mismatch while adding! \n"));
-		}
-		return Index;
-	}
-	else if (UOptiXGeometryInstance* GeomInstance = Cast<UOptiXGeometryInstance>(Child))
-	{
-		uint8 NativeIndex = static_cast<uint8>(NativeGroup->addChild(GeomInstance->GetNativeInstance()));
-		uint8 Index = Children.Add(Child);
-		if (NativeIndex != Index)
-		{
-			UE_LOG(LogTemp, Error, TEXT("OptiXGroup: Index Mismatch while adding! \n"));
-		}
-		return Index;
-	}
-	else if (UOptiXTransform* Transform = Cast<UOptiXTransform>(Child))
-	{
-		uint8 NativeIndex = static_cast<uint8>(NativeGroup->addChild(Transform->GetNativeTransform()));
-		uint8 Index = Children.Add(Child);
-		if (NativeIndex != Index)
-		{
-			UE_LOG(LogTemp, Error, TEXT("OptiXGroup: Index Mismatch while adding! \n"));
-		}
-		return Index;
-	}
-	else return 0; // Dangerous!	
-}
-
-uint8 UOptiXGroup::RemoveChild(UObject * Child)
-{
-	uint8 Index = GetChildIndex(Child);
-	RemoveChildByIndex(Index);
-	return Index;
-}
-
-void UOptiXGroup::RemoveChildByIndex(uint8 Index)
-{
-	if (!Children.IsValidIndex(Index))
-	{
-		UE_LOG(LogTemp, Error, TEXT("OptiXGroup: Index Mismatch while removing! \n"));
-		return;
-	}
-
-	if (NativeGroup == NULL)
-	{
-		UE_LOG(LogTemp, Error, TEXT("OptiXGroup: Native group is NULL when removing child! \n"));
-		return;
-	}
-
-	ChildCount--; // Not sure if OptiX internally resizes the array or if the child count stays the same?
-	Children.RemoveAt(Index); // Will shuffle the remaining indices correctly - hopefully.
-
-	// Can't do that in game thread!
-	if (IsInGameThread())
-	{
-		FOptiXModule::Get().GetOptiXContextManager()->GroupChildrenToRemoveQueue.Enqueue(TPair<optix::Group, uint32>(NativeGroup, Index ));
-	}
-	else
-	{
-		NativeGroup->removeChild(static_cast<unsigned int>(Index));
-	}
-}
-
-uint8 UOptiXGroup::GetChildIndex(UObject * Child)
-{
-	return Children.Find(Child);
-}
+#include "OptiXGroup.h"
+
+#include "CoreMinimal.h"
+#include "UObject/ObjectMacros.h"
+#include "Engine/EngineTypes.h"
+
+#include "OptiXModule.h"
+
+// Needed for debugging
+#include <EngineGlobals.h>
+#include <Runtime/Engine/Classes/Engine/Engine.h>
+
+DEFINE_LOG_CATEGORY(OptiXPluginGroup);
+
+// TODO LOOK INTO CONSTRUCTORS
+
+void UOptiXGroup::BeginDestroy()
+{
+	// Tell optix to clean up
+	UE_LOG(LogTemp, Warning, TEXT("OptiX Group BeginDestroy"));
+
+	DestroyOptiXObject();
+
+	Super::BeginDestroy();
+}
+
+
+void UOptiXGroup::DestroyOptiXObject()
+{
+	for (UObject* I : Children)
+	{
+		//RemoveChild(I);
+	}
+
+	if (NativeGroup != NULL)
+	{
+		//NativeGroup->destroy();
+		FOptiXModule::Get().GetOptiXContextManager()->GroupsToDeleteQueue.Enqueue(NativeGroup);
+	}
+
+	Children.Empty();
+	NativeGroup = NULL;
+}
+
+void UOptiXGroup::SetAcceleration(UOptiXAcceleration * Accel)
+{
+	try
+	{
+		NativeGroup->setAcceleration(Accel->GetNativeAcceleration());
+		Acceleration = Accel;
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginGroup, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+UOptiXAcceleration * UOptiXGroup::GetAcceleration()
+{
+	UOptiXAcceleration* Ptr = nullptr;
+	try
+	{
+		optix::Acceleration Native = NativeGroup->getAcceleration();
+
+		if (Native != Acceleration->GetNativeAcceleration())
+		{
+			FString Message = "Acceleration Mismatch in Group!";
+			UE_LOG(OptiXPluginGroup, Error, TEXT("OptiX Error: %s"), *Message);
+			GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+		}
+
+		Ptr = Acceleration;
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginGroup, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return Ptr;
+}
+
+void UOptiXGroup::SetChildCount(uint8 Count)
+{
+	NativeGroup->setChildCount(Count);
+	ChildCount = Count;
+
+	int32 Diff = Count - Children.Num();
+
+	if (Diff > 0)
+	{
+		Children.SetNum(Count);
+	}
+	else if (Diff < 0)
+	{
+		// Theoretically remove children but don't do this for now! TODOOOO
+	}
+}
+
+uint8 UOptiXGroup::GetChildCount()
+{
+	// Check if our count is the same
+	uint8 OptiXCount = NativeGroup->getChildCount();
+	if (OptiXCount != ChildCount)
+	{
+		UE_LOG(LogTemp, Error, TEXT("OptiXGroup Child Counts are mismatched! \n"));
+	}
+	return OptiXCount;
+}
+
+void UOptiXGroup::SetChild(uint8 Index, UObject * Child)
+{
+	// This will probably mess with child counts but shouldn't.
+
+	if (!Children.IsValidIndex(Index))
+	{
+		UE_LOG(LogTemp, Error, TEXT("OptiXGroup: Trying to insert child in non-existing place! \n"));
+		return;
+	}
+
+	// Check the different child types - don't do all for now just add the code when needed
+	// Doing GeometryGroup, GeometryInstance and Transform for now
+
+	if (UOptiXGeometryGroup* GeomGroup = Cast<UOptiXGeometryGroup>(Child))
+	{
+		NativeGroup->setChild(Index, GeomGroup->GetNativeGroup());
+		Children.Insert(Child, Index);
+	}
+	else if (UOptiXGeometryInstance* GeomInstance = Cast<UOptiXGeometryInstance>(Child))
+	{
+		NativeGroup->setChild(Index, GeomInstance->GetNativeInstance());
+		Children.Insert(Child, Index);
+	}
+	else if (UOptiXTransform* Transform = Cast<UOptiXTransform>(Child))
+	{
+		NativeGroup->setChild(Index, Transform->GetNativeTransform());
+		Children.Insert(Child, Index);
+	}
+}
+
+RTobjecttype UOptiXGroup::GetChildType(uint8 Index)
+{
+	RTobjecttype Type = RT_OBJECTTYPE_UNKNOWN;
+	if (!Children.IsValidIndex(Index))
+	{
+		UE_LOG(LogTemp, Error, TEXT("OptiXGroup: Trying to get child type in non-existing place! \n"));
+		return Type;
+	}
+	
+	return NativeGroup->getChildType(Index);
+}
+
+UObject * UOptiXGroup::GetChild(uint8 Index)
+{
+	if (!Children.IsValidIndex(Index))
+	{
+		UE_LOG(LogTemp, Error, TEXT("OptiXGroup: Child does not exist! \n"));
+	}
+
+	return Children[Index];
+}
+
+uint8 UOptiXGroup::AddChild(UObject * Child)
+{
+	if (UOptiXGeometryGroup* GeomGroup = Cast<UOptiXGeometryGroup>(Child))
+	{
+		uint8 NativeIndex = static_cast<uint8>(NativeGroup->addChild(GeomGroup->GetNativeGroup()));
+		uint8 Index = Children.Add(Child);
+		if (NativeIndex != Index)
+		{
+			UE_LOG(LogTemp, Error, TEXT("OptiXGroup: Index Mismatch while adding! \n"));
+		}
+		return Index;
+	}
+	else if (UOptiXGeometryInstance* GeomInstance = Cast<UOptiXGeometryInstance>(Child))
+	{
+		uint8 NativeIndex = static_cast<uint8>(NativeGroup->addChild(GeomInstance->GetNativeInstance()));
+		uint8 Index = Children.Add(Child);
+		if (NativeIndex != Index)
+		{
+			UE_LOG(LogTemp, Error, TEXT("OptiXGroup: Index Mismatch while adding! \n"));
+		}
+		return Index;
+	}
+	else if (UOptiXTransform* Transform = Cast<UOptiXTransform>(Child))
+	{
+		uint8 NativeIndex = static_cast<uint8>(NativeGroup->addChild(Transform->GetNativeTransform()));
+		uint8 Index = Children.Add(Child);
+		if (NativeIndex != Index)
+		{
+			UE_LOG(LogTemp, Error, TEXT("OptiXGroup: Index Mismatch while adding! \n"));
+		}
+		return Index;
+	}
+	else return 0; // Dangerous!	
+}
+
+uint8 UOptiXGroup::RemoveChild(UObject * Child)
+{
+	uint8 Index = GetChildIndex(Child);
+	RemoveChildByIndex(Index);
+	return Index;
+}
+
+void UOptiXGroup::RemoveChildByIndex(uint8 Index)
+{
+	if (!Children.IsValidIndex(Index))
+	{
+		UE_LOG(LogTemp, Error, TEXT("OptiXGroup: Index Mismatch while removing! \n"));
+		return;
+	}
+
+	if (NativeGroup == NULL)
+	{
+		UE_LOG(LogTemp, Error, TEXT("OptiXGroup: Native group is NULL when removing child! \n"));
+		return;
+	}
+
+	ChildCount--; // Not sure if OptiX internally resizes the array or if the child count stays the same?
+	Children.RemoveAt(Index); // Will shuffle the remaining indices correctly - hopefully.
+
+	// Can't do that in game thread!
+	if (IsInGameThread())
+	{
+		FOptiXModule::Get().GetOptiXContextManager()->GroupChildrenToRemoveQueue.Enqueue(TPair<optix::Group, uint32>(NativeGroup, Index ));
+	}
+	else
+	{
+		NativeGroup->removeChild(static_cast<unsigned int>(Index));
+	}
+}
+
+uint8 UOptiXGroup::GetChildIndex(UObject * Child)
+{
+	return Children.Find(Child);
+}
diff --git a/Source/OptiX/Private/OptiXMaterial.cpp b/Deprecated/Private/OptiXMaterial.cpp
similarity index 96%
rename from Source/OptiX/Private/OptiXMaterial.cpp
rename to Deprecated/Private/OptiXMaterial.cpp
index af91ecdc28e65d03191c0a195a99d39d048c1745..d8614905c2b52f69356077f6ed9d98143d9010ec 100644
--- a/Source/OptiX/Private/OptiXMaterial.cpp
+++ b/Deprecated/Private/OptiXMaterial.cpp
@@ -1,251 +1,251 @@
-#include "OptiXMaterial.h"
-
-#include "CoreMinimal.h"
-#include "UObject/ObjectMacros.h"
-#include "Engine/EngineTypes.h"
-
-#include "OptiXModule.h"
-
-
-
-void UOptiXMaterial::BeginDestroy()
-{
-	// Tell optix to clean up
-	UE_LOG(LogTemp, Warning, TEXT("OptiX Material BeginDestroy"));
-
-	DestroyOptiXObject();
-
-	Super::BeginDestroy();
-}
-
-void UOptiXMaterial::DestroyOptiXObject()
-{
-	if (NativeMaterial != NULL)
-	{
-		//NativeMaterial->destroy();
-		FOptiXModule::Get().GetOptiXContextManager()->MaterialsToDeleteQueue.Enqueue(NativeMaterial);
-	}
-
-	NativeMaterial = NULL;
-	ClosestHitPrograms.Empty();
-	AnyHitProgram = nullptr;
-}
-
-void UOptiXMaterial::SetFloat(FString string, float Var)
-{
-	NativeMaterial[std::string(TCHAR_TO_ANSI(*string))]->setFloat(Var);
-}
-
-void UOptiXMaterial::SetFloat2D(FString string, float Var1, float Var2)
-{
-	NativeMaterial[std::string(TCHAR_TO_ANSI(*string))]->setFloat(Var1, Var2);
-
-}
-
-void UOptiXMaterial::SetFloat3DVector(FString string, FVector Var)
-{
-	NativeMaterial[std::string(TCHAR_TO_ANSI(*string))]->setFloat(Var.X, Var.Y, Var.Z);
-
-}
-
-void UOptiXMaterial::SetFloat3D(FString string, float Var1, float Var2, float Var3)
-{
-	NativeMaterial[std::string(TCHAR_TO_ANSI(*string))]->setFloat(Var1, Var2, Var3);
-
-}
-
-void UOptiXMaterial::SetFloat4DVector(FString string, FVector4 Var)
-{
-	NativeMaterial[std::string(TCHAR_TO_ANSI(*string))]->setFloat(Var.X, Var.Y, Var.Z, Var.W);
-
-}
-
-void UOptiXMaterial::SetFloat4D(FString string, float Var1, float Var2, float Var3, float Var4)
-{
-	NativeMaterial[std::string(TCHAR_TO_ANSI(*string))]->setFloat(Var1, Var2, Var3, Var4);
-
-}
-
-void UOptiXMaterial::SetInt(FString string, int32 Var)
-{
-	NativeMaterial[std::string(TCHAR_TO_ANSI(*string))]->setInt(Var);
-
-}
-
-void UOptiXMaterial::SetInt2D(FString string, int32 Var1, int32 Var2)
-{
-	NativeMaterial[std::string(TCHAR_TO_ANSI(*string))]->setInt(Var1, Var2);
-
-}
-
-void UOptiXMaterial::SetInt3DVector(FString string, FIntVector Var)
-{
-	NativeMaterial[std::string(TCHAR_TO_ANSI(*string))]->setInt(Var.X, Var.Y, Var.Z);
-
-}
-
-void UOptiXMaterial::SetInt3D(FString string, int32 Var1, int32 Var2, int32 Var3)
-{
-	NativeMaterial[std::string(TCHAR_TO_ANSI(*string))]->setInt(Var1, Var2, Var3);
-
-}
-
-//void UOptiXMaterial::SetInt4DVector(FString string, FIntVector4 Var)
-//{
-//	NativeMaterial[std::string(TCHAR_TO_ANSI(*string))]->setInt(Var.X, Var.Y, Var.Z, Var.W);
-//
-//}
-
-void UOptiXMaterial::SetInt4D(FString string, int32 Var1, int32 Var2, int32 Var3, int32 Var4)
-{
-	NativeMaterial[std::string(TCHAR_TO_ANSI(*string))]->setInt(Var1, Var2, Var3, Var4);
-
-}
-
-void UOptiXMaterial::SetUint(FString string, uint8 Var)
-{
-	NativeMaterial[std::string(TCHAR_TO_ANSI(*string))]->setUint(Var);
-}
-
-void UOptiXMaterial::SetUint2D(FString string, uint8 Var1, uint8 Var2)
-{
-	NativeMaterial[std::string(TCHAR_TO_ANSI(*string))]->setUint(Var1, Var2);
-
-}
-
-void UOptiXMaterial::SetUint3D(FString string, uint8 Var1, uint8 Var2, uint8 Var3)
-{
-	NativeMaterial[std::string(TCHAR_TO_ANSI(*string))]->setUint(Var1, Var2, Var3);
-
-}
-
-void UOptiXMaterial::SetUint4D(FString string, uint8 Var1, uint8 Var2, uint8 Var3, uint8 Var4)
-{
-	NativeMaterial[std::string(TCHAR_TO_ANSI(*string))]->setUint(Var1, Var2, Var3, Var4);
-
-}
-
-float UOptiXMaterial::GetFloat(FString string)
-{
-	return NativeMaterial[std::string(TCHAR_TO_ANSI(*string))]->getFloat();
-}
-
-FVector2D UOptiXMaterial::GetFloat2D(FString string)
-{
-	optix::float2 V = NativeMaterial[std::string(TCHAR_TO_ANSI(*string))]->getFloat2();
-	return FVector2D(V.x, V.y);
-}
-
-FVector UOptiXMaterial::GetFloat3D(FString string)
-{
-	optix::float3 V = NativeMaterial[std::string(TCHAR_TO_ANSI(*string))]->getFloat3();
-	return FVector(V.x, V.y, V.z);
-}
-
-FVector4 UOptiXMaterial::GetFloat4D(FString string)
-{
-	optix::float4 V = NativeMaterial[std::string(TCHAR_TO_ANSI(*string))]->getFloat4();
-	return FVector4(V.x, V.y, V.z, V.w);
-}
-
-int32 UOptiXMaterial::GetInt(FString string)
-{
-	return NativeMaterial[std::string(TCHAR_TO_ANSI(*string))]->getInt();
-}
-
-FIntPoint UOptiXMaterial::GetInt2D(FString string)
-{
-	optix::int2 V = NativeMaterial[std::string(TCHAR_TO_ANSI(*string))]->getInt2();
-	return FIntPoint(V.x, V.y);
-}
-
-FIntVector UOptiXMaterial::GetInt3D(FString string)
-{
-	optix::int3 V = NativeMaterial[std::string(TCHAR_TO_ANSI(*string))]->getInt3();
-	return FIntVector(V.x, V.y, V.z);
-}
-
-//FIntVector4 UOptiXMaterial::GetInt4D(FString string)
-//{
-//	optix::int4 V = NativeMaterial[std::string(TCHAR_TO_ANSI(*string))]->getInt4();
-//	return FIntVector4(V.x, V.y, V.z, V.w);
-//}
-
-//uint8 UOptiXMaterial::GetUint(FString string)
-//{
-//	return static_cast<uint8>(NativeMaterial[std::string(TCHAR_TO_ANSI(*string))]->getUint());
-//}
-//
-//void UOptiXMaterial::GetUint2D(FString & string, uint8 & Var1, uint8 & Var2)
-//{
-//	NativeMaterial[std::string(TCHAR_TO_ANSI(*string))]->getUint(Var1, Var2);
-//
-//}
-//
-//void UOptiXMaterial::GetUint3D(FString string, uint8 & Var1, uint8 & Var2, uint8 & Var3)
-//{
-//	NativeMaterial[std::string(TCHAR_TO_ANSI(*string))]->getUint(Var1, Var2, Var3);
-//}
-//
-//FUintVector4 UOptiXMaterial::GetUint4D(FString string)
-//{
-//	optix::uint4 V = NativeMaterial[std::string(TCHAR_TO_ANSI(*string))]->getUint4();
-//	return FUintVector4(V.x, V.y, V.z, V.w);
-//}
-
-
-void UOptiXMaterial::SetClosestHitProgram(uint32 RayTypeIndex, UOptiXProgram* Program)
-{
-	try
-	{
-		NativeMaterial->setClosestHitProgram(RayTypeIndex, Program->GetNativeProgram());
-		if (ClosestHitPrograms.IsValidIndex(RayTypeIndex))
-		{
-			ClosestHitPrograms[RayTypeIndex] = Program;
-		}
-		else
-		{
-			ClosestHitPrograms.SetNum(RayTypeIndex + 1);
-			ClosestHitPrograms[RayTypeIndex] = Program;
-		}
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(LogTemp, Error, TEXT("OptiX Error: %s"), *Message);
-	}
-}
-
-UOptiXProgram* UOptiXMaterial::GetClosestHitProgram(uint32 RayTypeIndex)
-{
-	UOptiXProgram* P = nullptr;
-	try
-	{
-		optix::Program Native = NativeMaterial->getClosestHitProgram(RayTypeIndex);
-		if (ClosestHitPrograms.IsValidIndex(RayTypeIndex))
-		{
-			P = ClosestHitPrograms[RayTypeIndex];
-		}
-		else
-		{
-			UE_LOG(LogTemp, Error, TEXT("OptiX Error: Wrong index in GetClosestHitProgram"));
-		}
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(LogTemp, Error, TEXT("OptiX Error: %s"), *Message);
-	}
-	return P;
-}
-
-void UOptiXMaterial::SetAnyHitProgram(uint32 RayTypeIndex, UOptiXProgram* Program)
-{
-	AnyHitProgram = Program;
-	NativeMaterial->setAnyHitProgram(RayTypeIndex, Program->GetNativeProgram());
-}
-
-UOptiXProgram* UOptiXMaterial::GetAnyHitProgram(uint32 RayTypeIndex)
-{
-	return AnyHitProgram;
-}
+#include "OptiXMaterial.h"
+
+#include "CoreMinimal.h"
+#include "UObject/ObjectMacros.h"
+#include "Engine/EngineTypes.h"
+
+#include "OptiXModule.h"
+
+
+
+void UOptiXMaterial::BeginDestroy()
+{
+	// Tell optix to clean up
+	UE_LOG(LogTemp, Warning, TEXT("OptiX Material BeginDestroy"));
+
+	DestroyOptiXObject();
+
+	Super::BeginDestroy();
+}
+
+void UOptiXMaterial::DestroyOptiXObject()
+{
+	if (NativeMaterial != NULL)
+	{
+		//NativeMaterial->destroy();
+		FOptiXModule::Get().GetOptiXContextManager()->MaterialsToDeleteQueue.Enqueue(NativeMaterial);
+	}
+
+	NativeMaterial = NULL;
+	ClosestHitPrograms.Empty();
+	AnyHitProgram = nullptr;
+}
+
+void UOptiXMaterial::SetFloat(FString string, float Var)
+{
+	NativeMaterial[std::string(TCHAR_TO_ANSI(*string))]->setFloat(Var);
+}
+
+void UOptiXMaterial::SetFloat2D(FString string, float Var1, float Var2)
+{
+	NativeMaterial[std::string(TCHAR_TO_ANSI(*string))]->setFloat(Var1, Var2);
+
+}
+
+void UOptiXMaterial::SetFloat3DVector(FString string, FVector Var)
+{
+	NativeMaterial[std::string(TCHAR_TO_ANSI(*string))]->setFloat(Var.X, Var.Y, Var.Z);
+
+}
+
+void UOptiXMaterial::SetFloat3D(FString string, float Var1, float Var2, float Var3)
+{
+	NativeMaterial[std::string(TCHAR_TO_ANSI(*string))]->setFloat(Var1, Var2, Var3);
+
+}
+
+void UOptiXMaterial::SetFloat4DVector(FString string, FVector4 Var)
+{
+	NativeMaterial[std::string(TCHAR_TO_ANSI(*string))]->setFloat(Var.X, Var.Y, Var.Z, Var.W);
+
+}
+
+void UOptiXMaterial::SetFloat4D(FString string, float Var1, float Var2, float Var3, float Var4)
+{
+	NativeMaterial[std::string(TCHAR_TO_ANSI(*string))]->setFloat(Var1, Var2, Var3, Var4);
+
+}
+
+void UOptiXMaterial::SetInt(FString string, int32 Var)
+{
+	NativeMaterial[std::string(TCHAR_TO_ANSI(*string))]->setInt(Var);
+
+}
+
+void UOptiXMaterial::SetInt2D(FString string, int32 Var1, int32 Var2)
+{
+	NativeMaterial[std::string(TCHAR_TO_ANSI(*string))]->setInt(Var1, Var2);
+
+}
+
+void UOptiXMaterial::SetInt3DVector(FString string, FIntVector Var)
+{
+	NativeMaterial[std::string(TCHAR_TO_ANSI(*string))]->setInt(Var.X, Var.Y, Var.Z);
+
+}
+
+void UOptiXMaterial::SetInt3D(FString string, int32 Var1, int32 Var2, int32 Var3)
+{
+	NativeMaterial[std::string(TCHAR_TO_ANSI(*string))]->setInt(Var1, Var2, Var3);
+
+}
+
+//void UOptiXMaterial::SetInt4DVector(FString string, FIntVector4 Var)
+//{
+//	NativeMaterial[std::string(TCHAR_TO_ANSI(*string))]->setInt(Var.X, Var.Y, Var.Z, Var.W);
+//
+//}
+
+void UOptiXMaterial::SetInt4D(FString string, int32 Var1, int32 Var2, int32 Var3, int32 Var4)
+{
+	NativeMaterial[std::string(TCHAR_TO_ANSI(*string))]->setInt(Var1, Var2, Var3, Var4);
+
+}
+
+void UOptiXMaterial::SetUint(FString string, uint8 Var)
+{
+	NativeMaterial[std::string(TCHAR_TO_ANSI(*string))]->setUint(Var);
+}
+
+void UOptiXMaterial::SetUint2D(FString string, uint8 Var1, uint8 Var2)
+{
+	NativeMaterial[std::string(TCHAR_TO_ANSI(*string))]->setUint(Var1, Var2);
+
+}
+
+void UOptiXMaterial::SetUint3D(FString string, uint8 Var1, uint8 Var2, uint8 Var3)
+{
+	NativeMaterial[std::string(TCHAR_TO_ANSI(*string))]->setUint(Var1, Var2, Var3);
+
+}
+
+void UOptiXMaterial::SetUint4D(FString string, uint8 Var1, uint8 Var2, uint8 Var3, uint8 Var4)
+{
+	NativeMaterial[std::string(TCHAR_TO_ANSI(*string))]->setUint(Var1, Var2, Var3, Var4);
+
+}
+
+float UOptiXMaterial::GetFloat(FString string)
+{
+	return NativeMaterial[std::string(TCHAR_TO_ANSI(*string))]->getFloat();
+}
+
+FVector2D UOptiXMaterial::GetFloat2D(FString string)
+{
+	optix::float2 V = NativeMaterial[std::string(TCHAR_TO_ANSI(*string))]->getFloat2();
+	return FVector2D(V.x, V.y);
+}
+
+FVector UOptiXMaterial::GetFloat3D(FString string)
+{
+	optix::float3 V = NativeMaterial[std::string(TCHAR_TO_ANSI(*string))]->getFloat3();
+	return FVector(V.x, V.y, V.z);
+}
+
+FVector4 UOptiXMaterial::GetFloat4D(FString string)
+{
+	optix::float4 V = NativeMaterial[std::string(TCHAR_TO_ANSI(*string))]->getFloat4();
+	return FVector4(V.x, V.y, V.z, V.w);
+}
+
+int32 UOptiXMaterial::GetInt(FString string)
+{
+	return NativeMaterial[std::string(TCHAR_TO_ANSI(*string))]->getInt();
+}
+
+FIntPoint UOptiXMaterial::GetInt2D(FString string)
+{
+	optix::int2 V = NativeMaterial[std::string(TCHAR_TO_ANSI(*string))]->getInt2();
+	return FIntPoint(V.x, V.y);
+}
+
+FIntVector UOptiXMaterial::GetInt3D(FString string)
+{
+	optix::int3 V = NativeMaterial[std::string(TCHAR_TO_ANSI(*string))]->getInt3();
+	return FIntVector(V.x, V.y, V.z);
+}
+
+//FIntVector4 UOptiXMaterial::GetInt4D(FString string)
+//{
+//	optix::int4 V = NativeMaterial[std::string(TCHAR_TO_ANSI(*string))]->getInt4();
+//	return FIntVector4(V.x, V.y, V.z, V.w);
+//}
+
+//uint8 UOptiXMaterial::GetUint(FString string)
+//{
+//	return static_cast<uint8>(NativeMaterial[std::string(TCHAR_TO_ANSI(*string))]->getUint());
+//}
+//
+//void UOptiXMaterial::GetUint2D(FString & string, uint8 & Var1, uint8 & Var2)
+//{
+//	NativeMaterial[std::string(TCHAR_TO_ANSI(*string))]->getUint(Var1, Var2);
+//
+//}
+//
+//void UOptiXMaterial::GetUint3D(FString string, uint8 & Var1, uint8 & Var2, uint8 & Var3)
+//{
+//	NativeMaterial[std::string(TCHAR_TO_ANSI(*string))]->getUint(Var1, Var2, Var3);
+//}
+//
+//FUintVector4 UOptiXMaterial::GetUint4D(FString string)
+//{
+//	optix::uint4 V = NativeMaterial[std::string(TCHAR_TO_ANSI(*string))]->getUint4();
+//	return FUintVector4(V.x, V.y, V.z, V.w);
+//}
+
+
+void UOptiXMaterial::SetClosestHitProgram(uint32 RayTypeIndex, UOptiXProgram* Program)
+{
+	try
+	{
+		NativeMaterial->setClosestHitProgram(RayTypeIndex, Program->GetNativeProgram());
+		if (ClosestHitPrograms.IsValidIndex(RayTypeIndex))
+		{
+			ClosestHitPrograms[RayTypeIndex] = Program;
+		}
+		else
+		{
+			ClosestHitPrograms.SetNum(RayTypeIndex + 1);
+			ClosestHitPrograms[RayTypeIndex] = Program;
+		}
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(LogTemp, Error, TEXT("OptiX Error: %s"), *Message);
+	}
+}
+
+UOptiXProgram* UOptiXMaterial::GetClosestHitProgram(uint32 RayTypeIndex)
+{
+	UOptiXProgram* P = nullptr;
+	try
+	{
+		optix::Program Native = NativeMaterial->getClosestHitProgram(RayTypeIndex);
+		if (ClosestHitPrograms.IsValidIndex(RayTypeIndex))
+		{
+			P = ClosestHitPrograms[RayTypeIndex];
+		}
+		else
+		{
+			UE_LOG(LogTemp, Error, TEXT("OptiX Error: Wrong index in GetClosestHitProgram"));
+		}
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(LogTemp, Error, TEXT("OptiX Error: %s"), *Message);
+	}
+	return P;
+}
+
+void UOptiXMaterial::SetAnyHitProgram(uint32 RayTypeIndex, UOptiXProgram* Program)
+{
+	AnyHitProgram = Program;
+	NativeMaterial->setAnyHitProgram(RayTypeIndex, Program->GetNativeProgram());
+}
+
+UOptiXProgram* UOptiXMaterial::GetAnyHitProgram(uint32 RayTypeIndex)
+{
+	return AnyHitProgram;
+}
diff --git a/Source/OptiX/Private/OptiXTextureSampler.cpp b/Deprecated/Private/OptiXTextureSampler.cpp
similarity index 96%
rename from Source/OptiX/Private/OptiXTextureSampler.cpp
rename to Deprecated/Private/OptiXTextureSampler.cpp
index afd1e83871eb3c72fe93cb3747cfc5dec171abdd..0081371c7c948d37febac915b5be5b20bbc1056e 100644
--- a/Source/OptiX/Private/OptiXTextureSampler.cpp
+++ b/Deprecated/Private/OptiXTextureSampler.cpp
@@ -1,416 +1,416 @@
-#include "OptiXTextureSampler.h"
-
-#include "CoreMinimal.h"
-#include "UObject/ObjectMacros.h"
-#include "Engine/EngineTypes.h"
-
-#include "OptiXModule.h"
-
-// Needed for debugging
-#include <EngineGlobals.h>
-#include <Runtime/Engine/Classes/Engine/Engine.h>
-
-DEFINE_LOG_CATEGORY(OptiXPluginTextureSampler);
-
-void UOptiXTextureSampler::BeginDestroy()
-{
-	DestroyOptiXObject();
-
-	Super::BeginDestroy();
-}
-
-void UOptiXTextureSampler::DestroyOptiXObject()
-{
-	if (NativeTextureSampler != NULL)
-	{
-		try
-		{
-			FOptiXModule::Get().GetOptiXContextManager()->TextureSamplersToDeleteQueue.Enqueue(NativeTextureSampler);
-			//NativeTextureSampler->destroy();
-		}
-		catch (optix::Exception& E)
-		{
-			FString Message = FString(E.getErrorString().c_str());
-			UE_LOG(OptiXPluginTextureSampler, Fatal, TEXT("OptiX Error: %s"), *Message);
-			GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-		}
-	}
-	OptiXBuffer = nullptr; // Don't explicitly destroy the buffer here
-	NativeTextureSampler = NULL;
-}
-
-void UOptiXTextureSampler::Validate()
-{
-	try
-	{
-		NativeTextureSampler->validate();
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginTextureSampler, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-}
-
-void UOptiXTextureSampler::SetMipLevelCount(uint8 NumMipLevels)
-{
-	try
-	{
-		NativeTextureSampler->setMipLevelCount(NumMipLevels);
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginTextureSampler, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-}
-
-uint8 UOptiXTextureSampler::GetMipLevelCount()
-{
-	uint8 Count = 0;
-	try
-	{
-		Count = NativeTextureSampler->getMipLevelCount();
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginTextureSampler, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-	return Count;
-}
-
-void UOptiXTextureSampler::SetArraySize(int32 NumTexturesInArray)
-{
-	try
-	{
-		NativeTextureSampler->setArraySize(NumTexturesInArray);
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginTextureSampler, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-}
-
-int32 UOptiXTextureSampler::GetArraySize()
-{
-	int32 Count = 0;
-	try
-	{
-		Count = NativeTextureSampler->getArraySize();
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginTextureSampler, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-	return Count;
-}
-
-void UOptiXTextureSampler::SetWrapMode(int32 Dim, RTwrapmode Wrapmode)
-{
-	try
-	{
-		NativeTextureSampler->setWrapMode(Dim, Wrapmode);
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginTextureSampler, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-}
-
-RTwrapmode UOptiXTextureSampler::GetWrapMode(int32 Dim)
-{
-	RTwrapmode Mode = RT_WRAP_REPEAT;
-	try
-	{
-		Mode = NativeTextureSampler->getWrapMode(Dim);
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginTextureSampler, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-	return Mode;
-}
-
-void UOptiXTextureSampler::SetFilteringModes(RTfiltermode Minification, RTfiltermode Magnification, RTfiltermode Mipmapping)
-{
-	try
-	{
-		NativeTextureSampler->setFilteringModes(Minification, Magnification, Mipmapping);
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginTextureSampler, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-}
-
-void UOptiXTextureSampler::GetFilteringModes(RTfiltermode & Minification, RTfiltermode & Magnification, RTfiltermode & Mipmapping)
-{
-	try
-	{
-		NativeTextureSampler->getFilteringModes(Minification, Magnification, Mipmapping);
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginTextureSampler, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-}
-
-void UOptiXTextureSampler::SetMaxAnisotropy(float Value)
-{
-	try
-	{
-		NativeTextureSampler->setMaxAnisotropy(Value);
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginTextureSampler, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-}
-
-float UOptiXTextureSampler::GetMaxAnisotropy()
-{
-	float Count = 0;
-	try
-	{
-		Count = NativeTextureSampler->getMaxAnisotropy();
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginTextureSampler, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-	return Count;
-}
-
-void UOptiXTextureSampler::SetMipLevelClamp(float Min, float Max)
-{
-	try
-	{
-		NativeTextureSampler->setMipLevelClamp(Min, Max);
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginTextureSampler, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-}
-
-FVector2D UOptiXTextureSampler::GetMipLevelClamp()
-{
-	float Min;
-	float Max;
-	FVector2D MinMax;
-	try
-	{
-		NativeTextureSampler->getMipLevelClamp(Min, Max);
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginTextureSampler, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-	MinMax.X = Min;
-	MinMax.Y = Max;
-	return MinMax;
-}
-
-void UOptiXTextureSampler::SetMipLevelBias(float Value)
-{
-	try
-	{
-		NativeTextureSampler->setMipLevelBias(Value);
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginTextureSampler, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-}
-
-float UOptiXTextureSampler::GetMipLevelBias()
-{
-	float Bias = 0;
-	try
-	{
-		Bias = NativeTextureSampler->getMipLevelBias();
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginTextureSampler, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-	return Bias;
-}
-
-int32 UOptiXTextureSampler::GetId()
-{
-	int32 Id = 0;
-	try
-	{
-		Id = NativeTextureSampler->getId();
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginTextureSampler, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-	return Id;
-}
-
-void UOptiXTextureSampler::SetReadMode(RTtexturereadmode Readmode)
-{
-	try
-	{
-		NativeTextureSampler->setReadMode(Readmode);
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginTextureSampler, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-}
-
-RTtexturereadmode UOptiXTextureSampler::GetReadMode()
-{
-	RTtexturereadmode Mode = RT_TEXTURE_READ_ELEMENT_TYPE;
-	try
-	{
-		Mode = NativeTextureSampler->getReadMode();
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginTextureSampler, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-	return Mode;
-}
-
-void UOptiXTextureSampler::SetIndexingMode(RTtextureindexmode Mode)
-{
-	try
-	{
-		NativeTextureSampler->setIndexingMode(Mode);
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginTextureSampler, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-}
-
-RTtextureindexmode UOptiXTextureSampler::GetIndexingMode()
-{
-	RTtextureindexmode Mode = RT_TEXTURE_INDEX_NORMALIZED_COORDINATES;
-	try
-	{
-		Mode = NativeTextureSampler->getIndexingMode();
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginTextureSampler, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-	return Mode;
-}
-
-void UOptiXTextureSampler::SetBufferWithTextureIndexAndMiplevel(int32 TextureArrayIndex, int MipLevel, UOptiXBuffer * Buffer)
-{
-	try
-	{
-		NativeTextureSampler->setBuffer(TextureArrayIndex, MipLevel, Buffer->GetNativeBuffer());
-		OptiXBuffer = Buffer;
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginTextureSampler, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-}
-
-UOptiXBuffer * UOptiXTextureSampler::GetBufferByTextureIndexAndMiplevel(int32 TextureArrayIndex, int MipLevel)
-{
-	UE_LOG(OptiXPluginTextureSampler, Error, 
-		TEXT("GetBufferByTextureIndexAndMiplevel not implemented yet. Returning regular buffer."));
-	try
-	{
-		// Just check if it's actually possible to get the buffer - maybe do an equals here:
-		optix::Buffer B = NativeTextureSampler->getBuffer(TextureArrayIndex, MipLevel);
-		if (B != OptiXBuffer->GetNativeBuffer())
-		{
-			UE_LOG(OptiXPluginTextureSampler, Error, TEXT("Buffer Mismatch in Texture Sampler"));
-			//return nullptr;
-		}
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginTextureSampler, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-	return OptiXBuffer;
-}
-
-void UOptiXTextureSampler::SetBuffer(UOptiXBuffer * Buffer)
-{
-	try
-	{
-		NativeTextureSampler->setBuffer(Buffer->GetNativeBuffer());
-		OptiXBuffer = Buffer;
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginTextureSampler, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-}
-
-UOptiXBuffer * UOptiXTextureSampler::GetBuffer()
-{
-	try
-	{
-		// Just check if it's actually possible to get the buffer - maybe do an equals here:
-		optix::Buffer B = NativeTextureSampler->getBuffer();
-		if (B != OptiXBuffer->GetNativeBuffer())
-		{
-			UE_LOG(OptiXPluginTextureSampler, Error, TEXT("Buffer Mismatch in Texture Sampler"));
-			return nullptr;
-		}
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginTextureSampler, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-	return OptiXBuffer;
-}
+#include "OptiXTextureSampler.h"
+
+#include "CoreMinimal.h"
+#include "UObject/ObjectMacros.h"
+#include "Engine/EngineTypes.h"
+
+#include "OptiXModule.h"
+
+// Needed for debugging
+#include <EngineGlobals.h>
+#include <Runtime/Engine/Classes/Engine/Engine.h>
+
+DEFINE_LOG_CATEGORY(OptiXPluginTextureSampler);
+
+void UOptiXTextureSampler::BeginDestroy()
+{
+	DestroyOptiXObject();
+
+	Super::BeginDestroy();
+}
+
+void UOptiXTextureSampler::DestroyOptiXObject()
+{
+	if (NativeTextureSampler != NULL)
+	{
+		try
+		{
+			FOptiXModule::Get().GetOptiXContextManager()->TextureSamplersToDeleteQueue.Enqueue(NativeTextureSampler);
+			//NativeTextureSampler->destroy();
+		}
+		catch (optix::Exception& E)
+		{
+			FString Message = FString(E.getErrorString().c_str());
+			UE_LOG(OptiXPluginTextureSampler, Fatal, TEXT("OptiX Error: %s"), *Message);
+			GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+		}
+	}
+	OptiXBuffer = nullptr; // Don't explicitly destroy the buffer here
+	NativeTextureSampler = NULL;
+}
+
+void UOptiXTextureSampler::Validate()
+{
+	try
+	{
+		NativeTextureSampler->validate();
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginTextureSampler, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+void UOptiXTextureSampler::SetMipLevelCount(uint8 NumMipLevels)
+{
+	try
+	{
+		NativeTextureSampler->setMipLevelCount(NumMipLevels);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginTextureSampler, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+uint8 UOptiXTextureSampler::GetMipLevelCount()
+{
+	uint8 Count = 0;
+	try
+	{
+		Count = NativeTextureSampler->getMipLevelCount();
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginTextureSampler, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return Count;
+}
+
+void UOptiXTextureSampler::SetArraySize(int32 NumTexturesInArray)
+{
+	try
+	{
+		NativeTextureSampler->setArraySize(NumTexturesInArray);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginTextureSampler, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+int32 UOptiXTextureSampler::GetArraySize()
+{
+	int32 Count = 0;
+	try
+	{
+		Count = NativeTextureSampler->getArraySize();
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginTextureSampler, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return Count;
+}
+
+void UOptiXTextureSampler::SetWrapMode(int32 Dim, RTwrapmode Wrapmode)
+{
+	try
+	{
+		NativeTextureSampler->setWrapMode(Dim, Wrapmode);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginTextureSampler, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+RTwrapmode UOptiXTextureSampler::GetWrapMode(int32 Dim)
+{
+	RTwrapmode Mode = RT_WRAP_REPEAT;
+	try
+	{
+		Mode = NativeTextureSampler->getWrapMode(Dim);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginTextureSampler, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return Mode;
+}
+
+void UOptiXTextureSampler::SetFilteringModes(RTfiltermode Minification, RTfiltermode Magnification, RTfiltermode Mipmapping)
+{
+	try
+	{
+		NativeTextureSampler->setFilteringModes(Minification, Magnification, Mipmapping);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginTextureSampler, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+void UOptiXTextureSampler::GetFilteringModes(RTfiltermode & Minification, RTfiltermode & Magnification, RTfiltermode & Mipmapping)
+{
+	try
+	{
+		NativeTextureSampler->getFilteringModes(Minification, Magnification, Mipmapping);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginTextureSampler, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+void UOptiXTextureSampler::SetMaxAnisotropy(float Value)
+{
+	try
+	{
+		NativeTextureSampler->setMaxAnisotropy(Value);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginTextureSampler, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+float UOptiXTextureSampler::GetMaxAnisotropy()
+{
+	float Count = 0;
+	try
+	{
+		Count = NativeTextureSampler->getMaxAnisotropy();
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginTextureSampler, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return Count;
+}
+
+void UOptiXTextureSampler::SetMipLevelClamp(float Min, float Max)
+{
+	try
+	{
+		NativeTextureSampler->setMipLevelClamp(Min, Max);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginTextureSampler, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+FVector2D UOptiXTextureSampler::GetMipLevelClamp()
+{
+	float Min;
+	float Max;
+	FVector2D MinMax;
+	try
+	{
+		NativeTextureSampler->getMipLevelClamp(Min, Max);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginTextureSampler, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	MinMax.X = Min;
+	MinMax.Y = Max;
+	return MinMax;
+}
+
+void UOptiXTextureSampler::SetMipLevelBias(float Value)
+{
+	try
+	{
+		NativeTextureSampler->setMipLevelBias(Value);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginTextureSampler, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+float UOptiXTextureSampler::GetMipLevelBias()
+{
+	float Bias = 0;
+	try
+	{
+		Bias = NativeTextureSampler->getMipLevelBias();
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginTextureSampler, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return Bias;
+}
+
+int32 UOptiXTextureSampler::GetId()
+{
+	int32 Id = 0;
+	try
+	{
+		Id = NativeTextureSampler->getId();
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginTextureSampler, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return Id;
+}
+
+void UOptiXTextureSampler::SetReadMode(RTtexturereadmode Readmode)
+{
+	try
+	{
+		NativeTextureSampler->setReadMode(Readmode);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginTextureSampler, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+RTtexturereadmode UOptiXTextureSampler::GetReadMode()
+{
+	RTtexturereadmode Mode = RT_TEXTURE_READ_ELEMENT_TYPE;
+	try
+	{
+		Mode = NativeTextureSampler->getReadMode();
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginTextureSampler, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return Mode;
+}
+
+void UOptiXTextureSampler::SetIndexingMode(RTtextureindexmode Mode)
+{
+	try
+	{
+		NativeTextureSampler->setIndexingMode(Mode);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginTextureSampler, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+RTtextureindexmode UOptiXTextureSampler::GetIndexingMode()
+{
+	RTtextureindexmode Mode = RT_TEXTURE_INDEX_NORMALIZED_COORDINATES;
+	try
+	{
+		Mode = NativeTextureSampler->getIndexingMode();
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginTextureSampler, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return Mode;
+}
+
+void UOptiXTextureSampler::SetBufferWithTextureIndexAndMiplevel(int32 TextureArrayIndex, int MipLevel, UOptiXBuffer * Buffer)
+{
+	try
+	{
+		NativeTextureSampler->setBuffer(TextureArrayIndex, MipLevel, Buffer->GetNativeBuffer());
+		OptiXBuffer = Buffer;
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginTextureSampler, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+UOptiXBuffer * UOptiXTextureSampler::GetBufferByTextureIndexAndMiplevel(int32 TextureArrayIndex, int MipLevel)
+{
+	UE_LOG(OptiXPluginTextureSampler, Error, 
+		TEXT("GetBufferByTextureIndexAndMiplevel not implemented yet. Returning regular buffer."));
+	try
+	{
+		// Just check if it's actually possible to get the buffer - maybe do an equals here:
+		optix::Buffer B = NativeTextureSampler->getBuffer(TextureArrayIndex, MipLevel);
+		if (B != OptiXBuffer->GetNativeBuffer())
+		{
+			UE_LOG(OptiXPluginTextureSampler, Error, TEXT("Buffer Mismatch in Texture Sampler"));
+			//return nullptr;
+		}
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginTextureSampler, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return OptiXBuffer;
+}
+
+void UOptiXTextureSampler::SetBuffer(UOptiXBuffer * Buffer)
+{
+	try
+	{
+		NativeTextureSampler->setBuffer(Buffer->GetNativeBuffer());
+		OptiXBuffer = Buffer;
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginTextureSampler, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+UOptiXBuffer * UOptiXTextureSampler::GetBuffer()
+{
+	try
+	{
+		// Just check if it's actually possible to get the buffer - maybe do an equals here:
+		optix::Buffer B = NativeTextureSampler->getBuffer();
+		if (B != OptiXBuffer->GetNativeBuffer())
+		{
+			UE_LOG(OptiXPluginTextureSampler, Error, TEXT("Buffer Mismatch in Texture Sampler"));
+			return nullptr;
+		}
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginTextureSampler, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+	return OptiXBuffer;
+}
diff --git a/Source/OptiX/Private/OptiXTransform.cpp b/Deprecated/Private/OptiXTransform.cpp
similarity index 96%
rename from Source/OptiX/Private/OptiXTransform.cpp
rename to Deprecated/Private/OptiXTransform.cpp
index a361e5036fa9662ce750f67c34e35bfb114b16b0..836353b6c1aea200f6fc98af8ffc7f52d63416ac 100644
--- a/Source/OptiX/Private/OptiXTransform.cpp
+++ b/Deprecated/Private/OptiXTransform.cpp
@@ -1,143 +1,143 @@
-#include "OptiXTransform.h"
-
-#include "CoreMinimal.h"
-#include "UObject/ObjectMacros.h"
-#include "Engine/EngineTypes.h"
-
-#include "OptiXModule.h"
-
-// Needed for debugging
-#include <EngineGlobals.h>
-#include <Runtime/Engine/Classes/Engine/Engine.h>
-
-DEFINE_LOG_CATEGORY(OptiXPluginTransform);
-
-void UOptiXTransform::BeginDestroy()
-{
-	// Tell optix to clean up
-	UE_LOG(LogTemp, Warning, TEXT("OptiX Transform BeginDestroy"));
-
-	DestroyOptiXObject();
-	Super::BeginDestroy();
-}
-
-void UOptiXTransform::DestroyOptiXObject()
-{
-	if (NativeTransform != NULL)
-	{
-		FOptiXModule::Get().GetOptiXContextManager()->TransformsToDeleteQueue.Enqueue(NativeTransform);
-		//NativeTransform->destroy();
-	}
-
-	OptiXChild = nullptr; // Don't explicitly delete the child, maybe we should TODO
-	NativeTransform = NULL;
-}
-
-void UOptiXTransform::UpdateTransform()
-{
-	check(IsInRenderingThread());
-	try
-	{
-		// According to the optix doc false == row major
-		FMatrix Inverse = TransformMatrix.Inverse();
-		NativeTransform->setMatrix(true, &TransformMatrix.M[0][0], &Inverse.M[0][0]); // TODO - find out if false or true is column or row major
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginTransform, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-
-}
-
-void UOptiXTransform::SetChild(UObject * Child)
-{
-	if (UOptiXGeometryGroup* GeomGroup = Cast<UOptiXGeometryGroup>(Child))
-	{
-		NativeTransform->setChild(GeomGroup->GetNativeGroup());
-		OptiXChild = Child;
-	}
-	else if (UOptiXGeometryInstance* GeomInstance = Cast<UOptiXGeometryInstance>(Child))
-	{
-		NativeTransform->setChild(GeomInstance->GetNativeInstance());
-		OptiXChild = Child;
-	}
-	else return;
-}
-
-RTobjecttype UOptiXTransform::GetChildType()
-{
-	return NativeTransform->getChildType();
-}
-
-UObject * UOptiXTransform::GetChild()
-{
-	return OptiXChild;
-}
-
-void UOptiXTransform::SetMatrix(FMatrix Matrix)
-{	
-	// TODO This should maybe be a critical section?
-	TransformMatrix = Matrix;
-}
-
-
-void UOptiXTransform::SetMatrixImmediate(FMatrix Matrix)
-{
-	// WARNING! NON THREAD SAFE
-	try
-	{
-		// According to the optix doc false == row major
-		TransformMatrix = Matrix;
-		FMatrix Inverse = TransformMatrix.Inverse();
-		NativeTransform->setMatrix(true, &TransformMatrix.M[0][0], &Inverse.M[0][0]); // TODO - find out if false or true is column or row major
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginTransform, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-}
-
-
-FMatrix UOptiXTransform::GetMatrix()
-{
-	return TransformMatrix;
-}
-
-void UOptiXTransform::SetMotionRange(float TimeBegin, float TimeEnd)
-{
-	try
-	{
-		NativeTransform->setMotionRange(TimeBegin, TimeEnd);
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginTransform, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-}
-
-FVector2D UOptiXTransform::GetMotionRange()
-{
-	FVector2D V = FVector2D();
-	float X;
-	float Y;
-	try
-	{
-		NativeTransform->getMotionRange(X, Y);
-		V.X = X;
-		V.Y = Y;
-	}
-	catch (optix::Exception& E)
-	{
-		FString Message = FString(E.getErrorString().c_str());
-		UE_LOG(OptiXPluginTransform, Error, TEXT("OptiX Error: %s"), *Message);
-		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
-	}
-
-	return V;
-}
+#include "OptiXTransform.h"
+
+#include "CoreMinimal.h"
+#include "UObject/ObjectMacros.h"
+#include "Engine/EngineTypes.h"
+
+#include "OptiXModule.h"
+
+// Needed for debugging
+#include <EngineGlobals.h>
+#include <Runtime/Engine/Classes/Engine/Engine.h>
+
+DEFINE_LOG_CATEGORY(OptiXPluginTransform);
+
+void UOptiXTransform::BeginDestroy()
+{
+	// Tell optix to clean up
+	UE_LOG(LogTemp, Warning, TEXT("OptiX Transform BeginDestroy"));
+
+	DestroyOptiXObject();
+	Super::BeginDestroy();
+}
+
+void UOptiXTransform::DestroyOptiXObject()
+{
+	if (NativeTransform != NULL)
+	{
+		FOptiXModule::Get().GetOptiXContextManager()->TransformsToDeleteQueue.Enqueue(NativeTransform);
+		//NativeTransform->destroy();
+	}
+
+	OptiXChild = nullptr; // Don't explicitly delete the child, maybe we should TODO
+	NativeTransform = NULL;
+}
+
+void UOptiXTransform::UpdateTransform()
+{
+	check(IsInRenderingThread());
+	try
+	{
+		// According to the optix doc false == row major
+		FMatrix Inverse = TransformMatrix.Inverse();
+		NativeTransform->setMatrix(true, &TransformMatrix.M[0][0], &Inverse.M[0][0]); // TODO - find out if false or true is column or row major
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginTransform, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+
+}
+
+void UOptiXTransform::SetChild(UObject * Child)
+{
+	if (UOptiXGeometryGroup* GeomGroup = Cast<UOptiXGeometryGroup>(Child))
+	{
+		NativeTransform->setChild(GeomGroup->GetNativeGroup());
+		OptiXChild = Child;
+	}
+	else if (UOptiXGeometryInstance* GeomInstance = Cast<UOptiXGeometryInstance>(Child))
+	{
+		NativeTransform->setChild(GeomInstance->GetNativeInstance());
+		OptiXChild = Child;
+	}
+	else return;
+}
+
+RTobjecttype UOptiXTransform::GetChildType()
+{
+	return NativeTransform->getChildType();
+}
+
+UObject * UOptiXTransform::GetChild()
+{
+	return OptiXChild;
+}
+
+void UOptiXTransform::SetMatrix(FMatrix Matrix)
+{	
+	// TODO This should maybe be a critical section?
+	TransformMatrix = Matrix;
+}
+
+
+void UOptiXTransform::SetMatrixImmediate(FMatrix Matrix)
+{
+	// WARNING! NON THREAD SAFE
+	try
+	{
+		// According to the optix doc false == row major
+		TransformMatrix = Matrix;
+		FMatrix Inverse = TransformMatrix.Inverse();
+		NativeTransform->setMatrix(true, &TransformMatrix.M[0][0], &Inverse.M[0][0]); // TODO - find out if false or true is column or row major
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginTransform, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+
+FMatrix UOptiXTransform::GetMatrix()
+{
+	return TransformMatrix;
+}
+
+void UOptiXTransform::SetMotionRange(float TimeBegin, float TimeEnd)
+{
+	try
+	{
+		NativeTransform->setMotionRange(TimeBegin, TimeEnd);
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginTransform, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+}
+
+FVector2D UOptiXTransform::GetMotionRange()
+{
+	FVector2D V = FVector2D();
+	float X;
+	float Y;
+	try
+	{
+		NativeTransform->getMotionRange(X, Y);
+		V.X = X;
+		V.Y = Y;
+	}
+	catch (optix::Exception& E)
+	{
+		FString Message = FString(E.getErrorString().c_str());
+		UE_LOG(OptiXPluginTransform, Error, TEXT("OptiX Error: %s"), *Message);
+		GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("OptiX Error %s"), *Message));
+	}
+
+	return V;
+}
diff --git a/Source/OptiX/Public/OptiXAcceleration.h b/Deprecated/Public/OptiXAcceleration.h
similarity index 96%
rename from Source/OptiX/Public/OptiXAcceleration.h
rename to Deprecated/Public/OptiXAcceleration.h
index eadfcc7783761f61a3a9f11faeb3a5c3f1207c13..ce4d70d38cc342c26c54f82daf5ec833c7717dbd 100644
--- a/Source/OptiX/Public/OptiXAcceleration.h
+++ b/Deprecated/Public/OptiXAcceleration.h
@@ -1,69 +1,69 @@
-#pragma once
-
-#include "CoreMinimal.h"
-#include "UObject/ObjectMacros.h"
-#include "Engine/EngineTypes.h"
-
-#include "OptiXIncludes.h"
-
-#include "OptiXAcceleration.generated.h"
-
-DECLARE_LOG_CATEGORY_EXTERN(OptiXPluginAcceleration, Log, All);
-
-UCLASS(hidecategories = Object, BlueprintType)
-class OPTIX_API UOptiXAcceleration : public UObject
-{
-	GENERATED_BODY()
-
-public:
-
-	virtual void BeginDestroy() override;
-
-	optix::Acceleration GetNativeAcceleration()
-	{
-		return NativeAcceleration;
-	}
-
-	void SetNativeAcceleration(optix::Acceleration A)
-	{
-		NativeAcceleration = A;
-	}
-
-	void DestroyOptiXObject();
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXAcceleration")
-		void Validate();
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXAcceleration")
-		void MarkDirty();
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXAcceleration")
-		bool IsDirty();
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXAcceleration")
-		void SetProperty(FString Name, FString Value);
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXAcceleration")
-		FString GetProperty(FString Name);
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXAcceleration")
-		void SetBuilder(FString Builder);
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXAcceleration")
-		FString GetBuilder();
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXAcceleration")
-		void SetTraverser(FString Traverser);
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXAcceleration")
-		FString GetTraverser();
-
-	RTsize GetDataSize();
-	void GetData(void* Data);
-	void SetData(void* Data, RTsize Size);
-
-protected:
-
-	optix::Acceleration NativeAcceleration;
-
-};
+#pragma once
+
+#include "CoreMinimal.h"
+#include "UObject/ObjectMacros.h"
+#include "Engine/EngineTypes.h"
+
+#include "OptiXIncludes.h"
+
+#include "OptiXAcceleration.generated.h"
+
+DECLARE_LOG_CATEGORY_EXTERN(OptiXPluginAcceleration, Log, All);
+
+UCLASS(hidecategories = Object, BlueprintType)
+class OPTIX_API UOptiXAcceleration : public UObject
+{
+	GENERATED_BODY()
+
+public:
+
+	virtual void BeginDestroy() override;
+
+	optix::Acceleration GetNativeAcceleration()
+	{
+		return NativeAcceleration;
+	}
+
+	void SetNativeAcceleration(optix::Acceleration A)
+	{
+		NativeAcceleration = A;
+	}
+
+	void DestroyOptiXObject();
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXAcceleration")
+		void Validate();
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXAcceleration")
+		void MarkDirty();
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXAcceleration")
+		bool IsDirty();
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXAcceleration")
+		void SetProperty(FString Name, FString Value);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXAcceleration")
+		FString GetProperty(FString Name);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXAcceleration")
+		void SetBuilder(FString Builder);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXAcceleration")
+		FString GetBuilder();
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXAcceleration")
+		void SetTraverser(FString Traverser);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXAcceleration")
+		FString GetTraverser();
+
+	RTsize GetDataSize();
+	void GetData(void* Data);
+	void SetData(void* Data, RTsize Size);
+
+protected:
+
+	optix::Acceleration NativeAcceleration;
+
+};
diff --git a/Source/OptiX/Public/OptiXBuffer.h b/Deprecated/Public/OptiXBuffer.h
similarity index 96%
rename from Source/OptiX/Public/OptiXBuffer.h
rename to Deprecated/Public/OptiXBuffer.h
index 5c6bc3023b9a9476818a39841585aad7e5b41ef6..b5fc0a3c21a4e01518bced31ad8de1885e1c3f54 100644
--- a/Source/OptiX/Public/OptiXBuffer.h
+++ b/Deprecated/Public/OptiXBuffer.h
@@ -1,173 +1,171 @@
-#pragma once
-
-#include "CoreMinimal.h"
-#include "UObject/ObjectMacros.h"
-#include "Engine/EngineTypes.h"
-
-#include "OptiXIncludes.h"
-
-#include "OptiXDeclarations.h"
-
-#include "OptiXBuffer.generated.h"
-
-DECLARE_LOG_CATEGORY_EXTERN(OptiXPluginBuffer, Log, All);
-
-
-// We probably don't need such huge buffers anyway (way too slow etc), so int32 *should* be enough for everything.
-// That way, the whole thing becomes blueprint-able
-
-
-struct RTsize2
-{
-public:
-	RTsize X;
-	RTsize Y;
-};
-
-struct RTsize3
-{
-public:
-	RTsize X;
-	RTsize Y;
-	RTsize Z;
-};
-
-
-/*
-A Wrapper for the optix::Buffer class. Keep this as simple wrapper for now, 
-but it should probably be changed to allow Unreal to access the buffer data
-in a more native format.
-*/
-
-UCLASS(hidecategories = Object, BlueprintType)
-class OPTIX_API UOptiXBuffer : public UObject
-{
-	GENERATED_BODY() // Apparently GENERATED_UCLASS_BODY is deprecated?
-
-public:
-
-	virtual void BeginDestroy() override;
-
-	optix::Buffer GetNativeBuffer()
-	{
-		return NativeBuffer;
-	}
-
-	void SetBuffer(optix::Buffer B)
-	{
-		NativeBuffer = B;
-	}
-
-	void DestroyOptiXObject();
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXBuffer")
-	void Validate();
-
-	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXBuffer")
-	void SetFormat(RTformat Format); // TODO Enum
-
-	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXBuffer")
-	RTformat GetFormat();
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXBuffer")
-	void SetElementSize(int32 Size);
-
-	void SetElementSizeNative(RTsize Size);
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXBuffer")
-	int32 GetElementSize();
-
-	RTsize GetElementSizeNative();
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXBuffer")
-	void MarkDirty();
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXBuffer")
-	void SetSize1D(int32 Width);
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXBuffer")
-	int32 GetSize1D();
-
-
-	void SetSize1DNative(RTsize Width);
-	RTsize GetSize1DNative();
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXBuffer")
-	int32 GetMipLevelSize1D(uint8 Level);
-
-	RTsize GetMipLevelSize1DNative(uint8 Level);
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXBuffer")
-	void SetSize2D(int32 Width, int32 Height);
-	
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXBuffer")
-	FIntPoint GetSize2D();
-
-	void SetSize2DNative(RTsize Width, RTsize Height);
-	RTsize2 GetSize2DNative();
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXBuffer")
-	FIntPoint GetMipLevelSize2D(uint8 Level);
-
-	RTsize2 GetMipLevelSize2DNative(uint8 Level);
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXBuffer")
-	void SetSize3D(int32 Width, int32 Height, int32 Depth);
-	FIntVector GetSize3D();
-
-	void SetSize3DNative(RTsize Width, RTsize Height, RTsize Depth);
-	RTsize3 GetSize3DNative();
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXBuffer")
-	FIntVector GetMipLevelSize3D(uint8 Level);
-
-
-	RTsize3 GetMipLevelSize3DNative(uint8 Level);
-
-	// No support for more than 3 dimensions for now!
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXBuffer")
-	void SetMipLevelCount(uint8 Count);
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXBuffer")
-	uint8 GetMipLevelCount();
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXBuffer")
-	int GetId();
-
-	// TODO: LOOK INTO WHAT THIS RETURNS AND IF WE NEED IT! RETURNS A void* ORIGINALLY
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXBuffer")
-	void Map(uint8 Level = 0, uint8 MapFlags = 2);
-
-	void* MapNative(uint8 Level = 0, uint8 MapFlags = RT_BUFFER_MAP_READ_WRITE, void* UserOwned = 0);
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXBuffer")
-	void Unmap(uint8 Level = 0);
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXBuffer")
-	void BindProgressiveStream(UOptiXBuffer* Source);
-
-	void GetProgressiveUpdateReady(int* Ready, unsigned int* SubframeCount, unsigned int* MaxSubframes);
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXBuffer")
-	bool GetProgressiveUpdateReady();
-
-	void GetDevicePointer(int32 OptiXDeviceOrdinal, void** DevicePointer);
-	void* GetDevicePointer(int32 OptiXDeviceOrdinal);
-
-	void SetDevicePointer(int32 OptiXDeviceOrdinal, void* DevicePointer);
-
-	bool GetProgressiveUpdateReady(unsigned int& SubframeCount);
-	bool GetProgressiveUpdateReady(unsigned int& SubframeCount, unsigned int& MaxSubframes);
-
-	void SetAttribute(RTbufferattribute Attrib, RTsize Size, void *P);
-	void GetAttribute(RTbufferattribute Attrib, RTsize Size, void *P);
-
-	FString Name; // TODO DEBUG ONLY
-
-protected:
-
-	optix::Buffer NativeBuffer;
-
-
+#pragma once
+
+#include "CoreMinimal.h"
+#include "UObject/ObjectMacros.h"
+#include "Engine/EngineTypes.h"
+
+#include "OptiXIncludes.h"
+
+#include "OptiXBuffer.generated.h"
+
+DECLARE_LOG_CATEGORY_EXTERN(OptiXPluginBuffer, Log, All);
+
+
+// We probably don't need such huge buffers anyway (way too slow etc), so int32 *should* be enough for everything.
+// That way, the whole thing becomes blueprint-able
+
+
+struct RTsize2
+{
+public:
+	RTsize X;
+	RTsize Y;
+};
+
+struct RTsize3
+{
+public:
+	RTsize X;
+	RTsize Y;
+	RTsize Z;
+};
+
+
+/*
+A Wrapper for the optix::Buffer class. Keep this as simple wrapper for now, 
+but it should probably be changed to allow Unreal to access the buffer data
+in a more native format.
+*/
+
+UCLASS(hidecategories = Object, BlueprintType)
+class OPTIX_API UOptiXBuffer : public UObject
+{
+	GENERATED_BODY() // Apparently GENERATED_UCLASS_BODY is deprecated?
+
+public:
+
+	virtual void BeginDestroy() override;
+
+	optix::Buffer GetNativeBuffer()
+	{
+		return NativeBuffer;
+	}
+
+	void SetBuffer(optix::Buffer B)
+	{
+		NativeBuffer = B;
+	}
+
+	void DestroyOptiXObject();
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXBuffer")
+	void Validate();
+
+	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXBuffer")
+	void SetFormat(RTformat Format); // TODO Enum
+
+	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXBuffer")
+	RTformat GetFormat();
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXBuffer")
+	void SetElementSize(int32 Size);
+
+	void SetElementSizeNative(RTsize Size);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXBuffer")
+	int32 GetElementSize();
+
+	RTsize GetElementSizeNative();
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXBuffer")
+	void MarkDirty();
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXBuffer")
+	void SetSize1D(int32 Width);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXBuffer")
+	int32 GetSize1D();
+
+
+	void SetSize1DNative(RTsize Width);
+	RTsize GetSize1DNative();
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXBuffer")
+	int32 GetMipLevelSize1D(uint8 Level);
+
+	RTsize GetMipLevelSize1DNative(uint8 Level);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXBuffer")
+	void SetSize2D(int32 Width, int32 Height);
+	
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXBuffer")
+	FIntPoint GetSize2D();
+
+	void SetSize2DNative(RTsize Width, RTsize Height);
+	RTsize2 GetSize2DNative();
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXBuffer")
+	FIntPoint GetMipLevelSize2D(uint8 Level);
+
+	RTsize2 GetMipLevelSize2DNative(uint8 Level);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXBuffer")
+	void SetSize3D(int32 Width, int32 Height, int32 Depth);
+	FIntVector GetSize3D();
+
+	void SetSize3DNative(RTsize Width, RTsize Height, RTsize Depth);
+	RTsize3 GetSize3DNative();
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXBuffer")
+	FIntVector GetMipLevelSize3D(uint8 Level);
+
+
+	RTsize3 GetMipLevelSize3DNative(uint8 Level);
+
+	// No support for more than 3 dimensions for now!
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXBuffer")
+	void SetMipLevelCount(uint8 Count);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXBuffer")
+	uint8 GetMipLevelCount();
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXBuffer")
+	int GetId();
+
+	// TODO: LOOK INTO WHAT THIS RETURNS AND IF WE NEED IT! RETURNS A void* ORIGINALLY
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXBuffer")
+	void Map(uint8 Level = 0, uint8 MapFlags = 2);
+
+	void* MapNative(uint8 Level = 0, uint8 MapFlags = RT_BUFFER_MAP_READ_WRITE, void* UserOwned = 0);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXBuffer")
+	void Unmap(uint8 Level = 0);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXBuffer")
+	void BindProgressiveStream(UOptiXBuffer* Source);
+
+	void GetProgressiveUpdateReady(int* Ready, unsigned int* SubframeCount, unsigned int* MaxSubframes);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXBuffer")
+	bool GetProgressiveUpdateReady();
+
+	void GetDevicePointer(int32 OptiXDeviceOrdinal, void** DevicePointer);
+	void* GetDevicePointer(int32 OptiXDeviceOrdinal);
+
+	void SetDevicePointer(int32 OptiXDeviceOrdinal, void* DevicePointer);
+
+	bool GetProgressiveUpdateReady(unsigned int& SubframeCount);
+	bool GetProgressiveUpdateReady(unsigned int& SubframeCount, unsigned int& MaxSubframes);
+
+	void SetAttribute(RTbufferattribute Attrib, RTsize Size, void *P);
+	void GetAttribute(RTbufferattribute Attrib, RTsize Size, void *P);
+
+	FString Name; // TODO DEBUG ONLY
+
+protected:
+
+	optix::Buffer NativeBuffer;
+
+
 };
\ No newline at end of file
diff --git a/Source/OptiX/Public/OptiXContext.h b/Deprecated/Public/OptiXContext.h
similarity index 97%
rename from Source/OptiX/Public/OptiXContext.h
rename to Deprecated/Public/OptiXContext.h
index 500342e92ab3b83e919c2b00d8c221ee8e1c0200..7f2149242a84258b1be8748cd3eaa884dc314149 100644
--- a/Source/OptiX/Public/OptiXContext.h
+++ b/Deprecated/Public/OptiXContext.h
@@ -1,448 +1,448 @@
-#pragma once
-
-#include "CoreMinimal.h"
-#include "UObject/ObjectMacros.h"
-#include "Engine/EngineTypes.h"
-
-#include "OptiXIncludes.h"
-
-#include "OptiXGeometry.h"
-#include "OptiXGeometryInstance.h"
-#include "OptiXGeometryGroup.h"
-#include "OptiXMaterial.h"
-#include "OptiXBuffer.h"
-#include "OptiXProgram.h"
-#include "OptiXTextureSampler.h"
-#include "OptiXAcceleration.h"
-#include "OptiXTransform.h"
-#include "OptiXGroup.h"
-
-
-#include "OptiXContext.generated.h"
-
-DECLARE_LOG_CATEGORY_EXTERN(OptiXPluginContext, Log, All);
-
-
-UCLASS(hidecategories = Object, BlueprintType)
-class OPTIX_API UOptiXContext : public UObject
-{
-	GENERATED_BODY() // Apparently GENERATED_UCLASS_BODY is deprecated?
-
-	// We can have a lot of functions here which can interact with OptiX. 
-	// As mentioned in the OptiXObjects file, it might be really worth to keep those in the backend (FOptiXContextInstance e.g.)
-	// The real issue is kind of the nature of the optix framework, as the variables can be completely arbitrary and dependent on the
-	// shaders. Therefore there's no fixed set of UPROPERTYs which could act as an interface.
-	// I *could* write another layer here which caches the variables in a TArray and then pushes them through, but this would require 
-	// a lot of type-magic as the variables can be any type pretty much.
-
-	// Setter Functions - apparently overloading isn't actually possible so I need to restructure EVERYTHING again
-	// Only do the important ones for now as I might need to scrap that again.
-public:
-
-	UOptiXContext(const FObjectInitializer& ObjectInitializer);
-
-	// Unreal Constructors are scary, evil and do their own magic in the background.
-	// Use Init functions for everything until one day I maybe understand what Unreal is doing exactly...
-	optix::Context Init();
-
-	virtual void BeginDestroy() override;
-
-	// Called by the rendering thread to savely update the variables that need to be updated each tick.
-	// This is mostly just going to be the transforms.
-	void UpdateVariables();
-
-	// TODO Begin play?
-
-	// TODO 
-	optix::Context GetNativeContext()
-	{
-		return NativeContext;
-	}
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
-	void Reset();
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
-	UOptiXGeometry* CreateGeometry();
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
-	UOptiXMaterial* CreateMaterial();
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
-	UOptiXGeometryInstance* CreateGeometryInstance(UOptiXGeometry* Geometry, TArray<UOptiXMaterial*> Materials);
-
-	UOptiXGeometryInstance* CreateGeometryInstance(UOptiXGeometry* Geometry, UOptiXMaterial* Material);
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
-	UOptiXGeometryGroup* CreateGeometryGroup();
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
-	UOptiXGroup* CreateGroup();
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
-	UOptiXTransform* CreateTransform();
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
-	UOptiXAcceleration* CreateAcceleration(FString Builder);
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
-	void SetFloat(FString string, float Var);
-
-	//void SetFloat2D(FString string, FVector2D Var)
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
-	void SetFloat2D(FString string, float Var1, float Var2);
-
-	// 3D Float
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
-	void SetFloat3DVector(FString string, FVector Var);
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
-	void SetFloat3D(FString string, float Var1, float Var2, float Var3);
-
-	// 4D Float
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
-	void SetFloat4DVector(FString string, FVector4 Var);
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
-	void SetFloat4D(FString string, float Var1, float Var2, float Var3, float Var4);
-
-
-	// 1D Int
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
-	void SetInt(FString string, int32 Var);
-
-	// 2D Int - wow Unreal your naming scheme is really top notch...
-	//void SetInt2D(FString string, FIntPoint Var)
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
-	void SetInt2D(FString string, int32 Var1, int32 Var2);
-
-	// 3D Int
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
-	void SetInt3DVector(FString string, FIntVector Var);
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
-	void SetInt3D(FString string, int32 Var1, int32 Var2, int32 Var3);
-
-	// 4D Int
-	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
-	//void SetInt4DVector(FString string, FIntVector4 Var);
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
-	void SetInt4D(FString string, int32 Var1, int32 Var2, int32 Var3, int32 Var4);
-
-	// 1D Uint
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
-	void SetUint(FString string, uint8 Var);
-
-	// 2D Uint - wow Unreal your naming scheme is really top notch...
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
-	void SetUint2D(FString string, uint8 Var1, uint8 Var2);
-
-	// 3D Uint
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
-	void SetUint3D(FString string, uint8 Var1, uint8 Var2, uint8 Var3);
-
-	// 4D Uint
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
-	void SetUint4D(FString string, uint8 Var1, uint8 Var2, uint8 Var3, uint8 Var4);
-
-
-	// Matrices - careful Unreal uses ROW_MAJOR LAYOUT
-	// TODO They will be a pain
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
-	void SetMatrix(FString string, FMatrix Matrix);
-
-
-	////
-	//// Getters (gotta love wrappers)
-	////
-
-	// Can't overload return type so this is going to be ugly
-
-	// Floats
-	// 1D Float
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
-	float GetFloat(FString string);
-
-	// 2D Float
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
-	FVector2D GetFloat2D(FString string);
-
-	// 3D Float
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
-	FVector GetFloat3D(FString string);
-
-	// 4D Float
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
-	FVector4 GetFloat4D(FString string);
-
-
-	//// Ints
-
-	// 1D Int
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
-	int32 GetInt(FString string);
-
-	// 2D Int - wow Unreal your naming scheme is really top notch...
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
-	FIntPoint GetInt2D(FString string);
-
-	// 3D Int
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
-	FIntVector GetInt3D(FString string);
-
-	// 4D Int
-	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
-	//FIntVector4 GetInt4D(FString string);
-
-
-
-	//// UInts are bad
-
-	// 1D UInt
-	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
-	//uint8 GetUint(FString string);
-
-	//// 2D UInt
-	//// Have to do it per reference, TODO test me
-	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
-	//void GetUint2D(FString& string, uint8& Var1, uint8& Var2);
-
-	//// 3D UInt
-	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
-	//void GetUint3D(FString string, uint8& Var1, uint8& Var2, uint8& Var3);
-
-	//// 4D UInt
-	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
-	//FUintVector4 GetUint4D(FString string);
-
-
-	//// BUFFER FUNCTIONALITY
-
-	// A lot of those are using higher uints and ints, which is a bit iffy in blueprints.
-	// Keep the higher types as C++ functions.
-
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
-	void Validate();
-
-	// Lots of "Create" methods now, dunno if I really want them here or in the manager
-	// - they shouldn't be needlessly exposed outside of this plugin.
-	// CreateBuffer etc
-
-	uint32 GetDeviceCount();
-	FString GetDeviceName(int32 Ordinal);
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
-	void SetStackSize(int32 StackSize);
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
-	int32 GetStackSize();
-
-	void SetStackSize64(uint64 StackSize);
-	uint64 GetStackSize64();
-
-	// TODO TimeoutCallback
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
-	void SetEntryPointCount(int32 NumEntryPoints);
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
-	int32 GetEntryPointCount();
-
-
-	// Program wrapper needed!
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
-	void SetRayGenerationProgram(int32 EntryPointIndex, UOptiXProgram* Program);
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
-	UOptiXProgram* GetRayGenerationProgram(int32 EntryPointIndex);
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
-	void SetExceptionProgram(int32 EntryPointIndex, UOptiXProgram* Program);
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
-	UOptiXProgram* GetExceptionProgram(int32 EntryPointIndex);
-
-	// TODO RTexception
-	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
-	void SetExceptionEnabled(RTexception Exception, bool Enabled);
-
-	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
-	bool GetExceptionEnabled(RTexception Exception);
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
-	void SetRayTypeCount(int32 NumRayTypes);
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
-	int32 GetRayTypeCount();
-
-	// TODO
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
-	void SetMissProgram(int32 RayTypeIndex, UOptiXProgram* Program);
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
-	UOptiXProgram* GetMissProgram(int32 RayTypeIndex);
-
-	// Do not expose those for now!
-	void Launch(int32 EntryPointIndex, uint64 ImageWidth);
-	void Launch(int32 EntryPointIndex, uint64 ImageWidth, uint64 ImageHeight);
-	void Launch(int32 EntryPointIndex, uint64 ImageWidth, uint64 ImageHeight, uint64 ImageDepth);
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
-	void SetBuffer(FString Name, UOptiXBuffer* Buffer);
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
-	void SetGeometryGroup(FString Name, UOptiXGeometryGroup* GeoGroup);
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
-	void SetGroup(FString Name, UOptiXGroup* Group);
-
-	// TODO: Create Program Functions
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
-	UOptiXProgram* CreateProgramFromPTXFile(FString Path, FString Name);
-
-	// TODO: Create Buffer Functions
-
-	// General, non-blueprint buffer function
-
-	UOptiXBuffer* CreateBuffer(uint8 Type, RTformat Format, RTsize Width);
-	UOptiXBuffer* CreateBuffer(uint8 Type, RTformat Format, RTsize Width, RTsize Height );
-	UOptiXBuffer* CreateBuffer(uint8 Type, RTformat Format, RTsize Width, RTsize Height, RTsize Depth );
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
-	UOptiXBuffer* CreateBufferSimple(uint8 Type);
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
-	UOptiXBuffer* CreateBufferUByte(uint8 Type);
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
-	UOptiXBuffer* CreateBufferUByte1D(uint8 Type, int32 Width);
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
-	UOptiXBuffer* CreateBufferUByte2D(uint8 Type, int32 Width, int32 Height);
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
-	UOptiXBuffer* CreateBufferUByte3D(uint8 Type, int32 Width, int32 Height, int32 Depth);
-
-	// More Buffer Functions to avoid huge enums in blueprints:
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
-	UOptiXBuffer* CreateOutputBufferColor(int32 Width, int32 Height);
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
-	UOptiXBuffer* CreateOutputBufferUByte3D(int32 Width, int32 Height, int32 Depth);
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
-	UOptiXBuffer* CreateOutputBufferDepth(int32 Width, int32 Height);
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
-	UOptiXBuffer* CreateOutputBufferIntersections(int32 Width, int32 Height);
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
-	UOptiXBuffer* CreateInputBufferFloat(int32 Width);
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
-	UOptiXBuffer* CreateInputBufferFloat2D(int32 Width, int32 Height);
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
-	UOptiXBuffer* CreateInputBufferFloat3D(int32 Width, int32 Height, int32 Depth);
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
-	UOptiXBuffer* CreateCubemapBuffer(int32 Width, int32 Height);
-
-	// Texture Sampler
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
-	UOptiXTextureSampler* CreateTextureSampler();
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
-	void SetTextureSampler(FString Name, UOptiXTextureSampler* Sampler);
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
-	void SetSkybox(FString Name, UOptiXTextureSampler* Sampler);
-
-	// Getters
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
-	UOptiXBuffer* GetBuffer(FString Name);
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
-	UOptiXGeometryGroup* GetGeometryGroup(FString Name);
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
-	UOptiXGroup* GetGroup(FString Name);
-
-	// OptiX 6.0
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
-	void SetMaxTraceDepth(int32 Depth);
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
-	int32 GetMaxTraceDepth();
-
-
-
-
-
-	// TODO: ALL ABOVE FUNCTIONS ARE NOT THREAD-SAFE, DO NOT USE WHEN CALLING THEM EVERY FRAME
-	//	     USE THE CACHED ONES INSTEAD:
-
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
-	void SetFloat3DVectorThreadsafe(FString string, FVector Var);
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
-	void SetMatrixThreadsafe(FString string, FMatrix Matrix);
-
-// In case I use this as a base class? TODO
-private:
-
-	/*
-	Objects will not be added to the maps on creation but only on Set___().
-	As the GeometryInstance keeps a reference to the underlying set of Geometries and 
-	Materials, this should be safe from being GC'd.
-	*/
-
-
-	optix::Context NativeContext;
-
-	UPROPERTY() // Just here for now so we the objects don't ge GC'd
-	TMap<FString, UOptiXBuffer*> BufferMap;
-
-	UPROPERTY() // Just here for now so we the objects don't ge GC'd
-	TMap<FString, UOptiXMaterial*> MaterialMap;
-
-	UPROPERTY() // Just here for now so the objects don't ge GC'd
-	TMap<FString, UOptiXGeometry*> GeometryMap;
-
-	UPROPERTY() // Just here for now so the objects don't ge GC'd
-	TMap<FString, UOptiXGeometryInstance*> GeometryInstanceMap;
-
-	UPROPERTY() // Just here for now so the objects don't ge GC'd
-	TMap<FString, UOptiXGeometryGroup*> GeometryGroupMap;
-
-	UPROPERTY() // Just here for now so the objects don't ge GC'd
-	TMap<FString, UOptiXGroup*> GroupMap;
-
-	UPROPERTY() // Just here for now so the objects don't ge GC'd
-	TMap<FString, UOptiXTextureSampler*> TextureSamplerMap;
-
-	UPROPERTY() // Keep those here on creation so we can update their transforms.
-	TArray<UOptiXTransform*> TransformMap;
-
-	//UPROPERTY() // Just here for now so the objects don't ge GC'd
-	//TMap<FString, UOptiXProgram*> ProgramMap;
-	UPROPERTY()
-	TArray<UOptiXProgram*> RayGenerationPrograms;
-
-	UPROPERTY() // Just here for now so the objects don't ge GC'd
-	TArray<UOptiXProgram*> ExceptionPrograms;	
-
-	UPROPERTY() // Just here for now so the objects don't ge GC'd
-	TArray<UOptiXProgram*> MissPrograms;
-
-	UPROPERTY()
-	TMap<FString, FVector> VectorCache;
-
-	UPROPERTY()
-	TMap<FString, FMatrix> MatrixCache;
-	// TODO:
-	// Need maps for all data types tbh
-
+#pragma once
+
+#include "CoreMinimal.h"
+#include "UObject/ObjectMacros.h"
+#include "Engine/EngineTypes.h"
+
+#include "OptiXIncludes.h"
+
+#include "OptiXGeometry.h"
+#include "OptiXGeometryInstance.h"
+#include "OptiXGeometryGroup.h"
+#include "OptiXMaterial.h"
+#include "OptiXBuffer.h"
+#include "OptiXProgram.h"
+#include "OptiXTextureSampler.h"
+#include "OptiXAcceleration.h"
+#include "OptiXTransform.h"
+#include "OptiXGroup.h"
+
+
+#include "OptiXContext.generated.h"
+
+DECLARE_LOG_CATEGORY_EXTERN(OptiXPluginContext, Log, All);
+
+
+UCLASS(hidecategories = Object, BlueprintType)
+class OPTIX_API UOptiXContext : public UObject
+{
+	GENERATED_BODY() // Apparently GENERATED_UCLASS_BODY is deprecated?
+
+	// We can have a lot of functions here which can interact with OptiX. 
+	// As mentioned in the OptiXObjects file, it might be really worth to keep those in the backend (FOptiXContextInstance e.g.)
+	// The real issue is kind of the nature of the optix framework, as the variables can be completely arbitrary and dependent on the
+	// shaders. Therefore there's no fixed set of UPROPERTYs which could act as an interface.
+	// I *could* write another layer here which caches the variables in a TArray and then pushes them through, but this would require 
+	// a lot of type-magic as the variables can be any type pretty much.
+
+	// Setter Functions - apparently overloading isn't actually possible so I need to restructure EVERYTHING again
+	// Only do the important ones for now as I might need to scrap that again.
+public:
+
+	UOptiXContext(const FObjectInitializer& ObjectInitializer);
+
+	// Unreal Constructors are scary, evil and do their own magic in the background.
+	// Use Init functions for everything until one day I maybe understand what Unreal is doing exactly...
+	optix::Context Init();
+
+	virtual void BeginDestroy() override;
+
+	// Called by the rendering thread to savely update the variables that need to be updated each tick.
+	// This is mostly just going to be the transforms.
+	void UpdateVariables();
+
+	// TODO Begin play?
+
+	// TODO 
+	optix::Context GetNativeContext()
+	{
+		return NativeContext;
+	}
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	void Reset();
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	UOptiXGeometry* CreateGeometry();
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	UOptiXMaterial* CreateMaterial();
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	UOptiXGeometryInstance* CreateGeometryInstance(UOptiXGeometry* Geometry, TArray<UOptiXMaterial*> Materials);
+
+	UOptiXGeometryInstance* CreateGeometryInstance(UOptiXGeometry* Geometry, UOptiXMaterial* Material);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	UOptiXGeometryGroup* CreateGeometryGroup();
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	UOptiXGroup* CreateGroup();
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	UOptiXTransform* CreateTransform();
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	UOptiXAcceleration* CreateAcceleration(FString Builder);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	void SetFloat(FString string, float Var);
+
+	//void SetFloat2D(FString string, FVector2D Var)
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	void SetFloat2D(FString string, float Var1, float Var2);
+
+	// 3D Float
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	void SetFloat3DVector(FString string, FVector Var);
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	void SetFloat3D(FString string, float Var1, float Var2, float Var3);
+
+	// 4D Float
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	void SetFloat4DVector(FString string, FVector4 Var);
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	void SetFloat4D(FString string, float Var1, float Var2, float Var3, float Var4);
+
+
+	// 1D Int
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	void SetInt(FString string, int32 Var);
+
+	// 2D Int - wow Unreal your naming scheme is really top notch...
+	//void SetInt2D(FString string, FIntPoint Var)
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	void SetInt2D(FString string, int32 Var1, int32 Var2);
+
+	// 3D Int
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	void SetInt3DVector(FString string, FIntVector Var);
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	void SetInt3D(FString string, int32 Var1, int32 Var2, int32 Var3);
+
+	// 4D Int
+	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	//void SetInt4DVector(FString string, FIntVector4 Var);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	void SetInt4D(FString string, int32 Var1, int32 Var2, int32 Var3, int32 Var4);
+
+	// 1D Uint
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	void SetUint(FString string, uint8 Var);
+
+	// 2D Uint - wow Unreal your naming scheme is really top notch...
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	void SetUint2D(FString string, uint8 Var1, uint8 Var2);
+
+	// 3D Uint
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	void SetUint3D(FString string, uint8 Var1, uint8 Var2, uint8 Var3);
+
+	// 4D Uint
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	void SetUint4D(FString string, uint8 Var1, uint8 Var2, uint8 Var3, uint8 Var4);
+
+
+	// Matrices - careful Unreal uses ROW_MAJOR LAYOUT
+	// TODO They will be a pain
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	void SetMatrix(FString string, FMatrix Matrix);
+
+
+	////
+	//// Getters (gotta love wrappers)
+	////
+
+	// Can't overload return type so this is going to be ugly
+
+	// Floats
+	// 1D Float
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	float GetFloat(FString string);
+
+	// 2D Float
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	FVector2D GetFloat2D(FString string);
+
+	// 3D Float
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	FVector GetFloat3D(FString string);
+
+	// 4D Float
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	FVector4 GetFloat4D(FString string);
+
+
+	//// Ints
+
+	// 1D Int
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	int32 GetInt(FString string);
+
+	// 2D Int - wow Unreal your naming scheme is really top notch...
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	FIntPoint GetInt2D(FString string);
+
+	// 3D Int
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	FIntVector GetInt3D(FString string);
+
+	// 4D Int
+	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	//FIntVector4 GetInt4D(FString string);
+
+
+
+	//// UInts are bad
+
+	// 1D UInt
+	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	//uint8 GetUint(FString string);
+
+	//// 2D UInt
+	//// Have to do it per reference, TODO test me
+	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	//void GetUint2D(FString& string, uint8& Var1, uint8& Var2);
+
+	//// 3D UInt
+	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	//void GetUint3D(FString string, uint8& Var1, uint8& Var2, uint8& Var3);
+
+	//// 4D UInt
+	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	//FUintVector4 GetUint4D(FString string);
+
+
+	//// BUFFER FUNCTIONALITY
+
+	// A lot of those are using higher uints and ints, which is a bit iffy in blueprints.
+	// Keep the higher types as C++ functions.
+
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	void Validate();
+
+	// Lots of "Create" methods now, dunno if I really want them here or in the manager
+	// - they shouldn't be needlessly exposed outside of this plugin.
+	// CreateBuffer etc
+
+	uint32 GetDeviceCount();
+	FString GetDeviceName(int32 Ordinal);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	void SetStackSize(int32 StackSize);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	int32 GetStackSize();
+
+	void SetStackSize64(uint64 StackSize);
+	uint64 GetStackSize64();
+
+	// TODO TimeoutCallback
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	void SetEntryPointCount(int32 NumEntryPoints);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	int32 GetEntryPointCount();
+
+
+	// Program wrapper needed!
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	void SetRayGenerationProgram(int32 EntryPointIndex, UOptiXProgram* Program);
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	UOptiXProgram* GetRayGenerationProgram(int32 EntryPointIndex);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	void SetExceptionProgram(int32 EntryPointIndex, UOptiXProgram* Program);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	UOptiXProgram* GetExceptionProgram(int32 EntryPointIndex);
+
+	// TODO RTexception
+	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	void SetExceptionEnabled(RTexception Exception, bool Enabled);
+
+	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	bool GetExceptionEnabled(RTexception Exception);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	void SetRayTypeCount(int32 NumRayTypes);
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	int32 GetRayTypeCount();
+
+	// TODO
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	void SetMissProgram(int32 RayTypeIndex, UOptiXProgram* Program);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	UOptiXProgram* GetMissProgram(int32 RayTypeIndex);
+
+	// Do not expose those for now!
+	void Launch(int32 EntryPointIndex, uint64 ImageWidth);
+	void Launch(int32 EntryPointIndex, uint64 ImageWidth, uint64 ImageHeight);
+	void Launch(int32 EntryPointIndex, uint64 ImageWidth, uint64 ImageHeight, uint64 ImageDepth);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	void SetBuffer(FString Name, UOptiXBuffer* Buffer);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	void SetGeometryGroup(FString Name, UOptiXGeometryGroup* GeoGroup);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	void SetGroup(FString Name, UOptiXGroup* Group);
+
+	// TODO: Create Program Functions
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	UOptiXProgram* CreateProgramFromPTXFile(FString Path, FString Name);
+
+	// TODO: Create Buffer Functions
+
+	// General, non-blueprint buffer function
+
+	UOptiXBuffer* CreateBuffer(uint8 Type, RTformat Format, RTsize Width);
+	UOptiXBuffer* CreateBuffer(uint8 Type, RTformat Format, RTsize Width, RTsize Height );
+	UOptiXBuffer* CreateBuffer(uint8 Type, RTformat Format, RTsize Width, RTsize Height, RTsize Depth );
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	UOptiXBuffer* CreateBufferSimple(uint8 Type);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	UOptiXBuffer* CreateBufferUByte(uint8 Type);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	UOptiXBuffer* CreateBufferUByte1D(uint8 Type, int32 Width);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	UOptiXBuffer* CreateBufferUByte2D(uint8 Type, int32 Width, int32 Height);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	UOptiXBuffer* CreateBufferUByte3D(uint8 Type, int32 Width, int32 Height, int32 Depth);
+
+	// More Buffer Functions to avoid huge enums in blueprints:
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	UOptiXBuffer* CreateOutputBufferColor(int32 Width, int32 Height);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	UOptiXBuffer* CreateOutputBufferUByte3D(int32 Width, int32 Height, int32 Depth);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	UOptiXBuffer* CreateOutputBufferDepth(int32 Width, int32 Height);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	UOptiXBuffer* CreateOutputBufferIntersections(int32 Width, int32 Height);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	UOptiXBuffer* CreateInputBufferFloat(int32 Width);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	UOptiXBuffer* CreateInputBufferFloat2D(int32 Width, int32 Height);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	UOptiXBuffer* CreateInputBufferFloat3D(int32 Width, int32 Height, int32 Depth);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	UOptiXBuffer* CreateCubemapBuffer(int32 Width, int32 Height);
+
+	// Texture Sampler
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	UOptiXTextureSampler* CreateTextureSampler();
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	void SetTextureSampler(FString Name, UOptiXTextureSampler* Sampler);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	void SetSkybox(FString Name, UOptiXTextureSampler* Sampler);
+
+	// Getters
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	UOptiXBuffer* GetBuffer(FString Name);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	UOptiXGeometryGroup* GetGeometryGroup(FString Name);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	UOptiXGroup* GetGroup(FString Name);
+
+	// OptiX 6.0
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	void SetMaxTraceDepth(int32 Depth);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	int32 GetMaxTraceDepth();
+
+
+
+
+
+	// TODO: ALL ABOVE FUNCTIONS ARE NOT THREAD-SAFE, DO NOT USE WHEN CALLING THEM EVERY FRAME
+	//	     USE THE CACHED ONES INSTEAD:
+
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	void SetFloat3DVectorThreadsafe(FString string, FVector Var);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXContext")
+	void SetMatrixThreadsafe(FString string, FMatrix Matrix);
+
+// In case I use this as a base class? TODO
+private:
+
+	/*
+	Objects will not be added to the maps on creation but only on Set___().
+	As the GeometryInstance keeps a reference to the underlying set of Geometries and 
+	Materials, this should be safe from being GC'd.
+	*/
+
+
+	optix::Context NativeContext;
+
+	UPROPERTY() // Just here for now so we the objects don't ge GC'd
+	TMap<FString, UOptiXBuffer*> BufferMap;
+
+	UPROPERTY() // Just here for now so we the objects don't ge GC'd
+	TMap<FString, UOptiXMaterial*> MaterialMap;
+
+	UPROPERTY() // Just here for now so the objects don't ge GC'd
+	TMap<FString, UOptiXGeometry*> GeometryMap;
+
+	UPROPERTY() // Just here for now so the objects don't ge GC'd
+	TMap<FString, UOptiXGeometryInstance*> GeometryInstanceMap;
+
+	UPROPERTY() // Just here for now so the objects don't ge GC'd
+	TMap<FString, UOptiXGeometryGroup*> GeometryGroupMap;
+
+	UPROPERTY() // Just here for now so the objects don't ge GC'd
+	TMap<FString, UOptiXGroup*> GroupMap;
+
+	UPROPERTY() // Just here for now so the objects don't ge GC'd
+	TMap<FString, UOptiXTextureSampler*> TextureSamplerMap;
+
+	UPROPERTY() // Keep those here on creation so we can update their transforms.
+	TArray<UOptiXTransform*> TransformMap;
+
+	//UPROPERTY() // Just here for now so the objects don't ge GC'd
+	//TMap<FString, UOptiXProgram*> ProgramMap;
+	UPROPERTY()
+	TArray<UOptiXProgram*> RayGenerationPrograms;
+
+	UPROPERTY() // Just here for now so the objects don't ge GC'd
+	TArray<UOptiXProgram*> ExceptionPrograms;	
+
+	UPROPERTY() // Just here for now so the objects don't ge GC'd
+	TArray<UOptiXProgram*> MissPrograms;
+
+	UPROPERTY()
+	TMap<FString, FVector> VectorCache;
+
+	UPROPERTY()
+	TMap<FString, FMatrix> MatrixCache;
+	// TODO:
+	// Need maps for all data types tbh
+
 };
\ No newline at end of file
diff --git a/Source/OptiX/Public/OptiXGeometry.h b/Deprecated/Public/OptiXGeometry.h
similarity index 97%
rename from Source/OptiX/Public/OptiXGeometry.h
rename to Deprecated/Public/OptiXGeometry.h
index db967677ffc6d4804e45d01c6669530440e075cc..e634e308a283d4c441e7dc7c684eaca5ddd0f455 100644
--- a/Source/OptiX/Public/OptiXGeometry.h
+++ b/Deprecated/Public/OptiXGeometry.h
@@ -1,232 +1,232 @@
-#pragma once
-
-#include "CoreMinimal.h"
-#include "UObject/ObjectMacros.h"
-#include "Engine/EngineTypes.h"
-
-#include "OptiXIncludes.h"
-
-#include "OptiXProgram.h"
-#include "OptiXBuffer.h"
-
-#include "OptiXGeometry.generated.h"
-
-DECLARE_LOG_CATEGORY_EXTERN(OptiXPluginGeometry, Log, All);
-
-UCLASS(hidecategories = Object, BlueprintType)
-class OPTIX_API UOptiXGeometry : public UObject
-{
-	GENERATED_BODY() // Apparently GENERATED_UCLASS_BODY is deprecated?
-
-public:
-
-	virtual void BeginDestroy() override;
-
-	void SetGeometry(optix::Geometry Geom)
-	{
-		NativeGeometry = Geom;
-	}
-
-	void DestroyOptiXObject();
-
-	// Setter Functions - apparently overloading isn't actually possible so I need to restructure EVERYTHING again
-	// Only do the important ones for now as I might need to scrap that again.
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
-	void SetFloat(FString string, float Var);
-
-	//void SetFloat2D(FString string, FVector2D Var)
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
-	void SetFloat2D(FString string, float Var1, float Var2);
-
-	// 3D Float
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
-	void SetFloat3DVector(FString string, FVector Var);
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
-	void SetFloat3D(FString string, float Var1, float Var2, float Var3);
-
-	// 4D Float
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
-	void SetFloat4DVector(FString string, FVector4 Var);
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
-	void SetFloat4D(FString string, float Var1, float Var2, float Var3, float Var4);
-
-
-	// 1D Int
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
-	void SetInt(FString string, int32 Var);
-
-	// 2D Int - wow Unreal your naming scheme is really top notch...
-	//void SetInt2D(FString string, FIntPoint Var)
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
-	void SetInt2D(FString string, int32 Var1, int32 Var2);
-
-	// 3D Int
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
-	void SetInt3DVector(FString string, FIntVector Var);
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
-	void SetInt3D(FString string, int32 Var1, int32 Var2, int32 Var3);
-
-	// 4D Int
-	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
-	//void SetInt4DVector(FString string, FIntVector4 Var);
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
-	void SetInt4D(FString string, int32 Var1, int32 Var2, int32 Var3, int32 Var4);
-
-
-
-	// 1D Uint
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
-	void SetUint(FString string, uint8 Var);
-
-	// 2D Uint - wow Unreal your naming scheme is really top notch...
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
-	void SetUint2D(FString string, uint8 Var1, uint8 Var2);
-
-	// 3D Uint
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
-	void SetUint3D(FString string, uint8 Var1, uint8 Var2, uint8 Var3);
-
-	// 4D Uint
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
-	void SetUint4D(FString string, uint8 Var1, uint8 Var2, uint8 Var3, uint8 Var4);
-
-
-	// Matrices - careful Unreal uses ROW_MAJOR LAYOUT
-	// TODO They will be a pain
-
-	////
-	//// Getters (gotta love wrappers)
-	////
-
-	// Can't overload return type so this is going to be ugly
-
-	// Floats
-	// 1D Float
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
-	float GetFloat(FString string);
-
-	// 2D Float
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
-	FVector2D GetFloat2D(FString string);
-
-	// 3D Float
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
-	FVector GetFloat3D(FString string);
-
-	// 4D Float
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
-	FVector4 GetFloat4D(FString string);
-
-
-	//// Ints
-
-	// 1D Int
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
-	int32 GetInt(FString string);
-
-	// 2D Int - wow Unreal your naming scheme is really top notch...
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
-	FIntPoint GetInt2D(FString string);
-
-	// 3D Int
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
-	FIntVector GetInt3D(FString string);
-
-	// 4D Int
-	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
-	//FIntVector4 GetInt4D(FString string);
-
-
-
-	//// UInts are bad
-
-	// 1D UInt
-	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
-	//uint8 GetUint(FString string);
-
-	//// 2D UInt
-	//// Have to do it per reference, TODO test me
-	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
-	//void GetUint2D(FString& string, uint8& Var1, uint8& Var2);
-
-	//// 3D UInt
-	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
-	//void GetUint3D(FString string, uint8& Var1, uint8& Var2, uint8& Var3);
-
-	//// 4D UInt
-	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
-	//FUintVector4 GetUint4D(FString string);
-
-
-	// Geometry specific functions
-
-	// Sadly we still need this!
-	optix::Geometry GetNativeGeometry();
-
-	// Not sure which of those are actually needed, but let's add a few:
-	// Setters and getters are interleaved.
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
-	void SetPrimitiveCount(int32 NumPrimitives);
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
-	int32 GetPrimitiveCount();
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
-	void SetPrimitiveIndexOffset(int32 IndexOffsets);
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
-	int32 GetPrimitiveIndexOffset();
-
-
-	void SetPrimitiveCountUint(uint32 NumPrimitives);
-	uint32 GetPrimitiveCountUint();
-
-	void SetPrimitiveIndexOffsetUint(uint32 IndexOffsets);
-	uint32 GetPrimitiveIndexOffsetUint();
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
-	void SetMotionRange(float TimeBegin, float TimeEnd);
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
-	FVector2D GetMotionRange();
-
-	//TODO: As those two take and return two optix-specific types, either wrap those or
-	// make the whole thing only accessible through the actual optix object, as there's no real sense in wrapping this.
-	void SetMotionBorderMode(RTmotionbordermode BeginMode, RTmotionbordermode EndMode);
-	void GetMotionBorderMode(RTmotionbordermode& BeginMode, RTmotionbordermode& EndMode);
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
-	void SetMotionSteps(int32 N);
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
-	int32 GetMotionSteps();
-
-
-	void SetMotionStepsUint(uint32 N);
-	uint32 GetMotionStepsUint();
-
-	// Todo: Program def. needs to be wrapped as well and made available to the blueprint editor even!
-	void SetBoundingBoxProgram(UOptiXProgram* Program);
-	UOptiXProgram* GetBoundingBoxProgram();
-
-	void SetIntersectionProgram(UOptiXProgram* Program);
-	UOptiXProgram* GetIntersectionProgram();	
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
-	void SetBuffer(FString Name, UOptiXBuffer* Buffer);
-
-	// In case I use this as a base class? TODO
-protected:
-
-	optix::Geometry NativeGeometry;
-	
-	UPROPERTY()
-	UOptiXProgram* IntersectionProgram;
-
-	UPROPERTY()
-	UOptiXProgram* BoundingBoxProgram;
-
-	UPROPERTY() // Just here for now so we the objects don't ge GC'd
-	TMap<FString, UOptiXBuffer*> BufferMap;
+#pragma once
+
+#include "CoreMinimal.h"
+#include "UObject/ObjectMacros.h"
+#include "Engine/EngineTypes.h"
+
+#include "OptiXIncludes.h"
+
+#include "OptiXProgram.h"
+#include "OptiXBuffer.h"
+
+#include "OptiXGeometry.generated.h"
+
+DECLARE_LOG_CATEGORY_EXTERN(OptiXPluginGeometry, Log, All);
+
+UCLASS(hidecategories = Object, BlueprintType)
+class OPTIX_API UOptiXGeometry : public UObject
+{
+	GENERATED_BODY() // Apparently GENERATED_UCLASS_BODY is deprecated?
+
+public:
+
+	virtual void BeginDestroy() override;
+
+	void SetGeometry(optix::Geometry Geom)
+	{
+		NativeGeometry = Geom;
+	}
+
+	void DestroyOptiXObject();
+
+	// Setter Functions - apparently overloading isn't actually possible so I need to restructure EVERYTHING again
+	// Only do the important ones for now as I might need to scrap that again.
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
+	void SetFloat(FString string, float Var);
+
+	//void SetFloat2D(FString string, FVector2D Var)
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
+	void SetFloat2D(FString string, float Var1, float Var2);
+
+	// 3D Float
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
+	void SetFloat3DVector(FString string, FVector Var);
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
+	void SetFloat3D(FString string, float Var1, float Var2, float Var3);
+
+	// 4D Float
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
+	void SetFloat4DVector(FString string, FVector4 Var);
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
+	void SetFloat4D(FString string, float Var1, float Var2, float Var3, float Var4);
+
+
+	// 1D Int
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
+	void SetInt(FString string, int32 Var);
+
+	// 2D Int - wow Unreal your naming scheme is really top notch...
+	//void SetInt2D(FString string, FIntPoint Var)
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
+	void SetInt2D(FString string, int32 Var1, int32 Var2);
+
+	// 3D Int
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
+	void SetInt3DVector(FString string, FIntVector Var);
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
+	void SetInt3D(FString string, int32 Var1, int32 Var2, int32 Var3);
+
+	// 4D Int
+	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
+	//void SetInt4DVector(FString string, FIntVector4 Var);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
+	void SetInt4D(FString string, int32 Var1, int32 Var2, int32 Var3, int32 Var4);
+
+
+
+	// 1D Uint
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
+	void SetUint(FString string, uint8 Var);
+
+	// 2D Uint - wow Unreal your naming scheme is really top notch...
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
+	void SetUint2D(FString string, uint8 Var1, uint8 Var2);
+
+	// 3D Uint
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
+	void SetUint3D(FString string, uint8 Var1, uint8 Var2, uint8 Var3);
+
+	// 4D Uint
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
+	void SetUint4D(FString string, uint8 Var1, uint8 Var2, uint8 Var3, uint8 Var4);
+
+
+	// Matrices - careful Unreal uses ROW_MAJOR LAYOUT
+	// TODO They will be a pain
+
+	////
+	//// Getters (gotta love wrappers)
+	////
+
+	// Can't overload return type so this is going to be ugly
+
+	// Floats
+	// 1D Float
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
+	float GetFloat(FString string);
+
+	// 2D Float
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
+	FVector2D GetFloat2D(FString string);
+
+	// 3D Float
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
+	FVector GetFloat3D(FString string);
+
+	// 4D Float
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
+	FVector4 GetFloat4D(FString string);
+
+
+	//// Ints
+
+	// 1D Int
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
+	int32 GetInt(FString string);
+
+	// 2D Int - wow Unreal your naming scheme is really top notch...
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
+	FIntPoint GetInt2D(FString string);
+
+	// 3D Int
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
+	FIntVector GetInt3D(FString string);
+
+	// 4D Int
+	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
+	//FIntVector4 GetInt4D(FString string);
+
+
+
+	//// UInts are bad
+
+	// 1D UInt
+	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
+	//uint8 GetUint(FString string);
+
+	//// 2D UInt
+	//// Have to do it per reference, TODO test me
+	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
+	//void GetUint2D(FString& string, uint8& Var1, uint8& Var2);
+
+	//// 3D UInt
+	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
+	//void GetUint3D(FString string, uint8& Var1, uint8& Var2, uint8& Var3);
+
+	//// 4D UInt
+	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
+	//FUintVector4 GetUint4D(FString string);
+
+
+	// Geometry specific functions
+
+	// Sadly we still need this!
+	optix::Geometry GetNativeGeometry();
+
+	// Not sure which of those are actually needed, but let's add a few:
+	// Setters and getters are interleaved.
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
+	void SetPrimitiveCount(int32 NumPrimitives);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
+	int32 GetPrimitiveCount();
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
+	void SetPrimitiveIndexOffset(int32 IndexOffsets);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
+	int32 GetPrimitiveIndexOffset();
+
+
+	void SetPrimitiveCountUint(uint32 NumPrimitives);
+	uint32 GetPrimitiveCountUint();
+
+	void SetPrimitiveIndexOffsetUint(uint32 IndexOffsets);
+	uint32 GetPrimitiveIndexOffsetUint();
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
+	void SetMotionRange(float TimeBegin, float TimeEnd);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
+	FVector2D GetMotionRange();
+
+	//TODO: As those two take and return two optix-specific types, either wrap those or
+	// make the whole thing only accessible through the actual optix object, as there's no real sense in wrapping this.
+	void SetMotionBorderMode(RTmotionbordermode BeginMode, RTmotionbordermode EndMode);
+	void GetMotionBorderMode(RTmotionbordermode& BeginMode, RTmotionbordermode& EndMode);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
+	void SetMotionSteps(int32 N);
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
+	int32 GetMotionSteps();
+
+
+	void SetMotionStepsUint(uint32 N);
+	uint32 GetMotionStepsUint();
+
+	// Todo: Program def. needs to be wrapped as well and made available to the blueprint editor even!
+	void SetBoundingBoxProgram(UOptiXProgram* Program);
+	UOptiXProgram* GetBoundingBoxProgram();
+
+	void SetIntersectionProgram(UOptiXProgram* Program);
+	UOptiXProgram* GetIntersectionProgram();	
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometry")
+	void SetBuffer(FString Name, UOptiXBuffer* Buffer);
+
+	// In case I use this as a base class? TODO
+protected:
+
+	optix::Geometry NativeGeometry;
+	
+	UPROPERTY()
+	UOptiXProgram* IntersectionProgram;
+
+	UPROPERTY()
+	UOptiXProgram* BoundingBoxProgram;
+
+	UPROPERTY() // Just here for now so we the objects don't ge GC'd
+	TMap<FString, UOptiXBuffer*> BufferMap;
 };
\ No newline at end of file
diff --git a/Source/OptiX/Public/OptiXGeometryGroup.h b/Deprecated/Public/OptiXGeometryGroup.h
similarity index 96%
rename from Source/OptiX/Public/OptiXGeometryGroup.h
rename to Deprecated/Public/OptiXGeometryGroup.h
index 4b0a13b32643c7865ab029afcc36d3ddea1fc090..c675765a3748c7bc165bf7b7438c7e3c62396f34 100644
--- a/Source/OptiX/Public/OptiXGeometryGroup.h
+++ b/Deprecated/Public/OptiXGeometryGroup.h
@@ -1,87 +1,87 @@
-#pragma once
-
-#include "CoreMinimal.h"
-#include "UObject/ObjectMacros.h"
-#include "Engine/EngineTypes.h"
-
-#include "OptiXIncludes.h"
-
-#include "OptiXGeometryInstance.h"
-#include "OptiXAcceleration.h"
-
-#include "OptiXGeometryGroup.generated.h"
-
-DECLARE_LOG_CATEGORY_EXTERN(OptiXPluginGeometryGroup, Log, All);
-
-
-UCLASS(hidecategories = Object, BlueprintType)
-class OPTIX_API UOptiXGeometryGroup : public UObject
-{
-	GENERATED_BODY() // Apparently GENERATED_UCLASS_BODY is deprecated?
-
-public:
-
-	virtual void BeginDestroy() override;
-
-	optix::GeometryGroup GetNativeGroup()
-	{
-		return NativeGeometryGroup;
-	}
-
-	void SetNativeGroup(optix::GeometryGroup Group)
-	{
-		NativeGeometryGroup = Group;
-	}
-
-	void DestroyOptiXObject();
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometryGroup")
-	void SetAcceleration(UOptiXAcceleration* Accel);
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometryGroup")
-	UOptiXAcceleration* GetAcceleration();
-	
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometryGroup")
-	void SetChildCount(uint8 Count);
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometryGroup")
-	uint8 GetChildCount();
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometryGroup")
-	void SetChild(uint8 Index, UOptiXGeometryInstance* Child);
-
-	////// Adds the material and returns the index to the added material.
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometryGroup")
-	UOptiXGeometryInstance* GetChild(uint8 Index);
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometryGroup")
-	uint8 AddChild(UOptiXGeometryInstance* Child);
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometryGroup")
-	uint8 RemoveChild(UOptiXGeometryInstance* Child);
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometryGroup")
-	void RemoveChildByIndex(uint8 Index);
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometryGroup")
-	uint8 GetChildIndex(UOptiXGeometryInstance* Child);
-
-	UPROPERTY(BlueprintReadOnly, Category = "OptiXGeometryGroup")
-	int32 ChildCount = 0;
-
-	//// TODO Check if UPROPERTY is fine with the TARRAY
-	UPROPERTY()
-	TArray<UOptiXGeometryInstance*> OptiXGeometryInstances;
-
-	UPROPERTY()
-	UOptiXAcceleration* Acceleration;
-
-protected:
-
-
-
-	optix::GeometryGroup NativeGeometryGroup;
-
-
+#pragma once
+
+#include "CoreMinimal.h"
+#include "UObject/ObjectMacros.h"
+#include "Engine/EngineTypes.h"
+
+#include "OptiXIncludes.h"
+
+#include "OptiXGeometryInstance.h"
+#include "OptiXAcceleration.h"
+
+#include "OptiXGeometryGroup.generated.h"
+
+DECLARE_LOG_CATEGORY_EXTERN(OptiXPluginGeometryGroup, Log, All);
+
+
+UCLASS(hidecategories = Object, BlueprintType)
+class OPTIX_API UOptiXGeometryGroup : public UObject
+{
+	GENERATED_BODY() // Apparently GENERATED_UCLASS_BODY is deprecated?
+
+public:
+
+	virtual void BeginDestroy() override;
+
+	optix::GeometryGroup GetNativeGroup()
+	{
+		return NativeGeometryGroup;
+	}
+
+	void SetNativeGroup(optix::GeometryGroup Group)
+	{
+		NativeGeometryGroup = Group;
+	}
+
+	void DestroyOptiXObject();
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometryGroup")
+	void SetAcceleration(UOptiXAcceleration* Accel);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometryGroup")
+	UOptiXAcceleration* GetAcceleration();
+	
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometryGroup")
+	void SetChildCount(uint8 Count);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometryGroup")
+	uint8 GetChildCount();
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometryGroup")
+	void SetChild(uint8 Index, UOptiXGeometryInstance* Child);
+
+	////// Adds the material and returns the index to the added material.
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometryGroup")
+	UOptiXGeometryInstance* GetChild(uint8 Index);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometryGroup")
+	uint8 AddChild(UOptiXGeometryInstance* Child);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometryGroup")
+	uint8 RemoveChild(UOptiXGeometryInstance* Child);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometryGroup")
+	void RemoveChildByIndex(uint8 Index);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometryGroup")
+	uint8 GetChildIndex(UOptiXGeometryInstance* Child);
+
+	UPROPERTY(BlueprintReadOnly, Category = "OptiXGeometryGroup")
+	int32 ChildCount = 0;
+
+	//// TODO Check if UPROPERTY is fine with the TARRAY
+	UPROPERTY()
+	TArray<UOptiXGeometryInstance*> OptiXGeometryInstances;
+
+	UPROPERTY()
+	UOptiXAcceleration* Acceleration;
+
+protected:
+
+
+
+	optix::GeometryGroup NativeGeometryGroup;
+
+
 };
\ No newline at end of file
diff --git a/Source/OptiX/Public/OptiXGeometryInstance.h b/Deprecated/Public/OptiXGeometryInstance.h
similarity index 97%
rename from Source/OptiX/Public/OptiXGeometryInstance.h
rename to Deprecated/Public/OptiXGeometryInstance.h
index 17540059b8e4472611ba717c9ff7775b972c026b..713a226b81876d65e44b1d8341ffd1478cff7d78 100644
--- a/Source/OptiX/Public/OptiXGeometryInstance.h
+++ b/Deprecated/Public/OptiXGeometryInstance.h
@@ -1,119 +1,119 @@
-#pragma once
-
-#include "CoreMinimal.h"
-#include "UObject/ObjectMacros.h"
-#include "Engine/EngineTypes.h"
-
-#include "OptiXIncludes.h"
-
-#include "OptiXMaterial.h"
-#include "OptiXGeometry.h"
-#include "OptiXTextureSampler.h"
-#include "OptiXBuffer.h"
-
-#include "OptiXGeometryInstance.generated.h"
-
-UCLASS(hidecategories = Object, BlueprintType)
-class OPTIX_API UOptiXGeometryInstance : public UObject
-{
-	GENERATED_BODY() // Apparently GENERATED_UCLASS_BODY is deprecated?
-
-public:
-
-	virtual void BeginDestroy() override;
-
-	optix::GeometryInstance GetNativeInstance()
-	{
-		return NativeGeometryInstance;
-	}
-
-	void SetNativeInstance(optix::GeometryInstance Instance)
-	{
-		NativeGeometryInstance = Instance;
-	}
-
-	void DestroyOptiXObject();
-
-	// Maybe keep this but tbh we don't want to have an optix::Geometry object running around without an associated wrapper
-	//void SetNativeGeometry(Geometry Geometry);
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometryInstance")
-	void SetGeometry(UOptiXGeometry* OptiXGeometryPtr);
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometryInstance")
-	UOptiXGeometry* GetGeometry();
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometryInstance")
-	void SetMaterialCount(uint8 Count);
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometryInstance")
-	uint8 GetMaterialCount();
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometryInstance")
-	void SetMaterial(uint8 Idx, UOptiXMaterial*  Material);
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometryInstance")
-	UOptiXMaterial* GetMaterial(uint8 Idx);
-
-	////// Adds the material and returns the index to the added material.
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometryInstance")
-	uint8 AddMaterial(UOptiXMaterial* OptiXMaterialPtr);
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometryInstance")
-	void SetFloat(FString string, float Var);
-
-	//void SetFloat2D(FString string, FVector2D Var)
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometryInstance")
-	void SetFloat2D(FString string, float Var1, float Var2);
-
-	// 3D Float
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometryInstance")
-	void SetFloat3DVector(FString string, FVector Var);
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometryInstance")
-	void SetFloat3D(FString string, float Var1, float Var2, float Var3);
-
-	// 4D Float
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometryInstance")
-	void SetFloat4DVector(FString string, FVector4 Var);
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometryInstance")
-	void SetFloat4D(FString string, float Var1, float Var2, float Var3, float Var4);
-
-
-	// 1D Int
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometryInstance")
-	void SetInt(FString string, int32 Var);
-
-	// 2D Int - wow Unreal your naming scheme is really top notch...
-	//void SetInt2D(FString string, FIntPoint Var)
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometryInstance")
-	void SetInt2D(FString string, int32 Var1, int32 Var2);
-
-	// 3D Int
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometryInstance")
-	void SetInt3DVector(FString string, FIntVector Var);
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometryInstance")
-	void SetInt3D(FString string, int32 Var1, int32 Var2, int32 Var3);
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometryInstance")
-	void SetTextureSampler(FString Name, UOptiXTextureSampler* Sampler);
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometryInstance")
-	void SetBuffer(FString Name, UOptiXBuffer* Buffer);
-
-	UPROPERTY()
-	UOptiXGeometry* OptiXGeometry; // Maybe make this a weak obj pointer?
-
-	//// TODO Check if UPROPERTY is fine with the TARRAY
-	UPROPERTY()
-	TArray<UOptiXMaterial*> OptiXMaterials;
-
-protected:
-
-	optix::GeometryInstance NativeGeometryInstance;
-
-	UPROPERTY() // Just here for now so the objects don't ge GC'd
-	TMap<FString, UOptiXTextureSampler*> TextureSamplerMap;
-
-	UPROPERTY() // Just here for now so we the objects don't ge GC'd
-	TMap<FString, UOptiXBuffer*> BufferMap;
+#pragma once
+
+#include "CoreMinimal.h"
+#include "UObject/ObjectMacros.h"
+#include "Engine/EngineTypes.h"
+
+#include "OptiXIncludes.h"
+
+#include "OptiXMaterial.h"
+#include "OptiXGeometry.h"
+#include "OptiXTextureSampler.h"
+#include "OptiXBuffer.h"
+
+#include "OptiXGeometryInstance.generated.h"
+
+UCLASS(hidecategories = Object, BlueprintType)
+class OPTIX_API UOptiXGeometryInstance : public UObject
+{
+	GENERATED_BODY() // Apparently GENERATED_UCLASS_BODY is deprecated?
+
+public:
+
+	virtual void BeginDestroy() override;
+
+	optix::GeometryInstance GetNativeInstance()
+	{
+		return NativeGeometryInstance;
+	}
+
+	void SetNativeInstance(optix::GeometryInstance Instance)
+	{
+		NativeGeometryInstance = Instance;
+	}
+
+	void DestroyOptiXObject();
+
+	// Maybe keep this but tbh we don't want to have an optix::Geometry object running around without an associated wrapper
+	//void SetNativeGeometry(Geometry Geometry);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometryInstance")
+	void SetGeometry(UOptiXGeometry* OptiXGeometryPtr);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometryInstance")
+	UOptiXGeometry* GetGeometry();
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometryInstance")
+	void SetMaterialCount(uint8 Count);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometryInstance")
+	uint8 GetMaterialCount();
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometryInstance")
+	void SetMaterial(uint8 Idx, UOptiXMaterial*  Material);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometryInstance")
+	UOptiXMaterial* GetMaterial(uint8 Idx);
+
+	////// Adds the material and returns the index to the added material.
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometryInstance")
+	uint8 AddMaterial(UOptiXMaterial* OptiXMaterialPtr);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometryInstance")
+	void SetFloat(FString string, float Var);
+
+	//void SetFloat2D(FString string, FVector2D Var)
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometryInstance")
+	void SetFloat2D(FString string, float Var1, float Var2);
+
+	// 3D Float
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometryInstance")
+	void SetFloat3DVector(FString string, FVector Var);
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometryInstance")
+	void SetFloat3D(FString string, float Var1, float Var2, float Var3);
+
+	// 4D Float
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometryInstance")
+	void SetFloat4DVector(FString string, FVector4 Var);
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometryInstance")
+	void SetFloat4D(FString string, float Var1, float Var2, float Var3, float Var4);
+
+
+	// 1D Int
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometryInstance")
+	void SetInt(FString string, int32 Var);
+
+	// 2D Int - wow Unreal your naming scheme is really top notch...
+	//void SetInt2D(FString string, FIntPoint Var)
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometryInstance")
+	void SetInt2D(FString string, int32 Var1, int32 Var2);
+
+	// 3D Int
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometryInstance")
+	void SetInt3DVector(FString string, FIntVector Var);
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometryInstance")
+	void SetInt3D(FString string, int32 Var1, int32 Var2, int32 Var3);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometryInstance")
+	void SetTextureSampler(FString Name, UOptiXTextureSampler* Sampler);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGeometryInstance")
+	void SetBuffer(FString Name, UOptiXBuffer* Buffer);
+
+	UPROPERTY()
+	UOptiXGeometry* OptiXGeometry; // Maybe make this a weak obj pointer?
+
+	//// TODO Check if UPROPERTY is fine with the TARRAY
+	UPROPERTY()
+	TArray<UOptiXMaterial*> OptiXMaterials;
+
+protected:
+
+	optix::GeometryInstance NativeGeometryInstance;
+
+	UPROPERTY() // Just here for now so the objects don't ge GC'd
+	TMap<FString, UOptiXTextureSampler*> TextureSamplerMap;
+
+	UPROPERTY() // Just here for now so we the objects don't ge GC'd
+	TMap<FString, UOptiXBuffer*> BufferMap;
 };
\ No newline at end of file
diff --git a/Source/OptiX/Public/OptiXGroup.h b/Deprecated/Public/OptiXGroup.h
similarity index 96%
rename from Source/OptiX/Public/OptiXGroup.h
rename to Deprecated/Public/OptiXGroup.h
index 124863fd9d4f9b4136b0d1fe85b1dae5b790b55a..f2c59823d07afe498581de78f39bec9dd9352606 100644
--- a/Source/OptiX/Public/OptiXGroup.h
+++ b/Deprecated/Public/OptiXGroup.h
@@ -1,91 +1,91 @@
-#pragma once
-
-#include "CoreMinimal.h"
-#include "UObject/ObjectMacros.h"
-#include "Engine/EngineTypes.h"
-
-#include "OptiXIncludes.h"
-
-#include "OptiXAcceleration.h"
-#include "OptiXTransform.h"
-#include "OptiXGeometryInstance.h"
-#include "OptiXGeometryGroup.h"
-
-#include "OptiXGroup.generated.h"
-
-DECLARE_LOG_CATEGORY_EXTERN(OptiXPluginGroup, Log, All);
-
-
-UCLASS(hidecategories = Object, BlueprintType)
-class OPTIX_API UOptiXGroup : public UObject
-{
-	GENERATED_BODY() // Apparently GENERATED_UCLASS_BODY is deprecated?
-
-public:
-
-	virtual void BeginDestroy() override;
-
-	optix::Group GetNativeGroup()
-	{
-		return NativeGroup;
-	}
-
-	void SetNativeGroup(optix::Group Group)
-	{
-		NativeGroup = Group;
-	}
-
-	void DestroyOptiXObject();
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGroup")
-	void SetAcceleration(UOptiXAcceleration* Accel);
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGroup")
-	UOptiXAcceleration* GetAcceleration();
-
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGroup")
-	void SetChildCount(uint8 Count);
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGroup")
-	uint8 GetChildCount();
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGroup")
-	void SetChild(uint8 Index, UObject* Child);
-
-	RTobjecttype GetChildType(uint8 Index);
-	
-	////// Adds the material and returns the index to the added material.
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGroup")
-	UObject* GetChild(uint8 Index);
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGroup")
-	uint8 AddChild(UObject* Child);
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGroup")
-	uint8 RemoveChild(UObject* Child);
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGroup")
-	void RemoveChildByIndex(uint8 Index);
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGroup")
-	uint8 GetChildIndex(UObject* Child);
-
-
-	UPROPERTY(BlueprintReadOnly, Category = "OptiXGroup")
-	int32 ChildCount = 0;
-
-	// TODO Set up some nice inheritance so we don't need to use UObject here but maybe UOptiXObject
-	// or some kind of interface.
-	UPROPERTY()
-	TArray<UObject*> Children;
-
-	UPROPERTY()
-	UOptiXAcceleration* Acceleration;
-
-protected:
-
-	optix::Group NativeGroup;
-
-
+#pragma once
+
+#include "CoreMinimal.h"
+#include "UObject/ObjectMacros.h"
+#include "Engine/EngineTypes.h"
+
+#include "OptiXIncludes.h"
+
+#include "OptiXAcceleration.h"
+#include "OptiXTransform.h"
+#include "OptiXGeometryInstance.h"
+#include "OptiXGeometryGroup.h"
+
+#include "OptiXGroup.generated.h"
+
+DECLARE_LOG_CATEGORY_EXTERN(OptiXPluginGroup, Log, All);
+
+
+UCLASS(hidecategories = Object, BlueprintType)
+class OPTIX_API UOptiXGroup : public UObject
+{
+	GENERATED_BODY() // Apparently GENERATED_UCLASS_BODY is deprecated?
+
+public:
+
+	virtual void BeginDestroy() override;
+
+	optix::Group GetNativeGroup()
+	{
+		return NativeGroup;
+	}
+
+	void SetNativeGroup(optix::Group Group)
+	{
+		NativeGroup = Group;
+	}
+
+	void DestroyOptiXObject();
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGroup")
+	void SetAcceleration(UOptiXAcceleration* Accel);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGroup")
+	UOptiXAcceleration* GetAcceleration();
+
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGroup")
+	void SetChildCount(uint8 Count);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGroup")
+	uint8 GetChildCount();
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGroup")
+	void SetChild(uint8 Index, UObject* Child);
+
+	RTobjecttype GetChildType(uint8 Index);
+	
+	////// Adds the material and returns the index to the added material.
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGroup")
+	UObject* GetChild(uint8 Index);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGroup")
+	uint8 AddChild(UObject* Child);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGroup")
+	uint8 RemoveChild(UObject* Child);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGroup")
+	void RemoveChildByIndex(uint8 Index);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXGroup")
+	uint8 GetChildIndex(UObject* Child);
+
+
+	UPROPERTY(BlueprintReadOnly, Category = "OptiXGroup")
+	int32 ChildCount = 0;
+
+	// TODO Set up some nice inheritance so we don't need to use UObject here but maybe UOptiXObject
+	// or some kind of interface.
+	UPROPERTY()
+	TArray<UObject*> Children;
+
+	UPROPERTY()
+	UOptiXAcceleration* Acceleration;
+
+protected:
+
+	optix::Group NativeGroup;
+
+
 };
\ No newline at end of file
diff --git a/Source/OptiX/Public/OptiXMaterial.h b/Deprecated/Public/OptiXMaterial.h
similarity index 97%
rename from Source/OptiX/Public/OptiXMaterial.h
rename to Deprecated/Public/OptiXMaterial.h
index 5bbec39de26bb3faeb8bf821bdf4eee4bece5482..9acf5e1e6525b9c91cfe9d0f5e0f42eff6dd2754 100644
--- a/Source/OptiX/Public/OptiXMaterial.h
+++ b/Deprecated/Public/OptiXMaterial.h
@@ -1,182 +1,182 @@
-#pragma once
-
-#include "CoreMinimal.h"
-#include "UObject/ObjectMacros.h"
-#include "Engine/EngineTypes.h"
-
-#include "OptiXProgram.h"
-//#include "OptiXModule.h"
-
-#include "OptiXMaterial.generated.h"
-
-UCLASS(hidecategories = Object, BlueprintType)
-class OPTIX_API UOptiXMaterial : public UObject
-{
-	GENERATED_BODY() // Apparently GENERATED_UCLASS_BODY is deprecated?
-
-public:
-
-	virtual void BeginDestroy() override;
-
-	void SetMaterial(optix::Material Mat)
-	{
-		NativeMaterial = Mat;
-	}
-
-	void DestroyOptiXObject();
-
-	optix::Material GetNativeMaterial()
-	{
-		return NativeMaterial;
-	}
-	// Setter Functions - apparently overloading isn't actually possible so I need to restructure EVERYTHING again
-	// Only do the important ones for now as I might need to scrap that again.
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXMaterial")
-		void SetFloat(FString string, float Var);
-
-	//void SetFloat2D(FString string, FVector2D Var)
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXMaterial")
-		void SetFloat2D(FString string, float Var1, float Var2);
-
-	// 3D Float
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXMaterial")
-		void SetFloat3DVector(FString string, FVector Var);
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXMaterial")
-		void SetFloat3D(FString string, float Var1, float Var2, float Var3);
-
-	// 4D Float
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXMaterial")
-		void SetFloat4DVector(FString string, FVector4 Var);
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXMaterial")
-		void SetFloat4D(FString string, float Var1, float Var2, float Var3, float Var4);
-
-
-	// 1D Int
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXMaterial")
-		void SetInt(FString string, int32 Var);
-
-	// 2D Int - wow Unreal your naming scheme is really top notch...
-	//void SetInt2D(FString string, FIntPoint Var)
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXMaterial")
-		void SetInt2D(FString string, int32 Var1, int32 Var2);
-
-	// 3D Int
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXMaterial")
-		void SetInt3DVector(FString string, FIntVector Var);
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXMaterial")
-		void SetInt3D(FString string, int32 Var1, int32 Var2, int32 Var3);
-
-	// 4D Int
-	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXMaterial")
-	//void SetInt4DVector(FString string, FIntVector4 Var);
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXMaterial")
-		void SetInt4D(FString string, int32 Var1, int32 Var2, int32 Var3, int32 Var4);
-
-
-
-	// 1D Uint
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXMaterial")
-		void SetUint(FString string, uint8 Var);
-
-	// 2D Uint - wow Unreal your naming scheme is really top notch...
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXMaterial")
-		void SetUint2D(FString string, uint8 Var1, uint8 Var2);
-
-	// 3D Uint
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXMaterial")
-		void SetUint3D(FString string, uint8 Var1, uint8 Var2, uint8 Var3);
-
-	// 4D Uint
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXMaterial")
-		void SetUint4D(FString string, uint8 Var1, uint8 Var2, uint8 Var3, uint8 Var4);
-
-
-	// Matrices - careful Unreal uses ROW_MAJOR LAYOUT
-	// TODO They will be a pain
-
-	////
-	//// Getters (gotta love wrappers)
-	////
-
-	// Can't overload return type so this is going to be ugly
-
-	// Floats
-	// 1D Float
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXMaterial")
-		float GetFloat(FString string);
-
-	// 2D Float
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXMaterial")
-		FVector2D GetFloat2D(FString string);
-
-	// 3D Float
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXMaterial")
-		FVector GetFloat3D(FString string);
-
-	// 4D Float
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXMaterial")
-		FVector4 GetFloat4D(FString string);
-
-
-	//// Ints
-
-	// 1D Int
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXMaterial")
-		int32 GetInt(FString string);
-
-	// 2D Int - wow Unreal your naming scheme is really top notch...
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXMaterial")
-		FIntPoint GetInt2D(FString string);
-
-	// 3D Int
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXMaterial")
-		FIntVector GetInt3D(FString string);
-
-	// 4D Int
-	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXMaterial")
-	//FIntVector4 GetInt4D(FString string);
-
-
-
-	//// UInts are bad
-
-	// 1D UInt
-	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXMaterial")
-	//uint8 GetUint(FString string);
-
-	//// 2D UInt
-	//// Have to do it per reference, TODO test me
-	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXMaterial")
-	//void GetUint2D(FString& string, uint8& Var1, uint8& Var2);
-
-	//// 3D UInt
-	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXMaterial")
-	//void GetUint3D(FString string, uint8& Var1, uint8& Var2, uint8& Var3);
-
-	//// 4D UInt
-	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXMaterial")
-	//FUintVector4 GetUint4D(FString string);
-
-
-
-
-	// Todo: Program def. needs to be wrapped as well and made available to the blueprint editor even!
-	void SetClosestHitProgram(uint32 RayTypeIndex, UOptiXProgram* Program);
-	UOptiXProgram* GetClosestHitProgram(uint32 RayTypeIndex);
-
-	void SetAnyHitProgram(uint32 RayTypeIndex, UOptiXProgram* Program);
-	UOptiXProgram* GetAnyHitProgram(uint32 RayTypeIndex);
-
-protected:
-
-	optix::Material NativeMaterial;
-
-	UPROPERTY()
-	TArray<UOptiXProgram*> ClosestHitPrograms;
-
-	UPROPERTY()
-	UOptiXProgram* AnyHitProgram;
-
+#pragma once
+
+#include "CoreMinimal.h"
+#include "UObject/ObjectMacros.h"
+#include "Engine/EngineTypes.h"
+
+#include "OptiXProgram.h"
+//#include "OptiXModule.h"
+
+#include "OptiXMaterial.generated.h"
+
+UCLASS(hidecategories = Object, BlueprintType)
+class OPTIX_API UOptiXMaterial : public UObject
+{
+	GENERATED_BODY() // Apparently GENERATED_UCLASS_BODY is deprecated?
+
+public:
+
+	virtual void BeginDestroy() override;
+
+	void SetMaterial(optix::Material Mat)
+	{
+		NativeMaterial = Mat;
+	}
+
+	void DestroyOptiXObject();
+
+	optix::Material GetNativeMaterial()
+	{
+		return NativeMaterial;
+	}
+	// Setter Functions - apparently overloading isn't actually possible so I need to restructure EVERYTHING again
+	// Only do the important ones for now as I might need to scrap that again.
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXMaterial")
+		void SetFloat(FString string, float Var);
+
+	//void SetFloat2D(FString string, FVector2D Var)
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXMaterial")
+		void SetFloat2D(FString string, float Var1, float Var2);
+
+	// 3D Float
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXMaterial")
+		void SetFloat3DVector(FString string, FVector Var);
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXMaterial")
+		void SetFloat3D(FString string, float Var1, float Var2, float Var3);
+
+	// 4D Float
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXMaterial")
+		void SetFloat4DVector(FString string, FVector4 Var);
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXMaterial")
+		void SetFloat4D(FString string, float Var1, float Var2, float Var3, float Var4);
+
+
+	// 1D Int
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXMaterial")
+		void SetInt(FString string, int32 Var);
+
+	// 2D Int - wow Unreal your naming scheme is really top notch...
+	//void SetInt2D(FString string, FIntPoint Var)
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXMaterial")
+		void SetInt2D(FString string, int32 Var1, int32 Var2);
+
+	// 3D Int
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXMaterial")
+		void SetInt3DVector(FString string, FIntVector Var);
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXMaterial")
+		void SetInt3D(FString string, int32 Var1, int32 Var2, int32 Var3);
+
+	// 4D Int
+	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXMaterial")
+	//void SetInt4DVector(FString string, FIntVector4 Var);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXMaterial")
+		void SetInt4D(FString string, int32 Var1, int32 Var2, int32 Var3, int32 Var4);
+
+
+
+	// 1D Uint
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXMaterial")
+		void SetUint(FString string, uint8 Var);
+
+	// 2D Uint - wow Unreal your naming scheme is really top notch...
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXMaterial")
+		void SetUint2D(FString string, uint8 Var1, uint8 Var2);
+
+	// 3D Uint
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXMaterial")
+		void SetUint3D(FString string, uint8 Var1, uint8 Var2, uint8 Var3);
+
+	// 4D Uint
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXMaterial")
+		void SetUint4D(FString string, uint8 Var1, uint8 Var2, uint8 Var3, uint8 Var4);
+
+
+	// Matrices - careful Unreal uses ROW_MAJOR LAYOUT
+	// TODO They will be a pain
+
+	////
+	//// Getters (gotta love wrappers)
+	////
+
+	// Can't overload return type so this is going to be ugly
+
+	// Floats
+	// 1D Float
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXMaterial")
+		float GetFloat(FString string);
+
+	// 2D Float
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXMaterial")
+		FVector2D GetFloat2D(FString string);
+
+	// 3D Float
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXMaterial")
+		FVector GetFloat3D(FString string);
+
+	// 4D Float
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXMaterial")
+		FVector4 GetFloat4D(FString string);
+
+
+	//// Ints
+
+	// 1D Int
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXMaterial")
+		int32 GetInt(FString string);
+
+	// 2D Int - wow Unreal your naming scheme is really top notch...
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXMaterial")
+		FIntPoint GetInt2D(FString string);
+
+	// 3D Int
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXMaterial")
+		FIntVector GetInt3D(FString string);
+
+	// 4D Int
+	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXMaterial")
+	//FIntVector4 GetInt4D(FString string);
+
+
+
+	//// UInts are bad
+
+	// 1D UInt
+	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXMaterial")
+	//uint8 GetUint(FString string);
+
+	//// 2D UInt
+	//// Have to do it per reference, TODO test me
+	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXMaterial")
+	//void GetUint2D(FString& string, uint8& Var1, uint8& Var2);
+
+	//// 3D UInt
+	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXMaterial")
+	//void GetUint3D(FString string, uint8& Var1, uint8& Var2, uint8& Var3);
+
+	//// 4D UInt
+	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXMaterial")
+	//FUintVector4 GetUint4D(FString string);
+
+
+
+
+	// Todo: Program def. needs to be wrapped as well and made available to the blueprint editor even!
+	void SetClosestHitProgram(uint32 RayTypeIndex, UOptiXProgram* Program);
+	UOptiXProgram* GetClosestHitProgram(uint32 RayTypeIndex);
+
+	void SetAnyHitProgram(uint32 RayTypeIndex, UOptiXProgram* Program);
+	UOptiXProgram* GetAnyHitProgram(uint32 RayTypeIndex);
+
+protected:
+
+	optix::Material NativeMaterial;
+
+	UPROPERTY()
+	TArray<UOptiXProgram*> ClosestHitPrograms;
+
+	UPROPERTY()
+	UOptiXProgram* AnyHitProgram;
+
 };
\ No newline at end of file
diff --git a/Source/OptiX/Public/OptiXProgram.h b/Deprecated/Public/OptiXProgram.h
similarity index 94%
rename from Source/OptiX/Public/OptiXProgram.h
rename to Deprecated/Public/OptiXProgram.h
index 0530517d28778f6ab9d8688d311d9887ef58c081..7fe1c352a8aedbcc0cf5de5111382b6ed3d72f4f 100644
--- a/Source/OptiX/Public/OptiXProgram.h
+++ b/Deprecated/Public/OptiXProgram.h
@@ -1,62 +1,62 @@
-#pragma once
-
-#include "CoreMinimal.h"
-#include "UObject/ObjectMacros.h"
-#include "Engine/EngineTypes.h"
-
-#include "OptiXIncludes.h"
-
-#include "OptiXProgram.generated.h"
-/*
-
-Simple Program wrapper, should move to own file.
-Needs some functionality!
-
-*/
-
-UCLASS(hidecategories = Object, BlueprintType)
-class OPTIX_API UOptiXProgram : public UObject
-{
-	GENERATED_BODY()
-public:
-
-	void SetProgram(optix::Program Prog)
-	{
-		NativeProgram = Prog;
-	}
-
-	optix::Program GetNativeProgram()
-	{
-		return NativeProgram;
-	}
-
-	virtual void BeginDestroy() override
-	{
-		UE_LOG(LogTemp, Warning, TEXT("OptiX Program BeginDestroy %s"), *this->GetFullName());
-		//DestroyOptiXObject();
-
-
-		//void UOptiXProgram::DestroyOptiXObject()
-		//{
-		//	if (NativeProgram != NULL)
-		//	{
-		//		FOptiXModule::Get().GetOptiXContextManager()->QueueNativeObjectForDestruction(NativeProgram);
-		//		//NativeProgram->destroy();
-		//	}
-
-		//	NativeProgram = NULL;
-		//}
-
-
-		Super::BeginDestroy();
-	}
-
-	//void DestroyOptiXObject();
-
-
-
-protected:
-
-	optix::Program NativeProgram;
-
+#pragma once
+
+#include "CoreMinimal.h"
+#include "UObject/ObjectMacros.h"
+#include "Engine/EngineTypes.h"
+
+#include "OptiXIncludes.h"
+
+#include "OptiXProgram.generated.h"
+/*
+
+Simple Program wrapper, should move to own file.
+Needs some functionality!
+
+*/
+
+UCLASS(hidecategories = Object, BlueprintType)
+class OPTIX_API UOptiXProgram : public UObject
+{
+	GENERATED_BODY()
+public:
+
+	void SetProgram(optix::Program Prog)
+	{
+		NativeProgram = Prog;
+	}
+
+	optix::Program GetNativeProgram()
+	{
+		return NativeProgram;
+	}
+
+	virtual void BeginDestroy() override
+	{
+		UE_LOG(LogTemp, Warning, TEXT("OptiX Program BeginDestroy %s"), *this->GetFullName());
+		//DestroyOptiXObject();
+
+
+		//void UOptiXProgram::DestroyOptiXObject()
+		//{
+		//	if (NativeProgram != NULL)
+		//	{
+		//		FOptiXModule::Get().GetOptiXContextManager()->QueueNativeObjectForDestruction(NativeProgram);
+		//		//NativeProgram->destroy();
+		//	}
+
+		//	NativeProgram = NULL;
+		//}
+
+
+		Super::BeginDestroy();
+	}
+
+	//void DestroyOptiXObject();
+
+
+
+protected:
+
+	optix::Program NativeProgram;
+
 };
\ No newline at end of file
diff --git a/Source/OptiX/Public/OptiXTextureSampler.h b/Deprecated/Public/OptiXTextureSampler.h
similarity index 97%
rename from Source/OptiX/Public/OptiXTextureSampler.h
rename to Deprecated/Public/OptiXTextureSampler.h
index dac62c0911cb95f6687344abffca3ac19b38c39e..c2f77e2623bd4fcb2612fad78696b29871a47dfd 100644
--- a/Source/OptiX/Public/OptiXTextureSampler.h
+++ b/Deprecated/Public/OptiXTextureSampler.h
@@ -1,120 +1,119 @@
-#pragma once
-
-#include "CoreMinimal.h"
-#include "UObject/ObjectMacros.h"
-#include "Engine/EngineTypes.h"
-
-#include "OptiXIncludes.h"
-
-#include "OptiXDeclarations.h"
-#include "OptiXBuffer.h"
-
-#include "OptiXTextureSampler.generated.h"
-
-DECLARE_LOG_CATEGORY_EXTERN(OptiXPluginTextureSampler, Log, All);
-
-
-
-UCLASS(hidecategories = Object, BlueprintType)
-class OPTIX_API UOptiXTextureSampler : public UObject
-{
-	GENERATED_BODY() // Apparently GENERATED_UCLASS_BODY is deprecated?
-
-public:
-
-	virtual void BeginDestroy() override;
-
-	optix::TextureSampler GetNativeTextureSampler()
-	{
-		return NativeTextureSampler;
-	}
-
-	void SetTextureSampler(optix::TextureSampler S)
-	{
-		NativeTextureSampler = S;
-	}
-
-	void DestroyOptiXObject();
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXTextureSampler")
-	void Validate();
-	
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXTextureSampler")
-	void SetMipLevelCount(uint8 NumMipLevels);
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXTextureSampler")
-	uint8 GetMipLevelCount();
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXTextureSampler")
-	void SetArraySize(int32 NumTexturesInArray);
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXTextureSampler")
-	int32 GetArraySize();
-
-	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXTextureSampler")
-	void SetWrapMode(int32 Dim, RTwrapmode Wrapmode);
-
-	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXTextureSampler")
-	RTwrapmode GetWrapMode(int32 Dim);
-
-	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXTextureSampler")
-	void SetFilteringModes(RTfiltermode Minification, RTfiltermode Magnification, RTfiltermode Mipmapping);
-
-	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXTextureSampler")
-	void GetFilteringModes(RTfiltermode& Minification, RTfiltermode& Magnification, RTfiltermode& Mipmapping);
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXTextureSampler")
-	void SetMaxAnisotropy(float Value);
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXTextureSampler")
-	float GetMaxAnisotropy();
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXTextureSampler")
-	void SetMipLevelClamp(float Min, float Max);
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXTextureSampler")
-	FVector2D GetMipLevelClamp();
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXTextureSampler")
-	void SetMipLevelBias(float Value);
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXTextureSampler")
-	float GetMipLevelBias();
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXTextureSampler")
-	int32 GetId();
-
-	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXTextureSampler")
-	void SetReadMode(RTtexturereadmode Readmode);
-
-	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXTextureSampler")
-	RTtexturereadmode GetReadMode();
-
-	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXTextureSampler")
-	void SetIndexingMode(RTtextureindexmode Mode);
-
-	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXTextureSampler")
-	RTtextureindexmode GetIndexingMode();
-
-	// Damn blueprints don't allow overloading :|
-	// TODO Look into this and how it's actually used.
-	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXTextureSampler")
-	void SetBufferWithTextureIndexAndMiplevel(int32 TextureArrayIndex, int MipLevel, UOptiXBuffer* Buffer);
-
-	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXTextureSampler")
-	UOptiXBuffer* GetBufferByTextureIndexAndMiplevel(int32 TextureArrayIndex, int MipLevel);
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXTextureSampler")
-	void SetBuffer(UOptiXBuffer* Buffer);
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXTextureSampler")
-	UOptiXBuffer* GetBuffer();
-
-protected:
-
-	optix::TextureSampler NativeTextureSampler;
-
-	UPROPERTY()
-	UOptiXBuffer* OptiXBuffer;
-
+#pragma once
+
+#include "CoreMinimal.h"
+#include "UObject/ObjectMacros.h"
+#include "Engine/EngineTypes.h"
+
+#include "OptiXIncludes.h"
+
+#include "OptiXBuffer.h"
+
+#include "OptiXTextureSampler.generated.h"
+
+DECLARE_LOG_CATEGORY_EXTERN(OptiXPluginTextureSampler, Log, All);
+
+
+
+UCLASS(hidecategories = Object, BlueprintType)
+class OPTIX_API UOptiXTextureSampler : public UObject
+{
+	GENERATED_BODY() // Apparently GENERATED_UCLASS_BODY is deprecated?
+
+public:
+
+	virtual void BeginDestroy() override;
+
+	optix::TextureSampler GetNativeTextureSampler()
+	{
+		return NativeTextureSampler;
+	}
+
+	void SetTextureSampler(optix::TextureSampler S)
+	{
+		NativeTextureSampler = S;
+	}
+
+	void DestroyOptiXObject();
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXTextureSampler")
+	void Validate();
+	
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXTextureSampler")
+	void SetMipLevelCount(uint8 NumMipLevels);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXTextureSampler")
+	uint8 GetMipLevelCount();
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXTextureSampler")
+	void SetArraySize(int32 NumTexturesInArray);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXTextureSampler")
+	int32 GetArraySize();
+
+	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXTextureSampler")
+	void SetWrapMode(int32 Dim, RTwrapmode Wrapmode);
+
+	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXTextureSampler")
+	RTwrapmode GetWrapMode(int32 Dim);
+
+	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXTextureSampler")
+	void SetFilteringModes(RTfiltermode Minification, RTfiltermode Magnification, RTfiltermode Mipmapping);
+
+	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXTextureSampler")
+	void GetFilteringModes(RTfiltermode& Minification, RTfiltermode& Magnification, RTfiltermode& Mipmapping);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXTextureSampler")
+	void SetMaxAnisotropy(float Value);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXTextureSampler")
+	float GetMaxAnisotropy();
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXTextureSampler")
+	void SetMipLevelClamp(float Min, float Max);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXTextureSampler")
+	FVector2D GetMipLevelClamp();
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXTextureSampler")
+	void SetMipLevelBias(float Value);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXTextureSampler")
+	float GetMipLevelBias();
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXTextureSampler")
+	int32 GetId();
+
+	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXTextureSampler")
+	void SetReadMode(RTtexturereadmode Readmode);
+
+	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXTextureSampler")
+	RTtexturereadmode GetReadMode();
+
+	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXTextureSampler")
+	void SetIndexingMode(RTtextureindexmode Mode);
+
+	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXTextureSampler")
+	RTtextureindexmode GetIndexingMode();
+
+	// Damn blueprints don't allow overloading :|
+	// TODO Look into this and how it's actually used.
+	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXTextureSampler")
+	void SetBufferWithTextureIndexAndMiplevel(int32 TextureArrayIndex, int MipLevel, UOptiXBuffer* Buffer);
+
+	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXTextureSampler")
+	UOptiXBuffer* GetBufferByTextureIndexAndMiplevel(int32 TextureArrayIndex, int MipLevel);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXTextureSampler")
+	void SetBuffer(UOptiXBuffer* Buffer);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXTextureSampler")
+	UOptiXBuffer* GetBuffer();
+
+protected:
+
+	optix::TextureSampler NativeTextureSampler;
+
+	UPROPERTY()
+	UOptiXBuffer* OptiXBuffer;
+
 };
\ No newline at end of file
diff --git a/Source/OptiX/Public/OptiXTransform.h b/Deprecated/Public/OptiXTransform.h
similarity index 96%
rename from Source/OptiX/Public/OptiXTransform.h
rename to Deprecated/Public/OptiXTransform.h
index 752dc9363329ac3fc37bc95edcd66a75bc113207..9df22711c5ea0156b6ce6fb79640f2bfa2bc48f0 100644
--- a/Source/OptiX/Public/OptiXTransform.h
+++ b/Deprecated/Public/OptiXTransform.h
@@ -1,81 +1,81 @@
-#pragma once
-
-#include "CoreMinimal.h"
-#include "UObject/ObjectMacros.h"
-#include "Engine/EngineTypes.h"
-
-#include "OptiXIncludes.h"
-
-#include "OptiXAcceleration.h"
-#include "OptiXGeometryInstance.h"
-#include "OptiXGeometryGroup.h"
-
-#include "OptiXTransform.generated.h"
-
-DECLARE_LOG_CATEGORY_EXTERN(OptiXPluginTransform, Log, All);
-
-
-UCLASS(hidecategories = Object, BlueprintType)
-class OPTIX_API UOptiXTransform : public UObject
-{
-	GENERATED_BODY() // Apparently GENERATED_UCLASS_BODY is deprecated?
-
-public:
-
-	virtual void BeginDestroy() override;
-
-	optix::Transform GetNativeTransform()
-	{
-		return NativeTransform;
-	}
-
-	void SetNativeGroup(optix::Transform T)
-	{
-		NativeTransform = T;
-	}
-
-	void DestroyOptiXObject();
-
-	void UpdateTransform();
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXTransform")
-	void SetChild(UObject* Child);
-
-	RTobjecttype GetChildType();
-
-	////// Adds the material and returns the index to the added material.
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXTransform")
-	UObject* GetChild();
-
-	// Sets and caches the matrix, the rendering thread will then pass it to the optix context.
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXTransform")
-	void SetMatrix(FMatrix Matrix);
-
-	// WARNING: NOT THREADSAFE
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXTransform")
-	void SetMatrixImmediate(FMatrix Matrix);
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXTransform")
-	FMatrix GetMatrix();
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXTransform")
-	void SetMotionRange(float TimeBegin, float TimeEnd);
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXTransform")
-	FVector2D GetMotionRange();
-
-	// MotionBorderMode TODO but who needs that even
-
-	// TODO Set up some nice inheritance so we don't need to use UObject here but maybe UOptiXObject
-	// or some kind of interface.
-	UPROPERTY()
-	UObject* OptiXChild;
-
-	UPROPERTY()
-	FMatrix TransformMatrix;
-
-protected:
-
-	optix::Transform NativeTransform;
-
+#pragma once
+
+#include "CoreMinimal.h"
+#include "UObject/ObjectMacros.h"
+#include "Engine/EngineTypes.h"
+
+#include "OptiXIncludes.h"
+
+#include "OptiXAcceleration.h"
+#include "OptiXGeometryInstance.h"
+#include "OptiXGeometryGroup.h"
+
+#include "OptiXTransform.generated.h"
+
+DECLARE_LOG_CATEGORY_EXTERN(OptiXPluginTransform, Log, All);
+
+
+UCLASS(hidecategories = Object, BlueprintType)
+class OPTIX_API UOptiXTransform : public UObject
+{
+	GENERATED_BODY() // Apparently GENERATED_UCLASS_BODY is deprecated?
+
+public:
+
+	virtual void BeginDestroy() override;
+
+	optix::Transform GetNativeTransform()
+	{
+		return NativeTransform;
+	}
+
+	void SetNativeGroup(optix::Transform T)
+	{
+		NativeTransform = T;
+	}
+
+	void DestroyOptiXObject();
+
+	void UpdateTransform();
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXTransform")
+	void SetChild(UObject* Child);
+
+	RTobjecttype GetChildType();
+
+	////// Adds the material and returns the index to the added material.
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXTransform")
+	UObject* GetChild();
+
+	// Sets and caches the matrix, the rendering thread will then pass it to the optix context.
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXTransform")
+	void SetMatrix(FMatrix Matrix);
+
+	// WARNING: NOT THREADSAFE
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXTransform")
+	void SetMatrixImmediate(FMatrix Matrix);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXTransform")
+	FMatrix GetMatrix();
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXTransform")
+	void SetMotionRange(float TimeBegin, float TimeEnd);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXTransform")
+	FVector2D GetMotionRange();
+
+	// MotionBorderMode TODO but who needs that even
+
+	// TODO Set up some nice inheritance so we don't need to use UObject here but maybe UOptiXObject
+	// or some kind of interface.
+	UPROPERTY()
+	UObject* OptiXChild;
+
+	UPROPERTY()
+	FMatrix TransformMatrix;
+
+protected:
+
+	optix::Transform NativeTransform;
+
 };
\ No newline at end of file
diff --git a/Source/OptiX/OptiX.Build.cs b/Source/OptiX/OptiX.Build.cs
index 1cd1fc5737369172e3e9ab6f2e59e975b1d2168d..6de3f36b6ec6ab46fcf5699b4fd3a504eeb96b9d 100644
--- a/Source/OptiX/OptiX.Build.cs
+++ b/Source/OptiX/OptiX.Build.cs
@@ -47,7 +47,10 @@ public class OptiX : ModuleRules
                 "UMG",
                 "Slate",
                 "SlateCore",
-                "D3D11RHI"
+                "D3D11RHI",
+                "UtilityShaders",
+                "Analytics",
+                "EngineSettings"
 
             }
             );
@@ -65,7 +68,10 @@ public class OptiX : ModuleRules
                 "JsonUtilities",
                 "RenderCore",
                 "RHI",
-                "D3D11RHI"
+                "D3D11RHI",
+                "UtilityShaders",
+                "Analytics",
+                "EngineSettings"
             }
             );
 
diff --git a/Source/OptiX/Private/OptiXCameraActor.cpp b/Source/OptiX/Private/OptiXCameraActor.cpp
index fb472b14bafe6679d0e6dd6869c27ecf2488a929..d9ac0f250bcb12fb525523d7df1185b65360baa4 100644
--- a/Source/OptiX/Private/OptiXCameraActor.cpp
+++ b/Source/OptiX/Private/OptiXCameraActor.cpp
@@ -1,206 +1,205 @@
-#undef UpdateResource
-
-#include "OptiXCameraActor.h"
-
-#include "OptiXModule.h"
-#include "OptiXTextureSampler.h"
-#include "OptiXLaserActor.h"
-
-#include "Engine/EngineTypes.h"
-#include <EngineGlobals.h>
-#include "Runtime/Engine/Classes/Camera/PlayerCameraManager.h"
-#include "Runtime/Engine/Classes/Kismet/GameplayStatics.h"
-#include "Runtime/Engine/Classes/Engine/LocalPlayer.h"
-#include "Runtime/Engine/Public/SceneView.h"
-#include <Runtime/Engine/Classes/Engine/Engine.h>
-#include "Runtime/Engine/Public/HighResScreenshot.h"
-#include "Runtime/Engine/Classes/Engine/TextureRenderTarget2D.h"
-#include "Runtime/Engine/Classes/Engine/TextureRenderTargetCube.h"
-#include "Runtime/Engine/Classes/Materials/MaterialInstanceDynamic.h"
-#include "Runtime/Engine/Classes/Engine/Light.h"
-#include "Runtime/Engine/Classes/GameFramework/GameUserSettings.h"
-#include "Runtime/Engine/Classes/GameFramework/PlayerStart.h"
-
-// VR
-#include "Runtime/HeadMountedDisplay/Public/IHeadMountedDisplay.h"
-#include "Runtime/HeadMountedDisplay/Public/IXRTrackingSystem.h"
-#include "Runtime/HeadMountedDisplay/Public/IXRCamera.h"
-
-#include "Runtime/Engine/Classes/Camera/CameraActor.h"
-
-#include "StatsDefines.h"
-
-
-DEFINE_LOG_CATEGORY(OptiXPluginCameraActor);
-
-
-UOptiXBlendable::UOptiXBlendable(const FObjectInitializer& ObjectInitializer)
-	: Super(ObjectInitializer)
-{
-	BlendWeight = 1.0f;
-}
-
-void UOptiXBlendable::OverrideBlendableSettings(FSceneView & View, float InWeight) const
-{
-	float Weight = FMath::Clamp(BlendWeight, 0.0f, 1.0f) * InWeight;
-}
-
-AOptiXPlayerCameraManager::AOptiXPlayerCameraManager(const FObjectInitializer& ObjectInitializer)
-	: Super(ObjectInitializer)
-{
-	UE_LOG(OptiXPluginCameraActor, Display, TEXT("Optix Camera Manager Constructor!"));
-
-	SceneCaptureComponent = ObjectInitializer.CreateDefaultSubobject<USceneCaptureComponent2D>(this, TEXT("SceneCaptureComponent0"));
-	RootComponent = SceneCaptureComponent;
-	SceneCaptureComponent->bCaptureEveryFrame = false;
-	SceneCaptureComponent->bCaptureOnMovement = false;
-	//SceneCaptureComponent->bEnableClipPlane = true; // don't want ourself in the capture
-	SceneCaptureComponent->FOVAngle = 90.0f;
-	SceneCaptureComponent->HideActorComponents(this);
-	//SceneCaptureComponent->CaptureSource = SCS_SceneColorHDR;
-	//SceneCaptureComponent->HideActorComponents(UGameplayStatics::GetPlayerController(GetWorld(), 0));
-	//SceneCaptureComponent->HideActorComponents(UGameplayStatics::GetPlayerPawn(GetWorld(), 0));
-
-	SceneCaptureCubeComponent = ObjectInitializer.CreateDefaultSubobject<USceneCaptureComponentCube>(this, TEXT("SceneCaptureComponentCube0"));
-	SceneCaptureCubeComponent->SetupAttachment(SceneCaptureComponent);
-	SceneCaptureCubeComponent->bCaptureEveryFrame = false;
-	SceneCaptureCubeComponent->bCaptureOnMovement = false;
-	SceneCaptureCubeComponent->HideActorComponents(this);
-
-
-	PostProcessComponent = ObjectInitializer.CreateDefaultSubobject<UPostProcessComponent>(this, TEXT("PostProcessComponent0"));
-	PostProcessComponent->SetupAttachment(SceneCaptureCubeComponent); // Doesn't matter anyway
-	PostProcessComponent->bUnbound = true; // Should be default anyway
-
-	PrimaryActorTick.bCanEverTick = true;
-	//PrimaryActorTick.TickGroup = TG_PostUpdateWork;
-
-
-	// TODO DEBUG CREATE IN C++
-	//static ConstructorHelpers::FObjectFinder<UTextureRenderTargetCube> RT(TEXT("TextureRenderTarget2D'/OptiX/PPMaterials/RTCube.RTCube'"));
-
-	//if (RT.Object != NULL)
-	//{
-	//	CubeRenderTarget = RT.Object;
-	//	SceneCaptureCubeComponent->TextureTarget = CubeRenderTarget;
-
-	//}
-
-
-	CubeRenderTarget = NewObject<UTextureRenderTargetCube>();
-	CubeRenderTarget->Init(1024, PF_B8G8R8A8);
-	CubeRenderTarget->UpdateResource();
-	SceneCaptureCubeComponent->TextureTarget = CubeRenderTarget;
-
-	//FRotator Rotation = FRotationMatrix::MakeFromX(Directions[i]).Rotator();
-	//FQuat Q = FQuat({ 1, 0, 0 });
-	//SceneCaptureComponent->AddWorldRotation();
-
-	for (uint8 i = 0; i < 6; i++)
-	{
-		UTextureRenderTarget2D* RenderTarget = NewObject<UTextureRenderTarget2D>();
-		//RenderTarget->AddToRoot();
-		RenderTarget->InitCustomFormat(CubemapSize, CubemapSize, PF_B8G8R8A8, true);
-		//RenderTarget->CompressionSettings = TextureCompressionSettings::TC_VectorDisplacementmap;
-		//RenderTarget->SRGB = 0;
-		//RenderTarget->TargetGamma = 2.2;
-		RenderTarget->NeverStream = 1;
-		//RenderTarget->InitAutoFormat(CubemapSize, CubemapSize);
-		RenderTarget->UpdateResourceImmediate(); //???
-		//RenderTarget->AdjustBrightness = 1.0; // ??? TODO
-		CubemapRenderTargets.Add(RenderTarget);
-	}
-
-}
-
-void AOptiXPlayerCameraManager::BeginPlay()
-{
-	
-	//UGameplayStatics::GetPlayerController(GetWorld(), 0)->SetViewTarget(this);
-	UE_LOG(OptiXPluginCameraActor, Display, TEXT("OptiX Camera Manager Begin Play!"));
-	Super::BeginPlay();
-
-	Init();
-}
-
-void AOptiXPlayerCameraManager::EndPlay(const EEndPlayReason::Type EndPlayReason)
-{
-	// Clean up again TODO
-	Super::EndPlay(EndPlayReason);
-}
-
-void AOptiXPlayerCameraManager::Tick(float DeltaSeconds)
-{
-	TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("AOptiXPlayerCameraManager::Tick"))
-
-	Super::Tick(DeltaSeconds);
-	if (C == 2)
-	{
-		CaptureCubemap();
-		bCubemapCaptured.AtomicSet(true);
-		//InitCubemap();
-		SetActorTickEnabled(false);
-		return; // no need to increase C further
-	}
-	C++;
-}
-
-
-void AOptiXPlayerCameraManager::Init()
-{
-	BlendableVR = FOptiXModule::Get().GetOptiXContextManager()->GetOptiXMID();	
-	PostProcessComponent->AddOrUpdateBlendable(BlendableVR, 1.0f);
-	FOptiXModule::Get().GetOptiXContextManager()->SetActiveCameraActor(this);
-
-	BlendableOrtho = FOptiXModule::Get().GetOptiXContextManager()->GetOptiXMIDOrtho();
-	PostProcessComponent->AddOrUpdateBlendable(BlendableOrtho, 0.0f);
-}
-
-
-void AOptiXPlayerCameraManager::CaptureCubemap()
-{
-	TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("AOptiXPlayerCameraManager::CaptureCubemap"))
-
-	// 2D
-	TArray<FVector> Directions =
-	{
-		{1, 0, 0},
-		{-1, 0, 0},
-		{0, 1, 0},
-		{0, -1, 0},
-		{0, 0, -1},
-		{0, 0, 1}
-	};
-
-	SceneCaptureComponent->HideActorComponents(UGameplayStatics::GetPlayerController(GetWorld(), 0));
-	SceneCaptureComponent->HideActorComponents(UGameplayStatics::GetPlayerPawn(GetWorld(), 0));
-	
-	TArray<AActor*> FoundLaserActors;
-	UGameplayStatics::GetAllActorsOfClass(GetWorld(), AOptiXLaserActor::StaticClass(), FoundLaserActors);
-
-	for (AActor* Actor : FoundLaserActors)
-	{
-		SceneCaptureComponent->HideComponent(Cast<AOptiXLaserActor>(Actor)->LineInstancedStaticMeshComponent);
-		SceneCaptureCubeComponent->HideComponent(Cast<AOptiXLaserActor>(Actor)->LineInstancedStaticMeshComponent);
-	}
-
-	// the actual camera position is still 0 here, so the capture would be at the origin and not the actual player start.
-	// Let's move the capture "into" the first lens actor. 
-
-	TArray<AActor*> FoundPlayerStarts;
-	UGameplayStatics::GetAllActorsOfClass(GetWorld(), APlayerStart::StaticClass(), FoundPlayerStarts);
-
-
-	FVector Loc = FoundPlayerStarts[0]->GetActorLocation(); // Just use the first one
-
-	// CUBE
-
-	SceneCaptureCubeComponent->HideActorComponents(UGameplayStatics::GetPlayerController(GetWorld(), 0));
-	SceneCaptureCubeComponent->HideActorComponents(UGameplayStatics::GetPlayerPawn(GetWorld(), 0));
-	//SceneCaptureCubeComponent->SetWorldRotation(FQuat(FVector(0, 1, 0), 180));
-	SceneCaptureCubeComponent->SetWorldLocation(Loc);
-
-	SceneCaptureCubeComponent->CaptureScene();
-	
-
-}
+#undef UpdateResource
+
+#include "OptiXCameraActor.h"
+
+#include "OptiXModule.h"
+#include "OptiXLaserActor.h"
+
+#include "Engine/EngineTypes.h"
+#include <EngineGlobals.h>
+#include "Runtime/Engine/Classes/Camera/PlayerCameraManager.h"
+#include "Runtime/Engine/Classes/Kismet/GameplayStatics.h"
+#include "Runtime/Engine/Classes/Engine/LocalPlayer.h"
+#include "Runtime/Engine/Public/SceneView.h"
+#include <Runtime/Engine/Classes/Engine/Engine.h>
+#include "Runtime/Engine/Public/HighResScreenshot.h"
+#include "Runtime/Engine/Classes/Engine/TextureRenderTarget2D.h"
+#include "Runtime/Engine/Classes/Engine/TextureRenderTargetCube.h"
+#include "Runtime/Engine/Classes/Materials/MaterialInstanceDynamic.h"
+#include "Runtime/Engine/Classes/Engine/Light.h"
+#include "Runtime/Engine/Classes/GameFramework/GameUserSettings.h"
+#include "Runtime/Engine/Classes/GameFramework/PlayerStart.h"
+
+// VR
+#include "Runtime/HeadMountedDisplay/Public/IHeadMountedDisplay.h"
+#include "Runtime/HeadMountedDisplay/Public/IXRTrackingSystem.h"
+#include "Runtime/HeadMountedDisplay/Public/IXRCamera.h"
+
+#include "Runtime/Engine/Classes/Camera/CameraActor.h"
+
+#include "StatsDefines.h"
+
+
+DEFINE_LOG_CATEGORY(OptiXPluginCameraActor);
+
+
+UOptiXBlendable::UOptiXBlendable(const FObjectInitializer& ObjectInitializer)
+	: Super(ObjectInitializer)
+{
+	BlendWeight = 1.0f;
+}
+
+void UOptiXBlendable::OverrideBlendableSettings(FSceneView & View, float InWeight) const
+{
+	float Weight = FMath::Clamp(BlendWeight, 0.0f, 1.0f) * InWeight;
+}
+
+AOptiXPlayerCameraManager::AOptiXPlayerCameraManager(const FObjectInitializer& ObjectInitializer)
+	: Super(ObjectInitializer)
+{
+	UE_LOG(OptiXPluginCameraActor, Display, TEXT("Optix Camera Manager Constructor!"));
+
+	SceneCaptureComponent = ObjectInitializer.CreateDefaultSubobject<USceneCaptureComponent2D>(this, TEXT("SceneCaptureComponent0"));
+	RootComponent = SceneCaptureComponent;
+	SceneCaptureComponent->bCaptureEveryFrame = false;
+	SceneCaptureComponent->bCaptureOnMovement = false;
+	//SceneCaptureComponent->bEnableClipPlane = true; // don't want ourself in the capture
+	SceneCaptureComponent->FOVAngle = 90.0f;
+	SceneCaptureComponent->HideActorComponents(this);
+	//SceneCaptureComponent->CaptureSource = SCS_SceneColorHDR;
+	//SceneCaptureComponent->HideActorComponents(UGameplayStatics::GetPlayerController(GetWorld(), 0));
+	//SceneCaptureComponent->HideActorComponents(UGameplayStatics::GetPlayerPawn(GetWorld(), 0));
+
+	SceneCaptureCubeComponent = ObjectInitializer.CreateDefaultSubobject<USceneCaptureComponentCube>(this, TEXT("SceneCaptureComponentCube0"));
+	SceneCaptureCubeComponent->SetupAttachment(SceneCaptureComponent);
+	SceneCaptureCubeComponent->bCaptureEveryFrame = false;
+	SceneCaptureCubeComponent->bCaptureOnMovement = false;
+	SceneCaptureCubeComponent->HideActorComponents(this);
+
+
+	PostProcessComponent = ObjectInitializer.CreateDefaultSubobject<UPostProcessComponent>(this, TEXT("PostProcessComponent0"));
+	PostProcessComponent->SetupAttachment(SceneCaptureCubeComponent); // Doesn't matter anyway
+	PostProcessComponent->bUnbound = true; // Should be default anyway
+
+	PrimaryActorTick.bCanEverTick = true;
+	//PrimaryActorTick.TickGroup = TG_PostUpdateWork;
+
+
+	// TODO DEBUG CREATE IN C++
+	//static ConstructorHelpers::FObjectFinder<UTextureRenderTargetCube> RT(TEXT("TextureRenderTarget2D'/OptiX/PPMaterials/RTCube.RTCube'"));
+
+	//if (RT.Object != NULL)
+	//{
+	//	CubeRenderTarget = RT.Object;
+	//	SceneCaptureCubeComponent->TextureTarget = CubeRenderTarget;
+
+	//}
+
+
+	CubeRenderTarget = NewObject<UTextureRenderTargetCube>();
+	CubeRenderTarget->Init(1024, PF_B8G8R8A8);
+	CubeRenderTarget->UpdateResource();
+	SceneCaptureCubeComponent->TextureTarget = CubeRenderTarget;
+
+	//FRotator Rotation = FRotationMatrix::MakeFromX(Directions[i]).Rotator();
+	//FQuat Q = FQuat({ 1, 0, 0 });
+	//SceneCaptureComponent->AddWorldRotation();
+
+	for (uint8 i = 0; i < 6; i++)
+	{
+		UTextureRenderTarget2D* RenderTarget = NewObject<UTextureRenderTarget2D>();
+		//RenderTarget->AddToRoot();
+		RenderTarget->InitCustomFormat(CubemapSize, CubemapSize, PF_B8G8R8A8, true);
+		//RenderTarget->CompressionSettings = TextureCompressionSettings::TC_VectorDisplacementmap;
+		//RenderTarget->SRGB = 0;
+		//RenderTarget->TargetGamma = 2.2;
+		RenderTarget->NeverStream = 1;
+		//RenderTarget->InitAutoFormat(CubemapSize, CubemapSize);
+		RenderTarget->UpdateResourceImmediate(); //???
+		//RenderTarget->AdjustBrightness = 1.0; // ??? TODO
+		CubemapRenderTargets.Add(RenderTarget);
+	}
+
+}
+
+void AOptiXPlayerCameraManager::BeginPlay()
+{
+	
+	//UGameplayStatics::GetPlayerController(GetWorld(), 0)->SetViewTarget(this);
+	UE_LOG(OptiXPluginCameraActor, Display, TEXT("OptiX Camera Manager Begin Play!"));
+	Super::BeginPlay();
+
+	Init();
+}
+
+void AOptiXPlayerCameraManager::EndPlay(const EEndPlayReason::Type EndPlayReason)
+{
+	// Clean up again TODO
+	Super::EndPlay(EndPlayReason);
+}
+
+void AOptiXPlayerCameraManager::Tick(float DeltaSeconds)
+{
+	TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("AOptiXPlayerCameraManager::Tick"))
+
+	Super::Tick(DeltaSeconds);
+	if (C == 2)
+	{
+		CaptureCubemap();
+		bCubemapCaptured.AtomicSet(true);
+		//InitCubemap();
+		SetActorTickEnabled(false);
+		return; // no need to increase C further
+	}
+	C++;
+}
+
+
+void AOptiXPlayerCameraManager::Init()
+{
+	BlendableVR = FOptiXModule::Get().GetOptiXContextManager()->GetOptiXMID();	
+	PostProcessComponent->AddOrUpdateBlendable(BlendableVR, 1.0f);
+	FOptiXModule::Get().GetOptiXContextManager()->SetActiveCameraActor(this);
+
+	BlendableOrtho = FOptiXModule::Get().GetOptiXContextManager()->GetOptiXMIDOrtho();
+	PostProcessComponent->AddOrUpdateBlendable(BlendableOrtho, 0.0f);
+}
+
+
+void AOptiXPlayerCameraManager::CaptureCubemap()
+{
+	TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("AOptiXPlayerCameraManager::CaptureCubemap"))
+
+	// 2D
+	TArray<FVector> Directions =
+	{
+		{1, 0, 0},
+		{-1, 0, 0},
+		{0, 1, 0},
+		{0, -1, 0},
+		{0, 0, -1},
+		{0, 0, 1}
+	};
+
+	SceneCaptureComponent->HideActorComponents(UGameplayStatics::GetPlayerController(GetWorld(), 0));
+	SceneCaptureComponent->HideActorComponents(UGameplayStatics::GetPlayerPawn(GetWorld(), 0));
+	
+	TArray<AActor*> FoundLaserActors;
+	UGameplayStatics::GetAllActorsOfClass(GetWorld(), AOptiXLaserActor::StaticClass(), FoundLaserActors);
+
+	for (AActor* Actor : FoundLaserActors)
+	{
+		SceneCaptureComponent->HideComponent(Cast<AOptiXLaserActor>(Actor)->LineInstancedStaticMeshComponent);
+		SceneCaptureCubeComponent->HideComponent(Cast<AOptiXLaserActor>(Actor)->LineInstancedStaticMeshComponent);
+	}
+
+	// the actual camera position is still 0 here, so the capture would be at the origin and not the actual player start.
+	// Let's move the capture "into" the first lens actor. 
+
+	TArray<AActor*> FoundPlayerStarts;
+	UGameplayStatics::GetAllActorsOfClass(GetWorld(), APlayerStart::StaticClass(), FoundPlayerStarts);
+
+
+	FVector Loc = FoundPlayerStarts[0]->GetActorLocation(); // Just use the first one
+
+	// CUBE
+
+	SceneCaptureCubeComponent->HideActorComponents(UGameplayStatics::GetPlayerController(GetWorld(), 0));
+	SceneCaptureCubeComponent->HideActorComponents(UGameplayStatics::GetPlayerPawn(GetWorld(), 0));
+	//SceneCaptureCubeComponent->SetWorldRotation(FQuat(FVector(0, 1, 0), 180));
+	SceneCaptureCubeComponent->SetWorldLocation(Loc);
+
+	SceneCaptureCubeComponent->CaptureScene();
+	
+
+}
diff --git a/Source/OptiX/Private/OptiXContextManager.cpp b/Source/OptiX/Private/OptiXContextManager.cpp
index e6046a7a90227e4968ba3615a7e41458323815d5..64e2736466e492399a7d84de2eeb2e1a689e9a71 100644
--- a/Source/OptiX/Private/OptiXContextManager.cpp
+++ b/Source/OptiX/Private/OptiXContextManager.cpp
@@ -2,7 +2,6 @@
 
 #include "OptiXContextManager.h"
 #include "OptiXModule.h"
-#include "OptiXBuffer.h"
 
 #include "RenderCore.h"
 #include "EngineUtils.h"
@@ -36,6 +35,9 @@ typedef FD3D11StateCacheBase FD3D11StateCache;
 
 // Console variables todo
 
+DEFINE_LOG_CATEGORY(OptiXContextManagerLog);
+
+
 static TAutoConsoleVariable<int32> CVarDisableTrace(
 	TEXT("optix.DisableTrace"),
 	0,
@@ -49,13 +51,43 @@ static TAutoConsoleVariable<int32> CVarDisableLaserTrace(
 	ECVF_Scalability | ECVF_RenderThreadSafe);
 
 
+FOptiXContextUpdateManager::FOptiXContextUpdateManager(const FAutoRegister& AutoRegister)
+	: FSceneViewExtensionBase(AutoRegister)
+{}
+
+void FOptiXContextUpdateManager::SetupViewFamily(FSceneViewFamily& InViewFamily)
+{
+}
+void FOptiXContextUpdateManager::SetupView(FSceneViewFamily& InViewFamily, FSceneView& InView)
+{
+}
+void FOptiXContextUpdateManager::BeginRenderViewFamily(FSceneViewFamily& InViewFamily)
+{
+}
+void FOptiXContextUpdateManager::PreRenderView_RenderThread(FRHICommandListImmediate& RHICmdList, FSceneView& InView)
+{
+}
+void FOptiXContextUpdateManager::PreRenderViewFamily_RenderThread(FRHICommandListImmediate& RHICmdList, FSceneViewFamily& InViewFamily)
+{
+	// Hacky hacky
+	FOptiXModule::Get().GetOptiXContextManager()->ExecuteOptiXUpdate_PreLateUpdate(RHICmdList);
+}
+bool FOptiXContextUpdateManager::IsActiveThisFrame(class FViewport* InViewport) const
+{
+	return bIsActive;
+}
+int32 FOptiXContextUpdateManager::GetPriority() const
+{
+	return 100;
+}
+
 
 FOptiXContextManager::FOptiXContextManager(const FAutoRegister& AutoRegister)
 	: FSceneViewExtensionBase(AutoRegister)
 {
-	UE_LOG(LogTemp, Display, TEXT("FOptiXContextManager, is in rendering thread: %i"), static_cast<int32>(IsInRenderingThread()));
+	UE_LOG(OptiXContextManagerLog, Display, TEXT("FOptiXContextManager, is in rendering thread: %i"), static_cast<int32>(IsInRenderingThread()));
 
-	RTXOn = 0;
+	//RTXOn = 0;
 
 	LaserMaxDepth = 20;
 	LaserEntryPoint = 1; // Default, will be overwritten anyway
@@ -65,177 +97,84 @@ FOptiXContextManager::FOptiXContextManager(const FAutoRegister& AutoRegister)
 
 	LaserBufferSize = LaserBufferHeight * LaserBufferWidth;
 
-	bValidCubemap.AtomicSet(false);
 	OnSceneChangedDelegate.AddRaw(this, &FOptiXContextManager::SceneChangedCallback);
 
-}
+	OptiXPTXDir = FOptiXModule::Get().OptiXPTXDir;
 
+	OptiXContextUpdateManager = FSceneViewExtensions::NewExtension<FOptiXContextUpdateManager>();
+}
 
-void FOptiXContextManager::SetupViewFamily(FSceneViewFamily & InViewFamily)
+int32 FOptiXContextManager::GetPriority() const
 {
-	//UE_LOG(LogTemp, Warning, TEXT("SetupViewFamily"));
+	// FDefaultXRCamera: 0 (does the basic lateupdate)
+	// OculusHMD : -1
+	// SteamVR: seems to be default (0)
+	return 10;
 }
 
-void FOptiXContextManager::SetupView(FSceneViewFamily & InViewFamily, FSceneView & InView)
-{
-	//UE_LOG(LogTemp, Warning, TEXT("SetupView"));
 
-	// TODO Check Width/Height
-}
+// gamethread
+void FOptiXContextManager::SetupViewFamily(FSceneViewFamily & InViewFamily)
+{}
 
+void FOptiXContextManager::SetupView(FSceneViewFamily & InViewFamily, FSceneView & InView)
+{}
+
+// gamethread
 void FOptiXContextManager::BeginRenderViewFamily(FSceneViewFamily & InViewFamily)
-{
-	//UE_LOG(LogTemp, Warning, TEXT("BeginRenderViewFamily"));
-}
+{}
 
 // Called on render thread at the start of rendering, for each view, after PreRenderViewFamily_RenderThread call.
 void FOptiXContextManager::PreRenderView_RenderThread(FRHICommandListImmediate & RHICmdList, FSceneView & InView)
-{
-	TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("FOptiXContextManager::PreRenderView_RenderThread"))
-	return;
-
-	//OptiXContext->SetMatrix("invViewProjection", InView.ViewMatrices.GetInvViewProjectionMatrix());
-	//OptiXContext->SetMatrix("viewProjection", InView.ViewMatrices.GetViewProjectionMatrix());
-
-	////FIntPoint Size = OptiXContext->GetBuffer("result_color")->GetSize2D();
-
-	//bIsTracing.AtomicSet(true);
-	//OptiXContext->Launch(0, Width, Height);
-	//bIsTracing.AtomicSet(false);
-
-
-	//if (InView.StereoPass == EStereoscopicPass::eSSP_LEFT_EYE) // check validity
-	//{
-	//	//float* Data2 = static_cast<float*>(OptiXContext->GetBuffer("result_depth")->MapNative());
-	//	//RHICmdList.UpdateTexture2D(OutputTextureDepthLeftRef, 0, TextureRegion, Size.X * 4, (uint8*)Data2);
-	//	//OptiXContext->GetBuffer("result_depth")->Unmap();
-
-	//	if (Resources[0] == NULL && Resources[1] == NULL)
-	//	{
-	//		return;
-	//	}
-
-	//	cudaGraphicsMapResources(2, Resources, 0);
-	//	PrintLastCudaError("cudaGraphicsMapResources");
-
-	//	if (CudaResourceDepthLeft == NULL)
-	//	{
-	//		cudaGraphicsUnmapResources(2, Resources, 0);
-	//		return;
-	//	}
-
-	//	// Copy Depth
-	//	cudaArray *CuArrayDepth;
-	//	cudaGraphicsSubResourceGetMappedArray(&CuArrayDepth, CudaResourceDepthLeft, 0, 0);
-	//	PrintLastCudaError("cudaGraphicsSubResourceGetMappedArray");
-
-	//	cudaMemcpy2DToArray(
-	//		CuArrayDepth, // dst array
-	//		0, 0,    // offset
-	//		CudaLinearMemoryDepth, Width * sizeof(float),       // src
-	//		Width * sizeof(float), Height, // extent
-	//		cudaMemcpyDeviceToDevice); // kind
-	//	PrintLastCudaError("cudaMemcpy2DToArray");
-
-	//	// Copy Color
-
-	//	cudaArray *CuArrayColor;
-	//	cudaGraphicsSubResourceGetMappedArray(&CuArrayColor, CudaResourceColorLeft, 0, 0);
-	//	PrintLastCudaError("cudaGraphicsSubResourceGetMappedArray");
-
-	//	cudaMemcpy2DToArray(
-	//		CuArrayColor, // dst array
-	//		0, 0,    // offset
-	//		CudaLinearMemoryColor, Width * 4 * sizeof(float),       // src
-	//		Width * 4 * sizeof(float), Height, // extent
-	//		cudaMemcpyDeviceToDevice); // kind
-	//	PrintLastCudaError("cudaMemcpy2DToArray");
-
-
-	//	cudaGraphicsUnmapResources(2, Resources, 0);
-	//	PrintLastCudaError("cudaGraphicsUnmapResources");
-
-	//	//D3DDeviceContext->Flush();
-	//	LaunchLaser();
-	//	UpdateCubemapBuffer(RHICmdList);
-
-	//}
-	//else if (InView.StereoPass == EStereoscopicPass::eSSP_RIGHT_EYE)
-	//{
-	//	if (Resources[2] == NULL && Resources[3] == NULL)
-	//	{
-	//		return;
-	//	}
-	//	cudaGraphicsMapResources(2, Resources + 2, 0);
-	//	PrintLastCudaError("cudaGraphicsMapResources");
-
-	//	if (CudaResourceDepthRight == NULL)
-	//	{
-	//		cudaGraphicsUnmapResources(2, Resources + 2, 0);
-	//		return;
-	//	}
-	//	// Depth
-	//	cudaArray *CuArrayDepth;
-	//	cudaGraphicsSubResourceGetMappedArray(&CuArrayDepth, CudaResourceDepthRight, 0, 0);
-	//	PrintLastCudaError("cudaGraphicsSubResourceGetMappedArray");
-
-	//	cudaMemcpy2DToArray(
-	//		CuArrayDepth, // dst array
-	//		0, 0,    // offset
-	//		CudaLinearMemoryDepth, Width * sizeof(float),       // src
-	//		Width * sizeof(float), Height, // extent
-	//		cudaMemcpyDeviceToDevice); // kind
-	//	//PrintLastCudaError("cudaMemcpy2DToArray");
-
-
-	//	// Color
-	//	cudaArray *CuArrayColor;
-	//	cudaGraphicsSubResourceGetMappedArray(&CuArrayColor, CudaResourceColorRight, 0, 0);
-	//	PrintLastCudaError("cudaGraphicsSubResourceGetMappedArray");
-
-	//	cudaMemcpy2DToArray(
-	//		CuArrayColor, // dst array
-	//		0, 0,    // offset
-	//		CudaLinearMemoryColor, Width * 4 * sizeof(float),       // src
-	//		Width * 4 * sizeof(float), Height, // extent
-	//		cudaMemcpyDeviceToDevice); // kind
-	//	PrintLastCudaError("cudaMemcpy2DToArray");
-
-	//	cudaGraphicsUnmapResources(2, Resources + 2, 0);
-	//	PrintLastCudaError("cudaGraphicsUnmapResources");
-	//}
-	//if (bRequestOrthoPass)
-	//{
-	//	RenderOrthoPass();
-	//	bRequestOrthoPass.AtomicSet(false);
-	//}
-}
+{}
 
 // Called on render thread at the start of rendering.
 void FOptiXContextManager::PreRenderViewFamily_RenderThread(FRHICommandListImmediate & RHICmdList, FSceneViewFamily & InViewFamily)
 {
 	TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("FOptiXContextManager::PreRenderViewFamily_RenderThread"))
 
-	if (!bIsInitialized && !bClearToLaunch && !OptiXContext.IsValid() && !bStartTracing)
+	if (bEndPlayReceived)
 	{
+		Cleanup_RenderThread();
 		return;
 	}
-	if (InViewFamily.Views.Num() < 2)
-		return;
 
-	
+	// launch the laser trace if needed (todo)
+	LaunchLaser(RHICmdList);
+	//CopyLaserCudaTexture(RHICmdList);
+
+}
 
-	// Init the yet uninitialized optix components - this queue should be empty and do nothing if no new components are registered.
-	InitOptiXComponents(RHICmdList);
+void FOptiXContextManager::PostRenderViewFamily_RenderThread(FRHICommandListImmediate & RHICmdList, FSceneViewFamily & InViewFamily)
+{
+	LaunchStandardTrace(RHICmdList, InViewFamily);
+}
 
-	// Update the remaining variables TODO this needs to be only done once not once per eye!
-	OptiXContext->UpdateVariables();
-	UpdateOptiXComponentVariables();
-	UpdateRequestedCubemaps(RHICmdList);
+void FOptiXContextManager::PostRenderView_RenderThread(FRHICommandListImmediate & RHICmdList, FSceneView & InView)
+{}
 
-	RemovePendingChildrenFromGroups();
-	// Clean up any dangling optix objects here to not interfere with launch
-	DestroyOptiXObjects();	
+void FOptiXContextManager::ExecuteOptiXUpdate_PreLateUpdate(FRHICommandListImmediate & RHICmdList)
+{
+	// New functions
+	ParseCreationQueue(); // Create new stuff
+	ParseDestroyQueue(); // Get rid of removed objects - this order such that just created objects can be destroyed in the same tick and no ghost objects happen
+	ParseInitQueue();
+	ParseUpdateQueue(RHICmdList);
+	ParseCubemapUpdateQueue(RHICmdList);
+}
+
+void FOptiXContextManager::LaunchStandardTrace(FRHICommandListImmediate& RHICmdList, FSceneViewFamily& InViewFamily)
+{
+	TRACE_CPUPROFILER_EVENT_SCOPE("FOptiXContextManager::PreRenderViewFamily_RenderThread")
+
+
+		if (bEndPlayReceived)
+		{
+			return;
+		}
+
+	if (InViewFamily.Views.Num() < 2)
+		return;
 
 	// Get the views for the respective eyes:
 	EStereoscopicPass LeftEye = EStereoscopicPass::eSSP_LEFT_EYE;
@@ -244,37 +183,40 @@ void FOptiXContextManager::PreRenderViewFamily_RenderThread(FRHICommandListImmed
 	const FSceneView& LeftEyeView = InViewFamily.GetStereoEyeView(LeftEye);
 	const FSceneView& RightEyeView = InViewFamily.GetStereoEyeView(RightEye);
 
-	OptiXContext->SetMatrix("invViewProjectionLeft", LeftEyeView.ViewMatrices.GetInvViewProjectionMatrix());
-	OptiXContext->SetMatrix("viewProjectionLeft", LeftEyeView.ViewMatrices.GetViewProjectionMatrix());
-	OptiXContext->SetMatrix("invViewProjectionRight", RightEyeView.ViewMatrices.GetInvViewProjectionMatrix());
-	OptiXContext->SetMatrix("viewProjectionRight", RightEyeView.ViewMatrices.GetViewProjectionMatrix());
-
-	//UE_LOG(LogTemp, Warning, TEXT("Child count: %i"), TopObject->GetNativeGroup()->getChildCount());
-
+	// Set the required matrices
+	NativeContext["invViewProjectionLeft"]->setMatrix4x4fv(true, &LeftEyeView.ViewMatrices.GetInvViewProjectionMatrix().M[0][0]);
+	NativeContext["viewProjectionLeft"]->setMatrix4x4fv(true, &LeftEyeView.ViewMatrices.GetViewProjectionMatrix().M[0][0]);
+	NativeContext["invViewProjectionRight"]->setMatrix4x4fv(true, &RightEyeView.ViewMatrices.GetInvViewProjectionMatrix().M[0][0]);
+	NativeContext["viewProjectionRight"]->setMatrix4x4fv(true, &RightEyeView.ViewMatrices.GetViewProjectionMatrix().M[0][0]);
+	//NativeContext->validate();
 
 	{
-		TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("FOptiXContextManager::Trace"))
-		OptiXContext->Validate();
-		bIsTracing.AtomicSet(true);
-		OptiXContext->Launch(0, Width, Height);
-		bIsTracing.AtomicSet(false);
+		TRACE_CPUPROFILER_EVENT_SCOPE("FOptiXContextManager::Trace")
+			//bIsTracing.AtomicSet(true);
+			// Execute the actual trace
+			NativeContext->launch(0, Width, Height);
+		//bIsTracing.AtomicSet(false);
 		//return;
 	}
 	{
+		// Check cuda resources for NULL. Shouldn't be needed as they *should* never be NULL.
 		if (Resources[0] == NULL || Resources[1] == NULL || Resources[2] == NULL || Resources[3] == NULL)
 		{
-			UE_LOG(LogTemp, Warning, TEXT("CUDA Resources are NULL"));
+			UE_LOG(OptiXContextManagerLog, Error, TEXT("CUDA Resources are NULL"));
 			return;
 		}
 
+		// Map the four graphics resources corresponding to color, depth for both eyes.
 		cudaGraphicsMapResources(4, Resources, 0);
 		PrintLastCudaError("cudaGraphicsMapResources");
 
-		// Copy Color Left
+		// Map the left eye color resource to a cudaArray 
 		cudaArray *CuArrayColorLeft;
 		cudaGraphicsSubResourceGetMappedArray(&CuArrayColorLeft, CudaResourceColorLeft, 0, 0);
 		PrintLastCudaError("cudaGraphicsSubResourceGetMappedArray");
 
+		// Copy the result of the optix 2D color buffer into the mapped array. 
+		// As both passes are written into the same buffer, this copies only the first half corresponding to the left eye.
 		cudaMemcpy2DToArray(
 			CuArrayColorLeft, // dst array
 			0, 0,    // offset
@@ -289,6 +231,9 @@ void FOptiXContextManager::PreRenderViewFamily_RenderThread(FRHICommandListImmed
 		cudaGraphicsSubResourceGetMappedArray(&CuArrayColorRight, CudaResourceColorRight, 0, 0);
 		PrintLastCudaError("cudaGraphicsSubResourceGetMappedArray");
 
+		// Copy the result of the optix 2D color buffer into the mapped array. 
+		// As this copies the into the right eye, the buffer pointer needs to be offset by (Height * Width)
+		// to copy the second half.
 		cudaMemcpy2DToArray(
 			CuArrayColorRight, // dst array
 			0, 0,    // offset
@@ -322,148 +267,192 @@ void FOptiXContextManager::PreRenderViewFamily_RenderThread(FRHICommandListImmed
 			CudaLinearMemoryDepth + (Height * Width), Width * sizeof(float),       // src
 			Width * sizeof(float), Height, // extent
 			cudaMemcpyDeviceToDevice); // kind
-		PrintLastCudaError("cudaMemcpy2DToArray");		
+		PrintLastCudaError("cudaMemcpy2DToArray");
 
 
 		cudaGraphicsUnmapResources(4, Resources, 0);
 		PrintLastCudaError("cudaGraphicsUnmapResources");
 
 		//D3DDeviceContext->Flush();
-		UpdateCubemapBuffer(RHICmdList);
+		//UpdateCubemapBuffer(RHICmdList);
 	}
 
+	// If an ortho pass was previously requested, execute it now and clear the request
 	if (bRequestOrthoPass)
 	{
 		RenderOrthoPass();
 		bRequestOrthoPass.AtomicSet(false);
 	}
-	//LaunchLaser();
 
+	//CopyLaserCudaTexture(RHICmdList);
 }
 
-void FOptiXContextManager::PostRenderViewFamily_RenderThread(FRHICommandListImmediate & RHICmdList, FSceneViewFamily & InViewFamily)
+
+void FOptiXContextManager::CopyLaserCudaTexture(FRHICommandListImmediate & RHICmdList)
 {
-	//UE_LOG(LogTemp, Warning, TEXT("PostRenderViewFamily_RenderThread"));
-		// Laser Test part:
+	TRACE_CPUPROFILER_EVENT_SCOPE("FOptiXContextManager::CopyLaserCudaTexture")
+	if (/*bSceneChanged &&*/ bIsInitializedLaser && !CVarDisableLaserTrace.GetValueOnRenderThread())
+	{
+		if (Resources[4] == NULL)
+		{
+			return;
+		}
+		{
+			TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("FOptiXContextManager::LaunchLaser::CudaScope::MapAndCopy"))
 
-}
+				cudaGraphicsMapResources(1, Resources + 4, 0);
+			PrintLastCudaError("cudaGraphicsMapResources");
 
-void FOptiXContextManager::PostRenderView_RenderThread(FRHICommandListImmediate & RHICmdList, FSceneView & InView)
-{
-	//UE_LOG(LogTemp, Warning, TEXT("VPM: PostRenderViewFamily_RenderThread %s"), *InView.ViewMatrices.GetViewProjectionMatrix().ToString());
-	TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("FOptiXContextManager::PostRenderView_RenderThread"))
+			if (CudaResourceIntersections == NULL)
+			{
+				cudaGraphicsUnmapResources(1, Resources + 4, 0);
+				return;
+			}
 
+			cudaArray *CuArrayIntersections;
+			cudaGraphicsSubResourceGetMappedArray(&CuArrayIntersections, CudaResourceIntersections, 0, 0);
+			PrintLastCudaError("cudaGraphicsSubResourceGetMappedArray");
 
+			{
+				TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("FOptiXContextManager::LaunchLaser::CudaScope::Memcpy"))
 
-	//else if (InView.StereoPass == EStereoscopicPass::eSSP_FULL)
-	//{
-	//	UE_LOG(LogTemp, Display, TEXT("Full Pass"));
-	//}
+					cudaMemcpy2DToArray(
+						CuArrayIntersections, // dst array
+						0, 0,    // offset
+						CudaLinearMemoryIntersections, LaserBufferWidth * 4 * sizeof(float),       // src
+						LaserBufferWidth * 4 * sizeof(float), LaserBufferHeight, // extent
+						cudaMemcpyDeviceToDevice); // kind
+				PrintLastCudaError("cudaMemcpy2DToArray");
+			}
+		}
+		TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("FOptiXContextManager::LaunchLaser::CudaScope::Unmap"))
 
-	//if (bCleanup)
-	//{
-	//	CleanupOptiXOnEnd();
-	//	return;
-	//}
+		cudaGraphicsUnmapResources(1, Resources + 4, 0);
+		PrintLastCudaError("cudaGraphicsUnmapResources");
+		{
+			TRACE_CPUPROFILER_EVENT_SCOPE("FOptiXContextManager::LaunchLaser::BroadcastFinish")
+
+			//bSceneChanged.AtomicSet(false);
+			for (const auto& Pair : LaserTraceFinishedCallbacks)
+			{
+				optix::TextureSampler Sampler = nullptr;
+				TMap<FString, optix::Buffer>* BufferMap = nullptr;
+				FOptiXObjectData* Data = nullptr;
+				if (OptiXTextureSamplers.Contains(Pair.Key))
+				{
+					Sampler = OptiXTextureSamplers[Pair.Key];
+				}
+				if (OptiXBuffers.Contains(Pair.Key))
+				{
+					BufferMap = &OptiXBuffers[Pair.Key];
+				}
+				if (OptiXObjectData.Contains(Pair.Key))
+				{
+					Data = &OptiXObjectData[Pair.Key];
+				}
+				Pair.Value(Data, BufferMap, Sampler, RHICmdList);
+			}
+		}
+	}
 }
 
 
-void FOptiXContextManager::LaunchLaser()
+void FOptiXContextManager::LaunchLaser(FRHICommandListImmediate & RHICmdList)
 {
-	TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("FOptiXContextManager::LaunchLaser"))
-	if (/*bSceneChanged && */ bLaserIsInitialized && !CVarDisableLaserTrace.GetValueOnRenderThread())
+	TRACE_CPUPROFILER_EVENT_SCOPE("FOptiXContextManager::LaunchLaser")
+	if (/*bSceneChanged &&*/ bIsInitializedLaser && !CVarDisableLaserTrace.GetValueOnRenderThread())
 	{
-		if (LaserActor.IsValid())
+		static uint32 RandomSeed = 0;
+		NativeContext["random_frame_seed"]->setUint(RandomSeed++);
+
+		TRACE_CPUPROFILER_EVENT_SCOPE("FOptiXContextManager::NativeContext::launch")
+		NativeContext->launch(1, 50, 50, 20);		
+		if (Resources[4] == NULL)
 		{
-			LaserActor->OptiXLaserComponent->UpdateOptiXContextVariables();
+			return;
 		}
-
-
-		// Analyze this
-		
-		// uuuuuuuuh
-		static uint32 RandomSeed = 0;
-		OptiXContext->SetUint("random_frame_seed", RandomSeed++);
-		//UE_LOG(LogTemp, Warning, TEXT("Launching Laser Trace at Entry Point: %i"), LaserEntryPoint);
-		bIsTracing.AtomicSet(true);
-		OptiXContext->Launch(1, 50, 50, 20);
-		bIsTracing.AtomicSet(false);
 		{
-			TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("FOptiXContextManager::LaunchLaser::CudaScope"))
+			TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("FOptiXContextManager::LaunchLaser::CudaScope::MapAndCopy"))
 
-			if (Resources[4] == NULL)
+			cudaGraphicsMapResources(1, Resources + 4, 0);
+			PrintLastCudaError("cudaGraphicsMapResources");
+
+			if (CudaResourceIntersections == NULL)
 			{
+				cudaGraphicsUnmapResources(1, Resources + 4, 0);
 				return;
 			}
-			{
-				TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("FOptiXContextManager::LaunchLaser::CudaScope::MapAndCopy"))
 
-				cudaGraphicsMapResources(1, Resources + 4, 0);
-				PrintLastCudaError("cudaGraphicsMapResources");
+			cudaArray *CuArrayIntersections;
+			cudaGraphicsSubResourceGetMappedArray(&CuArrayIntersections, CudaResourceIntersections, 0, 0);
+			PrintLastCudaError("cudaGraphicsSubResourceGetMappedArray");
 
-				if (CudaResourceIntersections == NULL)
-				{
-					cudaGraphicsUnmapResources(1, Resources + 4, 0);
-					return;
-				}
-
-				cudaArray *CuArrayIntersections;
-				cudaGraphicsSubResourceGetMappedArray(&CuArrayIntersections, CudaResourceIntersections, 0, 0);
-				PrintLastCudaError("cudaGraphicsSubResourceGetMappedArray");
-
-				{
-					TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("FOptiXContextManager::LaunchLaser::CudaScope::Memcpy"))
+			{
+				TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("FOptiXContextManager::LaunchLaser::CudaScope::Memcpy"))
 
 					cudaMemcpy2DToArray(
-							CuArrayIntersections, // dst array
-							0, 0,    // offset
-							CudaLinearMemoryIntersections, LaserBufferWidth * 4 * sizeof(float),       // src
-							LaserBufferWidth * 4 * sizeof(float), LaserBufferHeight, // extent
-							cudaMemcpyDeviceToDevice); // kind
-					PrintLastCudaError("cudaMemcpy2DToArray");
-				}
+						CuArrayIntersections, // dst array
+						0, 0,    // offset
+						CudaLinearMemoryIntersections, LaserBufferWidth * 4 * sizeof(float),       // src
+						LaserBufferWidth * 4 * sizeof(float), LaserBufferHeight, // extent
+						cudaMemcpyDeviceToDevice); // kind
+				PrintLastCudaError("cudaMemcpy2DToArray");
 			}
-			TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("FOptiXContextManager::LaunchLaser::CudaScope::Unmap"))
-
-			cudaGraphicsUnmapResources(1, Resources + 4, 0);
-			PrintLastCudaError("cudaGraphicsUnmapResources");
-
 		}
+		TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("FOptiXContextManager::LaunchLaser::CudaScope::Unmap"))
+
+		cudaGraphicsUnmapResources(1, Resources + 4, 0);
+		PrintLastCudaError("cudaGraphicsUnmapResources");
 		{
-			TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("FOptiXContextManager::LaunchLaser::BroadcastFinish"))
+			TRACE_CPUPROFILER_EVENT_SCOPE("FOptiXContextManager::LaunchLaser::BroadcastFinish")
 
-			bSceneChanged.AtomicSet(false);
-			LaserTraceFinishedEvent.Broadcast();
+			//bSceneChanged.AtomicSet(false);
+			for (const auto& Pair : LaserTraceFinishedCallbacks)
+			{
+				optix::TextureSampler Sampler = nullptr;
+				TMap<FString, optix::Buffer>* BufferMap = nullptr;
+				FOptiXObjectData* Data = nullptr;
+				if (OptiXTextureSamplers.Contains(Pair.Key))
+				{
+					Sampler = OptiXTextureSamplers[Pair.Key];
+				}
+				if (OptiXBuffers.Contains(Pair.Key))
+				{
+					BufferMap = &OptiXBuffers[Pair.Key];
+				}
+				if (OptiXObjectData.Contains(Pair.Key))
+				{
+					Data = &OptiXObjectData[Pair.Key];
+				}
+				Pair.Value(Data, BufferMap, Sampler, RHICmdList);
+			}
 		}
 	}
 }
 
-
 bool FOptiXContextManager::IsActiveThisFrame(FViewport * InViewport) const
 {
-	//UE_LOG(LogTemp, Warning, TEXT("IsActiveThisFrame"));
-	TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("FOptiXContextManager::IsActiveThisFrame"))
+	//UE_LOG(OptiXContextManagerLog, Warning, TEXT("IsActiveThisFrame"));
+	TRACE_CPUPROFILER_EVENT_SCOPE("FOptiXContextManager::IsActiveThisFrame")
 
 	bool bDisableTrace = CVarDisableTrace.GetValueOnGameThread(); // Bad naming fix me
-	return OptiXContext.IsValid() && !bDisableTrace && bStartTracing /* && !bEndPlay*//* && TrackingSystem->IsHeadTrackingAllowed()*/;
+	return NativeContext != NULL && !bDisableTrace && bIsInitializedAll /*&& !bEndPlayReceived*/ /* && !bEndPlay*//* && TrackingSystem->IsHeadTrackingAllowed()*/;
 }
 
 void FOptiXContextManager::RenderOrthoPass()
 {
-	return;
-
-	TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("FOptiXContextManager::RenderOrthoPass"))
+	TRACE_CPUPROFILER_EVENT_SCOPE("FOptiXContextManager::RenderOrthoPass")
 
-	OptiXContext->SetInt("is_ortho", 1);
+	NativeContext["is_ortho"]->setInt(1);
 
-	OptiXContext->SetMatrix("invViewProjectionLeft", OrthoMatrix.Inverse());
-	OptiXContext->SetMatrix("viewProjectionLeft", OrthoMatrix);
+	NativeContext["invViewProjectionLeft"]->setMatrix4x4fv(true, &OrthoMatrix.Inverse().M[0][0]);
+	NativeContext["viewProjectionLeft"]->setMatrix4x4fv(true, &OrthoMatrix.M[0][0]);
 
 	//FIntPoint Size = OptiXContext->GetBuffer("result_color")->GetSize2D();
 
-	bIsTracing.AtomicSet(true);
-	OptiXContext->Launch(0, Width, Height);
-	bIsTracing.AtomicSet(false);
+	//bIsTracing.AtomicSet(true);
+	NativeContext->launch(0, Width, Height);
+	//bIsTracing.AtomicSet(false);
 
 	if (Resources[5] == NULL && Resources[6] == NULL)
 	{
@@ -510,13 +499,13 @@ void FOptiXContextManager::RenderOrthoPass()
 	cudaGraphicsUnmapResources(2, Resources + 5, 0);
 	PrintLastCudaError("cudaGraphicsUnmapResources");
 
-	OptiXContext->SetInt("is_ortho", 0);
+	NativeContext["is_ortho"]->setInt(0);
 
 }
 
 void FOptiXContextManager::Init()
 {
-	TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("FOptiXContextManager::Init"))
+	TRACE_CPUPROFILER_EVENT_SCOPE("FOptiXContextManager::Init")
 
 	// TODO Fix me there's still an optix error in there somewhere
 	//if (CubemapSampler.IsValid())
@@ -541,10 +530,18 @@ void FOptiXContextManager::Init()
 	//}
 
 	// Shouldn't be anything in the queues but clean up anyway just to be sure.
-	DestroyOptiXObjects();
+	//DestroyOptiXObjects();
 
 	//TODO: Shut this thing down correctly - for now just clean up anything when restarting
-	CleanupOptiXOnEnd();
+	//CleanupOptiXOnEnd();
+
+	bEndPlayReceived = false;
+	bValidCubemap = false;
+	bIsInitializedCuda = false;
+	bIsInitializedLaser = false;
+	bIsInitializedAll = false;
+	bSceneChanged = true;
+	bRequestOrthoPass = false;
 
 	InitContext();
 	InitRendering();
@@ -555,28 +552,25 @@ void FOptiXContextManager::Init()
 
 	InitCUDADX();
 
-	bIsInitialized = false;
-	bStartTracing = true;
+	bIsInitializedAll.AtomicSet(true);
+	OptiXContextUpdateManager->bIsActive = true;
 }
 
 void FOptiXContextManager::SceneChangedCallback()
 {
-	bSceneChanged.AtomicSet(true);
+	//bSceneChanged.AtomicSet(true);
 }
 
 void FOptiXContextManager::InitContext()
 {
-	TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("FOptiXContextManager::InitContext"))
+	TRACE_CPUPROFILER_EVENT_SCOPE("FOptiXContextManager::InitContext")
 
-	UE_LOG(LogTemp, Display, TEXT("Initializing Context in ContextManager"));
+	UE_LOG(OptiXContextManagerLog, Display, TEXT("Initializing Context in ContextManager"));
 
 	// Needs to be called BEFORE the context is created!
 	//rtGlobalSetAttribute(RT_GLOBAL_ATTRIBUTE_ENABLE_RTX, sizeof(RTXOn), &RTXOn);
 
-	OptiXContext = NewObject<UOptiXContext>(GetTransientPackage(), UOptiXContext::StaticClass());
-	OptiXContext->AddToRoot();
-	NativeContext = OptiXContext->Init();
-
+	NativeContext =	optix::Context::create();
 
 	//OptiXContext->SetExceptionEnabled(RTexception::RT_EXCEPTION_PAYLOAD_ACCESS_OUT_OF_BOUNDS, false);
 	//OptiXContext->SetExceptionEnabled(RTexception::RT_EXCEPTION_USER_EXCEPTION_CODE_OUT_OF_BOUNDS, true);
@@ -593,54 +587,48 @@ void FOptiXContextManager::InitContext()
 	//OptiXContext->SetExceptionEnabled(RTexception::RT_EXCEPTION_USER, true);
 	//OptiXContext->SetExceptionEnabled(RTexception::RT_EXCEPTION_USER_MAX, true);
 
-	OptiXContext->SetExceptionEnabled(RTexception::RT_EXCEPTION_ALL, true);
+	NativeContext->setExceptionEnabled(RTexception::RT_EXCEPTION_ALL, false);
 
-	NativeContext->setPrintEnabled(true);
+	NativeContext->setPrintEnabled(false);
 	//NativeContext->setPrintLaunchIndex(100, 100);
 	// Set some default values, they can (and should) be overwritten in the game mode as they're scene specific
-	OptiXContext->SetRayTypeCount(2);
-	OptiXContext->SetEntryPointCount(1);
+	NativeContext->setRayTypeCount(2);
+	NativeContext->setEntryPointCount(1);
 	//OptiXContext->SetStackSize(4000);
-	OptiXContext->SetMaxTraceDepth(31);
-
-	OptiXContext->SetInt("max_depth", 10);
-	OptiXContext->SetFloat("scene_epsilon", 1.e-2f);
+	NativeContext->setMaxTraceDepth(31);
 
-	TopObject = OptiXContext->CreateGroup();
-	TopAcceleration = OptiXContext->CreateAcceleration("NoAccel"); // Here the accel structure seems to be actually needed
-	//TopAcceleration->AddToRoot();
-	TopAcceleration->SetProperty("refit", "1");
+	NativeContext["max_depth"]->setInt(10);
+	NativeContext["scene_epsilon"]->setFloat(1.e-2f);
 
-	TopObject->SetAcceleration(TopAcceleration.Get());
+	TopObject = NativeContext->createGroup();
+	TopAcceleration = NativeContext->createAcceleration("Trbvh"); // Here the accel structure seems to be actually needed
+	TopAcceleration->setProperty("refit", "1");
 
-	UE_LOG(LogTemp, Warning, TEXT("Child count: %i"), TopObject->GetNativeGroup()->getChildCount());
+	TopObject->setAcceleration(TopAcceleration);
 
-
-	OptiXContext->SetGroup("top_object", TopObject.Get());
+	NativeContext["top_object"]->set(TopObject);
 	
-	OptiXContext->SetInt("is_ortho", 0);
-	// Keep buffers and programs with the camera manager for now, there's no real reason yet to force a refacturing there
-
+	NativeContext["is_ortho"]->setInt(0);
 }
 
 
 void FOptiXContextManager::InitRendering()
 {
-	TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("FOptiXContextManager::InitRendering"))
+	TRACE_CPUPROFILER_EVENT_SCOPE("FOptiXContextManager::InitRendering")
 
-	UE_LOG(LogTemp, Display, TEXT("Initializing Rendering in ContextManager"));
+	UE_LOG(OptiXContextManagerLog, Display, TEXT("Initializing Rendering in ContextManager"));
 
 
 	// Are we using an HMD?
 	if (GEngine->XRSystem.IsValid() && GEngine->XRSystem->GetHMDDevice() != nullptr)
 	{
-		UE_LOG(LogTemp, Display, TEXT("Got HMD in ContextManager"));
+		UE_LOG(OptiXContextManagerLog, Display, TEXT("Got HMD in ContextManager"));
 
 		bWithHMD = GEngine->XRSystem->GetHMDDevice()->IsHMDEnabled();
 	}
 	else
 	{
-		UE_LOG(LogTemp, Display, TEXT("Running without HMD in ContextManager"));
+		UE_LOG(OptiXContextManagerLog, Display, TEXT("Running without HMD in ContextManager"));
 
 		bWithHMD = false;
 	}
@@ -651,8 +639,8 @@ void FOptiXContextManager::InitRendering()
 	Width = CurrentViewport->GetSizeXY().X / 2.0;
 	Height = CurrentViewport->GetSizeXY().Y;
 
-	UE_LOG(LogTemp, Display, TEXT("Got viewport sizes: %i, %i"), Width, Height);
-	UE_LOG(LogTemp, Warning, TEXT("Full Res: %i %i"), Width * 2, Height);
+	UE_LOG(OptiXContextManagerLog, Display, TEXT("Got viewport sizes: %i, %i"), Width, Height);
+	UE_LOG(OptiXContextManagerLog, Warning, TEXT("Full Res: %i %i"), Width * 2, Height);
 
 
 	// Apparently those can be 0 in a packaged build? 
@@ -662,8 +650,7 @@ void FOptiXContextManager::InitRendering()
 		UGameUserSettings* GameSettings = GEngine->GetGameUserSettings();
 		Width = GameSettings->GetScreenResolution().X;
 		Height = GameSettings->GetScreenResolution().Y;
-		UE_LOG(LogTemp, Display, TEXT("Fallback to viewport size in settings: %i, %i"), Width, Height);
-
+		UE_LOG(OptiXContextManagerLog, Display, TEXT("Fallback to viewport size in settings: %i, %i"), Width, Height);
 	}
 
 	// Create the textures:
@@ -678,9 +665,6 @@ void FOptiXContextManager::InitRendering()
 	//// Allocate the texture HRI
 	DepthTexture->UpdateResource();
 
-	//OutputTextureColorRightRef = ((FTexture2DResource*)OutputTexture->Resource)->GetTexture2DRHI();
-	//OutputTextureDepthRightRef = ((FTexture2DResource*)DepthTexture->Resource)->GetTexture2DRHI();
-
 	if (bWithHMD)
 	{
 		OutputTexture2 = UTexture2D::CreateTransient(Width, Height, PF_A32B32G32R32F);
@@ -693,10 +677,6 @@ void FOptiXContextManager::InitRendering()
 		//// Allocate the texture HRI
 		DepthTexture2->UpdateResource();
 
-		//OutputTextureDepthLeftRef = ((FTexture2DResource*)DepthTexture2->Resource)->GetTexture2DRHI();
-		//OutputTextureColorLeftRef = ((FTexture2DResource*)OutputTexture2->Resource)->GetTexture2DRHI();
-
-
 		OutputTextureOrtho = UTexture2D::CreateTransient(Width, Height, PF_A32B32G32R32F);
 		OutputTextureOrtho->AddToRoot();
 		//// Allocate the texture HRI
@@ -706,15 +686,9 @@ void FOptiXContextManager::InitRendering()
 		DepthTextureOrtho->AddToRoot();
 		//// Allocate the texture HRI
 		DepthTextureOrtho->UpdateResource();
-
-		//OutputTextureDepthOrthoRef = ((FTexture2DResource*)DepthTextureOrtho->Resource)->GetTexture2DRHI();
-		//OutputTextureColorOrthoRef = ((FTexture2DResource*)OutputTextureOrtho->Resource)->GetTexture2DRHI();
-		
-
-		// TODO Maybe we need to do this after setting the parameter?
 	}
 
-	UE_LOG(LogTemp, Display, TEXT("Created the Textures"));
+	UE_LOG(OptiXContextManagerLog, Display, TEXT("Created the Textures"));
 
 	// Laser Texture
 	LaserIntersectionTexture = UTexture2D::CreateTransient(LaserBufferWidth, LaserBufferHeight, PF_A32B32G32R32F); // TODO Hardcoded values
@@ -722,15 +696,13 @@ void FOptiXContextManager::InitRendering()
 	//// Allocate the texture HRI
 	LaserIntersectionTexture->UpdateResource();
 
-	//LaserIntersectionTextureRef = ((FTexture2DResource*)LaserIntersectionTexture->Resource)->GetTexture2DRHI();
-
 	// Set up the material
 
 	// Load the materials
 	RegularMaterial = LoadObject<UMaterial>(GetTransientPackage(), TEXT("Material'/OptiX/PPMaterials/TextureMaterial.TextureMaterial'"));
 	VRMaterial = LoadObject<UMaterial>(GetTransientPackage(), TEXT("Material'/OptiX/PPMaterials/TextureMaterialVR.TextureMaterialVR'"));
 	LaserMaterial = LoadObject<UMaterial>(GetTransientPackage(), TEXT("Material'/OptiX/Laser/LaserMaterial.LaserMaterial'"));
-	LaserMaterialDynamic = UMaterialInstanceDynamic::Create(LaserMaterial.Get(), OptiXContext.Get(), "DynamicLaserMaterial");
+	LaserMaterialDynamic = UMaterialInstanceDynamic::Create(LaserMaterial.Get(), GetTransientPackage(), "DynamicLaserMaterial");
 
 	LaserMaterialDynamic->SetTextureParameterValue("IntersectionTexture", LaserIntersectionTexture.Get());
 	LaserMaterialDynamic->SetScalarParameterValue("Lines", 50);
@@ -739,133 +711,129 @@ void FOptiXContextManager::InitRendering()
 
 	if(RegularMaterial == nullptr || VRMaterial == nullptr)
 	{
-		UE_LOG(LogTemp, Error, TEXT("Couldn't load dummy Material!"));
+		UE_LOG(OptiXContextManagerLog, Error, TEXT("Couldn't load dummy Material!"));
 	}
 
 	if (bWithHMD)
 	{
-		DynamicMaterial = UMaterialInstanceDynamic::Create(VRMaterial.Get(), OptiXContext.Get(), "DynamicVRMaterial");
+		DynamicMaterial = UMaterialInstanceDynamic::Create(VRMaterial.Get(), GetTransientPackage(), "DynamicVRMaterial");
 		DynamicMaterial->SetTextureParameterValue("TextureRight", OutputTexture.Get());
 		DynamicMaterial->SetTextureParameterValue("DepthRight", DepthTexture.Get());
 		DynamicMaterial->SetTextureParameterValue("TextureLeft", OutputTexture2.Get());
 		DynamicMaterial->SetTextureParameterValue("DepthLeft", DepthTexture2.Get());
 
 
-		DynamicMaterialOrtho = UMaterialInstanceDynamic::Create(RegularMaterial.Get(), OptiXContext.Get(), "DynamicNonVRMaterial");
+		DynamicMaterialOrtho = UMaterialInstanceDynamic::Create(RegularMaterial.Get(), GetTransientPackage(), "DynamicNonVRMaterial");
 		DynamicMaterialOrtho->SetTextureParameterValue("Texture", OutputTextureOrtho.Get());
 		DynamicMaterialOrtho->SetTextureParameterValue("Depth", DepthTextureOrtho.Get());
 
 	}
 	else
 	{
-		DynamicMaterial = UMaterialInstanceDynamic::Create(RegularMaterial.Get(), OptiXContext.Get(), "DynamicNonVRMaterial");
+		DynamicMaterial = UMaterialInstanceDynamic::Create(RegularMaterial.Get(), GetTransientPackage(), "DynamicNonVRMaterial");
 		DynamicMaterial->SetTextureParameterValue("Texture", OutputTexture.Get());
 		DynamicMaterial->SetTextureParameterValue("Depth", DepthTexture.Get());
 	}
 
-	UE_LOG(LogTemp, Display, TEXT("Finished Initializing Rendering in ContextManager"));
+	UE_LOG(OptiXContextManagerLog, Display, TEXT("Finished Initializing Rendering in ContextManager"));
 	FlushRenderingCommands();
 
 }
 
 void FOptiXContextManager::InitBuffers()
 {
-	OutputBuffer = OptiXContext->CreateOutputBufferColor(Width, Height * 2);
-	OutputDepthBuffer = OptiXContext->CreateOutputBufferDepth(Width, Height * 2);
+	OutputBuffer = NativeContext->createBufferForCUDA(RT_BUFFER_INPUT_OUTPUT | RT_BUFFER_GPU_LOCAL, RT_FORMAT_FLOAT4, Width, Height * 2);
+	OutputDepthBuffer = NativeContext->createBufferForCUDA(RT_BUFFER_INPUT_OUTPUT | RT_BUFFER_GPU_LOCAL, RT_FORMAT_FLOAT, Width, Height * 2);
 
-	OptiXContext->SetBuffer("result_color", OutputBuffer.Get());
-	OptiXContext->SetBuffer("result_depth", OutputDepthBuffer.Get());
+	NativeContext["result_color"]->setBuffer(OutputBuffer);
+	NativeContext["result_depth"]->setBuffer(OutputDepthBuffer);
 }
 
 void FOptiXContextManager::InitPrograms()
 {
-	FString OptiXPTXDir = FOptiXModule::Get().OptiXPTXDir;
+	//FString OptiXPTXDir = FOptiXModule::Get().OptiXPTXDir;
+
+	std::string Dir = std::string(TCHAR_TO_ANSI(*OptiXPTXDir));
 
 	// Generation Program
-	RayGenerationProgram = OptiXContext->CreateProgramFromPTXFile
+	RayGenerationProgram = NativeContext->createProgramFromPTXFile
 	(
-		OptiXPTXDir + "generated/perspective_camera.ptx",
+		Dir + "generated/perspective_camera.ptx",
 		"pinhole_camera"
 	);
-	OptiXContext->SetRayGenerationProgram(0, RayGenerationProgram.Get());
+	NativeContext->setRayGenerationProgram(0, RayGenerationProgram);
 
 	// Exception program
-	ExceptionProgram = OptiXContext->CreateProgramFromPTXFile
+	ExceptionProgram = NativeContext->createProgramFromPTXFile
 	(
-		OptiXPTXDir + "generated/exception.ptx",
+		Dir + "generated/exception.ptx",
 		"exception"
 	);
-	OptiXContext->SetExceptionProgram(0, ExceptionProgram.Get());
+	NativeContext->setExceptionProgram(0, ExceptionProgram);
 
 	// Miss Program
-	MissProgram = OptiXContext->CreateProgramFromPTXFile
+	MissProgram = NativeContext->createProgramFromPTXFile
 	(
-		OptiXPTXDir + "generated/skybox.ptx",
+		Dir + "generated/skybox.ptx",
 		"skyboxLookup"
 	);
-	OptiXContext->SetMissProgram(0, MissProgram.Get());
-	OptiXContext->SetFloat3DVector("bg_color", FVector(1.0, 1.0, 1.0));
+	NativeContext->setMissProgram(0, MissProgram);
+	NativeContext["bg_color"]->setFloat(1.0, 1.0, 1.0);
 }
 
-
-
 void FOptiXContextManager::InitLaser()
 {
+	std::string Dir = std::string(TCHAR_TO_ANSI(*OptiXPTXDir));
 
-	FString OptiXPTXDir = FOptiXModule::Get().OptiXPTXDir;
-
+	LaserEntryPoint = NativeContext->getEntryPointCount();
 
-	LaserEntryPoint = OptiXContext->GetEntryPointCount();
+	int32 RayTypeCount = NativeContext->getRayTypeCount();
+	NativeContext->setRayTypeCount(RayTypeCount + 1);
 
-	int32 RayTypeCount = OptiXContext->GetRayTypeCount();
-	OptiXContext->SetRayTypeCount(RayTypeCount + 1);
-
-	UE_LOG(LogTemp, Display, TEXT("Setting Laser Entry Point to %i"), LaserEntryPoint);
-	UE_LOG(LogTemp, Display, TEXT("Setting Ray Type Index to %i"), RayTypeCount);
+	UE_LOG(OptiXContextManagerLog, Display, TEXT("Setting Laser Entry Point to %i"), LaserEntryPoint);
+	UE_LOG(OptiXContextManagerLog, Display, TEXT("Setting Ray Type Index to %i"), RayTypeCount);
 
 
 	// Increase EntryPointCount by 1
-	OptiXContext->SetEntryPointCount(LaserEntryPoint + 1);
+	NativeContext->setEntryPointCount(LaserEntryPoint + 1);
 
 	// TODO maybe do this explicitely - loads the same program twice, but at least it's clear which one is used then.
 
-	LaserExceptionProgram = OptiXContext->CreateProgramFromPTXFile
+	LaserExceptionProgram = NativeContext->createProgramFromPTXFile
 	(
-		OptiXPTXDir + "generated/exception.ptx",
+		Dir + "generated/exception.ptx",
 		"exception"
 	);
 
-	OptiXContext->SetExceptionProgram(1 /* todo- diff between raytypeindex and entrypointcount, this is 1 in the original app*/, LaserExceptionProgram.Get());
+	NativeContext->setExceptionProgram(1 /* todo- diff between raytypeindex and entrypointcount, this is 1 in the original app*/, LaserExceptionProgram);
 
-	LaserRayGenerationProgram = OptiXContext->CreateProgramFromPTXFile
+	LaserRayGenerationProgram = NativeContext->createProgramFromPTXFile
 	(
-		OptiXPTXDir + "generated/laser_caster.ptx",
+		Dir + "generated/laser_caster.ptx",
 		"laser_caster"
 	);
-	OptiXContext->SetRayGenerationProgram(LaserEntryPoint, LaserRayGenerationProgram.Get());
+	NativeContext->setRayGenerationProgram(LaserEntryPoint, LaserRayGenerationProgram);
 
-	LaserMissProgram = OptiXContext->CreateProgramFromPTXFile
+	LaserMissProgram = NativeContext->createProgramFromPTXFile
 	(
-		OptiXPTXDir + "generated/miss.ptx",
+		Dir + "generated/miss.ptx",
 		"miss_iterative"
 	);
 
-	OptiXContext->SetMissProgram(1 /*LaserEntryPoint /* this is 1 in the original application, why? TODO*/, LaserMissProgram.Get());
+	NativeContext->setMissProgram(1 /*LaserEntryPoint /* this is 1 in the original application, why? TODO*/, LaserMissProgram);
 
-	//LaserOutputBuffer = OptiXContext->CreateBuffer(RT_BUFFER_OUTPUT, RT_FORMAT_FLOAT4, LaserBufferSize);
-	LaserOutputBuffer = OptiXContext->CreateOutputBufferIntersections(LaserBufferWidth, LaserBufferHeight);
-	LaserOutputBuffer->AddToRoot();
-	OptiXContext->SetBuffer("result_laser", LaserOutputBuffer.Get());
+	LaserOutputBuffer = NativeContext->createBufferForCUDA(RT_BUFFER_INPUT_OUTPUT | RT_BUFFER_GPU_LOCAL, RT_FORMAT_FLOAT4, LaserBufferWidth, LaserBufferHeight);
+	NativeContext["result_laser"]->setBuffer(LaserOutputBuffer);
 
-	OptiXContext->SetInt("max_depth_laser", LaserMaxDepth);
+	NativeContext["max_depth_laser"]->setInt(LaserMaxDepth);
 
-	UOptiXBuffer* LaserIndexBuffer = OptiXContext->CreateBuffer(RT_BUFFER_INPUT, RT_FORMAT_INT, 50, 50);
-	//LaserIndexBuffer->AddToRoot();
-	UOptiXBuffer* LaserDirectionBuffer = OptiXContext->CreateBuffer(RT_BUFFER_INPUT, RT_FORMAT_FLOAT3, 50, 50);
-	//LaserDirectionBuffer->AddToRoot();
-	OptiXContext->SetBuffer("laserIndex", LaserIndexBuffer);
-	OptiXContext->SetBuffer("laserDir", LaserDirectionBuffer);
+	optix::Buffer LaserIndexBuffer = NativeContext->createBuffer(RT_BUFFER_INPUT, RT_FORMAT_INT, 50, 50);
+	optix::Buffer LaserDirectionBuffer = NativeContext->createBuffer(RT_BUFFER_INPUT, RT_FORMAT_FLOAT3, 50, 50);
+	NativeContext["laserIndex"]->setBuffer(LaserIndexBuffer);
+	NativeContext["laserDir"]->setBuffer(LaserDirectionBuffer);
+	NativeContext["laserSize"]->setFloat(3.5f); // Hardcode this for now
 
+	bIsInitializedLaser.AtomicSet(true);
 
 }
 
@@ -880,35 +848,31 @@ void FOptiXContextManager::InitCubemap()
 	// TODO: Try and see if destroying/creating the whole thing and doing a memcpy on the GPU only is 
 	// quicker than updating the cubemap each frame.
 
-	CubemapsInputBuffer = OptiXContext->CreateBuffer(RT_BUFFER_INPUT, RTformat::RT_FORMAT_INT, 10);
-	OptiXContext->SetBuffer("skyboxBuffer", CubemapsInputBuffer.Get());
-
-	CubemapSampler = OptiXContext->CreateTextureSampler();
-	//CubemapSampler->AddToRoot();
-	CubemapSampler->SetWrapMode(0, RT_WRAP_CLAMP_TO_EDGE);
-	CubemapSampler->SetWrapMode(1, RT_WRAP_CLAMP_TO_EDGE);
-	CubemapSampler->SetWrapMode(2, RT_WRAP_CLAMP_TO_EDGE);
-	CubemapSampler->SetIndexingMode(RT_TEXTURE_INDEX_NORMALIZED_COORDINATES);
-	CubemapSampler->SetReadMode(RT_TEXTURE_READ_NORMALIZED_FLOAT);
-	CubemapSampler->SetMaxAnisotropy(1.0f);
-	CubemapSampler->SetMipLevelCount(1u);
-	CubemapSampler->SetArraySize(1u);
+	CubemapsInputBuffer = NativeContext->createBuffer(RT_BUFFER_INPUT, RTformat::RT_FORMAT_INT, 10);
+	NativeContext["skyboxBuffer"]->setBuffer(CubemapsInputBuffer);
+	
+	CubemapSampler = NativeContext->createTextureSampler();
+	CubemapSampler->setWrapMode(0, RT_WRAP_CLAMP_TO_EDGE);
+	CubemapSampler->setWrapMode(1, RT_WRAP_CLAMP_TO_EDGE);
+	CubemapSampler->setWrapMode(2, RT_WRAP_CLAMP_TO_EDGE);
+	CubemapSampler->setIndexingMode(RT_TEXTURE_INDEX_NORMALIZED_COORDINATES);
+	CubemapSampler->setReadMode(RT_TEXTURE_READ_NORMALIZED_FLOAT);
+	CubemapSampler->setMaxAnisotropy(1.0f);
+	CubemapSampler->setMipLevelCount(1u);
+	CubemapSampler->setArraySize(1u);
 
 
-	CubemapBuffer = OptiXContext->CreateCubemapBuffer(1024, 1024);
-	//CubemapBuffer->AddToRoot();
+	CubemapBuffer = NativeContext->createBuffer(RT_BUFFER_INPUT | RT_BUFFER_CUBEMAP, RT_FORMAT_UNSIGNED_BYTE4, 1024, 1024, 6); // 6 slices
 
-	CubemapSampler->SetBufferWithTextureIndexAndMiplevel(0u, 0u, CubemapBuffer.Get());
-	CubemapSampler->SetFilteringModes(RT_FILTER_LINEAR, RT_FILTER_LINEAR, RT_FILTER_NONE);
+	CubemapSampler->setBuffer(0u, 0u, CubemapBuffer);
+	CubemapSampler->setFilteringModes(RT_FILTER_LINEAR, RT_FILTER_LINEAR, RT_FILTER_NONE);
 
-	OptiXContext->SetSkybox("skybox0", CubemapSampler.Get());
+	NativeContext["skybox0"]->setInt(CubemapSampler->getId());
 
-	//RequestCubemapId();
-	AddCubemapToBuffer(0, CubemapSampler->GetId());
+	AddCubemapToBuffer(0, CubemapSampler->getId());
 	
-	//OptiXContext->SetTextureSampler("skybox", CubemapSampler.Get());
 
-	UE_LOG(LogTemp, Display, TEXT("Successfully initialized cubemap."));
+	UE_LOG(OptiXContextManagerLog, Display, TEXT("Successfully initialized cubemap."));
 }
 
 int32 FOptiXContextManager::RequestCubemapId()
@@ -930,7 +894,7 @@ void FOptiXContextManager::DeleteCubemapId(int32 Id)
 
 	if (Id <= 10)
 	{
-		UE_LOG(LogTemp, Warning, TEXT("Trying to free a cubemap that isn't there."));
+		UE_LOG(OptiXContextManagerLog, Warning, TEXT("Trying to free a cubemap that isn't there."));
 		return;
 	}
 	// The Component itself should handle deletion of the sampler.
@@ -958,9 +922,7 @@ void FOptiXContextManager::UpdateCubemapBuffer(FRHICommandListImmediate & RHICmd
 	SurfaceDataCube.Empty();
 	SurfaceDataCube.SetNumZeroed(6);
 
-	//TArray<FLinearColor> SD;
-
-	optix::uchar4* BufferData = static_cast<optix::uchar4*>(CubemapBuffer->MapNative());
+	optix::uchar4* BufferData = static_cast<optix::uchar4*>(CubemapBuffer->map());
 
 	FTextureRenderTargetCubeResource* RenderTargetCube = static_cast<FTextureRenderTargetCubeResource*>(CameraActor->CubeRenderTarget->GetRenderTargetResource());
 
@@ -987,7 +949,7 @@ void FOptiXContextManager::UpdateCubemapBuffer(FRHICommandListImmediate & RHICmd
 	FMemory::Memcpy(BufferData + X * Y * 4, SurfaceDataCube[4].GetData(), MemSize); // 
 	FMemory::Memcpy(BufferData + X * Y * 5, SurfaceDataCube[5].GetData(), MemSize); //
 
-	CubemapBuffer->Unmap();
+	CubemapBuffer->unmap();
 	bValidCubemap.AtomicSet(true);
 }
 
@@ -995,9 +957,9 @@ void FOptiXContextManager::AddCubemapToBuffer(int32 CubemapId, int32 SamplerId)
 {
 	TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("FOptiXContextManager::AddCubemapToBuffer"))
 
-	int32* Data = static_cast<int32*>(CubemapsInputBuffer->MapNative());
+	int32* Data = static_cast<int32*>(CubemapsInputBuffer->map());
 	Data[CubemapId] = SamplerId;
-	CubemapsInputBuffer->Unmap();
+	CubemapsInputBuffer->unmap();
 }
 
 void FOptiXContextManager::InitCUDADX()
@@ -1007,10 +969,6 @@ void FOptiXContextManager::InitCUDADX()
 
 	check(IsInGameThread());
 
-	D3DDevice = (ID3D11Device*)GDynamicRHI->RHIGetNativeDevice();
-	D3DDevice->GetImmediateContext(&D3DDeviceContext);
-
-
 	// Depth
 	{
 		FD3D11TextureBase* D3D11TextureDepthLeft = GetD3D11TextureFromRHITexture(DepthTexture2->Resource->TextureRHI);
@@ -1033,6 +991,14 @@ void FOptiXContextManager::InitCUDADX()
 		cudaGraphicsD3D11RegisterResource(&CudaResourceColorRight, D3D11TextureColorRight->GetResource(), cudaGraphicsRegisterFlagsNone);
 		PrintLastCudaError("cudaGraphicsD3D11RegisterResource");
 	}
+	// Intersection
+
+	{
+		FD3D11TextureBase* D3D11TextureIntersections = GetD3D11TextureFromRHITexture(LaserIntersectionTexture->Resource->TextureRHI);
+		cudaGraphicsD3D11RegisterResource(&CudaResourceIntersections, D3D11TextureIntersections->GetResource(), cudaGraphicsRegisterFlagsNone);
+		PrintLastCudaError("cudaGraphicsD3D11RegisterResource");
+	}
+
 	// Ortho
 	{
 		FD3D11TextureBase* D3D11TextureOrthoDepth = GetD3D11TextureFromRHITexture(DepthTextureOrtho->Resource->TextureRHI);
@@ -1054,12 +1020,14 @@ void FOptiXContextManager::InitCUDADX()
 	cudaMalloc(&CudaLinearMemoryIntersections, LaserBufferWidth * LaserBufferHeight * 4 * sizeof(float));
 	PrintLastCudaError("cudaMalloc");
 	
-	OptiXContext->GetBuffer("result_depth")->SetDevicePointer(0, CudaLinearMemoryDepth);
-	OptiXContext->GetBuffer("result_color")->SetDevicePointer(0, CudaLinearMemoryColor);
-	OptiXContext->GetBuffer("result_laser")->SetDevicePointer(0, CudaLinearMemoryIntersections);
+	NativeContext["result_depth"]->getBuffer()->setDevicePointer(0, CudaLinearMemoryDepth);
+	NativeContext["result_color"]->getBuffer()->setDevicePointer(0, CudaLinearMemoryColor);
+	NativeContext["result_laser"]->getBuffer()->setDevicePointer(0, CudaLinearMemoryIntersections);
+
+	FString DeviceName = FString(NativeContext->getDeviceName(0).c_str());
 
-	UE_LOG(LogTemp, Display, TEXT("Device Count: %i"), OptiXContext->GetDeviceCount());
-	UE_LOG(LogTemp, Display, TEXT("Device Name 0: %s"), *OptiXContext->GetDeviceName(0));
+	UE_LOG(OptiXContextManagerLog, Display, TEXT("Device Count: %i"), NativeContext->getDeviceCount());
+	UE_LOG(OptiXContextManagerLog, Display, TEXT("Device Name 0: %s"), *DeviceName);
 	
 
 	Resources[0] = CudaResourceDepthLeft;
@@ -1070,5 +1038,721 @@ void FOptiXContextManager::InitCUDADX()
 	Resources[5] = CudaResourceColorOrtho;
 	Resources[6] = CudaResourceDepthOrtho;
 
-	bIsInitialized = true;
+	bIsInitializedCuda.AtomicSet(true);
+}
+
+void FOptiXContextManager::RequestNewOptiXBuffer(UniqueId ObjectId, FOptiXBufferData BufferData)
+{
+	OptiXBuffersToCreate.Enqueue(TPair<UniqueId, FOptiXBufferData>(ObjectId, BufferData));
+}
+
+
+void FOptiXContextManager::RequestNewOptiXGroup(UniqueId ObjectId)
+{
+
+}
+
+void FOptiXContextManager::RequestNewOptiXTextureSampler(UniqueId ObjectId)
+{
+	OptiXTextureSamplersToCreate.Enqueue(ObjectId);
+}
+
+void FOptiXContextManager::RequestDestroyOptiXObjects(UniqueId ObjectId)
+{
+	if(bIsInitializedAll)
+		OptiXObjectsToDestroy.Enqueue(ObjectId);
+}
+
+void FOptiXContextManager::RequestNewOptiXObject(UniqueId ObjectId, FString Program)
+{
+	OptiXObjectsToCreate.Enqueue(TPair<UniqueId, FString>(ObjectId, Program));
+}
+
+void FOptiXContextManager::RequestLensCubemapUpdate(UniqueId ObjectId, CubemapUpdateFunction UpdateFunction)
+{
+	CubemapsToUpdate.Enqueue(TPair<UniqueId, CubemapUpdateFunction>(ObjectId, UpdateFunction));
 }
+
+void FOptiXContextManager::EnqueueUpdateFunction(UniqueId ObjectId, OptiXObjectUpdateFunction UpdateFunction)
+{
+	OptiXObjectUpdateFunctions.Enqueue(TPair<UniqueId, OptiXObjectUpdateFunction>(ObjectId, UpdateFunction));
+}
+
+void FOptiXContextManager::EnqueueContextUpdateFunction(OptiXContextUpdateFunction UpdateFunction)
+{
+	OptiXContextUpdateQueue.Enqueue(UpdateFunction);
+}
+
+void FOptiXContextManager::EnqueueUpdateFunctionRHI(UniqueId ObjectId, OptiXObjectUpdateFunctionRHI UpdateFunction)
+{
+	OptiXObjectUpdateFunctionsRHI.Enqueue(TPair<UniqueId, OptiXObjectUpdateFunctionRHI>(ObjectId, UpdateFunction));
+}
+
+void FOptiXContextManager::EnqueueInitFunction(UniqueId ObjectId, OptiXObjectInitFunction InitFuntion)
+{
+	OptiXObjectInitFunctions.Enqueue(TPair<UniqueId, OptiXObjectUpdateFunction>(ObjectId, InitFuntion));
+}
+
+void FOptiXContextManager::RegisterLaserTraceCallback(UniqueId ObjectId, LaserTraceFinishedCallback Callback)
+{
+	LaserTraceFinishedCallbacks.Add(ObjectId, Callback);
+}
+
+void FOptiXContextManager::CreateNewOptiXObject(UniqueId ObjectId, FString Program)
+{
+	// Geometry
+	//NativeContext->validate();
+
+	FOptiXObjectData Data;
+
+	Data.OptiXGeometry = NativeContext->createGeometry();
+	Data.OptiXGeometry->setPrimitiveCount(1u);
+
+
+	FString PathGeometryPTX = OptiXPTXDir + "generated/" + Program + ".ptx";
+
+	std::string PG = std::string(TCHAR_TO_ANSI(*PathGeometryPTX));
+	optix::Program NewBoundingBoxProg = NativeContext->createProgramFromPTXFile(PG, "bounds");
+	optix::Program NewIntersectionProg = NativeContext->createProgramFromPTXFile(PG, "intersect");
+
+	// Material 
+	Data.OptiXMaterial = NativeContext->createMaterial();
+
+	FString PathMaterialPTX = OptiXPTXDir + "generated/" + Program + "_material.ptx";
+
+	std::string PM = std::string(TCHAR_TO_ANSI(*PathMaterialPTX));
+
+	optix::Program CHPerspective = NativeContext->createProgramFromPTXFile(PM, "closest_hit_radiance");
+	optix::Program CHIterative = NativeContext->createProgramFromPTXFile(PM, "closest_hit_iterative");
+
+	Data.OptiXPrograms =
+		TTuple<optix::Program, optix::Program, optix::Program, optix::Program>(NewBoundingBoxProg, NewIntersectionProg, CHPerspective, CHIterative);
+
+	Data.OptiXGeometry->setBoundingBoxProgram(NewBoundingBoxProg);
+	Data.OptiXGeometry->setIntersectionProgram(NewIntersectionProg);
+	Data.OptiXMaterial->setClosestHitProgram(0, CHPerspective);
+	Data.OptiXMaterial->setClosestHitProgram(1, CHIterative);
+	// Instance
+	Data.OptiXGeometryInstance = NativeContext->createGeometryInstance();
+	Data.OptiXGeometryInstance->setGeometry(Data.OptiXGeometry);
+	Data.OptiXGeometryInstance->addMaterial(Data.OptiXMaterial);
+
+	// Transform
+	Data.OptiXTransform = NativeContext->createTransform();
+
+	// Acceleration
+	Data.OptiXAcceleration = NativeContext->createAcceleration("NoAccel");
+
+	Data.OptiXGeometryGroup = NativeContext->createGeometryGroup();
+	Data.OptiXGeometryGroup->addChild(Data.OptiXGeometryInstance);
+	Data.OptiXGeometryGroup->setAcceleration(Data.OptiXAcceleration);
+
+	Data.OptiXTransform->setChild(Data.OptiXGeometryGroup);
+
+	TopObject->addChild(Data.OptiXTransform);
+	//TopObject->getAcceleration()->markDirty();
+
+	OptiXObjectData.Add(ObjectId, Data);
+}
+
+void FOptiXContextManager::CreateNewOptiXBuffer(UniqueId ObjectId, FOptiXBufferData BufferData)
+{
+	if (!OptiXBuffers.Contains(ObjectId))
+	{
+		OptiXBuffers.Add(ObjectId, TMap<FString, optix::Buffer>());
+	}
+	optix::Buffer NewBuffer;
+	if (BufferData.BufferHeight == 0)
+	{
+		NewBuffer = NativeContext->createBuffer(BufferData.Type, BufferData.Format, BufferData.BufferWidth);
+	}
+	else if (BufferData.BufferDepth == 0)
+	{
+		NewBuffer = NativeContext->createBuffer(BufferData.Type, BufferData.Format, BufferData.BufferWidth, BufferData.BufferHeight);
+	}
+	else
+	{
+		NewBuffer = NativeContext->createBuffer(BufferData.Type, BufferData.Format, BufferData.BufferWidth, BufferData.BufferHeight, BufferData.BufferDepth);
+	}
+
+	OptiXBuffers[ObjectId].Add(BufferData.Name, NewBuffer);
+}
+
+void FOptiXContextManager::CreateNewOptiXTextureSampler(UniqueId ObjectId)
+{
+	// Find the corresponding sampler
+	optix::TextureSampler Sampler = nullptr;
+	if (OptiXTextureSamplers.Contains(ObjectId))
+	{
+		UE_LOG(OptiXContextManagerLog, Warning, TEXT("A Texture Sampler already exists for %i"), ObjectId);
+		OptiXTextureSamplers[ObjectId]->destroy();
+		OptiXTextureSamplers[ObjectId] = NativeContext->createTextureSampler();
+	}
+	else
+	{
+		optix::TextureSampler NewSampler = NativeContext->createTextureSampler();
+		OptiXTextureSamplers.Add(ObjectId, NewSampler);
+	}
+}
+
+void FOptiXContextManager::ExecuteOptiXUpdate(UniqueId ObjectId, OptiXObjectUpdateFunction UpdateFunction)
+{
+	// Get the required parameters
+
+	optix::TextureSampler Sampler = nullptr;
+	TMap<FString, optix::Buffer>* BufferMap = nullptr;
+	FOptiXObjectData* Data = nullptr;
+	if (OptiXTextureSamplers.Contains(ObjectId))
+	{
+		Sampler = OptiXTextureSamplers[ObjectId];
+	}
+	if (OptiXBuffers.Contains(ObjectId))
+	{
+		BufferMap = &OptiXBuffers[ObjectId];
+	}
+	if (OptiXObjectData.Contains(ObjectId))
+	{
+		Data = &OptiXObjectData[ObjectId];
+	}
+	UpdateFunction(Data, BufferMap, Sampler);
+}
+
+void FOptiXContextManager::ExecuteOptiXUpdateRHI(UniqueId ObjectId, FRHICommandListImmediate& RHICmdList, OptiXObjectUpdateFunctionRHI UpdateFunction)
+{
+	// Get the required parameters
+
+	optix::TextureSampler Sampler = nullptr;
+	TMap<FString, optix::Buffer>* BufferMap = nullptr;
+	FOptiXObjectData* Data = nullptr;
+	if (OptiXTextureSamplers.Contains(ObjectId))
+	{
+		Sampler = OptiXTextureSamplers[ObjectId];
+	}
+	if (OptiXBuffers.Contains(ObjectId))
+	{
+		BufferMap = &OptiXBuffers[ObjectId];
+	}
+	if (OptiXObjectData.Contains(ObjectId))
+	{
+		Data = &OptiXObjectData[ObjectId];
+	}
+	UpdateFunction(Data, BufferMap, Sampler, RHICmdList);
+}
+
+void FOptiXContextManager::ExecuteContextUpdate(OptiXContextUpdateFunction UpdateFunction)
+{
+	UpdateFunction(NativeContext);
+}
+
+
+void FOptiXContextManager::DestroyOptiXObjects(UniqueId ObjectId)
+{
+	// Does the order matter?
+
+	// Remove buffers first, as they can have no children
+	if (OptiXBuffers.Contains(ObjectId))
+	{
+		TMap<FString, optix::Buffer> Buffers = OptiXBuffers.FindAndRemoveChecked(ObjectId);
+		for (TPair<FString, optix::Buffer>& Pair : Buffers)
+		{
+			Pair.Value->destroy();
+			Pair.Value = NULL;
+		}
+	}
+
+	// Remove callbacks
+	if (LaserTraceFinishedCallbacks.Contains(ObjectId))
+	{
+		LaserTraceFinishedCallbacks.FindAndRemoveChecked(ObjectId);
+	}
+
+	// Remove any texture samplers
+	if (OptiXTextureSamplers.Contains(ObjectId))
+	{
+		optix::TextureSampler Sampler = OptiXTextureSamplers.FindAndRemoveChecked(ObjectId);
+		Sampler->destroy();
+	}
+
+	// Clean up the ObjectData
+	if (OptiXObjectData.Contains(ObjectId))
+	{
+		FOptiXObjectData Data = OptiXObjectData.FindAndRemoveChecked(ObjectId);
+		
+
+		TopObject->removeChild(Data.OptiXTransform);
+
+		Data.OptiXTransform->destroy();
+		Data.OptiXTransform = NULL;
+
+		Data.OptiXGeometryGroup->removeChild(0);
+
+		Data.OptiXGeometryGroup->destroy();
+		Data.OptiXGeometryGroup = NULL;
+
+		Data.OptiXGeometryInstance->destroy();
+		Data.OptiXGeometryInstance = NULL;
+
+		Data.OptiXAcceleration->destroy();
+		Data.OptiXAcceleration = NULL;
+
+		Data.OptiXMaterial->destroy();
+		Data.OptiXMaterial = NULL;
+
+		Data.OptiXGeometry->destroy();
+		Data.OptiXGeometry = NULL;
+
+		Data.OptiXPrograms.Get<0>()->destroy();
+		Data.OptiXPrograms.Get<0>() = NULL;
+
+		Data.OptiXPrograms.Get<1>()->destroy();
+		Data.OptiXPrograms.Get<1>() = NULL;
+
+		Data.OptiXPrograms.Get<2>()->destroy();
+		Data.OptiXPrograms.Get<2>() = NULL;
+
+		Data.OptiXPrograms.Get<3>()->destroy();
+		Data.OptiXPrograms.Get<3>() = NULL;
+
+		TopAcceleration->markDirty();
+
+	}
+	// This should never happen
+	if (OptiXGroups.Contains(ObjectId))
+	{
+		optix::Group Group = OptiXGroups.FindAndRemoveChecked(ObjectId);
+		Group->destroy();
+	}
+}
+
+void FOptiXContextManager::InitializeOptiXObject(UniqueId ObjectId, OptiXObjectInitFunction InitFunction)
+{
+	// Get the required parameters
+
+	optix::TextureSampler Sampler = nullptr;
+	TMap<FString, optix::Buffer>* BufferMap = nullptr;
+	FOptiXObjectData* Data = nullptr;
+	if (OptiXTextureSamplers.Contains(ObjectId))
+	{
+		Sampler = OptiXTextureSamplers[ObjectId];
+	}
+	if (OptiXBuffers.Contains(ObjectId))
+	{
+		BufferMap = &OptiXBuffers[ObjectId];
+	}
+	if (OptiXObjectData.Contains(ObjectId))
+	{
+		Data = &OptiXObjectData[ObjectId];
+	}
+	InitFunction(Data, BufferMap, Sampler);
+}
+
+void FOptiXContextManager::UpdateCubemap(UniqueId ObjectId, FRHICommandListImmediate & RHICmdList, CubemapUpdateFunction UpdateFunction)
+{
+	if (OptiXBuffers.Contains(ObjectId))
+	{
+		optix::Buffer Buffer = OptiXBuffers[ObjectId]["texture_buffer"];
+		UpdateFunction(Buffer, RHICmdList);
+	}		
+}
+
+
+void FOptiXContextManager::ParseCreationQueue()
+{
+	for (uint32 i = 0; i < 100 && !OptiXObjectsToCreate.IsEmpty(); i++)
+	{
+		TPair<UniqueId, FString> QueueItem;
+		if (OptiXObjectsToCreate.Dequeue(QueueItem))
+		{
+			CreateNewOptiXObject(QueueItem.Get<0>(), QueueItem.Get<1>());
+		}
+	}
+	for (uint32 i = 0; i < 100 && !OptiXBuffersToCreate.IsEmpty(); i++)
+	{
+		TPair<UniqueId, FOptiXBufferData> QueueItem;
+		if (OptiXBuffersToCreate.Dequeue(QueueItem))
+		{
+			CreateNewOptiXBuffer(QueueItem.Get<0>(), QueueItem.Get<1>());
+		}
+	}
+	for (uint32 i = 0; i < 100 && !OptiXTextureSamplersToCreate.IsEmpty(); i++)
+	{
+		UniqueId QueueItem;
+		if (OptiXTextureSamplersToCreate.Dequeue(QueueItem))
+		{
+			CreateNewOptiXTextureSampler(QueueItem);
+		}
+	}
+}
+void FOptiXContextManager::ParseInitQueue()
+{
+	for (uint32 i = 0; i < 100 && !OptiXObjectInitFunctions.IsEmpty(); i++)
+	{
+		TPair<UniqueId, OptiXObjectInitFunction> QueueItem;
+		if (OptiXObjectInitFunctions.Dequeue(QueueItem))
+		{
+			InitializeOptiXObject(QueueItem.Key, QueueItem.Value);
+		}
+	}
+}
+void FOptiXContextManager::ParseUpdateQueue(FRHICommandListImmediate & RHICmdList)
+{
+	for (uint32 i = 0; i < 100 && !OptiXObjectUpdateFunctions.IsEmpty(); i++)
+	{
+		TPair<UniqueId, OptiXObjectUpdateFunction> QueueItem;
+		if (OptiXObjectUpdateFunctions.Dequeue(QueueItem))
+		{
+			ExecuteOptiXUpdate(QueueItem.Key, QueueItem.Value);
+		}
+	}
+	for (uint32 i = 0; i < 100 && !OptiXObjectUpdateFunctionsRHI.IsEmpty(); i++)
+	{
+		TPair<UniqueId, OptiXObjectUpdateFunctionRHI> QueueItem;
+		if (OptiXObjectUpdateFunctionsRHI.Dequeue(QueueItem))
+		{
+			ExecuteOptiXUpdateRHI(QueueItem.Key, RHICmdList, QueueItem.Value);
+		}
+	}
+	for (uint32 i = 0; i < 100 && !OptiXContextUpdateQueue.IsEmpty(); i++)
+	{
+		OptiXContextUpdateFunction QueueItem;
+		if (OptiXContextUpdateQueue.Dequeue(QueueItem))
+		{
+			ExecuteContextUpdate(QueueItem);
+		}
+	}
+}
+void FOptiXContextManager::ParseDestroyQueue()
+{
+	for (uint32 i = 0; i < 100 && !OptiXObjectsToDestroy.IsEmpty(); i++)
+	{
+		UniqueId QueueItem;
+		if (OptiXObjectsToDestroy.Dequeue(QueueItem))
+		{
+			DestroyOptiXObjects(QueueItem);
+		}
+	}
+}
+
+void FOptiXContextManager::ParseCubemapUpdateQueue(FRHICommandListImmediate & RHICmdList)
+{
+	for (uint32 i = 0; i < 100 && !CubemapsToUpdate.IsEmpty(); i++)
+	{
+		TPair<UniqueId, CubemapUpdateFunction> QueueItem;
+		if (CubemapsToUpdate.Dequeue(QueueItem))
+		{
+			UpdateCubemap(QueueItem.Key, RHICmdList, QueueItem.Value);
+		}
+	}
+}
+
+
+void FOptiXContextManager::LaserPositionLateUpdate_RenderThread(const FTransform LateUpdateTransform)
+{
+	TRACE_CPUPROFILER_EVENT_SCOPE("FOptiXContextManager::LaserPositionLateUpdate_RenderThread")
+
+	FVector Translation = LateUpdateTransform.GetTranslation();
+	FVector Forward = LateUpdateTransform.GetUnitAxis(EAxis::X);
+	FVector Right = LateUpdateTransform.GetUnitAxis(EAxis::Y);
+	FVector Up = LateUpdateTransform.GetUnitAxis(EAxis::Z);
+	FMatrix Rotation = LateUpdateTransform.ToMatrixNoScale();
+
+	// Only late-update the origin. Grabbing something with the motion controller should only change the translational part anyway,
+	// NEVER the rotation. 
+
+	NativeContext["laser_origin"]->setFloat(Translation.X, Translation.Y, Translation.Z);
+	NativeContext["laser_forward"]->setFloat(Forward.X, Forward.Y, Forward.Z);
+	NativeContext["laser_right"]->setFloat(Right.X, Right.Y, Right.Z);
+	NativeContext["laser_up"]->setFloat(Up.X, Up.Y, Up.Z);
+
+	NativeContext["laser_rot"]->setMatrix4x4fv(true, &Rotation.M[0][0]);
+}
+
+void FOptiXContextManager::ObjectPositionLateUpdate_RenderThread(UniqueId ObjectId, const FMatrix LateUpdateTransform)
+{
+	TRACE_CPUPROFILER_EVENT_SCOPE("FOptiXContextManager::ObjectPositionLateUpdate_RenderThread")	
+	if (OptiXObjectData.Contains(ObjectId))
+	{
+		FMatrix Update = FMatrix(LateUpdateTransform);
+		FMatrix Inverse = Update.Inverse();
+		FOptiXObjectData Data = OptiXObjectData[ObjectId];
+		Data.OptiXTransform->setMatrix(true, &Update.M[0][0], &Inverse.M[0][0]);
+		Data.OptiXAcceleration->markDirty();
+		Data.OptiXAcceleration->getContext()["top_object"]->getGroup()->getAcceleration()->markDirty();
+	}
+}
+
+// Cleanup functions
+
+void FOptiXContextManager::CleanupCuda()
+{
+	TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("FOptiXContextManager::CleanupCuda"))
+
+	if (CudaResourceDepthLeft != NULL)
+		cudaGraphicsUnregisterResource(CudaResourceDepthLeft);
+	PrintLastCudaError("cudaGraphicsUnregisterResource");
+
+	if (CudaResourceDepthRight != NULL)
+		cudaGraphicsUnregisterResource(CudaResourceDepthRight);
+	PrintLastCudaError("cudaGraphicsUnregisterResource");
+
+	if (CudaResourceColorLeft != NULL)
+		cudaGraphicsUnregisterResource(CudaResourceColorLeft);
+	PrintLastCudaError("cudaGraphicsUnregisterResource");
+
+	if (CudaResourceColorRight != NULL)
+		cudaGraphicsUnregisterResource(CudaResourceColorRight);
+	PrintLastCudaError("cudaGraphicsUnregisterResource");
+
+	if (CudaResourceDepthOrtho != NULL)
+		cudaGraphicsUnregisterResource(CudaResourceDepthOrtho);
+	PrintLastCudaError("cudaGraphicsUnregisterResource");
+
+	if (CudaResourceColorOrtho != NULL)
+		cudaGraphicsUnregisterResource(CudaResourceColorOrtho);
+	PrintLastCudaError("cudaGraphicsUnregisterResource");
+
+	if (CudaResourceIntersections != NULL)
+		cudaGraphicsUnregisterResource(CudaResourceIntersections);
+	PrintLastCudaError("cudaGraphicsUnregisterResource");
+
+	if (CudaLinearMemoryDepth != NULL)
+		cudaFree(CudaLinearMemoryDepth);
+	if (CudaLinearMemoryColor != NULL)
+		cudaFree(CudaLinearMemoryColor);
+	if (CudaLinearMemoryIntersections != NULL)
+		cudaFree(CudaLinearMemoryIntersections);
+	PrintLastCudaError("cudaFree");
+}
+
+void FOptiXContextManager::CleanupLocalOptiXObjects()
+{
+	if (LaserOutputBuffer != NULL)
+	{
+		LaserOutputBuffer->destroy();
+		LaserOutputBuffer = NULL;
+	}
+	if (LaserRayGenerationProgram != NULL)
+	{
+		LaserRayGenerationProgram->destroy();
+		LaserRayGenerationProgram = NULL;
+	}
+	if (LaserMissProgram != NULL)
+	{
+		LaserMissProgram->destroy();
+		LaserMissProgram = NULL;
+	}
+	if (LaserExceptionProgram != NULL)
+	{
+		LaserExceptionProgram->destroy();
+		LaserExceptionProgram = NULL;
+	}
+
+
+	if (RayGenerationProgram != NULL)
+	{
+		RayGenerationProgram->destroy();
+		RayGenerationProgram = NULL;
+	}
+	if (MissProgram != NULL)
+	{
+		MissProgram->destroy();
+		MissProgram = NULL;
+	}
+	if (ExceptionProgram != NULL)
+	{
+		ExceptionProgram->destroy();
+		ExceptionProgram = NULL;
+	}
+
+	if (CubemapSampler != NULL)
+	{
+		CubemapSampler->destroy();
+		CubemapSampler = NULL;
+	}
+	if (CubemapBuffer != NULL)
+	{
+		CubemapBuffer->destroy();
+		CubemapBuffer = NULL;
+	}
+	if (CubemapsInputBuffer != NULL)
+	{
+		CubemapsInputBuffer->destroy();
+		CubemapsInputBuffer = NULL;
+	}
+
+	if (OutputBuffer != NULL)
+	{
+		OutputBuffer->destroy();
+		OutputBuffer = NULL;
+	}
+	if (OutputDepthBuffer != NULL)
+	{
+		OutputDepthBuffer->destroy();
+		OutputDepthBuffer = NULL;
+	}
+
+	if (TopAcceleration != NULL)
+	{
+		TopAcceleration->destroy();
+		TopAcceleration = NULL;
+	}
+	if (TopObject != NULL)
+	{
+		TopObject->destroy();
+		TopObject = NULL;
+	}
+
+	if (NativeContext != NULL)
+	{
+		NativeContext->destroy();
+		NativeContext = NULL;
+	}
+}
+
+void FOptiXContextManager::Cleanup_RenderThread()
+{
+	bIsInitializedAll.AtomicSet(false);
+	OptiXContextUpdateManager->bIsActive = false;
+	CleanupCuda();
+
+
+	for (auto& Pair : OptiXBuffers)
+	{
+		for (TPair<FString, optix::Buffer>& BufferPair : Pair.Value)
+		{
+			BufferPair.Value->destroy();
+			BufferPair.Value = NULL;
+		}
+		Pair.Value.Empty();
+	}
+	OptiXBuffers.Empty();
+
+	for (auto& Pair : OptiXTextureSamplers)
+	{
+		Pair.Value->destroy();
+		Pair.Value = NULL;
+	}
+	OptiXTextureSamplers.Empty();
+
+	for (auto& Pair : OptiXObjectData)
+	{
+		Pair.Value.OptiXTransform->destroy();
+		Pair.Value.OptiXTransform = NULL;
+
+		Pair.Value.OptiXGeometryGroup->destroy();
+		Pair.Value.OptiXGeometryGroup = NULL;
+
+		Pair.Value.OptiXGeometryInstance->destroy();
+		Pair.Value.OptiXGeometryInstance = NULL;
+
+		Pair.Value.OptiXAcceleration->destroy();
+		Pair.Value.OptiXAcceleration = NULL;
+
+		Pair.Value.OptiXMaterial->destroy();
+		Pair.Value.OptiXMaterial = NULL;
+
+		Pair.Value.OptiXGeometry->destroy();
+		Pair.Value.OptiXGeometry = NULL;
+
+		Pair.Value.OptiXPrograms.Get<0>()->destroy();
+		Pair.Value.OptiXPrograms.Get<0>() = NULL;
+
+		Pair.Value.OptiXPrograms.Get<1>()->destroy();
+		Pair.Value.OptiXPrograms.Get<1>() = NULL;
+
+		Pair.Value.OptiXPrograms.Get<2>()->destroy();
+		Pair.Value.OptiXPrograms.Get<2>() = NULL;
+
+		Pair.Value.OptiXPrograms.Get<3>()->destroy();
+		Pair.Value.OptiXPrograms.Get<3>() = NULL;
+	}
+	OptiXObjectData.Empty();
+
+	for (auto& Pair : OptiXGroups)
+	{		
+		Pair.Value->destroy();
+		Pair.Value = NULL;
+	}
+	OptiXGroups.Empty();
+
+	CleanupLocalOptiXObjects();
+
+	// Empty queues
+	OptiXObjectsToCreate.Empty();
+	OptiXObjectInitFunctions.Empty();
+	OptiXObjectUpdateFunctions.Empty();
+	OptiXObjectUpdateFunctionsRHI.Empty();
+
+	OptiXBuffersToCreate.Empty();
+	OptiXTextureSamplersToCreate.Empty();
+	CubemapsToUpdate.Empty();
+	OptiXContextUpdateQueue.Empty();
+	OptiXObjectsToDestroy.Empty();
+}
+
+void FOptiXContextManager::Cleanup_GameThread()
+{
+	// Laser stuff
+	IntersectionData.Empty();
+	OldIntersectionData.Empty();
+	LaserIntersectionQueue.Empty();
+	PreviousLaserResults.Empty();
+	
+	LaserIntersectionTexture->RemoveFromRoot();
+	LaserMaterialDynamic->RemoveFromRoot();
+	LaserMaterial->RemoveFromRoot();
+
+	LaserIntersectionTexture->ConditionalBeginDestroy();
+	//LaserMaterialDynamic->ConditionalBeginDestroy();
+	//LaserMaterial->ConditionalBeginDestroy();
+
+	LaserIntersectionTexture.Reset();
+	LaserMaterialDynamic.Reset();
+	LaserMaterial.Reset();
+
+	// Rendering
+
+	OutputTexture->RemoveFromRoot();
+	DepthTexture->RemoveFromRoot();
+	OutputTexture2->RemoveFromRoot();
+	DepthTexture2->RemoveFromRoot();
+	OutputTextureOrtho->RemoveFromRoot();
+	DepthTextureOrtho->RemoveFromRoot();
+	DynamicMaterial->RemoveFromRoot();
+	DynamicMaterialOrtho->RemoveFromRoot();
+	RegularMaterial->RemoveFromRoot();
+	VRMaterial->RemoveFromRoot();
+
+	OutputTexture->ConditionalBeginDestroy();
+	DepthTexture->ConditionalBeginDestroy();
+	OutputTexture2->ConditionalBeginDestroy();
+	DepthTexture2->ConditionalBeginDestroy();
+	OutputTextureOrtho->ConditionalBeginDestroy();
+	DepthTextureOrtho->ConditionalBeginDestroy();
+	//DynamicMaterial->ConditionalBeginDestroy();
+	//DynamicMaterialOrtho->ConditionalBeginDestroy();
+	//RegularMaterial->ConditionalBeginDestroy();
+	//VRMaterial->ConditionalBeginDestroy();
+
+	OutputTexture.Reset();
+	DepthTexture.Reset();
+	OutputTexture2.Reset();
+	DepthTexture2.Reset();
+	OutputTextureOrtho.Reset();
+	DepthTextureOrtho.Reset();
+	DynamicMaterial.Reset();
+	DynamicMaterialOrtho.Reset();
+	RegularMaterial.Reset();
+	VRMaterial.Reset();
+
+	// Other
+	LaserActor.Reset();
+	CameraActor.Reset();
+
+	UnallocatedCubemapIds.Empty();
+	SurfaceDataCube.Empty();
+
+	LaserTraceFinishedCallbacks.Empty();
+
+}
+
diff --git a/Source/OptiX/Private/OptiXCubemapLateUpdateComponent.cpp b/Source/OptiX/Private/OptiXCubemapLateUpdateComponent.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..fd4ef9d69842aff9cb24995d89f65784f5f87bc6
--- /dev/null
+++ b/Source/OptiX/Private/OptiXCubemapLateUpdateComponent.cpp
@@ -0,0 +1,59 @@
+// Fill out your copyright notice in the Description page of Project Settings.
+
+
+#include "OptiXCubemapLateUpdateComponent.h"
+
+#include "PrimitiveSceneProxy.h"
+#include "OptiXModule.h"
+
+FPrimitiveSceneProxy* UOptiXCubemapLateUpdateComponent::CreateSceneProxy()
+{
+	class FOptiXCubemapComponentSceneProxy final : public FPrimitiveSceneProxy
+	{
+	public:
+		SIZE_T GetTypeHash() const override
+		{
+			static size_t UniquePointer;
+			return reinterpret_cast<size_t>(&UniquePointer);
+		}
+
+		/** Initialization constructor. */
+		FOptiXCubemapComponentSceneProxy(const UOptiXCubemapLateUpdateComponent* InComponent)
+			: FPrimitiveSceneProxy(InComponent), UniqueId(InComponent->GetOptiXComponentId())
+		{
+		}
+
+		// FPrimitiveSceneProxy interface.
+
+		virtual void ApplyLateUpdateTransform(const FMatrix& LateUpdateTransform) override
+		{
+
+			FMatrix NewTransform = GetLocalToWorld() * LateUpdateTransform;
+			FVector OriginChange = NewTransform.GetOrigin() - GetLocalToWorld().GetOrigin();
+			FMatrix ReducedLateUpdate = FMatrix::Identity;
+			ReducedLateUpdate.SetOrigin(OriginChange);
+
+			FPrimitiveSceneProxy::ApplyLateUpdateTransform(ReducedLateUpdate);
+
+
+			//FMatrix CachedTransform = GetLocalToWorld();
+			//FPrimitiveSceneProxy::ApplyLateUpdateTransform(LateUpdateTransform);
+			//CachedTransform.SetOrigin(GetLocalToWorld().GetOrigin());
+			////UE_LOG(LogTemp, Display, TEXT("Transform on late update: %s"), *UpdatedTransform.ToString());
+			FOptiXModule::Get().GetOptiXContextManager()->ObjectPositionLateUpdate_RenderThread(*UniqueId, GetLocalToWorld().GetMatrixWithoutScale());
+		}
+
+		virtual uint32 GetMemoryFootprint(void) const override { return(sizeof(*this) + GetAllocatedSize()); }
+		uint32 GetAllocatedSize(void) const { return(FPrimitiveSceneProxy::GetAllocatedSize()); }
+	private:
+		const uint32* UniqueId;
+	};
+
+	return new FOptiXCubemapComponentSceneProxy(this);
+}
+
+void UOptiXCubemapLateUpdateComponent::LinkOptiXComponent(UOptiXCubemapComponent* OptiXComponent)
+{
+	OptiXComponentId = OptiXComponent->GetUniqueID();
+	UE_LOG(LogTemp, Display, TEXT("Setting Unique id on UOptiXCubemapComponent: %i"), OptiXComponentId);
+}
diff --git a/Source/OptiX/Private/OptiXLaserComponent.cpp b/Source/OptiX/Private/OptiXLaserComponent.cpp
index 1f0b3e2f40b4dbc4d090db87de2b71ee3fa86886..474d4029f2f7a8563443d067e48bfc7ad49cf2da 100644
--- a/Source/OptiX/Private/OptiXLaserComponent.cpp
+++ b/Source/OptiX/Private/OptiXLaserComponent.cpp
@@ -1,456 +1,482 @@
-// Fill out your copyright notice in the Description page of Project Settings.
-
-#include "OptiXLaserComponent.h"
-#include "OptiXModule.h"
-
-#include "UObject/ConstructorHelpers.h"
-#include "StatsDefines.h"
-
-
-// Sets default values for this component's properties
-UOptiXLaserComponent::UOptiXLaserComponent()
-{
-	// Set this component to be initialized when the game starts, and to be ticked every frame.  You can turn these features
-	// off to improve performance if you don't need them.
-	PrimaryComponentTick.bCanEverTick = false; 
-	bWantsOnUpdateTransform = true; // why the hell do I need this here but not on the others?
-
-	// ...
-
-	LaserMaxDepth = 20;
-	LaserEntryPoint = 1; // Default, will be overwritten anyway
-
-	LaserBufferWidth = 50 * 50;
-	LaserBufferHeight = LaserMaxDepth * 2;
-
-	LaserBufferSize = LaserBufferHeight * LaserBufferWidth;
-
-
-	RayTIR = false;
-	TargetBufferWrite = 1; //todo
-	TargetColorMode = 0; // todo
-	Wavelength = 450.0f;
-	LaserWidth = 0.025f;
-	CurrentLaserPattern = EPatternTypes::POINTER;
-	LaserTracesPerFrame = 20;
-
-	// Find and load default patterns:
-
-	static ConstructorHelpers::FObjectFinder<UTexture2D> CrossTexture(TEXT("Texture2D'/OptiX/Laser/Cross.Cross'"));
-	static ConstructorHelpers::FObjectFinder<UTexture2D> CrossTextureDir(TEXT("Texture2D'/OptiX/Laser/Cross_dir.Cross_dir'"));
-	static ConstructorHelpers::FObjectFinder<UTexture2D> PointerTexture(TEXT("Texture2D'/OptiX/Laser/Pointer.Pointer'"));
-	static ConstructorHelpers::FObjectFinder<UTexture2D> PointerTextureDir(TEXT("Texture2D'/OptiX/Laser/Pointer_dir.Pointer_dir'"));
-	static ConstructorHelpers::FObjectFinder<UTexture2D> CircleTexture(TEXT("Texture2D'/OptiX/Laser/Circle.Circle'"));
-	static ConstructorHelpers::FObjectFinder<UTexture2D> CircleTextureDir(TEXT("Texture2D'/OptiX/Laser/Circle_dir.Circle_dir'"));
-	static ConstructorHelpers::FObjectFinder<UTexture2D> QuadTexture(TEXT("Texture2D'/OptiX/Laser/Quad.Quad'"));
-	static ConstructorHelpers::FObjectFinder<UTexture2D> QuadTextureDir(TEXT("Texture2D'/OptiX/Laser/Quad_dir.Quad_dir'"));
-
-
-
-	if (CrossTexture.Object != NULL)
-	{
-		Patterns.Add(EPatternTypes::CROSS, CrossTexture.Object);
-		UE_LOG(LogTemp, Display, TEXT("OptiX Laser Component Added Cross Pattern."));
-	}
-	if (CrossTextureDir.Object != NULL)
-	{
-		PatternDirections.Add(EPatternTypes::CROSS, CrossTextureDir.Object);
-		UE_LOG(LogTemp, Display, TEXT("OptiX Laser Component Added Cross Dir Pattern."));
-	}
-	if (PointerTexture.Object != NULL)
-	{
-		Patterns.Add(EPatternTypes::POINTER, PointerTexture.Object);
-		UE_LOG(LogTemp, Display, TEXT("OptiX Laser Component Added Pointer Pattern."));
-	}
-	if (PointerTextureDir.Object != NULL)
-	{
-		PatternDirections.Add(EPatternTypes::POINTER, PointerTextureDir.Object);
-		UE_LOG(LogTemp, Display, TEXT("OptiX Laser Component Added Pointer Dir Pattern."));
-	}	
-	if (CircleTexture.Object != NULL)
-	{
-		Patterns.Add(EPatternTypes::CIRCLE, CircleTexture.Object);
-		UE_LOG(LogTemp, Display, TEXT("OptiX Laser Component Added Circle Pattern."));
-	}	
-	if (CircleTextureDir.Object != NULL)
-	{
-		PatternDirections.Add(EPatternTypes::CIRCLE, CircleTextureDir.Object);
-		UE_LOG(LogTemp, Display, TEXT("OptiX Laser Component Added Circle Dir Pattern."));
-	}
-	if (QuadTexture.Object != NULL)
-	{
-		Patterns.Add(EPatternTypes::QUAD, QuadTexture.Object);
-		UE_LOG(LogTemp, Display, TEXT("OptiX Laser Component Added Quad Pattern."));
-	}
-	if (QuadTextureDir.Object != NULL)
-	{
-		PatternDirections.Add(EPatternTypes::QUAD, QuadTextureDir.Object);
-		UE_LOG(LogTemp, Display, TEXT("OptiX Laser Component Added Quad Dir Pattern."));
-	}	
-
-	// Init the # of rays and their indices
-
-	// This crashes on packaging for some reason, apparently Mips has length 0.
-
-	if (Patterns[CurrentLaserPattern]->PlatformData->Mips.Num() != 0)
-	{
-		FTexture2DMipMap& IndexMip = Patterns[CurrentLaserPattern]->PlatformData->Mips[0];
-
-		UE_LOG(LogTemp, Display, TEXT("Got Texture mips"));
-
-
-		FColor* TextureData = static_cast<FColor*>(IndexMip.BulkData.Lock(LOCK_READ_WRITE));
-
-
-		int X = Patterns[CurrentLaserPattern]->GetSizeX();
-		int Y = Patterns[CurrentLaserPattern]->GetSizeY();
-
-
-		// Save the texture indices for the direction:
-
-		// Texture index conversion is a real pain...
-		for (int32 i = 0; i < X; ++i) {
-			for (int32 j = 0; j < Y; ++j) {
-
-				int32 TextureIndex = (X * Y - 1) - i * X - j;
-				int32 BufferIndex = ((j)*(X)+i);
-
-				if (TextureData[TextureIndex].R || TextureData[TextureIndex].G || TextureData[TextureIndex].B)
-				{
-					LaserIndices.Add(BufferIndex);
-					LaserIndexColorMap.Add(TextureData[TextureIndex]);
-				}
-			}
-		}
-
-		IndexMip.BulkData.Unlock();
-
-		UE_LOG(LogTemp, Display, TEXT("Finished Laser Component texture conversion."));
-	}
-	else
-	{
-		UE_LOG(LogTemp, Warning, TEXT("Texture Mip array is empty in OptiXLaserComponent Constructor. Skipping laser texture reading, hopefully fixed on beginplay()."));
-	}
-}
-
-
-// Called when the game starts
-void UOptiXLaserComponent::BeginPlay()
-{
-	Super::BeginPlay();
-	Init();
-}
-
-void UOptiXLaserComponent::EndPlay(const EEndPlayReason::Type EndPlayReason)
-{
-	Super::EndPlay(EndPlayReason);
-
-	UE_LOG(LogTemp, Warning, TEXT("OptiX Laser Component EndPlay"));
-
-	CleanOptiXObjects();
-}
-
-
-void UOptiXLaserComponent::OnUpdateTransform(EUpdateTransformFlags UpdateTransformFlags, ETeleportType Teleport/* = ETeleportType::None*/)
-{
-	Super::OnUpdateTransform(EUpdateTransformFlags::SkipPhysicsUpdate, Teleport);
-	UpdateLaserPosition();
-}
-
-void UOptiXLaserComponent::UpdateOptiXContextVariables()
-{
-	TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("FOptiXContextManager::UpdateOptiXContextVariables"))
-
-	check(IsInRenderingThread());
-
-	if (bUpdateQueued)
-	{
-		OptiXContext->SetInt("allowTir", RayTIR);
-		OptiXContext->SetInt("targetBufferWrite", static_cast<int32>(TargetBufferWrite));
-		OptiXContext->SetFloat("laserWaveLength", Wavelength);
-
-		OptiXContext->SetFloat("laserSize", 3.5f); // Hardcode this for now
-
-		OptiXContext->SetFloat("laserBeamWidth", LaserWidth);
-
-
-		// Upload buffer data
-
-		if (bPatternChanged)
-		{
-
-			int X = Patterns[CurrentLaserPattern]->GetSizeX();
-			int Y = Patterns[CurrentLaserPattern]->GetSizeY();
-
-			// Those get set on the game thread already
-			//LaserIndices.Empty();
-			//LaserIndexColorMap.Empty();
-
-
-			UOptiXBuffer* LaserIndexBuffer = OptiXContext->GetBuffer("laserIndex");
-			UOptiXBuffer* LaserDirectionBuffer = OptiXContext->GetBuffer("laserDir");
-			{
-				UE_LOG(LogTemp, Display, TEXT("New Pattern: %i"), static_cast<uint8>(CurrentLaserPattern));
-
-				int32* BufferIndexData = static_cast<int32*>(LaserIndexBuffer->MapNative(0, RT_BUFFER_MAP_WRITE));
-				// Reset the buffer explicitly 
-				FMemory::Memset(BufferIndexData, 0u, X * Y * 4);
-
-				FTexture2DMipMap& IndexMip = Patterns[CurrentLaserPattern]->PlatformData->Mips[0];
-
-				FColor* TextureData = static_cast<FColor*>(IndexMip.BulkData.Lock(LOCK_READ_WRITE));
-
-				// Save the texture indices for the direction:
-
-				TArray<int32> TextureIndices;
-
-				// Texture index conversion is a real pain...
-				for (int32 i = 0; i < X; ++i) {
-					for (int32 j = 0; j < Y; ++j) {
-
-						int32 TextureIndex = (X * Y - 1) - i * X - j;
-						int32 BufferIndex = ((j)*(X)+i);
-
-						BufferIndexData[BufferIndex] = 0;
-
-						if (TextureData[TextureIndex].R || TextureData[TextureIndex].G || TextureData[TextureIndex].B)
-						{
-							BufferIndexData[BufferIndex] = 1;
-							//LaserIndices.Add(BufferIndex);
-							TextureIndices.Add(TextureIndex);
-							//LaserIndexColorMap.Add(BufferIndex, TextureData[TextureIndex]);
-						}
-						else
-						{
-							BufferIndexData[BufferIndex] = -1; // do not cast ray
-						}
-					}
-				}
-
-				UE_LOG(LogTemp, Display, TEXT("# Ray Indices in Pattern %i"), static_cast<uint8>(TextureIndices.Num()));
-
-				IndexMip.BulkData.Unlock();
-				LaserIndexBuffer->Unmap();
-			}
-
-			{
-
-				// TODO: It should really suffice to just copy the respective texture index. If we don't shoot a ray, the direction won't matter anyway
-
-				float* BufferDirectionData = static_cast<float*>(LaserDirectionBuffer->MapNative(0, RT_BUFFER_MAP_WRITE));
-
-				FTexture2DMipMap& DirectionMip = PatternDirections[CurrentLaserPattern]->PlatformData->Mips[0];
-
-				FColor* TextureData = static_cast<FColor*>(DirectionMip.BulkData.Lock(LOCK_READ_WRITE));
-
-				// Texture index conversion is a real pain...
-				for (int32 i = 0; i < X; ++i) {
-					for (int32 j = 0; j < Y; ++j) {
-
-						int32 TextureIndex = (X * Y - 1) - i * X - j;
-						int32 BufferIndex = ((j)*(X)+i) * 3;
-
-						//UE_LOG(LogTemp, Display, TEXT("Values: %i"), TextureData[BufferIndex]);
-
-						FVector DirNormalSpace = FVector();
-						DirNormalSpace.X = (TextureData[TextureIndex].R / 256.0f) * 2.0f - 1.0f;
-						DirNormalSpace.Y = (TextureData[TextureIndex].G / 256.0f) * 2.0f - 1.0f;
-						DirNormalSpace.Z = (TextureData[TextureIndex].B / 256.0f);
-
-						// We need to rotate this to face forward (1, 0, 0):
-
-						FMatrix Mat = FRotationMatrix::MakeFromX(FVector(0, 0, 1));
-						FVector Dir = Mat.TransformVector(DirNormalSpace);
-
-						BufferDirectionData[BufferIndex] = Dir.X;
-						BufferDirectionData[BufferIndex + 1] = Dir.Y;
-						BufferDirectionData[BufferIndex + 2] = Dir.Z;
-
-					}
-				}
-				DirectionMip.BulkData.Unlock();
-				LaserDirectionBuffer->Unmap();
-			}
-			bPatternChanged.AtomicSet(false);
-		}
-
-
-		FTransform CurrentTransform = GetComponentTransform();
-		FVector Translation = CurrentTransform.GetTranslation();
-		FVector Forward = GetForwardVector();
-		FVector Right = GetRightVector();
-		FVector Up = GetUpVector();
-			//FMatrix Rotation = GetComponentRotation().;
-
-			// Hard code this for now: laser is around 10x10x10 cube
-
-		OptiXContext->SetFloat3DVectorThreadsafe("laser_origin", Translation);
-		OptiXContext->SetFloat3DVectorThreadsafe("laser_forward", Forward);
-		OptiXContext->SetFloat3DVectorThreadsafe("laser_right", Right);
-		OptiXContext->SetFloat3DVectorThreadsafe("laser_up", Up);
-
-
-		OptiXContext->SetMatrixThreadsafe("laser_rot", CurrentTransform.ToMatrixNoScale());
-
-
-		FOptiXModule::Get().GetOptiXContextManager()->OnSceneChangedDelegate.Broadcast();
-
-		bUpdateQueued.AtomicSet(false);
-
-	}
-}
-
-void UOptiXLaserComponent::Init()
-{
-	OptiXContext = FOptiXModule::Get().GetContext();
-	FString OptiXPTXDir = FOptiXModule::Get().OptiXPTXDir;
-
-	UE_LOG(LogTemp, Display, TEXT("Init Laser, got context instance."));
-
-	// Setup buffers and stuff, make sure to make this compatible with an arbitrary # of lasers.
-	// Use the entry points to do this?
-
-
-	SetRayTIR(RayTIR);
-	SetTargetBufferWrite(TargetBufferWrite);
-	SetTargetColorMode(TargetColorMode);
-	SetWavelength(Wavelength);
-	SetLaserWidth(LaserWidth);
-
-	OptiXContext->SetInt("allowTir", RayTIR);
-	OptiXContext->SetInt("targetBufferWrite", static_cast<int>(TargetBufferWrite));
-	OptiXContext->SetFloat("laserWaveLength", Wavelength);
-
-	OptiXContext->SetFloat("laserSize", 3.5f); // Hardcode this for now
-
-	OptiXContext->SetFloat("laserBeamWidth", LaserWidth);
-
-	SetLaserPattern(CurrentLaserPattern);
-
-	FOptiXModule::Get().GetOptiXContextManager()->bLaserIsInitialized.AtomicSet(true);
-
-}
-
-
-void UOptiXLaserComponent::SetRayTIR(bool Active)
-{
-	RayTIR = Active;
-	bUpdateQueued.AtomicSet(true);
-}
-
-bool UOptiXLaserComponent::GetRayTIR() const
-{
-	return RayTIR;
-}
-
-void UOptiXLaserComponent::SetTargetBufferWrite(bool Flag)
-{
-	TargetBufferWrite = Flag;
-	bUpdateQueued.AtomicSet(true);
-}
-
-bool UOptiXLaserComponent::GetTargetBufferWrite() const
-{
-	return TargetBufferWrite;
-}
-
-void UOptiXLaserComponent::SetTargetColorMode(bool Flag)
-{
-	TargetColorMode = Flag;
-	bUpdateQueued.AtomicSet(true);
-}
-
-bool UOptiXLaserComponent::GetTargetColorMode() const
-{
-	return TargetColorMode;
-}
-
-void UOptiXLaserComponent::SetWavelength(float WL)
-{
-	Wavelength = WL;
-	FOptiXModule::Get().GetOptiXContextManager()->BroadcastWavelengthChange(WL);
-	bUpdateQueued.AtomicSet(true);
-}
-
-float UOptiXLaserComponent::GetWavelength() const
-{
-	return Wavelength;
-}
-
-void UOptiXLaserComponent::SetLaserWidth(float Width)
-{
-	LaserWidth = Width;
-	bUpdateQueued.AtomicSet(true);
-}
-
-float UOptiXLaserComponent::GetLaserWidth() const
-{
-	return LaserWidth;
-}
-
-void UOptiXLaserComponent::SetLaserPattern(EPatternTypes Pattern)
-{
-
-	/*
-	The original way of setting up the buffer and pattern seems a bit wasteful, as the whole 50 * 50 * 20 buffer gets allocated,
-	even tho only a very tiny amount of rays actually get cast. For now, keep it that way on the optix side, but actually save the 
-	number of rays and their index here, so we don't have to copy and draw the whole result buffer. 
-	*/
-
-	UE_LOG(LogTemp, Display, TEXT("OptiX Laser Component Queuing Laser Pattern Change"));
-
-	CurrentLaserPattern = Pattern;
-
-	// Update the base indices first so that the game thread can directly create the insanced lines instead of having to wait for the render thread
-	// The actual positions will get updated when the render thread catches up.
-	
-	bUpdateQueued.AtomicSet(true);
-	bPatternChanged.AtomicSet(true);
-}
-
-void UOptiXLaserComponent::PreparePatternChange(EPatternTypes Pattern)
-{
-	UE_LOG(LogTemp, Display, TEXT("OptiX Laser Component Preparing Laser Pattern Change"));
-
-	if (Patterns[Pattern]->PlatformData->Mips.Num() != 0)
-	{
-
-		LaserIndices.Empty();
-		LaserIndexColorMap.Empty();
-
-		FTexture2DMipMap& IndexMip = Patterns[Pattern]->PlatformData->Mips[0];
-		UE_LOG(LogTemp, Display, TEXT("Got Texture mips"));
-		FColor* TextureData = static_cast<FColor*>(IndexMip.BulkData.Lock(LOCK_READ_WRITE));
-
-		int X = Patterns[Pattern]->GetSizeX();
-		int Y = Patterns[Pattern]->GetSizeY();
-
-		for (int32 i = 0; i < X; ++i) {
-			for (int32 j = 0; j < Y; ++j) {
-
-				int32 TextureIndex = (X * Y - 1) - i * X - j;
-				int32 BufferIndex = ((j)*(X)+i);
-
-				if (TextureData[TextureIndex].R || TextureData[TextureIndex].G || TextureData[TextureIndex].B)
-				{
-					LaserIndices.Add(BufferIndex);
-					LaserIndexColorMap.Add(TextureData[TextureIndex]);
-				}
-			}
-		}
-		IndexMip.BulkData.Unlock();
-	}
-}
-
-EPatternTypes UOptiXLaserComponent::GetLaserPattern() const
-{
-	return CurrentLaserPattern;
-}
-
-
-void UOptiXLaserComponent::UpdateLaserPosition()
-{
-	//UE_LOG(LogTemp, Warning, TEXT("OptiX Laser Component Updating Position"));
-	bUpdateQueued.AtomicSet(true);
-}
-
+// Fill out your copyright notice in the Description page of Project Settings.
+
+#include "OptiXLaserComponent.h"
+
+#include "UObject/ConstructorHelpers.h"
+
+#include "OptiXModule.h"
+#include "StatsDefines.h"
+
+
+// Sets default values for this component's properties
+UOptiXLaserComponent::UOptiXLaserComponent()
+{
+	// Set this component to be initialized when the game starts, and to be ticked every frame.  You can turn these features
+	// off to improve performance if you don't need them.
+	PrimaryComponentTick.bCanEverTick = false; 
+	bWantsOnUpdateTransform = false; // why the hell do I need this here but not on the others?
+
+	// ...
+
+	LaserMaxDepth = 20;
+	LaserEntryPoint = 1; // Default, will be overwritten anyway
+
+	LaserBufferWidth = 50 * 50;
+	LaserBufferHeight = LaserMaxDepth * 2;
+
+	LaserBufferSize = LaserBufferHeight * LaserBufferWidth;
+
+
+	RayTIR = false;
+	TargetBufferWrite = 1; //todo
+	TargetColorMode = 0; // todo
+	Wavelength = 450.0f;
+	LaserWidth = 0.025f;
+	CurrentLaserPattern = EPatternTypes::POINTER;
+	LaserTracesPerFrame = 20;
+
+	// Find and load default patterns:
+
+	static ConstructorHelpers::FObjectFinder<UTexture2D> CrossTexture(TEXT("Texture2D'/OptiX/Laser/Cross.Cross'"));
+	static ConstructorHelpers::FObjectFinder<UTexture2D> CrossTextureDir(TEXT("Texture2D'/OptiX/Laser/Cross_dir.Cross_dir'"));
+	static ConstructorHelpers::FObjectFinder<UTexture2D> PointerTexture(TEXT("Texture2D'/OptiX/Laser/Pointer.Pointer'"));
+	static ConstructorHelpers::FObjectFinder<UTexture2D> PointerTextureDir(TEXT("Texture2D'/OptiX/Laser/Pointer_dir.Pointer_dir'"));
+	static ConstructorHelpers::FObjectFinder<UTexture2D> CircleTexture(TEXT("Texture2D'/OptiX/Laser/Circle.Circle'"));
+	static ConstructorHelpers::FObjectFinder<UTexture2D> CircleTextureDir(TEXT("Texture2D'/OptiX/Laser/Circle_dir.Circle_dir'"));
+	static ConstructorHelpers::FObjectFinder<UTexture2D> QuadTexture(TEXT("Texture2D'/OptiX/Laser/Quad.Quad'"));
+	static ConstructorHelpers::FObjectFinder<UTexture2D> QuadTextureDir(TEXT("Texture2D'/OptiX/Laser/Quad_dir.Quad_dir'"));
+
+
+
+	if (CrossTexture.Object != NULL)
+	{
+		Patterns.Add(EPatternTypes::CROSS, CrossTexture.Object);
+		UE_LOG(LogTemp, Display, TEXT("OptiX Laser Component Added Cross Pattern."));
+	}
+	if (CrossTextureDir.Object != NULL)
+	{
+		PatternDirections.Add(EPatternTypes::CROSS, CrossTextureDir.Object);
+		UE_LOG(LogTemp, Display, TEXT("OptiX Laser Component Added Cross Dir Pattern."));
+	}
+	if (PointerTexture.Object != NULL)
+	{
+		Patterns.Add(EPatternTypes::POINTER, PointerTexture.Object);
+		UE_LOG(LogTemp, Display, TEXT("OptiX Laser Component Added Pointer Pattern."));
+	}
+	if (PointerTextureDir.Object != NULL)
+	{
+		PatternDirections.Add(EPatternTypes::POINTER, PointerTextureDir.Object);
+		UE_LOG(LogTemp, Display, TEXT("OptiX Laser Component Added Pointer Dir Pattern."));
+	}	
+	if (CircleTexture.Object != NULL)
+	{
+		Patterns.Add(EPatternTypes::CIRCLE, CircleTexture.Object);
+		UE_LOG(LogTemp, Display, TEXT("OptiX Laser Component Added Circle Pattern."));
+	}	
+	if (CircleTextureDir.Object != NULL)
+	{
+		PatternDirections.Add(EPatternTypes::CIRCLE, CircleTextureDir.Object);
+		UE_LOG(LogTemp, Display, TEXT("OptiX Laser Component Added Circle Dir Pattern."));
+	}
+	if (QuadTexture.Object != NULL)
+	{
+		Patterns.Add(EPatternTypes::QUAD, QuadTexture.Object);
+		UE_LOG(LogTemp, Display, TEXT("OptiX Laser Component Added Quad Pattern."));
+	}
+	if (QuadTextureDir.Object != NULL)
+	{
+		PatternDirections.Add(EPatternTypes::QUAD, QuadTextureDir.Object);
+		UE_LOG(LogTemp, Display, TEXT("OptiX Laser Component Added Quad Dir Pattern."));
+	}	
+
+	// Init the # of rays and their indices
+
+	// This crashes on packaging for some reason, apparently Mips has length 0.
+
+	if (Patterns[CurrentLaserPattern]->PlatformData->Mips.Num() != 0)
+	{
+		FTexture2DMipMap& IndexMip = Patterns[CurrentLaserPattern]->PlatformData->Mips[0];
+
+		UE_LOG(LogTemp, Display, TEXT("Got Texture mips"));
+
+
+		FColor* TextureData = static_cast<FColor*>(IndexMip.BulkData.Lock(LOCK_READ_WRITE));
+
+
+		int X = Patterns[CurrentLaserPattern]->GetSizeX();
+		int Y = Patterns[CurrentLaserPattern]->GetSizeY();
+
+
+		// Save the texture indices for the direction:
+
+		// Texture index conversion is a real pain...
+		for (int32 i = 0; i < X; ++i) {
+			for (int32 j = 0; j < Y; ++j) {
+
+				int32 TextureIndex = (X * Y - 1) - i * X - j;
+				int32 BufferIndex = ((j)*(X)+i);
+
+				if (TextureData[TextureIndex].R || TextureData[TextureIndex].G || TextureData[TextureIndex].B)
+				{
+					LaserIndices.Add(BufferIndex);
+					LaserIndexColorMap.Add(TextureData[TextureIndex]);
+				}
+			}
+		}
+
+		IndexMip.BulkData.Unlock();
+
+		UE_LOG(LogTemp, Display, TEXT("Finished Laser Component texture conversion."));
+	}
+	else
+	{
+		UE_LOG(LogTemp, Warning, TEXT("Texture Mip array is empty in OptiXLaserComponent Constructor. Skipping laser texture reading, hopefully fixed on beginplay()."));
+	}
+}
+
+
+FPrimitiveSceneProxy* UOptiXLaserComponent::CreateSceneProxy()
+{
+	class FLaserComponentSceneProxy final : public FPrimitiveSceneProxy
+	{
+	public:
+		SIZE_T GetTypeHash() const override
+		{
+			static size_t UniquePointer;
+			return reinterpret_cast<size_t>(&UniquePointer);
+		}
+
+		/** Initialization constructor. */
+		FLaserComponentSceneProxy(const UOptiXLaserComponent* InComponent)
+			: FPrimitiveSceneProxy(InComponent)
+		{}
+
+		// FPrimitiveSceneProxy interface.
+
+		virtual void ApplyLateUpdateTransform(const FMatrix& LateUpdateTransform) override
+		{
+			FMatrix CachedTransform = GetLocalToWorld();
+			FPrimitiveSceneProxy::ApplyLateUpdateTransform(LateUpdateTransform);
+			CachedTransform.SetOrigin(GetLocalToWorld().GetOrigin());
+			FTransform UpdatedTransform(CachedTransform.GetMatrixWithoutScale());
+			//UE_LOG(LogTemp, Display, TEXT("Transform on late update: %s"), *UpdatedTransform.ToString());
+			FOptiXModule::Get().GetOptiXContextManager()->LaserPositionLateUpdate_RenderThread(UpdatedTransform);
+		}
+
+		virtual uint32 GetMemoryFootprint(void) const override { return(sizeof(*this) + GetAllocatedSize()); }
+		uint32 GetAllocatedSize(void) const { return(FPrimitiveSceneProxy::GetAllocatedSize()); }
+	};
+
+	return new FLaserComponentSceneProxy(this);
+}
+
+
+// Called when the game starts
+void UOptiXLaserComponent::BeginPlay()
+{
+	Super::BeginPlay();
+	bWantsOnUpdateTransform = true;
+
+	UE_LOG(LogTemp, Display, TEXT("Initializing OptiX Laser"));
+
+	SetLaserPattern(CurrentLaserPattern);
+
+	SetRayTIR(RayTIR);
+	SetTargetBufferWrite(TargetBufferWrite);
+	SetTargetColorMode(TargetColorMode);
+	SetWavelength(Wavelength);
+	SetLaserWidth(LaserWidth);
+
+	FOptiXModule::Get().GetOptiXContextManager()->OnSceneChangedDelegate.Broadcast();
+	//FOptiXModule::Get().GetOptiXContextManager()->bIsInitializedLaser.AtomicSet(true);
+
+	UpdateLaserPosition();
+
+}
+
+void UOptiXLaserComponent::EndPlay(const EEndPlayReason::Type EndPlayReason)
+{
+	Super::EndPlay(EndPlayReason);
+
+	UE_LOG(LogTemp, Warning, TEXT("OptiX Laser Component EndPlay"));
+
+	CleanOptiXObjects();
+}
+
+void UOptiXLaserComponent::CleanOptiXObjects()
+{
+	UE_LOG(LogTemp, Warning, TEXT("OptiX Laser Component Cleaning up")); // TODO
+	FOptiXModule::Get().GetOptiXContextManager()->RequestDestroyOptiXObjects(GetUniqueID());
+}
+
+
+void UOptiXLaserComponent::OnUpdateTransform(EUpdateTransformFlags UpdateTransformFlags, ETeleportType Teleport/* = ETeleportType::None*/)
+{
+	Super::OnUpdateTransform(EUpdateTransformFlags::SkipPhysicsUpdate, Teleport);
+	UpdateLaserPosition();
+}
+
+void UOptiXLaserComponent::SetRayTIR(bool Active)
+{
+	RayTIR = Active;
+	OptiXContextUpdateFunction UpdateFunction =
+		[RayTIR = RayTIR](optix::Context Context)
+	{
+		Context["allowTir"]->setInt(static_cast<int>(RayTIR));
+	};
+
+	FOptiXModule::Get().GetOptiXContextManager()->EnqueueContextUpdateFunction(UpdateFunction);
+}
+
+bool UOptiXLaserComponent::GetRayTIR() const
+{
+	return RayTIR;
+}
+
+void UOptiXLaserComponent::SetTargetBufferWrite(bool Flag)
+{
+	TargetBufferWrite = Flag;
+	OptiXContextUpdateFunction UpdateFunction =
+		[TargetBufferWrite = TargetBufferWrite](optix::Context Context)
+	{
+		Context["targetBufferWrite"]->setInt(static_cast<int>(TargetBufferWrite));
+	};
+
+	FOptiXModule::Get().GetOptiXContextManager()->EnqueueContextUpdateFunction(UpdateFunction);
+}
+
+bool UOptiXLaserComponent::GetTargetBufferWrite() const
+{
+	return TargetBufferWrite;
+}
+
+void UOptiXLaserComponent::SetTargetColorMode(bool Flag)
+{
+	TargetColorMode = Flag;
+	//OptiXContextUpdateFunction UpdateFunction =
+	//	[TargetBufferWrite = TargetBufferWrite](optix::Context Context)
+	//{
+	//	Context["targetBufferWrite"]->setInt(static_cast<int>(TargetBufferWrite));
+	//};
+
+	//FOptiXModule::Get().GetOptiXContextManager()->EnqueueContextUpdateFunction(UpdateFunction);
+}
+
+bool UOptiXLaserComponent::GetTargetColorMode() const
+{
+	return TargetColorMode;
+}
+
+void UOptiXLaserComponent::SetWavelength(float WL)
+{
+	Wavelength = WL;
+	FOptiXModule::Get().GetOptiXContextManager()->BroadcastWavelengthChange(WL);
+	OptiXContextUpdateFunction UpdateFunction =
+		[Wavelength = Wavelength](optix::Context Context)
+	{
+		Context["laserWaveLength"]->setInt(static_cast<int>(Wavelength));
+	};
+
+	FOptiXModule::Get().GetOptiXContextManager()->EnqueueContextUpdateFunction(UpdateFunction);
+}
+
+float UOptiXLaserComponent::GetWavelength() const
+{
+	return Wavelength;
+}
+
+void UOptiXLaserComponent::SetLaserWidth(float Width)
+{
+	LaserWidth = Width;
+	OptiXContextUpdateFunction UpdateFunction =
+		[LaserWidth = LaserWidth](optix::Context Context)
+	{
+		Context["laserBeamWidth"]->setFloat(LaserWidth);
+	};
+	FOptiXModule::Get().GetOptiXContextManager()->EnqueueContextUpdateFunction(UpdateFunction);
+}
+
+float UOptiXLaserComponent::GetLaserWidth() const
+{
+	return LaserWidth;
+}
+
+void UOptiXLaserComponent::SetLaserPattern(EPatternTypes Pattern)
+{
+
+	/*
+	The original way of setting up the buffer and pattern seems a bit wasteful, as the whole 50 * 50 * 20 buffer gets allocated,
+	even tho only a very tiny amount of rays actually get cast. For now, keep it that way on the optix side, but actually save the 
+	number of rays and their index here, so we don't have to copy and draw the whole result buffer. 
+	*/
+
+	UE_LOG(LogTemp, Display, TEXT("OptiX Laser Component Queuing Laser Pattern Change"));
+
+	CurrentLaserPattern = Pattern;
+	UE_LOG(LogTemp, Display, TEXT("New Pattern queued: %i"), static_cast<uint8>(CurrentLaserPattern));
+
+
+	int X = Patterns[CurrentLaserPattern]->GetSizeX();
+	int Y = Patterns[CurrentLaserPattern]->GetSizeY();
+
+	UTexture2D* NewPattern = Patterns[CurrentLaserPattern];
+	UTexture2D* NewDirectionPattern = PatternDirections[CurrentLaserPattern];
+
+	OptiXContextUpdateFunction UpdateFunction =
+		[X, Y, NewPattern, NewDirectionPattern](optix::Context Context)
+	{
+		TRACE_CPUPROFILER_EVENT_SCOPE("UOptiXLaserComponent::LaserPatternUpdate")
+		//UE_LOG(LogTemp, Display, TEXT("Changing to new laser pattern: %i"), static_cast<uint8>(CurrentLaserPattern));
+
+		{
+			optix::Buffer LaserIndexBuffer = Context["laserIndex"]->getBuffer();
+
+			int32* BufferIndexData = static_cast<int32*>(LaserIndexBuffer->map(0, RT_BUFFER_MAP_WRITE));
+			// Reset the buffer explicitly 
+			FMemory::Memset(BufferIndexData, 0u, X * Y * 4);
+
+			FTexture2DMipMap& IndexMip = NewPattern->PlatformData->Mips[0];
+
+			FColor* TextureData = static_cast<FColor*>(IndexMip.BulkData.Lock(LOCK_READ_WRITE));
+
+			TArray<int32> TextureIndices;
+
+			// Texture index conversion is a real pain...
+			for (int32 i = 0; i < X; ++i) {
+				for (int32 j = 0; j < Y; ++j) {
+
+					int32 TextureIndex = (X * Y - 1) - i * X - j;
+					int32 BufferIndex = ((j)*(X)+i);
+
+					BufferIndexData[BufferIndex] = 0;
+
+					if (TextureData[TextureIndex].R || TextureData[TextureIndex].G || TextureData[TextureIndex].B)
+					{
+						BufferIndexData[BufferIndex] = 1;
+						//LaserIndices.Add(BufferIndex);
+						TextureIndices.Add(TextureIndex);
+						//LaserIndexColorMap.Add(BufferIndex, TextureData[TextureIndex]);
+					}
+					else
+					{
+						BufferIndexData[BufferIndex] = -1; // do not cast ray
+					}
+				}
+			}
+
+			UE_LOG(LogTemp, Display, TEXT("# Ray Indices in Pattern %i"), static_cast<uint8>(TextureIndices.Num()));
+
+			IndexMip.BulkData.Unlock();
+			LaserIndexBuffer->unmap();
+		}
+		{
+			optix::Buffer LaserDirectionBuffer = Context["laserDir"]->getBuffer();
+			float* BufferDirectionData = static_cast<float*>(LaserDirectionBuffer->map(0, RT_BUFFER_MAP_WRITE));
+
+			FTexture2DMipMap& DirectionMip = NewDirectionPattern->PlatformData->Mips[0];
+
+			FColor* TextureData = static_cast<FColor*>(DirectionMip.BulkData.Lock(LOCK_READ_WRITE));
+
+			// Texture index conversion is a real pain...
+			for (int32 i = 0; i < X; ++i) {
+				for (int32 j = 0; j < Y; ++j) {
+
+					int32 TextureIndex = (X * Y - 1) - i * X - j;
+					int32 BufferIndex = ((j)*(X)+i) * 3;
+
+					//UE_LOG(LogTemp, Display, TEXT("Values: %i"), TextureData[BufferIndex]);
+
+					FVector DirNormalSpace = FVector();
+					DirNormalSpace.X = (TextureData[TextureIndex].R / 256.0f) * 2.0f - 1.0f;
+					DirNormalSpace.Y = (TextureData[TextureIndex].G / 256.0f) * 2.0f - 1.0f;
+					DirNormalSpace.Z = (TextureData[TextureIndex].B / 256.0f);
+
+					// We need to rotate this to face forward (1, 0, 0):
+
+					FMatrix Mat = FRotationMatrix::MakeFromX(FVector(0, 0, 1));
+					FVector Dir = Mat.TransformVector(DirNormalSpace);
+
+					BufferDirectionData[BufferIndex] = Dir.X;
+					BufferDirectionData[BufferIndex + 1] = Dir.Y;
+					BufferDirectionData[BufferIndex + 2] = Dir.Z;
+
+				}
+			}
+			DirectionMip.BulkData.Unlock();
+			LaserDirectionBuffer->unmap();
+		}
+	};
+	FOptiXModule::Get().GetOptiXContextManager()->EnqueueContextUpdateFunction(UpdateFunction);
+}
+
+void UOptiXLaserComponent::PreparePatternChange(EPatternTypes Pattern)
+{
+	UE_LOG(LogTemp, Display, TEXT("OptiX Laser Component Preparing Laser Pattern Change"));
+
+	if (Patterns[Pattern]->PlatformData->Mips.Num() != 0)
+	{
+
+		LaserIndices.Empty();
+		LaserIndexColorMap.Empty();
+
+		FTexture2DMipMap& IndexMip = Patterns[Pattern]->PlatformData->Mips[0];
+		UE_LOG(LogTemp, Display, TEXT("Got Texture mips"));
+		FColor* TextureData = static_cast<FColor*>(IndexMip.BulkData.Lock(LOCK_READ_WRITE));
+
+		int X = Patterns[Pattern]->GetSizeX();
+		int Y = Patterns[Pattern]->GetSizeY();
+
+		for (int32 i = 0; i < X; ++i) {
+			for (int32 j = 0; j < Y; ++j) {
+
+				int32 TextureIndex = (X * Y - 1) - i * X - j;
+				int32 BufferIndex = ((j)*(X)+i);
+
+				if (TextureData[TextureIndex].R || TextureData[TextureIndex].G || TextureData[TextureIndex].B)
+				{
+					LaserIndices.Add(BufferIndex);
+					LaserIndexColorMap.Add(TextureData[TextureIndex]);
+				}
+			}
+		}
+		IndexMip.BulkData.Unlock();
+	}
+}
+
+EPatternTypes UOptiXLaserComponent::GetLaserPattern() const
+{
+	return CurrentLaserPattern;
+}
+
+
+void UOptiXLaserComponent::UpdateLaserPosition()
+{
+	//UE_LOG(LogTemp, Warning, TEXT("OptiX Laser Component Updating Position"));
+	FTransform CurrentTransform = GetComponentTransform();
+	FVector Translation = CurrentTransform.GetTranslation();
+	FVector Forward = GetForwardVector();
+	FVector Right = GetRightVector();
+	FVector Up = GetUpVector();
+	FMatrix Rotation = CurrentTransform.ToMatrixNoScale();
+
+	//UE_LOG(LogTemp, Display, TEXT("Transform on update: %s"), *GetComponentTransform().ToString());
+
+
+	// Hard code this for now: laser is around 10x10x10 cube
+	   	  
+	OptiXContextUpdateFunction UpdateFunction =
+		[Translation, Forward, Right, Up, Rotation](optix::Context Context)
+	{
+		Context["laser_origin"]->setFloat(Translation.X, Translation.Y, Translation.Z);
+		Context["laser_forward"]->setFloat(Forward.X, Forward.Y, Forward.Z);
+		Context["laser_right"]->setFloat(Right.X, Right.Y, Right.Z);
+		Context["laser_up"]->setFloat(Up.X, Up.Y, Up.Z);
+
+		Context["laser_rot"]->setMatrix4x4fv(true, &Rotation.M[0][0]);		
+	};
+	FOptiXModule::Get().GetOptiXContextManager()->EnqueueContextUpdateFunction(UpdateFunction);
+
+
+	FOptiXModule::Get().GetOptiXContextManager()->OnSceneChangedDelegate.Broadcast();
+}
+
diff --git a/Source/OptiX/Private/OptiXLaserDetectorActor.cpp b/Source/OptiX/Private/OptiXLaserDetectorActor.cpp
index 75bbc9a556c27c15cfd639af7c2464493e610b8d..7ead3802300c4f92579780bb92d02fc7a00fa35a 100644
--- a/Source/OptiX/Private/OptiXLaserDetectorActor.cpp
+++ b/Source/OptiX/Private/OptiXLaserDetectorActor.cpp
@@ -1,178 +1,226 @@
-// Fill out your copyright notice in the Description page of Project Settings.
-
-#include "OptiXLaserDetectorActor.h"
-
-
-#include "UObject/ConstructorHelpers.h"
-#include "Runtime/Engine/Classes/Components/StaticMeshComponent.h"
-#include "Runtime/Engine/Classes/Engine/StaticMesh.h"
-#include "Runtime/Engine/Classes/Materials/MaterialInstanceDynamic.h"
-#include "Runtime/Engine/Classes/Kismet/GameplayStatics.h"
-
-#include "OptiXModule.h"
-#include "OptiXLaserActor.h"
-#include "StatsDefines.h"
-
-AOptiXLaserDetectorActor::AOptiXLaserDetectorActor(const FObjectInitializer& ObjectInitializer)
-	: Super(ObjectInitializer)
-{
-	UE_LOG(LogTemp, Display, TEXT("OptiX Laser Detector Actor Constructor"));
-
-	PrimaryActorTick.bCanEverTick = true;
-	bIsEnabled = true;
-
-	static ConstructorHelpers::FObjectFinder<UStaticMesh>MeshAsset(TEXT("StaticMesh'/OptiX/Targets/target.target'"));
-	UStaticMesh* Asset = MeshAsset.Object;
-
-	GetStaticMeshComponent()->SetStaticMesh(Asset);
-	//SetActorEnableCollision(false);
-
-	OptiXLaserTargetComponent = CreateDefaultSubobject<UOptiXLaserTargetComponent>(TEXT("LaserTargetComponent"));
-	OptiXLaserTargetComponent->SetupAttachment(GetStaticMeshComponent());
-
-	HighlightColor = FColor(255, 255, 255);
-
-}
-
-void AOptiXLaserDetectorActor::BeginPlay()
-{
-	Super::BeginPlay();
-	Init();
-}
-
-void AOptiXLaserDetectorActor::EndPlay(const EEndPlayReason::Type EndPlayReason)
-{
-	Super::EndPlay(EndPlayReason);
-	// Might need to remove the delegate thingy here?
-}
-
-void AOptiXLaserDetectorActor::Tick(float DeltaTime)
-{
-	TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("AOptiXLaserDetectorActor::Tick"))
-
-	Super::Tick(DeltaTime);
-	//OnLaserTraceFinished();
-}
-
-void AOptiXLaserDetectorActor::Init()
-{
-	// Subscribe to the laser actor:
-	TArray<AActor*> FoundLaserActors;
-	UGameplayStatics::GetAllActorsOfClass(GetWorld(), AOptiXLaserActor::StaticClass(), FoundLaserActors);
-	
-	//FOptiXModule::Get().GetOptiXContextManager()->LaserTraceFinishedEvent.AddUFunction(this, "OnLaserTraceFinished");
-
-	// Setup DIM
-
-	DynamicScreenMaterial = UMaterialInstanceDynamic::Create(GetStaticMeshComponent()->GetMaterial(1), this);
-	GetStaticMeshComponent()->SetMaterial(1, DynamicScreenMaterial);
-
-	// Set up the texture
-
-	int32 Size = static_cast<int32>(OptiXLaserTargetComponent->TargetRes);
-
-	DetectorResultTexture = UTexture2D::CreateTransient(Size, Size, PF_R32_FLOAT);
-	//OutputTexture->AddToRoot();
-	//// Allocate the texture HRI
-	DetectorResultTexture->UpdateResource();
-
-
-	TextureRegion = MakeUnique<FUpdateTextureRegion2D>();
-	TextureRegion->Height = Size;
-	TextureRegion->Width = Size;
-	TextureRegion->SrcX = 0;
-	TextureRegion->SrcY = 0;
-	TextureRegion->DestX = 0;
-	TextureRegion->DestY = 0;
-
-	FOptiXModule::Get().GetOptiXContextManager()->OnSceneChangedDelegate.Broadcast();
-
-}
-
-void AOptiXLaserDetectorActor::OnLaserTraceFinished()
-{
-	//UE_LOG(LogTemp, Warning, TEXT("lasertracefinished"));
-	TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("AOptiXLaserDetectorActor::OnLaserTraceFinished"))
-
-	if (bIsEnabled)
-	{
-		//OptiXLaserTargetComponent->UpdateBufferData();
-		RenderDataToTarget();
-	}
-}
-
-void AOptiXLaserDetectorActor::RenderDataToTarget()
-{		
-	TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("AOptiXLaserDetectorActor::RenderDataToTarget"))
-
-	// Let's try something else:
-
-	if (OptiXLaserTargetComponent->OptiXContext == nullptr)
-	{
-		return;
-	}
-
-	int32 Size = static_cast<int32>(OptiXLaserTargetComponent->TargetRes);
-
-	Max = OptiXLaserTargetComponent->GetMaxFromBuffer();
-
-	float* Data = static_cast<float*>(OptiXLaserTargetComponent->TargetBuffer->MapNative(0, RT_BUFFER_MAP_READ));
-	DetectorResultTexture->UpdateTextureRegions(0, 1, TextureRegion.Get(), Size * 4, 4, (uint8*)Data);
-	OptiXLaserTargetComponent->TargetBuffer->Unmap();
-
-	if (DynamicScreenMaterial != nullptr)
-	{
-		DynamicScreenMaterial->SetScalarParameterValue("ColorMode", bIsColorMode ? 1.0f : 0.0f);
-		DynamicScreenMaterial->SetVectorParameterValue("ColorMode", HighlightColor);
-		DynamicScreenMaterial->SetTextureParameterValue("ResultTexture", DetectorResultTexture);
-		DynamicScreenMaterial->SetScalarParameterValue("ResultMax", Max);
-	}
-
-	//int32 Size = static_cast<int32>(OptiXLaserTargetComponent->TargetRes);
-	//DetectorResultTexture->UpdateTextureRegions(0, 1, TextureRegion.Get(), Size * 4, 4, (uint8*)OptiXLaserTargetComponent->ColorData.GetData());
-
-	//if (DynamicScreenMaterial != nullptr)
-	//{
-	//	DynamicScreenMaterial->SetTextureParameterValue("Texture", DetectorResultTexture);
-	//}
-
-}
-
-void AOptiXLaserDetectorActor::Clear()
-{
-	TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("AOptiXLaserDetectorActor::Clear"))
-
-	uint32 Size = static_cast<int32>(OptiXLaserTargetComponent->TargetRes);
-
-	TArray<FColor> Black;
-	Black.AddZeroed(Size * Size);
-
-	DetectorResultTexture->UpdateTextureRegions(0, 1, TextureRegion.Get(), Size * 4, 4, (uint8*)Black.GetData());
-
-	if (DynamicScreenMaterial != nullptr)
-	{
-		DynamicScreenMaterial->SetTextureParameterValue("ResultTexture", DetectorResultTexture);
-		DynamicScreenMaterial->SetScalarParameterValue("ResultMax", 0);
-	}
-
-	float* Data = static_cast<float*>(OptiXLaserTargetComponent->TargetBuffer->MapNative(0, RT_BUFFER_MAP_WRITE));
-	FMemory::Memset(Data, 0u, Size * Size * 4);
-	OptiXLaserTargetComponent->TargetBuffer->Unmap();
-
-}
-
-void AOptiXLaserDetectorActor::Save()
-{
-	// Hope this makes a copy - it doesn't
-	UTexture2D* NewTexture = UTexture2D::CreateTransient(DetectorResultTexture->GetSizeX(), DetectorResultTexture->GetSizeY(), DetectorResultTexture->GetPixelFormat());
-	NewTexture->UpdateResource();
-	
-	int32 Size = static_cast<int32>(OptiXLaserTargetComponent->TargetRes);
-	//Max = OptiXLaserTargetComponent->GetMaxFromBuffer();
-
-	float* Data = static_cast<float*>(OptiXLaserTargetComponent->TargetBuffer->MapNative(0, RT_BUFFER_MAP_READ));
-	NewTexture->UpdateTextureRegions(0, 1, TextureRegion.Get(), Size * 4, 4, (uint8*)Data);
-	OptiXLaserTargetComponent->TargetBuffer->Unmap();
-
-	SavedDetectorTextures.Add(NewTexture);
-}
+// Fill out your copyright notice in the Description page of Project Settings.
+
+#include "OptiXLaserDetectorActor.h"
+
+
+#include "UObject/ConstructorHelpers.h"
+#include "Runtime/Engine/Classes/Components/StaticMeshComponent.h"
+#include "Runtime/Engine/Classes/Engine/StaticMesh.h"
+#include "Runtime/Engine/Classes/Materials/MaterialInstanceDynamic.h"
+#include "Runtime/Engine/Classes/Kismet/GameplayStatics.h"
+
+#include "OptiXModule.h"
+#include "OptiXLaserActor.h"
+#include "StatsDefines.h"
+
+#include "Materials/MaterialInstance.h"
+
+
+AOptiXLaserDetectorActor::AOptiXLaserDetectorActor(const FObjectInitializer& ObjectInitializer)
+	: Super(ObjectInitializer)
+{
+	UE_LOG(LogTemp, Display, TEXT("OptiX Laser Detector Actor Constructor"));
+
+	PrimaryActorTick.bCanEverTick = true;
+	bIsEnabled = true;
+
+	static ConstructorHelpers::FObjectFinder<UStaticMesh>MeshAsset(TEXT("StaticMesh'/OptiX/Targets/target.target'"));
+	UStaticMesh* Asset = MeshAsset.Object;
+
+	GetStaticMeshComponent()->SetStaticMesh(Asset);
+	//SetActorEnableCollision(false);
+
+	OptiXLaserTargetComponent = CreateDefaultSubobject<UOptiXLaserTargetComponent>(TEXT("LaserTargetComponent"));
+	OptiXLaserTargetComponent->SetupAttachment(GetStaticMeshComponent());
+
+	HighlightColor = FColor(255, 255, 255);
+
+}
+
+void AOptiXLaserDetectorActor::BeginPlay()
+{
+	Super::BeginPlay();
+	Init();
+}
+
+void AOptiXLaserDetectorActor::EndPlay(const EEndPlayReason::Type EndPlayReason)
+{
+	Super::EndPlay(EndPlayReason);
+	// Might need to remove the delegate thingy here?
+}
+
+void AOptiXLaserDetectorActor::Tick(float DeltaTime)
+{
+	TRACE_CPUPROFILER_EVENT_SCOPE("AOptiXLaserDetectorActor::Tick")
+
+	Super::Tick(DeltaTime);
+	//OnLaserTraceFinished(); // todo
+}
+
+void AOptiXLaserDetectorActor::Init()
+{
+	int32 Size = static_cast<int32>(OptiXLaserTargetComponent->TargetRes);
+
+
+	TextureRegion = MakeUnique<FUpdateTextureRegion2D>();
+	TextureRegion->Height = Size;
+	TextureRegion->Width = Size;
+	TextureRegion->SrcX = 0;
+	TextureRegion->SrcY = 0;
+	TextureRegion->DestX = 0;
+	TextureRegion->DestY = 0;
+
+
+	// Subscribe to the laser actor:
+	TArray<AActor*> FoundLaserActors;
+	UGameplayStatics::GetAllActorsOfClass(GetWorld(), AOptiXLaserActor::StaticClass(), FoundLaserActors);
+	
+	//FOptiXModule::Get().GetOptiXContextManager()->LaserTraceFinishedEvent.AddUFunction(this, "OnLaserTraceFinished");
+
+	// Setup DIM
+
+	DynamicScreenMaterial = UMaterialInstanceDynamic::Create(GetStaticMeshComponent()->GetMaterial(1), this);
+	GetStaticMeshComponent()->SetMaterial(1, DynamicScreenMaterial);
+
+	// Set up the texture
+
+
+	DetectorResultTexture = UTexture2D::CreateTransient(Size, Size, PF_R32_FLOAT);
+	//OutputTexture->AddToRoot();
+	//// Allocate the texture HRI
+	DetectorResultTexture->UpdateResource();
+
+	LaserTraceFinishedCallback Callback =
+		[&MaxRef =Max, &bIsColorMode = bIsColorMode, &HighlightColor = HighlightColor, TargetRes = Size, &DynamicScreenMaterial = DynamicScreenMaterial, TextureRegion = TextureRegion.Get(), DetectorResultTexture = DetectorResultTexture]
+	(FOptiXObjectData* Data, TMap<FString, optix::Buffer>* Buffers, optix::TextureSampler TextureSampler, FRHICommandListImmediate& RHICmdList)
+	{
+		TRACE_CPUPROFILER_EVENT_SCOPE("AOptiXLaserDetectorActor::LaserTraceFinishedCallback")
+
+			// Get Max
+		float Max;
+		{
+			TRACE_CPUPROFILER_EVENT_SCOPE("AOptiXLaserDetectorActor::LaserTraceFinishedCallback::GetMax")
+
+			optix::Buffer BufferMax = *Buffers->Find("target_buffer_max");
+			Max = (float)*static_cast<unsigned int*>(BufferMax->map(0, RT_BUFFER_MAP_READ));
+			BufferMax->unmap();
+			if (Max == 0)
+			{
+				Max = 1; // TODO WHY?
+			}
+		}
+		MaxRef = Max;
+		FTexture2DRHIRef TextureRef = ((FTexture2DResource*)DetectorResultTexture->Resource)->GetTexture2DRHI();
+
+		{
+			TRACE_CPUPROFILER_EVENT_SCOPE("AOptiXLaserDetectorActor::LaserTraceFinishedCallback::GetTargetBuffer")
+
+			optix::Buffer Buffer = *Buffers->Find("target_buffer");
+			float* DataPtr = static_cast<float*>(Buffer->map(0, RT_BUFFER_MAP_READ));
+			//DetectorResultTexture->UpdateTextureRegions(0, 1, TextureRegion, TargetRes * 4, 4, (uint8*)DataPtr);
+			{
+				TRACE_CPUPROFILER_EVENT_SCOPE("AOptiXLaserDetectorActor::LaserTraceFinishedCallback::GetTargetBuffer::UpdateTexture2D")
+
+				RHICmdList.UpdateTexture2D(TextureRef, 0, *TextureRegion, TargetRes * 4, (uint8*)DataPtr);
+			}
+			Buffer->unmap();
+		}
+		// todo
+		//DynamicScreenMaterial->Resource->RenderThread_UpdateParameter()
+
+		if (DynamicScreenMaterial != nullptr)
+		{
+			TRACE_CPUPROFILER_EVENT_SCOPE("AOptiXLaserDetectorActor::LaserTraceFinishedCallback::UpdateMaterial")
+
+			DynamicScreenMaterial->SetScalarParameterValue("ColorMode", bIsColorMode ? 1.0f : 0.0f);
+			DynamicScreenMaterial->SetVectorParameterValue("ColorMode", HighlightColor);
+			DynamicScreenMaterial->SetTextureParameterValue("ResultTexture", DetectorResultTexture);
+			DynamicScreenMaterial->SetScalarParameterValue("ResultMax", Max);
+		}
+	};
+	FOptiXModule::Get().GetOptiXContextManager()->RegisterLaserTraceCallback(OptiXLaserTargetComponent->GetUniqueID(), Callback);
+	//FOptiXModule::Get().GetOptiXContextManager()->OnSceneChangedDelegate.Broadcast();
+}
+
+void AOptiXLaserDetectorActor::OnLaserTraceFinished()
+{
+	//UE_LOG(LogTemp, Warning, TEXT("lasertracefinished"));
+	TRACE_CPUPROFILER_EVENT_SCOPE("AOptiXLaserDetectorActor::OnLaserTraceFinished")
+
+	if (bIsEnabled)
+	{
+		//OptiXLaserTargetComponent->UpdateBufferData();
+		RenderDataToTarget();
+	}
+}
+
+void AOptiXLaserDetectorActor::RenderDataToTarget()
+{		
+	TRACE_CPUPROFILER_EVENT_SCOPE("AOptiXLaserDetectorActor::RenderDataToTarget")
+			   
+	//int32 Size = static_cast<int32>(OptiXLaserTargetComponent->TargetRes);
+
+	//Max = OptiXLaserTargetComponent->GetMaxFromBuffer();
+
+	//float* Data = static_cast<float*>(OptiXLaserTargetComponent->TargetBuffer->MapNative(0, RT_BUFFER_MAP_READ));
+	//DetectorResultTexture->UpdateTextureRegions(0, 1, TextureRegion.Get(), Size * 4, 4, (uint8*)Data);
+	//OptiXLaserTargetComponent->TargetBuffer->Unmap();
+
+
+
+	//int32 Size = static_cast<int32>(OptiXLaserTargetComponent->TargetRes);
+	//DetectorResultTexture->UpdateTextureRegions(0, 1, TextureRegion.Get(), Size * 4, 4, (uint8*)OptiXLaserTargetComponent->ColorData.GetData());
+
+	//if (DynamicScreenMaterial != nullptr)
+	//{
+	//	DynamicScreenMaterial->SetTextureParameterValue("Texture", DetectorResultTexture);
+	//}
+
+	//if (DynamicScreenMaterial != nullptr)
+	//{
+	//	DynamicScreenMaterial->SetScalarParameterValue("ColorMode", bIsColorMode ? 1.0f : 0.0f);
+	//	DynamicScreenMaterial->SetVectorParameterValue("ColorMode", HighlightColor);
+	//}
+
+
+
+
+	//FOptiXModule::Get().GetOptiXContextManager()->EnqueueUpdateFunctionRHI(OptiXLaserTargetComponent->GetUniqueID(), UpdateFunction);
+
+}
+
+void AOptiXLaserDetectorActor::Clear()
+{
+	TRACE_CPUPROFILER_EVENT_SCOPE("AOptiXLaserDetectorActor::Clear")
+
+	//uint32 Size = static_cast<int32>(OptiXLaserTargetComponent->TargetRes);
+
+	//TArray<FColor> Black;
+	//Black.AddZeroed(Size * Size);
+
+	//DetectorResultTexture->UpdateTextureRegions(0, 1, TextureRegion.Get(), Size * 4, 4, (uint8*)Black.GetData());
+
+	//if (DynamicScreenMaterial != nullptr)
+	//{
+	//	DynamicScreenMaterial->SetTextureParameterValue("ResultTexture", DetectorResultTexture);
+	//	DynamicScreenMaterial->SetScalarParameterValue("ResultMax", 0);
+	//}
+
+	OptiXLaserTargetComponent->ClearOptiXBuffer();
+}
+
+void AOptiXLaserDetectorActor::Save()
+{
+	//// Hope this makes a copy - it doesn't
+	//UTexture2D* NewTexture = UTexture2D::CreateTransient(DetectorResultTexture->GetSizeX(), DetectorResultTexture->GetSizeY(), DetectorResultTexture->GetPixelFormat());
+	//NewTexture->UpdateResource();
+	//
+	//int32 Size = static_cast<int32>(OptiXLaserTargetComponent->TargetRes);
+	////Max = OptiXLaserTargetComponent->GetMaxFromBuffer();
+
+	//float* Data = static_cast<float*>(OptiXLaserTargetComponent->TargetBuffer->MapNative(0, RT_BUFFER_MAP_READ));
+	//NewTexture->UpdateTextureRegions(0, 1, TextureRegion.Get(), Size * 4, 4, (uint8*)Data);
+	//OptiXLaserTargetComponent->TargetBuffer->Unmap();
+
+	//SavedDetectorTextures.Add(NewTexture);
+}
diff --git a/Source/OptiX/Private/OptiXLaserTargetComponent.cpp b/Source/OptiX/Private/OptiXLaserTargetComponent.cpp
index fa1780cac9c086b14f658e4899649595af6b2e66..52570adc4c508a39ad405c5f1865a292320e6d31 100644
--- a/Source/OptiX/Private/OptiXLaserTargetComponent.cpp
+++ b/Source/OptiX/Private/OptiXLaserTargetComponent.cpp
@@ -1,210 +1,174 @@
-// Fill out your copyright notice in the Description page of Project Settings.
-
-#include "OptiXLaserTargetComponent.h"
-
-#include "OptiXModule.h"
-
-#include "UObject/ConstructorHelpers.h"
-#include "Runtime/Engine/Classes/Components/StaticMeshComponent.h"
-#include "Runtime/Engine/Classes/Engine/StaticMesh.h"
-#include "Runtime/Engine/Classes/Materials/MaterialInstanceDynamic.h"
-#include "StatsDefines.h"
-
-
-UOptiXLaserTargetComponent::UOptiXLaserTargetComponent(const FObjectInitializer& ObjectInitializer)
-	: Super(ObjectInitializer)
-{
-	UE_LOG(LogTemp, Display, TEXT("OptiX Laser Target Component Constructor"));
-
-	TargetRes = 512;
-	bIsColorMode = true;
-	HighlightColor = FLinearColor(1.0f, 0.0f, 0.0f).ToFColor(false);
-
-	ColorLUT.SetNumZeroed(256);
-	ColorData.SetNumZeroed(512*512);
-	
-	static ConstructorHelpers::FObjectFinder<UTexture2D> LT(TEXT("Texture2D'/OptiX/Targets/Target_LUT.Target_LUT'"));
-	if (LT.Object != NULL)
-	{
-		UE_LOG(LogTemp, Display, TEXT("OptiX Laser Target Component: Initialized LUT Texture"));
-
-		LUTTexture = LT.Object;
-	}
-	else
-	{
-		UE_LOG(LogTemp, Error, TEXT("OptiX Laser Target Component Constructor: LUT TEXTURE ASSET NOT FOUND"));
-	}
-
-}
-
-void UOptiXLaserTargetComponent::UpdateOptiXComponentVariables()
-{
-}
-
-void UOptiXLaserTargetComponent::UpdateOptiXComponent()
-{
-	if (OptiXGeometry != nullptr && OptiXTransform != nullptr && OptiXAcceleration != nullptr)
-	{
-		FMatrix T = GetComponentToWorld().ToMatrixNoScale();
-		OptiXTransform->SetMatrix(T);
-		//OptiXAcceleration->MarkDirty();
-		OptiXContext->GetGroup("top_object")->GetAcceleration()->MarkDirty();
-		FOptiXModule::Get().GetOptiXContextManager()->OnSceneChangedDelegate.Broadcast();
-	}
-}
-
-void UOptiXLaserTargetComponent::InitOptiXGeometry()
-{
-	OptiXGeometry = OptiXContext->CreateGeometry();
-	OptiXGeometry->SetPrimitiveCount(1u);
-	UOptiXProgram* BB = OptiXContext->CreateProgramFromPTXFile(OptiXPTXDir + "generated/laser_target.ptx", "bounds");
-	UOptiXProgram* IP = OptiXContext->CreateProgramFromPTXFile(OptiXPTXDir + "generated/laser_target.ptx", "intersect");
-
-	OptiXGeometry->SetBoundingBoxProgram(BB);
-	OptiXGeometry->SetIntersectionProgram(IP);
-}
-
-void UOptiXLaserTargetComponent::InitOptiXMaterial()
-{
-	UOptiXProgram* AHPerspective = OptiXContext->CreateProgramFromPTXFile(OptiXPTXDir + "generated/laser_target_material.ptx", "any_hit_radiance");
-	UOptiXProgram* CHIterative = OptiXContext->CreateProgramFromPTXFile(OptiXPTXDir + "generated/laser_target_material.ptx", "closest_hit_iterative");
-
-	OptiXMaterial = OptiXContext->CreateMaterial();
-	OptiXMaterial->SetAnyHitProgram(0, AHPerspective);
-	OptiXMaterial->SetClosestHitProgram(1, CHIterative);
-}
-
-void UOptiXLaserTargetComponent::InitOptiXGroups()
-{
-	// Buffers:
-
-	TargetBuffer = OptiXContext->CreateBuffer(RT_BUFFER_INPUT_OUTPUT, RT_FORMAT_FLOAT, TargetRes, TargetRes);
-	TargetBufferMax = OptiXContext->CreateBuffer(RT_BUFFER_INPUT_OUTPUT, RT_FORMAT_UNSIGNED_INT, 1);
-
-	// Clear target buffers?
-
-	// Color lookup table here
-
-
-	OptiXGeometryInstance = OptiXContext->CreateGeometryInstance(OptiXGeometry, OptiXMaterial);
-	//OptiXAcceleration->SetProperty("refit", "1");
-
-
-
-	FVector P1 = FVector(2.89f, 0.0f, 0.0f); // TODO WHAT IS THIS THING
-
-	FVector P2 = FVector(-0.129f, 0.0f, 0.08f) * 1; // TODO WHAT IS THIS THING
-
-	OptiXGeometryInstance->SetFloat3DVector("p1", P1 * 1.0f); // Detector
-	OptiXGeometryInstance->SetFloat3DVector("p2", P2 * 1000); 
-
-	OptiXGeometryInstance->SetFloat2D("stretchXY1", 0.05f * 100.0f, 0.05f * 100.0f); // Detector
-	OptiXGeometryInstance->SetFloat2D("stretchXZ2", 0.05f * 10.0f, 0.05f * 10.0f); // Corresponds to P2
-
-	//OptiXGeometryInstance->SetInt("targetBufferWrite", 1);
-
-	OptiXGeometryInstance->SetBuffer("targetBuffer", TargetBuffer);
-	OptiXGeometryInstance->SetBuffer("targetBufferMax", TargetBufferMax);
-
-	OptiXGeometryInstance->SetFloat2D("targetBufferDim", TargetRes, TargetRes);
-
-	OptiXTransform = OptiXContext->CreateTransform();
-
-	FMatrix WorldTransform = GetComponentToWorld().ToMatrixNoScale();
-	OptiXTransform->SetMatrix(WorldTransform);
-
-	OptiXGeometryGroup = OptiXContext->CreateGeometryGroup();
-	OptiXGeometryGroup->AddChild(OptiXGeometryInstance);
-
-	OptiXAcceleration = OptiXContext->CreateAcceleration("NoAccel"); // Seems to be faster for now
-	OptiXGeometryGroup->SetAcceleration(OptiXAcceleration);
-	OptiXTransform->SetChild(OptiXGeometryGroup);
-
-	OptiXContext->GetGroup("top_object")->AddChild(OptiXTransform);
-	//FMatrix T = GetComponentToWorld().ToMatrixNoScale();
-	//OptiXTransform->SetMatrix(T);
-
-	OptiXContext->GetGroup("top_object")->GetAcceleration()->MarkDirty();
-
-
-	// Init LUT:
-
-	FTexture2DMipMap& IndexMip = LUTTexture->PlatformData->Mips[0];
-
-	FColor* TextureData = static_cast<FColor*>(IndexMip.BulkData.Lock(LOCK_READ_ONLY));
-
-	for (uint32 i = 0; i < 256; i++)
-	{
-		ColorLUT[i] = TextureData[i];
-	}
-	IndexMip.BulkData.Unlock();
-	UE_LOG(LogTemp, Display, TEXT("Finished filling color LUT for the laser target"));
-
-}
-
-void UOptiXLaserTargetComponent::CleanOptiXComponent()
-{
-	if(OptiXContext->GetGroup("top_object") != NULL)
-		OptiXContext->GetGroup("top_object")->RemoveChild(OptiXTransform);
-
-	OptiXTransform = nullptr;
-	Super::CleanOptiXComponent();
-	OptiXGeometryGroup = nullptr;
-}
-
-float UOptiXLaserTargetComponent::GetMaxFromBuffer()
-{
-	float Max = (float)*static_cast<unsigned int*>(TargetBufferMax->MapNative(0, RT_BUFFER_MAP_READ));
-	TargetBufferMax->Unmap();
-	if (Max == 0)
-	{
-		Max = 1; // TODO WHY?
-	}
-	return Max;
-}
-
-void UOptiXLaserTargetComponent::UpdateBufferData()
-{
-	TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("UOptiXLaserTargetComponent::UpdateBufferData"))
-
-	check(IsInRenderingThread());
-
-	float Max = GetMaxFromBuffer();
-	UE_LOG(LogTemp, Warning, TEXT("UPDATING DEPRECATED BUFFER DATA"));
-
-
-	float* Data = static_cast<float*>(TargetBuffer->MapNative(0, RT_BUFFER_MAP_READ));
-
-	// Just use the previous algorithm for now without thinking too much about it
-	// But honestly doing this on the cpu hurts so much...
-	// TODO: Either
-	// 1) Make optix just output the correct colors directly OR
-	// 2) move the LUT stuff into the actual material...
-
-	float CurrentVal = 0;
-	FColor CurrentColor;
-	bool Tmp = false;
-
-	if (!bIsColorMode)
-	{
-		for (uint32 i = 0; i < TargetRes * TargetRes; i++)
-		{
-			CurrentVal = Data[i] / Max;
-			Tmp = (CurrentVal >= HighlightColorValue);
-			ColorData[i] = (Tmp) ? HighlightColor : FLinearColor(CurrentVal, CurrentVal, CurrentVal).ToFColor(false);
-		}
-	}
-	else
-	{
-		for (uint32 i = 0; i < TargetRes * TargetRes; i++)
-		{
-			CurrentVal = Data[i] / Max;
-
-			CurrentColor = ColorLUT[(int)(255.0f * CurrentVal)]; // Uh oh todo
-			ColorData[i] = CurrentColor;
-		}
-
-	}
-	TargetBuffer->Unmap();
-}
-
+// Fill out your copyright notice in the Description page of Project Settings.
+
+#include "OptiXLaserTargetComponent.h"
+
+#include "OptiXModule.h"
+
+#include "UObject/ConstructorHelpers.h"
+#include "Runtime/Engine/Classes/Components/StaticMeshComponent.h"
+#include "Runtime/Engine/Classes/Engine/StaticMesh.h"
+#include "Runtime/Engine/Classes/Materials/MaterialInstanceDynamic.h"
+#include "StatsDefines.h"
+
+
+UOptiXLaserTargetComponent::UOptiXLaserTargetComponent(const FObjectInitializer& ObjectInitializer)
+	: Super(ObjectInitializer)
+{
+	UE_LOG(LogTemp, Display, TEXT("OptiX Laser Target Component Constructor"));
+
+	TargetRes = 512;
+	bIsColorMode = true;
+	HighlightColor = FLinearColor(1.0f, 0.0f, 0.0f).ToFColor(false);
+
+	ColorLUT.SetNumZeroed(256);
+	ColorData.SetNumZeroed(512*512);
+	
+	static ConstructorHelpers::FObjectFinder<UTexture2D> LT(TEXT("Texture2D'/OptiX/Targets/Target_LUT.Target_LUT'"));
+	if (LT.Object != NULL)
+	{
+		UE_LOG(LogTemp, Display, TEXT("OptiX Laser Target Component: Initialized LUT Texture"));
+
+		LUTTexture = LT.Object;
+	}
+	else
+	{
+		UE_LOG(LogTemp, Error, TEXT("OptiX Laser Target Component Constructor: LUT TEXTURE ASSET NOT FOUND"));
+	}
+
+}
+
+void UOptiXLaserTargetComponent::BeginPlay()
+{
+	Super::BeginPlay();
+
+	FTexture2DMipMap& IndexMip = LUTTexture->PlatformData->Mips[0];
+
+	FColor* TextureData = static_cast<FColor*>(IndexMip.BulkData.Lock(LOCK_READ_ONLY));
+
+	for (uint32 i = 0; i < 256; i++)
+	{
+		ColorLUT[i] = TextureData[i];
+	}
+	IndexMip.BulkData.Unlock();
+	UE_LOG(LogTemp, Display, TEXT("Finished filling color LUT for the laser target"));
+		   
+	FOptiXModule::Get().GetOptiXContextManager()->RequestNewOptiXObject(GetUniqueID(), "laser_target");
+
+	FOptiXBufferData TargetBufferData;
+	TargetBufferData.Name = "target_buffer";
+	TargetBufferData.Type = RT_BUFFER_INPUT_OUTPUT;
+	TargetBufferData.Format = RT_FORMAT_FLOAT;
+	TargetBufferData.BufferWidth = TargetRes;
+	TargetBufferData.BufferHeight = TargetRes;
+
+	FOptiXBufferData TargetBufferMaxData;
+	TargetBufferMaxData.Name = "target_buffer_max";
+	TargetBufferMaxData.Type = RT_BUFFER_INPUT_OUTPUT;
+	TargetBufferMaxData.Format = RT_FORMAT_UNSIGNED_INT;
+	TargetBufferMaxData.BufferWidth = 1;
+
+	FOptiXModule::Get().GetOptiXContextManager()->RequestNewOptiXBuffer(GetUniqueID(), TargetBufferData);
+	FOptiXModule::Get().GetOptiXContextManager()->RequestNewOptiXBuffer(GetUniqueID(), TargetBufferMaxData);
+
+	FMatrix Transform = GetComponentToWorld().ToMatrixNoScale();
+	FMatrix Inverse = Transform.Inverse();
+
+	OptiXObjectInitFunction InitFunction =
+		[Transform, Inverse, &TargetRes = TargetRes]
+	(FOptiXObjectData* Data, TMap<FString, optix::Buffer>* Buffers, optix::TextureSampler TextureSampler)
+	{
+		//FVector P1 = FVector(2.89f, 0.0f, 0.0f);
+		//FVector P2 = FVector(-0.129f, 0.0f, 0.08f) * 1;
+
+		Data->OptiXGeometryInstance["p1"]->setFloat(2.89f, 0.0f, 0.0f); // Detector
+		Data->OptiXGeometryInstance["p2"]->setFloat(-0.129f * 1000, 0.0f * 1000, 0.08f * 1000);
+
+		Data->OptiXGeometryInstance["stretchXY1"]->setFloat(0.05f * 100.0f, 0.05f * 100.0f); // Detector
+		Data->OptiXGeometryInstance["stretchXZ2"]->setFloat(0.05f * 10.0f, 0.05f * 10.0f); // Corresponds to P2
+
+		//OptiXGeometryInstance->SetInt("targetBufferWrite", 1);
+
+		Data->OptiXGeometryInstance["targetBuffer"]->setBuffer(*Buffers->Find("target_buffer"));
+		Data->OptiXGeometryInstance["targetBufferMax"]->setBuffer(*Buffers->Find("target_buffer_max"));
+
+		Data->OptiXGeometryInstance["targetBufferDim"]->setFloat(TargetRes, TargetRes);
+	};
+
+	FOptiXModule::Get().GetOptiXContextManager()->EnqueueInitFunction(GetUniqueID(), InitFunction);
+}
+
+//float UOptiXLaserTargetComponent::GetMaxFromBuffer()
+//{
+//	//check(IsInRenderingThread());
+//
+//
+//	//float Max = (float)*static_cast<unsigned int*>(TargetBufferMax->MapNative(0, RT_BUFFER_MAP_READ));
+//	//TargetBufferMax->Unmap();
+//	//if (Max == 0)
+//	//{
+//	//	Max = 1; // TODO WHY?
+//	//}
+//	//return Max;
+//}
+
+void UOptiXLaserTargetComponent::ClearOptiXBuffer()
+{
+	OptiXObjectUpdateFunction UpdateFunction =
+		[&TargetRes =TargetRes](FOptiXObjectData* Data, TMap<FString, optix::Buffer>* Buffers, optix::TextureSampler TextureSampler)
+	{
+		optix::Buffer Buffer = *Buffers->Find("target_buffer");
+		float* DataPtr = static_cast<float*>(Buffer->map(0, RT_BUFFER_MAP_WRITE));
+		FMemory::Memset(DataPtr, 0u, TargetRes * TargetRes * 4);
+		Buffer->unmap();
+	};
+
+	FOptiXModule::Get().GetOptiXContextManager()->EnqueueUpdateFunction(GetUniqueID(), UpdateFunction);
+}
+
+//void UOptiXLaserTargetComponent::UpdateBufferData()
+//{
+
+
+	//TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("UOptiXLaserTargetComponent::UpdateBufferData"))
+
+	//check(IsInRenderingThread());
+
+	//float Max = GetMaxFromBuffer();
+	//UE_LOG(LogTemp, Warning, TEXT("UPDATING DEPRECATED BUFFER DATA"));
+
+
+	//float* Data = static_cast<float*>(TargetBuffer->MapNative(0, RT_BUFFER_MAP_READ));
+
+	//// Just use the previous algorithm for now without thinking too much about it
+	//// But honestly doing this on the cpu hurts so much...
+	//// TODO: Either
+	//// 1) Make optix just output the correct colors directly OR
+	//// 2) move the LUT stuff into the actual material...
+
+	//float CurrentVal = 0;
+	//FColor CurrentColor;
+	//bool Tmp = false;
+
+	//if (!bIsColorMode)
+	//{
+	//	for (uint32 i = 0; i < TargetRes * TargetRes; i++)
+	//	{
+	//		CurrentVal = Data[i] / Max;
+	//		Tmp = (CurrentVal >= HighlightColorValue);
+	//		ColorData[i] = (Tmp) ? HighlightColor : FLinearColor(CurrentVal, CurrentVal, CurrentVal).ToFColor(false);
+	//	}
+	//}
+	//else
+	//{
+	//	for (uint32 i = 0; i < TargetRes * TargetRes; i++)
+	//	{
+	//		CurrentVal = Data[i] / Max;
+
+	//		CurrentColor = ColorLUT[(int)(255.0f * CurrentVal)]; // Uh oh todo
+	//		ColorData[i] = CurrentColor;
+	//	}
+
+	//}
+	//TargetBuffer->Unmap();
+//}
+
diff --git a/Source/OptiX/Private/OptiXLensComponent.cpp b/Source/OptiX/Private/OptiXLensComponent.cpp
index 68277c3b22019511e2e6d5eed4b077604c42c4e9..761bed7c0e4f840beb611b8510dfa5217e13a7c0 100644
--- a/Source/OptiX/Private/OptiXLensComponent.cpp
+++ b/Source/OptiX/Private/OptiXLensComponent.cpp
@@ -1,483 +1,418 @@
-// Fill out your copyright notice in the Description page of Project Settings.
-
-#include "OptiXLensComponent.h"
-
-#include "Runtime/Engine/Classes/Engine/TextureRenderTargetCube.h"
-
-
-#include "OptiXModule.h"
-#include "StatsDefines.h"
-
-UOptiXLensComponent::UOptiXLensComponent(const FObjectInitializer& ObjectInitializer)
-	: Super(ObjectInitializer)
-{
-	Radius1 = 0.8 * 100; // todo default values
-	Radius2 = 1.0 * 100;
-	LensRadius = 0.1 * 100;
-
-	LensType1 = ELensSideType::CONVEX;
-	LensType2 = ELensSideType::CONVEX;
-	LensThickness = 0.025 * 100;
-	CurrentWavelength = 450.0f;
-
-	// A little hacky but w/e
-	for (const TPair<FString, FGlassDefinition>& Pair : FOptiXModule::Get().GetGlassDefinitions())
-	{
-		GlassType = Pair.Key;
-		break;
-	}
-	
-}
-
-
-void UOptiXLensComponent::BeginPlay()
-{
-	Super::BeginPlay();
-
-
-	// do this on the game thread
-	// hook into WL update:
-	//UE_LOG(LogTemp, Display, TEXT("Begin Play on LensComponent, GameThread"));
-
-	FOptiXModule::Get().GetOptiXContextManager()->WavelengthChangedEvent.AddUFunction(this, "OnWavelengthChangedEvent");
-}
-
-
-void UOptiXLensComponent::UpdateOptiXComponentVariables()
-{
-	TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("UOptiXLensComponent::UpdateOptiXComponentVariables"))
-
-	check(IsInRenderingThread());
-
-
-	OptiXGeometryInstance->SetFloat("radius", Radius1);
-	//UE_LOG(LogTemp, Display, TEXT("radius1 : %f"), Radius1);
-
-	OptiXGeometryInstance->SetFloat("radius2", Radius2);
-	//UE_LOG(LogTemp, Display, TEXT("radius2 : %f"), Radius2);
-
-	OptiXGeometryInstance->SetFloat("lensRadius", LensRadius);
-	//UE_LOG(LogTemp, Display, TEXT("lensradius : %f"), LensRadius);
-
-	OptiXGeometryInstance->SetFloat("halfCylinderLength", GetCylinderLength(LensThickness) / 2.0f);
-	//UE_LOG(LogTemp, Display, TEXT("halfCylinderLength : %f"), GetCylinderLength(LensThickness) / 2.0f);
-
-	OptiXGeometryInstance->SetInt("side1Type", static_cast<int32>(LensType1));
-	//UE_LOG(LogTemp, Display, TEXT("type1 : %i"), static_cast<int32>(LensType1));
-
-	OptiXGeometryInstance->SetInt("side2Type", static_cast<int32>(LensType2));
-	//UE_LOG(LogTemp, Display, TEXT("type2 : %i"), static_cast<int32>(LensType2));
-
-
-	double WL2 = FMath::Pow(CurrentWavelength / 1000.0, 2.0f);
-	FGlassDefinition Def = FOptiXModule::Get().GetGlassDefinitions()[GlassType];
-	//UE_LOG(LogTemp, Display, TEXT("Glass Def: %f, %f, %F"), Def.B.X, Def.B.Y, Def.B.Z);
-
-	float Index = FMath::Sqrt(1 +
-		Def.B.X * WL2 / (WL2 - Def.C.X) +
-		Def.B.Y * WL2 / (WL2 - Def.C.Y) +
-		Def.B.Z * WL2 / (WL2 - Def.C.Z));
-
-	OptiXMaterial->SetFloat("refraction_index", Index);
-
-	MarkDirty();
-}
-
-
-void UOptiXLensComponent::UpdateOptiXComponent()
-{
-	if (OptiXGeometry != nullptr && OptiXTransform != nullptr && OptiXAcceleration != nullptr)
-	{
-		FMatrix T = GetComponentToWorld().ToMatrixNoScale();
-		OptiXTransform->SetMatrix(T);
-		//OptiXAcceleration->MarkDirty();
-		OptiXContext->GetGroup("top_object")->GetAcceleration()->MarkDirty();
-		FOptiXModule::Get().GetOptiXContextManager()->OnSceneChangedDelegate.Broadcast();
-	}
-}
-
-void UOptiXLensComponent::InitOptiXGeometry()
-{
-	OptiXGeometry = OptiXContext->CreateGeometry();
-	OptiXGeometry->SetPrimitiveCount(1u);
-	UOptiXProgram* BB = OptiXContext->CreateProgramFromPTXFile(OptiXPTXDir + "generated/lens_parametric.ptx", "bounds");
-	UOptiXProgram* IP = OptiXContext->CreateProgramFromPTXFile(OptiXPTXDir + "generated/lens_parametric.ptx", "intersect");
-
-	OptiXGeometry->SetBoundingBoxProgram(BB);
-	OptiXGeometry->SetIntersectionProgram(IP);
-}
-
-void UOptiXLensComponent::InitOptiXMaterial()
-{
-	UOptiXProgram* CHPerspective = OptiXContext->CreateProgramFromPTXFile(OptiXPTXDir + "generated/glass_perspective_camera.ptx", "closest_hit_radiance");
-	UOptiXProgram* CHIterative = OptiXContext->CreateProgramFromPTXFile(OptiXPTXDir + "generated/glass_iterative_camera.ptx", "closest_hit_radiance");
-
-	OptiXMaterial = OptiXContext->CreateMaterial();
-	OptiXMaterial->SetClosestHitProgram(0, CHPerspective);
-	OptiXMaterial->SetClosestHitProgram(1, CHIterative);
-
-	OptiXMaterial->SetFloat("importance_cutoff", 1e-2f);
-	OptiXMaterial->SetFloat3D("cutoff_color", 0.035f, 0.102f, 0.169f);
-	OptiXMaterial->SetFloat("fresnel_exponent", 3.0f);
-	OptiXMaterial->SetFloat("fresnel_minimum", 0.1f);
-	OptiXMaterial->SetFloat("fresnel_maximum", 1.0f);
-	OptiXMaterial->SetFloat("refraction_index", 1.4f);
-
-	OptiXMaterial->SetFloat3D("refraction_color", 1.0f, 1.0f, 1.0f);
-	OptiXMaterial->SetFloat3D("reflection_color", 1.0f, 1.0f, 1.0f);
-
-	OptiXMaterial->SetInt("refraction_maxdepth", 10);
-	OptiXMaterial->SetInt("reflection_maxdepth", 5);
-
-	OptiXMaterial->SetFloat3D("extinction_constant", FMath::Loge(0.83f), FMath::Loge(0.83f), FMath::Loge(0.83f));
-
-	OptiXMaterial->SetInt("lens_id", OptiXCubemapId);
-
-}
-
-void UOptiXLensComponent::InitOptiXGroups()
-{
-	OptiXGeometryInstance = OptiXContext->CreateGeometryInstance(OptiXGeometry, OptiXMaterial);
-
-	OptiXGeometryInstance->SetFloat3D("center", 0.0f, 0.0f, 0.0f);
-
-	OptiXGeometryInstance->SetFloat3DVector("orientation", {0, 0, -1}); // TODO Why this vector?!?!
-
-
-	SetRadius1(Radius1);
-	SetRadius2(Radius2);
-	SetLensRadius(LensRadius);
-	SetThickness(LensThickness);
-	SetLensType1(LensType1);
-	SetLensType2(LensType2);
-	SetWavelength(CurrentWavelength); // min value
-
-	OptiXTransform = OptiXContext->CreateTransform();
-
-	FMatrix WorldTransform = GetComponentToWorld().ToMatrixNoScale();
-	OptiXTransform->SetMatrix(WorldTransform);
-
-	OptiXGeometryGroup = OptiXContext->CreateGeometryGroup();
-	OptiXGeometryGroup->AddChild(OptiXGeometryInstance);
-
-	OptiXAcceleration = OptiXContext->CreateAcceleration("NoAccel"); // Seems to be faster for now
-	//OptiXAcceleration->SetProperty("refit", "1");
-
-	OptiXGeometryGroup->SetAcceleration(OptiXAcceleration);
-
-	OptiXTransform->SetChild(OptiXGeometryGroup);
-
-
-	OptiXContext->GetGroup("top_object")->AddChild(OptiXTransform);
-	MarkDirty();
-}
-
-void UOptiXLensComponent::InitCubemap(FRHICommandListImmediate & RHICmdList)
-{
-	UE_LOG(LogTemp, Display, TEXT("Init Cubemap"));
-
-	//OptiXContext->SetBuffer("skyboxBuffer", CubemapBuffer);
-
-	CubemapSampler = OptiXContext->CreateTextureSampler();
-	//CubemapSampler->AddToRoot();
-	CubemapSampler->SetWrapMode(0, RT_WRAP_CLAMP_TO_EDGE);
-	CubemapSampler->SetWrapMode(1, RT_WRAP_CLAMP_TO_EDGE);
-	CubemapSampler->SetWrapMode(2, RT_WRAP_CLAMP_TO_EDGE);
-	CubemapSampler->SetIndexingMode(RT_TEXTURE_INDEX_NORMALIZED_COORDINATES);
-	CubemapSampler->SetReadMode(RT_TEXTURE_READ_NORMALIZED_FLOAT);
-	CubemapSampler->SetMaxAnisotropy(1.0f);
-	CubemapSampler->SetMipLevelCount(1u);
-	CubemapSampler->SetArraySize(1u);
-
-
-	CubemapBuffer = OptiXContext->CreateCubemapBuffer(1024, 1024);
-	//CubemapBuffer->AddToRoot();
-
-	CubemapSampler->SetBufferWithTextureIndexAndMiplevel(0u, 0u, CubemapBuffer);
-	CubemapSampler->SetFilteringModes(RT_FILTER_LINEAR, RT_FILTER_LINEAR, RT_FILTER_NONE);
-	
-
-	UpdateCubemap(RHICmdList);
-
-
-	// Writes the variable into the input buffer
-	FOptiXModule::Get().GetOptiXContextManager()->AddCubemapToBuffer(OptiXCubemapId, CubemapSampler->GetId());
-	UE_LOG(LogTemp, Display, TEXT("Finished Init Cubemap"));
-
-}
-
-void UOptiXLensComponent::UpdateCubemap(FRHICommandListImmediate & RHICmdList)
-{
-	TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("UOptiXLensComponent::UpdateCubemap"))
-
-	UE_LOG(LogTemp, Display, TEXT("Updating Cubemap"));
-
-
-	int32 X = 1024; // todo hardcoded
-	int32 Y = X;
-
-	TArray<TArray<FColor>> SurfaceDataCube;
-	SurfaceDataCube.SetNumZeroed(6);
-
-	//TArray<FLinearColor> SD;
-
-	optix::uchar4* BufferData = static_cast<optix::uchar4*>(CubemapBuffer->MapNative());
-
-	FTextureRenderTargetCubeResource* RenderTargetCube = static_cast<FTextureRenderTargetCubeResource*>(CubeRenderTarget->GetRenderTargetResource());
-
-	FIntRect InRectCube = FIntRect(0, 0, RenderTargetCube->GetSizeXY().X, RenderTargetCube->GetSizeXY().Y);
-	FReadSurfaceDataFlags FlagsCube0(RCM_UNorm, CubeFace_PosX);
-	FReadSurfaceDataFlags FlagsCube1(RCM_UNorm, CubeFace_NegX);
-	FReadSurfaceDataFlags FlagsCube2(RCM_UNorm, CubeFace_PosY);
-	FReadSurfaceDataFlags FlagsCube3(RCM_UNorm, CubeFace_NegY);
-	FReadSurfaceDataFlags FlagsCube4(RCM_UNorm, CubeFace_PosZ);
-	FReadSurfaceDataFlags FlagsCube5(RCM_UNorm, CubeFace_NegZ);
-
-	RHICmdList.ReadSurfaceData(RenderTargetCube->GetTextureRHI(), InRectCube, SurfaceDataCube[0], FlagsCube0);
-	RHICmdList.ReadSurfaceData(RenderTargetCube->GetTextureRHI(), InRectCube, SurfaceDataCube[1], FlagsCube1);
-	RHICmdList.ReadSurfaceData(RenderTargetCube->GetTextureRHI(), InRectCube, SurfaceDataCube[2], FlagsCube2);
-	RHICmdList.ReadSurfaceData(RenderTargetCube->GetTextureRHI(), InRectCube, SurfaceDataCube[3], FlagsCube3);
-	RHICmdList.ReadSurfaceData(RenderTargetCube->GetTextureRHI(), InRectCube, SurfaceDataCube[4], FlagsCube4);
-	RHICmdList.ReadSurfaceData(RenderTargetCube->GetTextureRHI(), InRectCube, SurfaceDataCube[5], FlagsCube5);
-
-	uint32 MemSize = (X * Y * sizeof(FColor));
-	FMemory::Memcpy(BufferData, SurfaceDataCube[0].GetData(), MemSize); // front
-	FMemory::Memcpy(BufferData + X * Y * 1, SurfaceDataCube[1].GetData(), MemSize); // back
-	FMemory::Memcpy(BufferData + X * Y * 2, SurfaceDataCube[2].GetData(), MemSize); // 
-	FMemory::Memcpy(BufferData + X * Y * 3, SurfaceDataCube[3].GetData(), MemSize); // 
-	FMemory::Memcpy(BufferData + X * Y * 4, SurfaceDataCube[4].GetData(), MemSize); // 
-	FMemory::Memcpy(BufferData + X * Y * 5, SurfaceDataCube[5].GetData(), MemSize); //
-
-	CubemapBuffer->Unmap();
-
-	UE_LOG(LogTemp, Display, TEXT("Finished Updating Cubemap"));
-
-
-}
-
-
-void UOptiXLensComponent::CleanOptiXComponent()
-{
-	if(OptiXContext != NULL && OptiXContext->GetGroup("top_object") != NULL)
-		OptiXContext->GetGroup("top_object")->RemoveChild(OptiXTransform);
-	OptiXTransform = nullptr;
-
-	Super::CleanOptiXComponent();
-	OptiXGeometryGroup = nullptr;
-
-}
-
-void UOptiXLensComponent::InitFromData(const FLensData& Data)
-{
-	SetLensRadius(Data.LensRadius * 10);
-	SetRadius1(Data.Radius1 * 10);
-	SetRadius2(Data.Radius2 * 10);
-	SetThickness(Data.Thickness);
-	SetLensType1(Data.LensTypeSide1);
-	SetLensType2(Data.LensTypeSide2);
-	SetGlassType(Data.GlassType);
-}
-
-void UOptiXLensComponent::SetThickness(float Thickness)
-{
-	UE_LOG(LogTemp, Display, TEXT("Setting Thickness: %f"), Thickness);
-	LensThickness = Thickness;
-	QueueOptiXContextUpdate();
-	if(IsInGameThread())
-		OnLensThicknessChanged.Broadcast(LensThickness);
-}
-
-float UOptiXLensComponent::GetThickness() const
-{
-	// No silly conversions...
-	return LensThickness;
-}
-
-void UOptiXLensComponent::SetRadius1(float Radius)
-{
-	UE_LOG(LogTemp, Display, TEXT("Setting Radius 1: %f"), Radius);
-	Radius1 = Radius;
-	QueueOptiXContextUpdate();
-}
-
-float UOptiXLensComponent::GetRadius1() const
-{
-	return Radius1;
-}
-
-void UOptiXLensComponent::SetRadius2(float Radius)
-{
-
-	UE_LOG(LogTemp, Display, TEXT("Setting Radius 2: %f"), Radius);
-	Radius2 = Radius;
-	QueueOptiXContextUpdate();
-}
-
-float UOptiXLensComponent::GetRadius2() const
-{
-	return Radius2;
-}
-
-void UOptiXLensComponent::SetLensRadius(float Radius)
-{
-	UE_LOG(LogTemp, Display, TEXT("Setting Lens Radius: %f"), Radius);
-	LensRadius = Radius;
-	QueueOptiXContextUpdate();
-	if (IsInGameThread())
-		OnLensRadiusChanged.Broadcast(Radius);
-}
-
-float UOptiXLensComponent::GetLensRadius() const
-{
-	return LensRadius;
-}
-
-void UOptiXLensComponent::SetLensType1(ELensSideType Type)
-{
-	UE_LOG(LogTemp, Display, TEXT("Setting Lens Side 1 Type: %i"), static_cast<int>(Type));
-
-	LensType1 = Type;
-	// Recalculate Thickness and set new half cylinder length
-	//SetThickness(LensThickness);
-	QueueOptiXContextUpdate();
-}
-
-ELensSideType UOptiXLensComponent::GetLensType1() const
-{
-	return LensType1;
-}
-
-void UOptiXLensComponent::SetLensType2(ELensSideType Type)
-{
-	UE_LOG(LogTemp, Display, TEXT("Setting Lens Side 2 Type: %i"), static_cast<int>(Type));
-
-	LensType2 = Type;
-	// Recalculate Thickness and set new half cylinder length
-	//SetThickness(LensThickness);
-	QueueOptiXContextUpdate();
-}
-
-ELensSideType UOptiXLensComponent::GetLensType2() const
-{
-	return LensType2;
-}
-
-void UOptiXLensComponent::SetGlassType(FString Type)
-{
-	UE_LOG(LogTemp, Display, TEXT("Setting Glass Type: %s"), *Type);
-
-	GlassType = Type;
-	SetWavelength(CurrentWavelength); // ???
-	QueueOptiXContextUpdate();
-}
-
-FString UOptiXLensComponent::GetGlassType() const
-{
-	return GlassType;
-}
-
-void UOptiXLensComponent::SetWavelength(float WL)
-{
-	UE_LOG(LogTemp, Display, TEXT("Setting new WL in lens: %s"), *GetName());
-	CurrentWavelength = WL;
-	QueueOptiXContextUpdate();
-}
-
-float UOptiXLensComponent::GetWavelength() const
-{
-	return CurrentWavelength;
-}
-
-void UOptiXLensComponent::MarkDirty()
-{
-
-	UE_LOG(LogTemp, Display, TEXT("Marking Dirty"));
-
-	if (OptiXAcceleration != nullptr)
-	{
-		OptiXAcceleration->MarkDirty();
-	}
-
-	//manager_->TopAccelerationMarkDirty();
-	UOptiXAcceleration* TopAccel = OptiXContext->GetGroup("top_object")->GetAcceleration();
-	if (TopAccel != nullptr)
-	{
-		TopAccel->MarkDirty(); // This should never be null, but check anyway
-	}
-
-	//RecalculateBoundingBox(); // TODO
-
-}
-
-
-float UOptiXLensComponent::GetCylinderLength(float Thickness) const
-{
-	// Halfsphere thickness
-	float HalfThickness1;
-	float HalfThickness2;
-
-	// Side 1
-	if (LensType1 == ELensSideType::PLANE)
-	{
-		HalfThickness1 = 0;
-	}
-	else
-	{
-		HalfThickness1 = Radius1 - FMath::Sqrt(-LensRadius * LensRadius + Radius1 * Radius1);
-		if (LensType1 == ELensSideType::CONCAVE)
-		{
-			HalfThickness1 *= -1;
-		}
-	}
-
-	// Side 2
-	if (LensType2 == ELensSideType::PLANE)
-	{
-		HalfThickness2 = 0;
-	}
-	else
-	{
-		HalfThickness2 = Radius2 - FMath::Sqrt(-LensRadius * LensRadius + Radius2 * Radius2);
-		if (LensType2 == ELensSideType::CONCAVE)
-		{
-			HalfThickness2 *= -1;
-		}
-	}
-	return Thickness - HalfThickness1 - HalfThickness2;
-}
-
-
-void UOptiXLensComponent::RecalculateBoundingBox()
-{
-
-	// Do we even need this? Seems like it was just used for phoenix stuff TODO
-	return;
-
-	// TODO Shouldn't have to call the getter here - this should just be the actor rotation transform?
-	/*FVector Orientation = OptiXGeometry->GetFloat3D("orientation");
-	float HalfThickness1;	
-	LensType1 == ELensSideType::CONVEX ? HalfThickness1 = Radius1 - FMath::Sqrt(-LensRadius * LensRadius + Radius1 * Radius1) : HalfThickness1 = 0;
-
-	float HalfThickness2;
-	LensType2 == ELensSideType::CONVEX ? HalfThickness2 = Radius2 - FMath::Sqrt(-LensRadius * LensRadius + Radius2 * Radius2) : HalfThickness2 = 0;
-*/
-	// TODO
-
-}
-
-TArray<FString> UOptiXLensComponent::GetGlassDefinitionNames()
-{
-	TArray<FString> Names;
-
-	for (const TPair<FString, FGlassDefinition>& Pair : FOptiXModule::Get().GetGlassDefinitions())
-	{
-		Names.Add(Pair.Key);
-	}
-
-	return Names;
-}
-
-void UOptiXLensComponent::OnWavelengthChangedEvent(float WL)
-{
-	SetWavelength(WL);
-}
+// Fill out your copyright notice in the Description page of Project Settings.
+
+#include "OptiXLensComponent.h"
+
+#include "Runtime/Engine/Classes/Engine/TextureRenderTargetCube.h"
+
+
+#include "OptiXModule.h"
+#include "StatsDefines.h"
+
+UOptiXLensComponent::UOptiXLensComponent(const FObjectInitializer& ObjectInitializer)
+	: Super(ObjectInitializer)
+{
+	Radius1 = 0.8 * 100; // todo default values
+	Radius2 = 1.0 * 100;
+	LensRadius = 0.1 * 100;
+
+	LensType1 = ELensSideType::CONVEX;
+	LensType2 = ELensSideType::CONVEX;
+	LensThickness = 0.025 * 100;
+	CurrentWavelength = 450.0f;
+
+	// A little hacky but w/e
+	for (const TPair<FString, FGlassDefinition>& Pair : FOptiXModule::Get().GetGlassDefinitions())
+	{
+		GlassType = Pair.Key;
+		break;
+	}
+	
+}
+
+
+void UOptiXLensComponent::BeginPlay()
+{
+	Super::BeginPlay();
+
+
+	// do this on the game thread
+	// hook into WL update:
+	//UE_LOG(LogTemp, Display, TEXT("Begin Play on LensComponent, GameThread"));
+
+	FOptiXModule::Get().GetOptiXContextManager()->WavelengthChangedEvent.AddUFunction(this, "OnWavelengthChangedEvent");
+
+
+	// New functions
+
+	FOptiXModule::Get().GetOptiXContextManager()->RequestNewOptiXObject(GetUniqueID(), "lens_parametric");
+
+	// Create the required buffer and sampler 
+	FOptiXBufferData BufferData;
+	BufferData.Name = "texture_buffer";
+	BufferData.Type = RT_BUFFER_INPUT | RT_BUFFER_CUBEMAP;
+	BufferData.Format = RT_FORMAT_UNSIGNED_BYTE4;
+	BufferData.BufferWidth = 1024;
+	BufferData.BufferHeight = 1024;
+	BufferData.BufferDepth = 6;
+
+	FOptiXModule::Get().GetOptiXContextManager()->RequestNewOptiXBuffer(GetUniqueID(), BufferData);
+	FOptiXModule::Get().GetOptiXContextManager()->RequestNewOptiXTextureSampler(GetUniqueID());
+
+	FMatrix T = GetComponentToWorld().ToMatrixNoScale();
+	FMatrix I = T.Inverse();
+
+	double WL2 = FMath::Pow(CurrentWavelength / 1000.0, 2.0f);
+	FGlassDefinition Def = FOptiXModule::Get().GetGlassDefinitions()[GlassType];
+	//UE_LOG(LogTemp, Display, TEXT("Glass Def: %f, %f, %F"), Def.B.X, Def.B.Y, Def.B.Z);
+
+	float Index = FMath::Sqrt(1 +
+		Def.B.X * WL2 / (WL2 - Def.C.X) +
+		Def.B.Y * WL2 / (WL2 - Def.C.Y) +
+		Def.B.Z * WL2 / (WL2 - Def.C.Z));
+
+	float HalfCylinderHeight = GetCylinderLength(LensThickness) / 2.0f;
+
+	// Could just capture this as well
+	OptiXObjectInitFunction InitFunction =
+		[&OptiXCubemapId = OptiXCubemapId, Transform = T, Inverse = I, 
+			Index, &Radius1 = Radius1, &Radius2 = Radius2, &LensRadius = LensRadius, 
+			HalfCylinderHeight, &LensType1 = LensType1, &LensType2 = LensType2]
+	(FOptiXObjectData* Data, TMap<FString, optix::Buffer>* Buffers, optix::TextureSampler TextureSampler)
+	{
+		// Material stuff:
+		Data->OptiXMaterial["importance_cutoff"]->setFloat(1e-2f);
+		Data->OptiXMaterial["cutoff_color"]->setFloat(0.035f, 0.102f, 0.169f);
+		Data->OptiXMaterial["fresnel_exponent"]->setFloat(3.0f);
+		Data->OptiXMaterial["fresnel_minimum"]->setFloat(0.1f);
+		Data->OptiXMaterial["fresnel_maximum"]->setFloat(1.0f);
+		//Data->OptiXMaterial["refraction_index"]->setFloat(1.4f);
+		Data->OptiXMaterial["refraction_color"]->setFloat(1.0f, 1.0f, 1.0f);
+		Data->OptiXMaterial["reflection_color"]->setFloat(1.0f, 1.0f, 1.0f);
+		Data->OptiXMaterial["refraction_maxdepth"]->setInt(10);
+		Data->OptiXMaterial["reflection_maxdepth"]->setInt(5);
+		Data->OptiXMaterial["extinction_constant"]->setFloat(FMath::Loge(0.83f), FMath::Loge(0.83f), FMath::Loge(0.83f));
+
+		Data->OptiXMaterial["lens_id"]->setInt(OptiXCubemapId); // todo
+		Data->OptiXMaterial["refraction_index"]->setFloat(Index);
+
+		// General stuff
+
+		Data->OptiXGeometryInstance["center"]->setFloat(0.0f, 0.0f, 0.0f);		
+		Data->OptiXGeometryInstance["orientation"]->setFloat(0, 0, -1); 
+		Data->OptiXGeometryInstance["radius"]->setFloat(Radius1);
+		Data->OptiXGeometryInstance["radius2"]->setFloat(Radius2);
+		Data->OptiXGeometryInstance["lensRadius"]->setFloat(LensRadius);
+		Data->OptiXGeometryInstance["halfCylinderLength"]->setFloat(HalfCylinderHeight);
+		Data->OptiXGeometryInstance["side1Type"]->setInt(static_cast<int32>(LensType1));
+		Data->OptiXGeometryInstance["side2Type"]->setInt(static_cast<int32>(LensType2));
+		Data->OptiXTransform->setMatrix(true, &Transform.M[0][0], &Inverse.M[0][0]);
+		Data->OptiXAcceleration->markDirty();
+		Data->OptiXAcceleration->getContext()["top_object"]->getGroup()->getAcceleration()->markDirty();
+
+		// Texture Sampler and Buffer
+		TextureSampler->setWrapMode(0, RT_WRAP_CLAMP_TO_EDGE);
+		TextureSampler->setWrapMode(1, RT_WRAP_CLAMP_TO_EDGE);
+		TextureSampler->setWrapMode(2, RT_WRAP_CLAMP_TO_EDGE);
+		TextureSampler->setIndexingMode(RT_TEXTURE_INDEX_NORMALIZED_COORDINATES);
+		TextureSampler->setReadMode(RT_TEXTURE_READ_NORMALIZED_FLOAT);
+		TextureSampler->setMaxAnisotropy(1.0f);
+		TextureSampler->setMipLevelCount(1u);
+		TextureSampler->setArraySize(1u);
+
+		optix::Buffer TextureBuffer = *Buffers->Find("texture_buffer");
+
+		TextureSampler->setBuffer(0u, 0u, TextureBuffer);
+		TextureSampler->setFilteringModes(RT_FILTER_LINEAR, RT_FILTER_LINEAR, RT_FILTER_NONE);
+
+		FOptiXModule::Get().GetOptiXContextManager()->AddCubemapToBuffer(OptiXCubemapId, TextureSampler->getId());
+
+		UE_LOG(LogTemp, Display, TEXT("Finished Init Cubemap"));
+
+	};
+
+	FOptiXModule::Get().GetOptiXContextManager()->EnqueueInitFunction(GetUniqueID(), InitFunction);
+
+	RequestCubemapUpdate();
+
+	UE_LOG(LogTemp, Display, TEXT("Enqueued Cubemap Init"));
+
+}
+
+void UOptiXLensComponent::InitFromData(const FLensData& Data)
+{
+	SetLensRadius(Data.LensRadius * 10);
+	SetRadius1(Data.Radius1 * 10);
+	SetRadius2(Data.Radius2 * 10);
+	SetThickness(Data.Thickness);
+	SetLensType1(Data.LensTypeSide1);
+	SetLensType2(Data.LensTypeSide2);
+	SetGlassType(Data.GlassType);
+}
+
+void UOptiXLensComponent::SetThickness(float Thickness)
+{
+	UE_LOG(LogTemp, Display, TEXT("Setting Thickness: %f"), Thickness);
+	LensThickness = Thickness;
+	float HalfCylinderHeight = GetCylinderLength(LensThickness) / 2.0f;
+
+	OptiXObjectUpdateFunction UpdateFunction =
+		[HalfCylinderHeight](FOptiXObjectData* Data, TMap<FString, optix::Buffer>* Buffers, optix::TextureSampler TextureSampler)
+	{
+		Data->OptiXGeometryInstance["halfCylinderLength"]->setFloat(HalfCylinderHeight);
+		Data->OptiXAcceleration->markDirty();
+		Data->OptiXAcceleration->getContext()["top_object"]->getGroup()->getAcceleration()->markDirty();
+	};
+	FOptiXModule::Get().GetOptiXContextManager()->EnqueueUpdateFunction(GetUniqueID(), UpdateFunction);
+
+	OnLensThicknessChanged.Broadcast(LensThickness);
+}
+
+float UOptiXLensComponent::GetThickness() const
+{
+	// No silly conversions...
+	return LensThickness;
+}
+
+float UOptiXLensComponent::GetThicknessForCylinderLength(float Length) const
+{
+	// With silly conversions:
+		// Halfsphere thickness
+	float HalfThickness1;
+	float HalfThickness2;
+
+	// Side 1
+	if (LensType1 == ELensSideType::PLANE)
+	{
+		HalfThickness1 = 0;
+	}
+	else
+	{
+		HalfThickness1 = Radius1 - FMath::Sqrt(-LensRadius * LensRadius + Radius1 * Radius1);
+		if (LensType1 == ELensSideType::CONCAVE)
+		{
+			HalfThickness1 *= -1;
+		}
+	}
+
+	// Side 2
+	if (LensType2 == ELensSideType::PLANE)
+	{
+		HalfThickness2 = 0;
+	}
+	else
+	{
+		HalfThickness2 = Radius2 - FMath::Sqrt(-LensRadius * LensRadius + Radius2 * Radius2);
+		if (LensType2 == ELensSideType::CONCAVE)
+		{
+			HalfThickness2 *= -1;
+		}
+	}
+	return Length + HalfThickness1 + HalfThickness2;
+}
+
+void UOptiXLensComponent::SetRadius1(float Radius)
+{
+	UE_LOG(LogTemp, Display, TEXT("Setting Radius 1: %f"), Radius);
+	Radius1 = Radius;
+	OptiXObjectUpdateFunction UpdateFunction =
+		[&Radius1 = Radius1](FOptiXObjectData* Data, TMap<FString, optix::Buffer>* Buffers, optix::TextureSampler TextureSampler)
+	{
+		Data->OptiXGeometryInstance["radius"]->setFloat(Radius1);
+		Data->OptiXAcceleration->markDirty();
+		Data->OptiXAcceleration->getContext()["top_object"]->getGroup()->getAcceleration()->markDirty();
+
+	};
+	FOptiXModule::Get().GetOptiXContextManager()->EnqueueUpdateFunction(GetUniqueID(), UpdateFunction);
+
+}
+
+float UOptiXLensComponent::GetRadius1() const
+{
+	return Radius1;
+}
+
+void UOptiXLensComponent::SetRadius2(float Radius)
+{
+
+	UE_LOG(LogTemp, Display, TEXT("Setting Radius 2: %f"), Radius);
+	Radius2 = Radius;
+	OptiXObjectUpdateFunction UpdateFunction =
+		[&Radius2 = Radius2](FOptiXObjectData* Data, TMap<FString, optix::Buffer>* Buffers, optix::TextureSampler TextureSampler)
+	{
+		Data->OptiXGeometryInstance["radius2"]->setFloat(Radius2);
+		Data->OptiXAcceleration->markDirty();
+		Data->OptiXAcceleration->getContext()["top_object"]->getGroup()->getAcceleration()->markDirty();
+
+	};
+	FOptiXModule::Get().GetOptiXContextManager()->EnqueueUpdateFunction(GetUniqueID(), UpdateFunction);
+}
+
+float UOptiXLensComponent::GetRadius2() const
+{
+	return Radius2;
+}
+
+void UOptiXLensComponent::SetLensRadius(float Radius)
+{
+	UE_LOG(LogTemp, Display, TEXT("Setting Lens Radius: %f"), Radius);
+	LensRadius = Radius;
+	
+	OptiXObjectUpdateFunction UpdateFunction =
+		[&LensRadius = LensRadius](FOptiXObjectData* Data, TMap<FString, optix::Buffer>* Buffers, optix::TextureSampler TextureSampler)
+	{
+		Data->OptiXGeometryInstance["lensRadius"]->setFloat(LensRadius);
+		Data->OptiXAcceleration->markDirty();
+		Data->OptiXAcceleration->getContext()["top_object"]->getGroup()->getAcceleration()->markDirty();
+
+	};
+	FOptiXModule::Get().GetOptiXContextManager()->EnqueueUpdateFunction(GetUniqueID(), UpdateFunction);
+
+	OnLensRadiusChanged.Broadcast(Radius);
+}
+
+float UOptiXLensComponent::GetLensRadius() const
+{
+	return LensRadius;
+}
+
+void UOptiXLensComponent::SetLensType1(ELensSideType Type)
+{
+	UE_LOG(LogTemp, Display, TEXT("Setting Lens Side 1 Type: %i"), static_cast<int>(Type));
+
+	LensType1 = Type;
+	OptiXObjectUpdateFunction UpdateFunction =
+		[&LensType1 = LensType1](FOptiXObjectData* Data, TMap<FString, optix::Buffer>* Buffers, optix::TextureSampler TextureSampler)
+	{
+		Data->OptiXGeometryInstance["side1Type"]->setInt(static_cast<int>(LensType1));
+		Data->OptiXAcceleration->markDirty();
+		Data->OptiXAcceleration->getContext()["top_object"]->getGroup()->getAcceleration()->markDirty();
+
+	};
+	FOptiXModule::Get().GetOptiXContextManager()->EnqueueUpdateFunction(GetUniqueID(), UpdateFunction);
+	SetThickness(LensThickness);
+}
+
+ELensSideType UOptiXLensComponent::GetLensType1() const
+{
+	return LensType1;
+}
+
+void UOptiXLensComponent::SetLensType2(ELensSideType Type)
+{
+	UE_LOG(LogTemp, Display, TEXT("Setting Lens Side 2 Type: %i"), static_cast<int>(Type));
+
+	LensType2 = Type;
+	OptiXObjectUpdateFunction UpdateFunction =
+		[&LensType2 = LensType2](FOptiXObjectData* Data, TMap<FString, optix::Buffer>* Buffers, optix::TextureSampler TextureSampler)
+	{
+		Data->OptiXGeometryInstance["side2Type"]->setInt(static_cast<int>(LensType2));
+		Data->OptiXAcceleration->markDirty();
+		Data->OptiXAcceleration->getContext()["top_object"]->getGroup()->getAcceleration()->markDirty();
+
+	};
+	FOptiXModule::Get().GetOptiXContextManager()->EnqueueUpdateFunction(GetUniqueID(), UpdateFunction);
+	SetThickness(LensThickness);
+}
+
+ELensSideType UOptiXLensComponent::GetLensType2() const
+{
+	return LensType2;
+}
+
+void UOptiXLensComponent::SetGlassType(FString Type)
+{
+	UE_LOG(LogTemp, Display, TEXT("Setting Glass Type: %s"), *Type);
+
+	GlassType = Type;
+	SetWavelength(CurrentWavelength); // ???
+}
+
+FString UOptiXLensComponent::GetGlassType() const
+{
+	return GlassType;
+}
+
+void UOptiXLensComponent::SetWavelength(float WL)
+{
+	UE_LOG(LogTemp, Display, TEXT("Setting new WL in lens: %s"), *GetName());
+	CurrentWavelength = WL;
+
+	double WL2 = FMath::Pow(CurrentWavelength / 1000.0, 2.0f);
+	FGlassDefinition Def = FOptiXModule::Get().GetGlassDefinitions()[GlassType];
+	//UE_LOG(LogTemp, Display, TEXT("Glass Def: %f, %f, %F"), Def.B.X, Def.B.Y, Def.B.Z);
+
+	float Index = FMath::Sqrt(1 +
+		Def.B.X * WL2 / (WL2 - Def.C.X) +
+		Def.B.Y * WL2 / (WL2 - Def.C.Y) +
+		Def.B.Z * WL2 / (WL2 - Def.C.Z));
+
+	OptiXObjectUpdateFunction UpdateFunction =
+		[Index](FOptiXObjectData* Data, TMap<FString, optix::Buffer>* Buffers, optix::TextureSampler TextureSampler)
+	{
+		Data->OptiXGeometryInstance["refraction_index"]->setFloat(Index);
+		Data->OptiXAcceleration->markDirty();
+		Data->OptiXAcceleration->getContext()["top_object"]->getGroup()->getAcceleration()->markDirty();
+
+	};
+	FOptiXModule::Get().GetOptiXContextManager()->EnqueueUpdateFunction(GetUniqueID(), UpdateFunction);
+}
+
+float UOptiXLensComponent::GetWavelength() const
+{
+	return CurrentWavelength;
+}
+
+
+float UOptiXLensComponent::GetCylinderLength(float Thickness) const
+{
+	// Halfsphere thickness
+	float HalfThickness1;
+	float HalfThickness2;
+
+	// Side 1
+	if (LensType1 == ELensSideType::PLANE)
+	{
+		HalfThickness1 = 0;
+	}
+	else
+	{
+		HalfThickness1 = Radius1 - FMath::Sqrt(-LensRadius * LensRadius + Radius1 * Radius1);
+		if (LensType1 == ELensSideType::CONCAVE)
+		{
+			HalfThickness1 *= -1;
+		}
+	}
+
+	// Side 2
+	if (LensType2 == ELensSideType::PLANE)
+	{
+		HalfThickness2 = 0;
+	}
+	else
+	{
+		HalfThickness2 = Radius2 - FMath::Sqrt(-LensRadius * LensRadius + Radius2 * Radius2);
+		if (LensType2 == ELensSideType::CONCAVE)
+		{
+			HalfThickness2 *= -1;
+		}
+	}
+	return Thickness - HalfThickness1 - HalfThickness2;
+}
+
+
+TArray<FString> UOptiXLensComponent::GetGlassDefinitionNames()
+{
+	TArray<FString> Names;
+
+	for (const TPair<FString, FGlassDefinition>& Pair : FOptiXModule::Get().GetGlassDefinitions())
+	{
+		Names.Add(Pair.Key);
+	}
+
+	return Names;
+}
+
+void UOptiXLensComponent::OnWavelengthChangedEvent(float WL)
+{
+	SetWavelength(WL);
+}
diff --git a/Source/OptiX/Private/OptiXObjectComponent.cpp b/Source/OptiX/Private/OptiXObjectComponent.cpp
index 8bfff78f7b50aeaf0c90f3d97fbb8a9b7d428623..e5c6c30374c3bc9e30dba8f488bcc9de4fc44e2a 100644
--- a/Source/OptiX/Private/OptiXObjectComponent.cpp
+++ b/Source/OptiX/Private/OptiXObjectComponent.cpp
@@ -1,335 +1,296 @@
-#include "OptiXObjectComponent.h"
-
-#include "Runtime/Engine/Classes/Engine/TextureRenderTargetCube.h"
-#include "Runtime/Engine/Classes/Kismet/GameplayStatics.h"
-#include "Runtime/CoreUObject/Public/UObject/UObjectIterator.h"
-
-
-
-#include "OptiXLaserActor.h"
-#include "OptiXTargetComponent.h"
-#include "OptiXModule.h"
-#include "StatsDefines.h"
-
-UOptiXObjectComponent::UOptiXObjectComponent(const FObjectInitializer& ObjectInitializer)
-	: Super(ObjectInitializer)
-{
-	// Register the component with OptiX and get the currently singular context. 
-	// If this works, I should move the Context from the singleton away somehow into the scene to make it accessible via blueprints etc.
-	// Maybe have 1 context per level? That would make most sense and allow for different scenes in a world, not that this is needed anyway.
-	// But the singleton thing seems really limiting.
-
-	// Only as a safety measure because I have no idea how the editor factory actually sets this stuff.
-
-	bIsInitialized = false;
-
-	UE_LOG(LogTemp, Display, TEXT("OptiX Component Constructor"));
-	PrimaryComponentTick.bCanEverTick = false; // Don't need to tick 
-	bWantsOnUpdateTransform = true;
-
-}
-
-
-void UOptiXObjectComponent::OnUnregister()
-{
-	UE_LOG(LogTemp, Display, TEXT("OptiX Component OnUnregister"));
-
-	Super::OnUnregister();
-
-	//if (OptiXGeometryGroup != nullptr)
-	//{
-	//	OptiXGeometryGroup->RemoveChild(OptiXGeometryInstance);
-	//}
-
-	//OptiXGeometry = nullptr;
-	//OptiXContext = nullptr;
-	//OptiXGeometryGroup = nullptr; // Dunno if that's needed?
-	//OptiXGeometryInstance = nullptr; // Dunno if that's needed?
-}
-
-
-void UOptiXObjectComponent::BeginPlay()
-{
-	Super::BeginPlay();
-	UE_LOG(LogTemp, Display, TEXT("OptiX Component BeginPlay"));
-
-	// Create and Init the optix stuff here
-
-	//InitOptiXComponent();	
-	RegisterOptiXComponent();
-	QueueOptiXContextUpdate();
-}
-
-void UOptiXObjectComponent::RegisterOptiXComponent()
-{
-	FOptiXModule::Get().GetOptiXContextManager()->RegisterOptiXComponent(this);
-}
-
-void UOptiXObjectComponent::QueueOptiXContextUpdate()
-{
-	TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("UOptiXObjectComponent::QueueOptiXContextUpdate"))
-
-	if (!bUpdateQueued)
-	{
-		FOptiXModule::Get().GetOptiXContextManager()->QueueComponentUpdate(this);
-	}
-}
-
-void UOptiXObjectComponent::EndPlay(const EEndPlayReason::Type EndPlayReason)
-{
-	Super::EndPlay(EndPlayReason);
-	UE_LOG(LogTemp, Display, TEXT(" ---------------- OptiX Component EndPlay, starting cleanup."));
-
-	CleanOptiXComponent();
-}
-
-void UOptiXObjectComponent::OnUpdateTransform(EUpdateTransformFlags UpdateTransformFlags, ETeleportType Teleport/* = ETeleportType::None*/)
-{
-	TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("UOptiXObjectComponent::OnUpdateTransform"))
-
-	Super::OnUpdateTransform(EUpdateTransformFlags::SkipPhysicsUpdate, Teleport);
-
-	UpdateOptiXComponent();
-}
-
-
-void UOptiXObjectComponent::InitOptiXComponent(FRHICommandListImmediate & RHICmdList)
-{
-	check(IsInRenderingThread());
-
-	OptiXContext = FOptiXModule::Get().GetContext();
-	OptiXPTXDir = FOptiXModule::Get().OptiXPTXDir;
-
-	IOptiXComponentInterface::InitOptiXComponent(RHICmdList); // Calls the other stuff
-
-	bIsInitialized = true;
-	SetComponentTickEnabled(false);
-	UE_LOG(LogTemp, Display, TEXT("Initialized Object Component"));
-}
-
-void UOptiXObjectComponent::CleanOptiXComponent()
-{
-
-	// Remove all the optix stuff again here from top to bottom
-
-
-	OptiXGeometryGroup->RemoveChild(OptiXGeometryInstance);
-	//OptiXGeometryGroup = nullptr; // This should trigger the GC and eat the object if this is the last reference
-
-	OptiXGeometryInstance->RemoveFromRoot();
-	//OptiXGeometryInstance->DestroyOptiXObject();
-	OptiXGeometryInstance = nullptr;
-
-	OptiXGeometry->RemoveFromRoot();
-	OptiXGeometry->DestroyOptiXObject();
-	OptiXGeometry = nullptr;
-
-	OptiXMaterial->RemoveFromRoot();
-	OptiXMaterial->DestroyOptiXObject();
-	OptiXMaterial = nullptr;
-}
-
-void UOptiXObjectComponent::SetUpdateQueued(bool UpdateQueued)
-{
-	bUpdateQueued.AtomicSet(UpdateQueued);
-}
-
-
-
-
-UOptiXCubemapComponent::UOptiXCubemapComponent(const FObjectInitializer& ObjectInitializer)
-	: Super(ObjectInitializer)
-{
-	// Register the component with OptiX and get the currently singular context. 
-	// If this works, I should move the Context from the singleton away somehow into the scene to make it accessible via blueprints etc.
-	// Maybe have 1 context per level? That would make most sense and allow for different scenes in a world, not that this is needed anyway.
-	// But the singleton thing seems really limiting.
-
-	// Only as a safety measure because I have no idea how the editor factory actually sets this stuff.
-
-	bIsInitialized = false;
-
-	UE_LOG(LogTemp, Display, TEXT("OptiX Cubemap Component Constructor"));
-	PrimaryComponentTick.bCanEverTick = false; // Don't need to tick 
-	bWantsOnUpdateTransform = true;
-
-
-	bCaptureEveryFrame = false;
-	bCaptureOnMovement = false;
-
-
-}
-
-
-void UOptiXCubemapComponent::OnUnregister()
-{
-	UE_LOG(LogTemp, Display, TEXT("OptiX Component OnUnregister"));
-
-	Super::OnUnregister();
-
-	//if (OptiXGeometryGroup != nullptr)
-	//{
-	//	OptiXGeometryGroup->RemoveChild(OptiXGeometryInstance);
-	//}
-
-	//OptiXGeometry = nullptr;
-	//OptiXContext = nullptr;
-	//OptiXGeometryGroup = nullptr; // Dunno if that's needed?
-	//OptiXGeometryInstance = nullptr; // Dunno if that's needed?
-}
-
-
-void UOptiXCubemapComponent::BeginPlay()
-{
-	Super::BeginPlay();
-	UE_LOG(LogTemp, Display, TEXT("OptiX Component BeginPlay"));
-
-	// Create and Init the optix stuff here
-
-	TArray<AActor*> FoundLaserActors;
-	UGameplayStatics::GetAllActorsOfClass(GetWorld(), AOptiXLaserActor::StaticClass(), FoundLaserActors);
-
-	for (AActor* Actor : FoundLaserActors)
-	{
-		HideComponent(Cast<AOptiXLaserActor>(Actor)->LineInstancedStaticMeshComponent);
-	}
-
-
-	for (TObjectIterator<UOptiXCubemapComponent> Itr; Itr; ++Itr)
-	{
-		// Filter out objects not contained in the target world.
-		if (Itr->GetWorld() != GetWorld())
-		{
-			continue;
-		}
-		HideActorComponents(Itr->GetOwner());
-	}
-
-	for (TObjectIterator<UOptiXTargetComponent> Itr; Itr; ++Itr)
-	{
-		// Filter out objects not contained in the target world.
-		if (Itr->GetWorld() != GetWorld())
-		{
-			continue;
-		}
-		HideActorComponents(Itr->GetOwner());
-	}
-
-	for (TObjectIterator<UWidgetComponent> Itr; Itr; ++Itr)
-	{
-		// Filter out objects not contained in the target world.
-		if (Itr->GetWorld() != GetWorld())
-		{
-			continue;
-		}
-
-		if (Itr->GetWidgetClass() != NULL && Itr->GetWidgetClass()->GetName().Contains("ScreenWidget"))
-		{
-			HideActorComponents(Itr->GetOwner());
-		}
-	}
-
-
-	HideActorComponents(UGameplayStatics::GetPlayerController(GetWorld(), 0));
-	HideActorComponents(UGameplayStatics::GetPlayerPawn(GetWorld(), 0));
-
-	CubeRenderTarget = NewObject<UTextureRenderTargetCube>();
-	CubeRenderTarget->Init(1024, PF_B8G8R8A8);
-	CubeRenderTarget->UpdateResource();
-	TextureTarget = CubeRenderTarget;
-
-	CaptureScene();
-	CaptureSceneDeferred();
-	CubeRenderTarget->UpdateResource();
-	bCubemapCaptured.AtomicSet(true);
-
-	//InitOptiXComponent();	
-	RegisterOptiXComponent();
-	QueueOptiXContextUpdate();
-
-
-}
-
-void UOptiXCubemapComponent::RegisterOptiXComponent()
-{
-	FOptiXModule::Get().GetOptiXContextManager()->RegisterOptiXComponent(this);
-}
-
-void UOptiXCubemapComponent::QueueOptiXContextUpdate()
-{
-	if (!bUpdateQueued)
-	{
-		FOptiXModule::Get().GetOptiXContextManager()->QueueComponentUpdate(this);
-	}
-}
-
-void UOptiXCubemapComponent::EndPlay(const EEndPlayReason::Type EndPlayReason)
-{
-	Super::EndPlay(EndPlayReason);
-	UE_LOG(LogTemp, Display, TEXT(" ---------------- OptiX Component EndPlay, starting cleanup."));
-
-	CleanOptiXComponent();
-}
-
-void UOptiXCubemapComponent::OnUpdateTransform(EUpdateTransformFlags UpdateTransformFlags, ETeleportType Teleport/* = ETeleportType::None*/)
-{
-	Super::OnUpdateTransform(EUpdateTransformFlags::SkipPhysicsUpdate, Teleport);
-
-	UpdateOptiXComponent();
-}
-
-
-void UOptiXCubemapComponent::InitOptiXComponent(FRHICommandListImmediate & RHICmdList)
-{
-	check(IsInRenderingThread());
-
-	OptiXContext = FOptiXModule::Get().GetContext();
-	OptiXPTXDir = FOptiXModule::Get().OptiXPTXDir;
-
-	OptiXCubemapId = FOptiXModule::Get().GetOptiXContextManager()->RequestCubemapId();
-
-
-	IOptiXComponentInterface::InitOptiXComponent(RHICmdList); // Calls the other stuff
-	InitCubemap(RHICmdList);
-
-	bIsInitialized = true;
-	SetComponentTickEnabled(false);
-	UE_LOG(LogTemp, Display, TEXT("Initialized Object Component"));
-}
-
-void UOptiXCubemapComponent::CleanOptiXComponent()
-{
-
-	FOptiXModule::Get().GetOptiXContextManager()->DeleteCubemapId(OptiXCubemapId);
-
-	// Remove all the optix stuff again here from top to bottom
-
-	if (OptiXContext == NULL)
-		return;
-	//OptiXGeometryGroup = nullptr; // This should trigger the GC and eat the object if this is the last reference
-
-	OptiXGeometryInstance->RemoveFromRoot();
-	OptiXGeometryInstance->DestroyOptiXObject();
-	OptiXGeometryInstance = nullptr;
-
-	OptiXGeometry->RemoveFromRoot();
-	OptiXGeometry->DestroyOptiXObject();
-	OptiXGeometry = nullptr;
-
-	OptiXMaterial->RemoveFromRoot();
-	OptiXMaterial->DestroyOptiXObject();
-	OptiXMaterial = nullptr;
-}
-
-void UOptiXCubemapComponent::SetUpdateQueued(bool UpdateQueued)
-{
-	bUpdateQueued.AtomicSet(UpdateQueued);
-}
-
-void UOptiXCubemapComponent::RequestCubemapUpdate()
-{
-	TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("UOptiXCubemapComponent::RequestCubemapUpdate"))
-
-	CaptureScene();
-	FOptiXModule::Get().GetOptiXContextManager()->RequestCubemapUpdate(this);
-}
+#include "OptiXObjectComponent.h"
+
+#include "Runtime/Engine/Classes/Engine/TextureRenderTargetCube.h"
+#include "Runtime/Engine/Classes/Kismet/GameplayStatics.h"
+#include "Runtime/CoreUObject/Public/UObject/UObjectIterator.h"
+
+
+
+#include "OptiXLaserActor.h"
+#include "OptiXTargetComponent.h"
+#include "OptiXModule.h"
+#include "StatsDefines.h"
+
+UOptiXObjectComponent::UOptiXObjectComponent(const FObjectInitializer& ObjectInitializer)
+	: Super(ObjectInitializer)
+{
+	// Register the component with OptiX and get the currently singular context. 
+	// If this works, I should move the Context from the singleton away somehow into the scene to make it accessible via blueprints etc.
+	// Maybe have 1 context per level? That would make most sense and allow for different scenes in a world, not that this is needed anyway.
+	// But the singleton thing seems really limiting.
+
+	// Only as a safety measure because I have no idea how the editor factory actually sets this stuff.
+
+	UE_LOG(LogTemp, Display, TEXT("OptiX Component Constructor"));
+	PrimaryComponentTick.bCanEverTick = false; // Don't need to tick 
+	bWantsOnUpdateTransform = false;
+
+}
+
+FPrimitiveSceneProxy* UOptiXObjectComponent::CreateSceneProxy()
+{
+	class FOptiXObjectComponentSceneProxy final : public FPrimitiveSceneProxy
+	{
+	public:
+		SIZE_T GetTypeHash() const override
+		{
+			static size_t UniquePointer;
+			return reinterpret_cast<size_t>(&UniquePointer);
+		}
+
+		/** Initialization constructor. */
+		FOptiXObjectComponentSceneProxy(const UOptiXObjectComponent* InComponent)
+			: FPrimitiveSceneProxy(InComponent)
+		{
+			UniqueId = InComponent->GetUniqueID();
+		}
+
+		// FPrimitiveSceneProxy interface.
+
+		virtual void ApplyLateUpdateTransform(const FMatrix& LateUpdateTransform) override
+		{
+			//FTransform UpdatedTransform = FTransform(LocalToWorld * LateUpdateTransform);
+			//UE_LOG(LogTemp, Display, TEXT("Applying late update to laser"));
+			FMatrix CachedTransform = GetLocalToWorld();
+			FPrimitiveSceneProxy::ApplyLateUpdateTransform(LateUpdateTransform);			
+			CachedTransform.SetOrigin(GetLocalToWorld().GetOrigin());
+			//UE_LOG(LogTemp, Display, TEXT("Transform on late update: %s"), *UpdatedTransform.ToString());
+			FOptiXModule::Get().GetOptiXContextManager()->ObjectPositionLateUpdate_RenderThread(UniqueId, CachedTransform.GetMatrixWithoutScale());
+		}
+
+		virtual uint32 GetMemoryFootprint(void) const override { return(sizeof(*this) + GetAllocatedSize()); }
+		uint32 GetAllocatedSize(void) const { return(FPrimitiveSceneProxy::GetAllocatedSize()); }
+	private:
+		int32 UniqueId;
+	};
+
+	return new FOptiXObjectComponentSceneProxy(this);
+}
+
+void UOptiXObjectComponent::BeginPlay()
+{
+	Super::BeginPlay();
+	UE_LOG(LogTemp, Display, TEXT("OptiX Component BeginPlay"));
+
+	bWantsOnUpdateTransform = true;
+	FOptiXModule::Get().GetOptiXContextManager()->OnSceneChangedDelegate.Broadcast();
+}
+
+void UOptiXObjectComponent::EndPlay(const EEndPlayReason::Type EndPlayReason)
+{
+	Super::EndPlay(EndPlayReason);
+	UE_LOG(LogTemp, Display, TEXT(" ---------------- OptiX Component EndPlay, starting cleanup."));
+
+	CleanOptiXComponent();
+}
+
+void UOptiXObjectComponent::OnUpdateTransform(EUpdateTransformFlags UpdateTransformFlags, ETeleportType Teleport/* = ETeleportType::None*/)
+{
+	Super::OnUpdateTransform(EUpdateTransformFlags::SkipPhysicsUpdate, Teleport);
+
+	FMatrix T = GetComponentToWorld().ToMatrixNoScale();
+	FMatrix Inverse = T.Inverse();
+	OptiXObjectUpdateFunction UpdateFunction =
+		[Transform = T, Inverse](FOptiXObjectData* Data, TMap<FString, optix::Buffer>* Buffers, optix::TextureSampler TextureSampler)
+	{
+		//OptiXGeometryInstance->SetFloat3DVector("size", TargetSize);
+		Data->OptiXTransform->setMatrix(true, &Transform.M[0][0], &Inverse.M[0][0]);
+		Data->OptiXAcceleration->markDirty();
+		Data->OptiXAcceleration->getContext()["top_object"]->getGroup()->getAcceleration()->markDirty();
+	};
+
+	FOptiXModule::Get().GetOptiXContextManager()->EnqueueUpdateFunction(GetUniqueID(), UpdateFunction);
+}
+
+
+void UOptiXObjectComponent::CleanOptiXComponent()
+{
+	FOptiXModule::Get().GetOptiXContextManager()->RequestDestroyOptiXObjects(GetUniqueID());
+}
+
+
+UOptiXCubemapComponent::UOptiXCubemapComponent(const FObjectInitializer& ObjectInitializer)
+	: Super(ObjectInitializer)
+{
+	// Register the component with OptiX and get the currently singular context. 
+	// If this works, I should move the Context from the singleton away somehow into the scene to make it accessible via blueprints etc.
+	// Maybe have 1 context per level? That would make most sense and allow for different scenes in a world, not that this is needed anyway.
+	// But the singleton thing seems really limiting.
+
+	// Only as a safety measure because I have no idea how the editor factory actually sets this stuff.
+
+	//bIsInitialized = false;
+
+	UE_LOG(LogTemp, Display, TEXT("OptiX Cubemap Component Constructor"));
+	PrimaryComponentTick.bCanEverTick = false; // Don't need to tick 
+	bWantsOnUpdateTransform = false;
+
+
+	bCaptureEveryFrame = false;
+	bCaptureOnMovement = false;
+}
+
+void UOptiXCubemapComponent::BeginPlay()
+{
+	Super::BeginPlay();
+	UE_LOG(LogTemp, Display, TEXT("OptiX Component BeginPlay"));
+
+	OptiXCubemapId = FOptiXModule::Get().GetOptiXContextManager()->RequestCubemapId();
+
+	// Create and Init the optix stuff here
+
+	TArray<AActor*> FoundLaserActors;
+	UGameplayStatics::GetAllActorsOfClass(GetWorld(), AOptiXLaserActor::StaticClass(), FoundLaserActors);
+
+	for (AActor* Actor : FoundLaserActors)
+	{
+		HideComponent(Cast<AOptiXLaserActor>(Actor)->LineInstancedStaticMeshComponent);
+	}
+
+
+	for (TObjectIterator<UOptiXCubemapComponent> Itr; Itr; ++Itr)
+	{
+		// Filter out objects not contained in the target world.
+		if (Itr->GetWorld() != GetWorld())
+		{
+			continue;
+		}
+		HideActorComponents(Itr->GetOwner());
+	}
+
+	for (TObjectIterator<UOptiXTargetComponent> Itr; Itr; ++Itr)
+	{
+		// Filter out objects not contained in the target world.
+		if (Itr->GetWorld() != GetWorld())
+		{
+			continue;
+		}
+		HideActorComponents(Itr->GetOwner());
+	}
+
+	for (TObjectIterator<UWidgetComponent> Itr; Itr; ++Itr)
+	{
+		// Filter out objects not contained in the target world.
+		if (Itr->GetWorld() != GetWorld())
+		{
+			continue;
+		}
+
+		if (Itr->GetWidgetClass() != NULL && Itr->GetWidgetClass()->GetName().Contains("ScreenWidget"))
+		{
+			HideActorComponents(Itr->GetOwner());
+		}
+	}
+
+
+	HideActorComponents(UGameplayStatics::GetPlayerController(GetWorld(), 0));
+	HideActorComponents(UGameplayStatics::GetPlayerPawn(GetWorld(), 0));
+
+	CubeRenderTarget = NewObject<UTextureRenderTargetCube>();
+	CubeRenderTarget->Init(1024, PF_B8G8R8A8);
+	CubeRenderTarget->UpdateResource();
+	TextureTarget = CubeRenderTarget;
+
+	CaptureScene();
+	CaptureSceneDeferred();
+	CubeRenderTarget->UpdateResource();
+	bCubemapCaptured.AtomicSet(true);
+
+	//InitOptiXComponent();	
+	//RegisterOptiXComponent();
+	//QueueOptiXContextUpdate();
+
+	bWantsOnUpdateTransform = true;
+	FOptiXModule::Get().GetOptiXContextManager()->OnSceneChangedDelegate.Broadcast();
+}
+
+void UOptiXCubemapComponent::EndPlay(const EEndPlayReason::Type EndPlayReason)
+{
+	Super::EndPlay(EndPlayReason);
+	UE_LOG(LogTemp, Display, TEXT(" ---------------- OptiX Component EndPlay, starting cleanup."));
+
+	CleanOptiXComponent();
+}
+
+void UOptiXCubemapComponent::OnUpdateTransform(EUpdateTransformFlags UpdateTransformFlags, ETeleportType Teleport/* = ETeleportType::None*/)
+{
+	Super::OnUpdateTransform(EUpdateTransformFlags::SkipPhysicsUpdate, Teleport);
+
+
+	FMatrix T = GetComponentToWorld().ToMatrixNoScale();
+	FMatrix Inverse = T.Inverse();
+	OptiXObjectUpdateFunction UpdateFunction =
+		[Transform = T, Inverse](FOptiXObjectData* Data, TMap<FString, optix::Buffer>* Buffers, optix::TextureSampler TextureSampler)
+	{
+		//OptiXGeometryInstance->SetFloat3DVector("size", TargetSize);
+		Data->OptiXTransform->setMatrix(true, &Transform.M[0][0], &Inverse.M[0][0]);
+		Data->OptiXAcceleration->markDirty();
+		Data->OptiXAcceleration->getContext()["top_object"]->getGroup()->getAcceleration()->markDirty();
+	};
+
+	FOptiXModule::Get().GetOptiXContextManager()->EnqueueUpdateFunction(GetUniqueID(), UpdateFunction);
+}
+
+void UOptiXCubemapComponent::CleanOptiXComponent()
+{
+	FOptiXModule::Get().GetOptiXContextManager()->DeleteCubemapId(OptiXCubemapId);
+	FOptiXModule::Get().GetOptiXContextManager()->RequestDestroyOptiXObjects(GetUniqueID());
+}
+
+void UOptiXCubemapComponent::RequestCubemapUpdate()
+{
+	TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("UOptiXCubemapComponent::RequestCubemapUpdate"))
+
+	CaptureScene();
+	
+	UE_LOG(LogTemp, Display, TEXT("Requesting Cubemap Update"));
+
+
+	//int32 X = 1024; // todo hardcoded
+	//int32 Y = X;
+
+	CubemapUpdateFunction UpdateFunction =
+		[&CubeRenderTarget = CubeRenderTarget]
+	(optix::Buffer CubemapBuffer, FRHICommandListImmediate & RHICmdList)
+	{
+		TArray<TArray<FColor>> SurfaceDataCube;
+		SurfaceDataCube.SetNumZeroed(6);
+		//TArray<FLinearColor> SD;
+
+		int32 X = 1024; // todo hardcoded
+		int32 Y = X;
+
+		optix::uchar4* BufferData = static_cast<optix::uchar4*>(CubemapBuffer->map());
+
+		FTextureRenderTargetCubeResource* RenderTargetCube = static_cast<FTextureRenderTargetCubeResource*>(CubeRenderTarget->GetRenderTargetResource());
+
+		FIntRect InRectCube = FIntRect(0, 0, RenderTargetCube->GetSizeXY().X, RenderTargetCube->GetSizeXY().Y);
+		FReadSurfaceDataFlags FlagsCube0(RCM_UNorm, CubeFace_PosX);
+		FReadSurfaceDataFlags FlagsCube1(RCM_UNorm, CubeFace_NegX);
+		FReadSurfaceDataFlags FlagsCube2(RCM_UNorm, CubeFace_PosY);
+		FReadSurfaceDataFlags FlagsCube3(RCM_UNorm, CubeFace_NegY);
+		FReadSurfaceDataFlags FlagsCube4(RCM_UNorm, CubeFace_PosZ);
+		FReadSurfaceDataFlags FlagsCube5(RCM_UNorm, CubeFace_NegZ);
+
+		RHICmdList.ReadSurfaceData(RenderTargetCube->GetTextureRHI(), InRectCube, SurfaceDataCube[0], FlagsCube0);
+		RHICmdList.ReadSurfaceData(RenderTargetCube->GetTextureRHI(), InRectCube, SurfaceDataCube[1], FlagsCube1);
+		RHICmdList.ReadSurfaceData(RenderTargetCube->GetTextureRHI(), InRectCube, SurfaceDataCube[2], FlagsCube2);
+		RHICmdList.ReadSurfaceData(RenderTargetCube->GetTextureRHI(), InRectCube, SurfaceDataCube[3], FlagsCube3);
+		RHICmdList.ReadSurfaceData(RenderTargetCube->GetTextureRHI(), InRectCube, SurfaceDataCube[4], FlagsCube4);
+		RHICmdList.ReadSurfaceData(RenderTargetCube->GetTextureRHI(), InRectCube, SurfaceDataCube[5], FlagsCube5);
+
+		uint32 MemSize = (X * Y * sizeof(FColor));
+		FMemory::Memcpy(BufferData, SurfaceDataCube[0].GetData(), MemSize); // front
+		FMemory::Memcpy(BufferData + X * Y * 1, SurfaceDataCube[1].GetData(), MemSize); // back
+		FMemory::Memcpy(BufferData + X * Y * 2, SurfaceDataCube[2].GetData(), MemSize); // 
+		FMemory::Memcpy(BufferData + X * Y * 3, SurfaceDataCube[3].GetData(), MemSize); // 
+		FMemory::Memcpy(BufferData + X * Y * 4, SurfaceDataCube[4].GetData(), MemSize); // 
+		FMemory::Memcpy(BufferData + X * Y * 5, SurfaceDataCube[5].GetData(), MemSize); //
+
+		CubemapBuffer->unmap();
+
+		UE_LOG(LogTemp, Display, TEXT("Finished Updating Cubemap"));
+	};
+
+	FOptiXModule::Get().GetOptiXContextManager()->RequestLensCubemapUpdate(GetUniqueID(), UpdateFunction);
+}
diff --git a/Source/OptiX/Private/OptiXTargetComponent.cpp b/Source/OptiX/Private/OptiXTargetComponent.cpp
index 8669dfeb4e3b876872e5f9dba4b8fb1032eaa29b..7d2ac88a840f4d0c0d3c9d0b01884bba563201c6 100644
--- a/Source/OptiX/Private/OptiXTargetComponent.cpp
+++ b/Source/OptiX/Private/OptiXTargetComponent.cpp
@@ -1,235 +1,152 @@
-// Fill out your copyright notice in the Description page of Project Settings.
-
-#include "OptiXTargetComponent.h"
-
-#include "UObject/ConstructorHelpers.h"
-
-#include "OptiXModule.h"
-
-
-
-UOptiXTargetComponent::UOptiXTargetComponent(const FObjectInitializer& ObjectInitializer)
-	: Super(ObjectInitializer)
-{	
-	CurrentTexturePattern = ETexturePattern::TP_CHECKER;
-	//FString N = "Texture2D'/OptiX/Targets/Checker.Checker'";
-	//Texture = LoadObject<UTexture2D>(this, *N);
-
-	static ConstructorHelpers::FObjectFinder<UTexture2D> TextureLoader(TEXT("Texture2D'/OptiX/Targets/Checker.Checker'"));
-	Texture = TextureLoader.Object;
-
-	if (Texture != NULL)
-	{
-		TextureSize = FIntPoint(Texture->GetSizeX(), Texture->GetSizeY());
-		TargetSize = FVector(2.0f, 20.0f, 20.0f * static_cast<float>(TextureSize.Y) / static_cast<float>(TextureSize.X));
-	}
-}
-
-// God sometimes unreal is annoying
-void UOptiXTargetComponent::BeginPlay()
-{
-	//CurrentTexturePattern = ETexturePattern::TP_CIRCLES;
-
-	FString N = "Texture2D'/OptiX/Targets/Checker.Checker'";
-	if (CurrentTexturePattern == ETexturePattern::TP_BLACK)
-	{
-		N = "Texture2D'/OptiX/Targets/Black.Black'";
-	}
-	else if (CurrentTexturePattern == ETexturePattern::TP_CIRCLES)
-	{
-		N = "Texture2D'/OptiX/Targets/Circles.Circles'";
-	}
-	else if (CurrentTexturePattern == ETexturePattern::TP_GRID)
-	{
-		N = "Texture2D'/OptiX/Targets/Raster.Raster'";
-	}
-	Texture = nullptr;
-	Texture = LoadObject<UTexture2D>(this, *N);
-	TextureSize = FIntPoint(Texture->GetSizeX(), Texture->GetSizeY());
-	TargetSize = FVector(2.0f, 20.0f, 20.0f * static_cast<float>(TextureSize.Y) / static_cast<float>(TextureSize.X));
-	Super::BeginPlay();
-
-}
-
-void UOptiXTargetComponent::UpdateOptiXComponent()
-{
-	if (OptiXGeometry != nullptr && OptiXTransform != nullptr && OptiXAcceleration != nullptr)
-	{
-		FMatrix T = GetComponentToWorld().ToMatrixNoScale();
-		OptiXTransform->SetMatrix(T);
-		//OptiXAcceleration->MarkDirty();
-		OptiXContext->GetGroup("top_object")->GetAcceleration()->MarkDirty();
-		FOptiXModule::Get().GetOptiXContextManager()->OnSceneChangedDelegate.Broadcast();
-	}
-
-}
-
-void UOptiXTargetComponent::InitOptiXGeometry()
-{
-	OptiXGeometry = OptiXContext->CreateGeometry();
-	OptiXGeometry->SetPrimitiveCount(1u);
-	UOptiXProgram* BB = OptiXContext->CreateProgramFromPTXFile(OptiXPTXDir + "generated/box_intersect.ptx", "bounds");
-	UOptiXProgram* IP = OptiXContext->CreateProgramFromPTXFile(OptiXPTXDir + "generated/box_intersect.ptx", "intersect");
-
-	OptiXGeometry->SetBoundingBoxProgram(BB);
-	OptiXGeometry->SetIntersectionProgram(IP);
-}
-
-void UOptiXTargetComponent::InitOptiXMaterial()
-{
-	UOptiXProgram* CHPerspective = OptiXContext->CreateProgramFromPTXFile(OptiXPTXDir + "generated/frame_material.ptx", "closest_hit_radiance");
-	UOptiXProgram* CHIterative = OptiXContext->CreateProgramFromPTXFile(OptiXPTXDir + "generated/frame_material.ptx", "closest_hit_iterative");
-
-	OptiXMaterial = OptiXContext->CreateMaterial();
-	OptiXMaterial->SetClosestHitProgram(0, CHPerspective);
-	OptiXMaterial->SetClosestHitProgram(1, CHIterative);
-
-	/*OptiXMaterial->SetFloat("importance_cutoff", 1e-2f);
-	OptiXMaterial->SetFloat3D("cutoff_color", 0.035f, 0.102f, 0.169f);
-	OptiXMaterial->SetFloat("fresnel_exponent", 3.0f);
-	OptiXMaterial->SetFloat("fresnel_minimum", 0.1f);
-	OptiXMaterial->SetFloat("fresnel_maximum", 1.0f);
-	OptiXMaterial->SetFloat("refraction_index", 1.4f);
-
-	OptiXMaterial->SetFloat3D("refraction_color", 1.0f, 1.0f, 1.0f);
-	OptiXMaterial->SetFloat3D("reflection_color", 1.0f, 1.0f, 1.0f);
-
-	OptiXMaterial->SetInt("refraction_maxdepth", 10);
-	OptiXMaterial->SetInt("reflection_maxdepth", 5);
-
-	OptiXMaterial->SetFloat3D("extinction_constant", FMath::Loge(0.83f), FMath::Loge(0.83f), FMath::Loge(0.83f));*/
-}
-
-void UOptiXTargetComponent::InitOptiXGroups()
-{
-	OptiXGeometryInstance = OptiXContext->CreateGeometryInstance(OptiXGeometry, OptiXMaterial);
-	
-	SetSize(TargetSize);
-
-	UOptiXTextureSampler* Sampler = OptiXContext->CreateTextureSampler();
-	//Sampler->AddToRoot();
-	Sampler->SetWrapMode(0, RT_WRAP_CLAMP_TO_EDGE);
-	Sampler->SetWrapMode(1, RT_WRAP_CLAMP_TO_EDGE);
-	Sampler->SetWrapMode(2, RT_WRAP_CLAMP_TO_EDGE);
-	Sampler->SetIndexingMode(RT_TEXTURE_INDEX_NORMALIZED_COORDINATES);
-	Sampler->SetReadMode(RT_TEXTURE_READ_NORMALIZED_FLOAT);
-	Sampler->SetMaxAnisotropy(1.0f);
-	Sampler->SetMipLevelCount(1u);
-	Sampler->SetArraySize(1u);
-
-
-
-	UE_LOG(LogTemp, Display, TEXT("Texture with Size: (%i, %i)"), TextureSize.X, TextureSize.Y);
-
-	TextureBuffer = OptiXContext->CreateBufferUByte2D(RT_BUFFER_INPUT, TextureSize.X, TextureSize.Y);
-	
-	TextureSize = FIntPoint(Texture->GetSizeX(), Texture->GetSizeY());
-	TargetSize = FVector(2.0f, 20.0f, 20.0f * static_cast<float>(TextureSize.Y) / static_cast<float>(TextureSize.X));
-
-	optix::uchar4* BufferData = static_cast<optix::uchar4*>(TextureBuffer->MapNative());
-
-
-	FTexture2DMipMap& Mip = Texture->PlatformData->Mips[0];
-
-	FColor* TextureData = static_cast<FColor*>(Mip.BulkData.Lock(LOCK_READ_WRITE));
-
-	// Texture index conversion is a real pain...
-	for (int32 i = 0; i < TextureSize.X; ++i) {
-		for (int32 j = 0; j < TextureSize.Y; ++j) {
-
-			int32 TextureIndex = (TextureSize.X * TextureSize.Y - 1) - i * TextureSize.X - j;
-			int32 BufferIndex = ((j)*(TextureSize.X) + i);
-			//UE_LOG(LogTemp, Display, TEXT("Values: %i"), TextureData[BufferIndex]);
-
-			BufferData[BufferIndex].x = TextureData[TextureIndex].R;
-			BufferData[BufferIndex].y = TextureData[TextureIndex].G;
-			BufferData[BufferIndex].z = TextureData[TextureIndex].B;
-			BufferData[BufferIndex].w = TextureData[TextureIndex].A;
-
-		}
-	}
-
-	// TODO: Check if we can copy automatically via Memcpy
-	//FMemory::Memcpy(BufferData + (X * Y), TextureData, (X * Y * sizeof(FColor))); // Try copying the buffer data directly here TODO
-	Mip.BulkData.Unlock();
-	TextureBuffer->Unmap();
-	
-
-	Sampler->SetBufferWithTextureIndexAndMiplevel(0u, 0u, TextureBuffer);
-	Sampler->SetFilteringModes(RT_FILTER_NEAREST, RT_FILTER_NEAREST, RT_FILTER_NONE);
-
-	OptiXGeometryInstance->SetTextureSampler("frameTexture", Sampler);
-
-	FMatrix T = GetComponentToWorld().ToMatrixNoScale();
-	OptiXTransform = OptiXContext->CreateTransform();
-	OptiXTransform->SetMatrix(T);
-
-	OptiXGeometryGroup = OptiXContext->CreateGeometryGroup();
-	OptiXGeometryGroup->AddChild(OptiXGeometryInstance);
-
-	OptiXAcceleration = OptiXContext->CreateAcceleration("NoAccel"); // This should be faster
-	//OptiXAcceleration->SetProperty("refit", "1");
-	//OptiXAcceleration->MarkDirty();
-
-	OptiXGeometryGroup->SetAcceleration(OptiXAcceleration);
-
-	OptiXTransform->SetChild(OptiXGeometryGroup);
-
-	OptiXContext->GetGroup("top_object")->AddChild(OptiXTransform);
-	OptiXContext->GetGroup("top_object")->GetAcceleration()->MarkDirty();
-
-}
-
-void UOptiXTargetComponent::UpdateOptiXComponentVariables()
-{
-	check(IsInRenderingThread());
-
-
-	// Size
-	OptiXGeometryInstance->SetFloat3DVector("size", TargetSize);	
-}
-
-
-//// TODO: Do it this way for now, alternatively custom getters and setters might be better/less clutter-y?
-//void UOptiXLensComponent::PostEditChangeProperty(FPropertyChangedEvent & PropertyChangedEvent)
-//{
-//
-//	FName PropertyName = (PropertyChangedEvent.Property != NULL) ? PropertyChangedEvent.Property->GetFName() : NAME_None;
-//
-//	// Huge case distinction coming now, I don't really like this, seems like a lot of boilerplate code compared to setters/getters but w/e
-//
-//
-//
-//
-//
-//	Super::PostEditChangeProperty(PropertyChangedEvent);
-//}
-
-void UOptiXTargetComponent::CleanOptiXComponent()
-{
-	if (OptiXContext == NULL)
-	{
-		Super::CleanOptiXComponent();
-		return;
-	}
-
-	OptiXContext->GetGroup("top_object")->RemoveChild(OptiXTransform);
-	
-	OptiXTransform = nullptr;
-	OptiXAcceleration = nullptr;
-
-	Super::CleanOptiXComponent();
-
-	OptiXGeometryGroup = nullptr;
-}
-
-void UOptiXTargetComponent::SetSize(FVector NewSize)
-{
-	TargetSize = NewSize;
-	QueueOptiXContextUpdate();
-}
-
-FVector UOptiXTargetComponent::GetSize()
-{
-	return TargetSize;
-}
+// Fill out your copyright notice in the Description page of Project Settings.
+
+#include "OptiXTargetComponent.h"
+
+#include "UObject/ConstructorHelpers.h"
+
+#include "OptiXModule.h"
+
+
+UOptiXTargetComponent::UOptiXTargetComponent(const FObjectInitializer& ObjectInitializer)
+	: Super(ObjectInitializer)
+{	
+	CurrentTexturePattern = ETexturePattern::TP_CHECKER;
+	//FString N = "Texture2D'/OptiX/Targets/Checker.Checker'";
+	//Texture = LoadObject<UTexture2D>(this, *N);
+
+	static ConstructorHelpers::FObjectFinder<UTexture2D> TextureLoader(TEXT("Texture2D'/OptiX/Targets/Checker.Checker'"));
+	Texture = TextureLoader.Object;
+
+	if (Texture != NULL)
+	{
+		TextureSize = FIntPoint(Texture->GetSizeX(), Texture->GetSizeY());
+		TargetSize = FVector(2.0f, 20.0f, 20.0f * static_cast<float>(TextureSize.Y) / static_cast<float>(TextureSize.X));
+	}
+}
+
+// God sometimes unreal is annoying
+void UOptiXTargetComponent::BeginPlay()
+{
+	//CurrentTexturePattern = ETexturePattern::TP_CIRCLES;
+
+	FString N = "Texture2D'/OptiX/Targets/Checker.Checker'";
+	if (CurrentTexturePattern == ETexturePattern::TP_BLACK)
+	{
+		N = "Texture2D'/OptiX/Targets/Black.Black'";
+	}
+	else if (CurrentTexturePattern == ETexturePattern::TP_CIRCLES)
+	{
+		N = "Texture2D'/OptiX/Targets/Circles.Circles'";
+	}
+	else if (CurrentTexturePattern == ETexturePattern::TP_GRID)
+	{
+		N = "Texture2D'/OptiX/Targets/Raster.Raster'";
+	}
+	Texture = nullptr;
+	Texture = LoadObject<UTexture2D>(this, *N);
+	TextureSize = FIntPoint(Texture->GetSizeX(), Texture->GetSizeY());
+	TargetSize = FVector(2.0f, 20.0f, 20.0f * static_cast<float>(TextureSize.Y) / static_cast<float>(TextureSize.X));
+
+	Super::BeginPlay();
+
+
+	// Request creation of the optix objects
+	FOptiXModule::Get().GetOptiXContextManager()->RequestNewOptiXObject(GetUniqueID(), "box_intersect");
+
+	// Init them
+	SetSize(TargetSize);
+
+	// Create the required buffer and sampler
+	FOptiXBufferData BufferData;
+	BufferData.Name = "texture_buffer";
+	BufferData.Type = RT_BUFFER_INPUT;
+	BufferData.Format = RT_FORMAT_UNSIGNED_BYTE4;
+	BufferData.BufferWidth = TextureSize.X;
+	BufferData.BufferHeight = TextureSize.Y;
+	FOptiXModule::Get().GetOptiXContextManager()->RequestNewOptiXBuffer(GetUniqueID(), BufferData);
+
+	TextureSize = FIntPoint(Texture->GetSizeX(), Texture->GetSizeY());
+	TargetSize = FVector(2.0f, 20.0f, 20.0f * static_cast<float>(TextureSize.Y) / static_cast<float>(TextureSize.X));
+
+	FOptiXModule::Get().GetOptiXContextManager()->RequestNewOptiXTextureSampler(GetUniqueID());
+
+	FMatrix Transform = GetComponentToWorld().ToMatrixNoScale();
+	FMatrix Inverse = Transform.Inverse();
+
+	OptiXObjectInitFunction InitFunction =
+		[&TextureSize = TextureSize, &TargetSize = TargetSize, &Texture = Texture, Transform, Inverse]
+	(FOptiXObjectData* Data, TMap<FString, optix::Buffer>* Buffers, optix::TextureSampler TextureSampler)
+	{
+		TextureSampler->setWrapMode(0, RT_WRAP_CLAMP_TO_EDGE);
+		TextureSampler->setWrapMode(1, RT_WRAP_CLAMP_TO_EDGE);
+		TextureSampler->setWrapMode(2, RT_WRAP_CLAMP_TO_EDGE);
+		TextureSampler->setIndexingMode(RT_TEXTURE_INDEX_NORMALIZED_COORDINATES);
+		TextureSampler->setReadMode(RT_TEXTURE_READ_NORMALIZED_FLOAT);
+		TextureSampler->setMaxAnisotropy(1.0f);
+		TextureSampler->setMipLevelCount(1u);
+		TextureSampler->setArraySize(1u);
+
+		UE_LOG(LogTemp, Display, TEXT("Texture with Size: (%i, %i)"), TextureSize.X, TextureSize.Y);
+
+		optix::Buffer TextureBuffer = *Buffers->Find("texture_buffer");
+		optix::uchar4* BufferData = static_cast<optix::uchar4*>(TextureBuffer->map());
+
+		FTexture2DMipMap& Mip = Texture->PlatformData->Mips[0];
+
+		FColor* TextureData = static_cast<FColor*>(Mip.BulkData.Lock(LOCK_READ_WRITE));
+
+		// Texture index conversion is a real pain...
+		for (int32 i = 0; i < TextureSize.X; ++i) {
+			for (int32 j = 0; j < TextureSize.Y; ++j) {
+
+				int32 TextureIndex = (TextureSize.X * TextureSize.Y - 1) - i * TextureSize.X - j;
+				int32 BufferIndex = ((j)*(TextureSize.X) + i);
+				//UE_LOG(LogTemp, Display, TEXT("Values: %i"), TextureData[BufferIndex]);
+
+				BufferData[BufferIndex].x = TextureData[TextureIndex].R;
+				BufferData[BufferIndex].y = TextureData[TextureIndex].G;
+				BufferData[BufferIndex].z = TextureData[TextureIndex].B;
+				BufferData[BufferIndex].w = TextureData[TextureIndex].A;
+
+			}
+		}
+
+		// TODO: Check if we can copy automatically via Memcpy
+		//FMemory::Memcpy(BufferData + (X * Y), TextureData, (X * Y * sizeof(FColor))); // Try copying the buffer data directly here TODO
+		Mip.BulkData.Unlock();
+		TextureBuffer->unmap();
+
+		TextureSampler->setBuffer(0u, 0u, TextureBuffer);
+		TextureSampler->setFilteringModes(RT_FILTER_NEAREST, RT_FILTER_NEAREST, RT_FILTER_NONE);
+
+		Data->OptiXGeometryInstance["frameTexture"]->setTextureSampler(TextureSampler);
+
+		Data->OptiXTransform->setMatrix(true, &Transform.M[0][0], &Inverse.M[0][0]);
+		Data->OptiXAcceleration->markDirty();
+		Data->OptiXAcceleration->getContext()["top_object"]->getGroup()->getAcceleration()->markDirty();
+
+	};
+
+	FOptiXModule::Get().GetOptiXContextManager()->EnqueueInitFunction(GetUniqueID(), InitFunction);
+
+}
+
+void UOptiXTargetComponent::SetSize(FVector NewSize)
+{
+	TargetSize = NewSize;
+	OptiXObjectUpdateFunction UpdateFunction = 
+		[&TargetSize = TargetSize](FOptiXObjectData* Data, TMap<FString, optix::Buffer>* Buffers, optix::TextureSampler TextureSampler) 
+		{
+			//OptiXGeometryInstance->SetFloat3DVector("size", TargetSize);
+			Data->OptiXGeometryInstance["size"]->setFloat(TargetSize.X, TargetSize.Y, TargetSize.Z);
+			Data->OptiXAcceleration->markDirty();
+			Data->OptiXAcceleration->getContext()["top_object"]->getGroup()->getAcceleration()->markDirty();
+		};
+
+	FOptiXModule::Get().GetOptiXContextManager()->EnqueueUpdateFunction(GetUniqueID(), UpdateFunction);
+}
+
+FVector UOptiXTargetComponent::GetSize()
+{
+	return TargetSize;
+}
diff --git a/Source/OptiX/Private/OptiXVRPawn.cpp b/Source/OptiX/Private/OptiXVRPawn.cpp
index 869b3d81896b32d81b1babc51531a2bbbb3f333b..672302c48f361d832670b133fed9838b0604713f 100644
--- a/Source/OptiX/Private/OptiXVRPawn.cpp
+++ b/Source/OptiX/Private/OptiXVRPawn.cpp
@@ -15,14 +15,13 @@ AOptiXVRPawn::AOptiXVRPawn()
 {
 	// Set this pawn to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
 	PrimaryActorTick.bCanEverTick = true;
-
 }
 
 // Called when the game starts or when spawned
 void AOptiXVRPawn::BeginPlay()
 {
 	Super::BeginPlay();
-
+	//HMDLocation = UGameplayStatics::GetPlayerController(GetWorld(), 0)->GetViewTarget()->GetActorLocation();
 }
 
 // Called every frame
@@ -38,7 +37,6 @@ void AOptiXVRPawn::Tick(float DeltaTime)
 void AOptiXVRPawn::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
 {
 	Super::SetupPlayerInputComponent(PlayerInputComponent);
-
 }
 
 void AOptiXVRPawn::UpdateTranslation(UPrimitiveComponent* Interaction)
@@ -183,4 +181,4 @@ AActor * AOptiXVRPawn::GetActorNearHand(UPrimitiveComponent * Hand)
 void AOptiXVRPawn::CaptureDeferredHelper(USceneCaptureComponent2D* SceneCapture)
 {
 	SceneCapture->CaptureSceneDeferred();
-}
\ No newline at end of file
+}
diff --git a/Source/OptiX/Private/OutlineStaticMeshComponent.cpp b/Source/OptiX/Private/OutlineStaticMeshComponent.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..206d64f83061a82f32152c785b0818c305f4b9f1
--- /dev/null
+++ b/Source/OptiX/Private/OutlineStaticMeshComponent.cpp
@@ -0,0 +1,58 @@
+// Fill out your copyright notice in the Description page of Project Settings.
+
+
+#include "OutlineStaticMeshComponent.h"
+#include "PrimitiveSceneProxy.h"
+#include "StaticMeshResources.h"
+#include "Engine/StaticMesh.h"
+
+
+FPrimitiveSceneProxy* UOutlineStaticMeshComponent::CreateSceneProxy()
+{
+
+	class FOutlineStaticMeshProxy final : public FStaticMeshSceneProxy
+	{
+	public:
+		SIZE_T GetTypeHash() const override
+		{
+			static size_t UniquePointer;
+			return reinterpret_cast<size_t>(&UniquePointer);
+		}
+
+		/** Initialization constructor. */
+		FOutlineStaticMeshProxy(UOutlineStaticMeshComponent* InComponent)
+			: FStaticMeshSceneProxy(InComponent, false)
+		{}
+
+		virtual void ApplyLateUpdateTransform(const FMatrix& LateUpdateTransform) override
+		{
+			// As the SetTransform function is private, this needs to be a little hacky
+
+			FMatrix NewTransform = GetLocalToWorld() * LateUpdateTransform;
+			FVector OriginChange = NewTransform.GetOrigin() - GetLocalToWorld().GetOrigin();
+			FMatrix ReducedLateUpdate = FMatrix::Identity;
+			ReducedLateUpdate.SetOrigin(OriginChange);
+
+			FStaticMeshSceneProxy::ApplyLateUpdateTransform(ReducedLateUpdate);
+		}
+	};
+
+	if (GetStaticMesh() == nullptr || GetStaticMesh()->RenderData == nullptr)
+	{
+		return nullptr;
+	}
+
+	const TIndirectArray<FStaticMeshLODResources>& LODResources = GetStaticMesh()->RenderData->LODResources;
+	if (LODResources.Num() == 0 || LODResources[FMath::Clamp<int32>(GetStaticMesh()->MinLOD.Default, 0, LODResources.Num() - 1)].VertexBuffers.StaticMeshVertexBuffer.GetNumVertices() == 0)
+	{
+		return nullptr;
+	}
+	LLM_SCOPE(ELLMTag::StaticMesh);
+
+	FPrimitiveSceneProxy* Proxy = ::new FOutlineStaticMeshProxy(this);
+#if STATICMESH_ENABLE_DEBUG_RENDERING
+	SendRenderDebugPhysics(Proxy);
+#endif
+
+	return Proxy;
+}
\ No newline at end of file
diff --git a/Source/OptiX/Private/SelectableActorBase.cpp b/Source/OptiX/Private/SelectableActorBase.cpp
index d8ef4014198a59cf828610d16dcaf43cf4ec5aed..004d8fedeea1f7e3d19e8f8b923b8a573596dfa2 100644
--- a/Source/OptiX/Private/SelectableActorBase.cpp
+++ b/Source/OptiX/Private/SelectableActorBase.cpp
@@ -6,8 +6,11 @@
 #include "Kismet/GameplayStatics.h"
 #include "Blueprint/UserWidget.h"
 #include "Runtime/Engine/Classes/Materials/MaterialInstanceDynamic.h"
+#include "UObject/FrameworkObjectVersion.h"
+
+#include "OutlineStaticMeshComponent.h"
+
 
-#include "OptiXVRPawn.h"
 #include "StatsDefines.h"
 
 ASelectableActorBase::ASelectableActorBase(const FObjectInitializer& ObjectInitializer)
@@ -16,10 +19,22 @@ ASelectableActorBase::ASelectableActorBase(const FObjectInitializer& ObjectIniti
 
 	UE_LOG(LogTemp, Display, TEXT("OptiX ASelectableActorBase Constructor Start"));
 
+	bCanBeDamaged = false;
+
+	StaticMeshComponent = CreateDefaultSubobject<UOutlineStaticMeshComponent>(TEXT("StaticMeshComponent0"));
+	StaticMeshComponent->SetCollisionProfileName(UCollisionProfile::BlockAll_ProfileName);
+	StaticMeshComponent->Mobility = EComponentMobility::Static;
+	StaticMeshComponent->SetGenerateOverlapEvents(false);
+	StaticMeshComponent->bUseDefaultCollision = true;
+
+	RootComponent = StaticMeshComponent;
+
 	SetMobility(EComponentMobility::Movable);
 
 	GetStaticMeshComponent()->SetGenerateOverlapEvents(true);
 	GetStaticMeshComponent()->CastShadow = 0;
+	GetStaticMeshComponent()->SetHiddenInGame(false);
+	GetStaticMeshComponent()->SetRenderInMainPass(false);
 
 	UE_LOG(LogTemp, Display, TEXT("OptiX ASelectableActorBase Constructor Component Setup Start"));
 
@@ -348,6 +363,8 @@ void ASelectableActorBase::BeginPlay()
 {
 	Super::BeginPlay();
 
+	OptiXVRPawn = Cast<AOptiXVRPawn>(UGameplayStatics::GetPlayerPawn(GetWorld(), 0));
+
 	ArrowX->CreateAndSetMaterialInstanceDynamicFromMaterial(0, ArrowX->GetMaterial(0));
 	ArrowX->CreateAndSetMaterialInstanceDynamicFromMaterial(1, ArrowX->GetMaterial(1));
 	ArrowY->CreateAndSetMaterialInstanceDynamicFromMaterial(0, ArrowY->GetMaterial(0));
@@ -380,8 +397,8 @@ void ASelectableActorBase::Tick(float DeltaTime)
 	Super::Tick(DeltaTime);
 	TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("ASelectableActorBase::Tick"))
 
-
-	FVector PlayerLocation = UGameplayStatics::GetPlayerPawn(GetWorld(), 0)->GetActorLocation();
+	//FVector PlayerLocation = UGameplayStatics::GetPlayerPawn(GetWorld(), 0)->GetActorLocation();
+	FVector PlayerLocation = OptiXVRPawn->HMDLocation;
 	{
 		FVector Diff = PlayerLocation - DegreeWidgetV->GetComponentTransform().GetLocation();
 		FVector Projected = FVector::VectorPlaneProject(Diff, FVector(0, 0, 1));
@@ -436,7 +453,6 @@ void ASelectableActorBase::EnableTranslation()
 	ArrowY->SetGenerateOverlapEvents(true);
 	ArrowZ->SetGenerateOverlapEvents(true);
 
-	AOptiXVRPawn* OptiXVRPawn = Cast<AOptiXVRPawn>(UGameplayStatics::GetPlayerPawn(GetWorld(), 0));
 	if (OptiXVRPawn)
 	{
 		OptiXVRPawn->UIEventTranslation();
@@ -455,7 +471,6 @@ void ASelectableActorBase::EnableRotation()
 	ArrowY->SetGenerateOverlapEvents(false);
 	ArrowZ->SetGenerateOverlapEvents(false);
 
-	AOptiXVRPawn* OptiXVRPawn = Cast<AOptiXVRPawn>(UGameplayStatics::GetPlayerPawn(GetWorld(), 0));
 	if (OptiXVRPawn)
 	{
 		OptiXVRPawn->UIEventRotation();
@@ -464,7 +479,6 @@ void ASelectableActorBase::EnableRotation()
 
 void ASelectableActorBase::DeselectActor()
 {
-	AOptiXVRPawn* OptiXVRPawn = Cast<AOptiXVRPawn>(UGameplayStatics::GetPlayerPawn(GetWorld(), 0));
 	if (OptiXVRPawn)
 	{
 		OptiXVRPawn->UIEventDeselect();
@@ -474,7 +488,6 @@ void ASelectableActorBase::DeselectActor()
 
 void ASelectableActorBase::DeleteActor()
 {
-	AOptiXVRPawn* OptiXVRPawn = Cast<AOptiXVRPawn>(UGameplayStatics::GetPlayerPawn(GetWorld(), 0));
 	if (OptiXVRPawn)
 	{
 		OptiXVRPawn->UIEventDelete();
@@ -550,3 +563,25 @@ void ASelectableActorBase::OnOverlapEnd_Implementation(UPrimitiveComponent* Over
 	//	Cast<UMaterialInstanceDynamic>(OverlappedComp->GetMaterial(i))->SetVectorParameterValue("Color", FLinearColor(0.4, 0.4, 0.4));
 	//}
 }
+
+FString ASelectableActorBase::GetDetailedInfoInternal() const
+{
+	return StaticMeshComponent ? StaticMeshComponent->GetDetailedInfoInternal() : TEXT("No_StaticMeshComponent");
+}
+
+void ASelectableActorBase::SetMobility(EComponentMobility::Type InMobility)
+{
+	if (StaticMeshComponent)
+	{
+		StaticMeshComponent->SetMobility(InMobility);
+	}
+}
+
+void ASelectableActorBase::Serialize(FArchive& Ar)
+{
+	Super::Serialize(Ar);
+#if WITH_EDITOR
+	Ar.UsingCustomVersion(FFrameworkObjectVersion::GUID);
+#endif
+}
+
diff --git a/Source/OptiX/Private/cuda/box_intersect_material.cu b/Source/OptiX/Private/cuda/box_intersect_material.cu
new file mode 100644
index 0000000000000000000000000000000000000000..644fe03ab14429c8c10f57b86da18eae0e74f39b
--- /dev/null
+++ b/Source/OptiX/Private/cuda/box_intersect_material.cu
@@ -0,0 +1,49 @@
+//------------------------------------------------------------------------------
+// Project Phoenix
+//
+// Copyright (c) 2017-2018 RWTH Aachen University, Germany,
+// Virtual Reality & Immersive Visualization Group.
+//------------------------------------------------------------------------------
+//                                 License
+//
+// Licensed under the 3-Clause BSD License (the "License");
+// you may not use this file except in compliance with the License.
+// See the file LICENSE for the full text.
+// You may obtain a copy of the License at
+//
+//     https://opensource.org/licenses/BSD-3-Clause
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//------------------------------------------------------------------------------
+
+#include <optix_world.h>
+#include "prd.h"
+
+rtDeclareVariable(PerRayData_radiance, prd_radiance, rtPayload, );
+rtDeclareVariable(PerRayData_radiance_iterative, prd_radiance_it, rtPayload, );
+rtTextureSampler<float4, 2> frameTexture;
+rtDeclareVariable(float2, texture_coord, attribute texture_coord, );
+rtDeclareVariable(float, hit_depth, rtIntersectionDistance, );
+rtDeclareVariable(optix::Ray, ray, rtCurrentRay, );
+
+RT_PROGRAM void closest_hit_radiance()
+{ 
+	if(texture_coord.x >= 0 && texture_coord.y >= 0){
+		prd_radiance.result = make_float3(tex2D(frameTexture, texture_coord.x, texture_coord.y)); 	
+	}else{
+		prd_radiance.result = make_float3(1.0f);
+	}
+	
+	prd_radiance.hit_depth = hit_depth;
+}
+
+RT_PROGRAM void closest_hit_iterative()
+{ 
+	float3 hit_point = ray.origin + hit_depth * ray.direction;
+	prd_radiance_it.origin = hit_point;
+	prd_radiance_it.done = true;
+}
diff --git a/Source/OptiX/Private/cuda/glass_iterative_camera.cu b/Source/OptiX/Private/cuda/glass_iterative_camera.cu
index d00726dd26d909997b3f9d7f24b43e2f1d327e47..338106baeb3fced7fb159fa7a48a52ca6c7ec586 100644
--- a/Source/OptiX/Private/cuda/glass_iterative_camera.cu
+++ b/Source/OptiX/Private/cuda/glass_iterative_camera.cu
@@ -47,7 +47,7 @@ rtDeclareVariable(float, laserWaveLength, , );
 
 rtDeclareVariable(PerRayData_radiance_iterative, prd_radiance, rtPayload, );
 
-RT_PROGRAM void closest_hit_radiance()
+RT_PROGRAM void closest_hit_iterative()
 {
 	prd_radiance.hit_lens = 1;
 
diff --git a/Source/OptiX/Private/cuda/laser_target_material.cu b/Source/OptiX/Private/cuda/laser_target_material.cu
index a6d5695810e30579edff85c420bf13085f71380f..f95f4783d9100a6ea73a0abf134347f8ff4b2590 100644
--- a/Source/OptiX/Private/cuda/laser_target_material.cu
+++ b/Source/OptiX/Private/cuda/laser_target_material.cu
@@ -47,6 +47,11 @@ RT_PROGRAM void any_hit_radiance(){
 	//prd_radiance.hit_depth = hit_depth;
 }
 
+RT_PROGRAM void closest_hit_radiance()
+{ 
+	//rtIgnoreIntersection();
+}
+
 RT_PROGRAM void closest_hit_iterative()
 { 
 	float3 hit_point = ray.origin + hit_depth * ray.direction;
diff --git a/Source/OptiX/Private/cuda/lens_parametric_material.cu b/Source/OptiX/Private/cuda/lens_parametric_material.cu
new file mode 100644
index 0000000000000000000000000000000000000000..eef16660083386510a8bf20f229cfdf90107d2f6
--- /dev/null
+++ b/Source/OptiX/Private/cuda/lens_parametric_material.cu
@@ -0,0 +1,176 @@
+/* 
+ * Copyright(c)2017 NVIDIA CORPORATION. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of NVIDIA CORPORATION nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES(INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION)HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *(INCLUDING NEGLIGENCE OR OTHERWISE)ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <optix.h>
+#include <optixu/optixu_math_namespace.h>
+#include "helpers.h"
+#include "prd.h"
+
+using namespace optix;
+
+rtDeclareVariable(rtObject, top_object, ,);
+rtDeclareVariable(float, scene_epsilon, ,);
+rtDeclareVariable(int, max_depth, ,);
+
+rtDeclareVariable(float3, shading_normal, attribute shading_normal,); 
+rtDeclareVariable(float3, front_hit_point, attribute front_hit_point,);
+rtDeclareVariable(float3, back_hit_point, attribute back_hit_point,);
+
+rtDeclareVariable(float, hit_depth, rtIntersectionDistance,);
+rtDeclareVariable(optix::Ray, ray, rtCurrentRay,);
+
+rtDeclareVariable(float, importance_cutoff, ,);
+rtDeclareVariable(float3, cutoff_color, ,);
+rtDeclareVariable(float, fresnel_exponent, ,);
+rtDeclareVariable(float, fresnel_minimum, ,);
+rtDeclareVariable(float, fresnel_maximum, ,);
+rtDeclareVariable(float, refraction_index, ,);
+rtDeclareVariable(int, refraction_maxdepth, ,);
+rtDeclareVariable(int, reflection_maxdepth, ,);
+rtDeclareVariable(float3, refraction_color, ,);
+rtDeclareVariable(float3, reflection_color, ,);
+rtDeclareVariable(float3, extinction_constant, ,);
+rtDeclareVariable(int, lens_id, ,);
+
+rtDeclareVariable(int, allowTir, , );
+rtDeclareVariable(float, laserWaveLength, , );
+
+rtDeclareVariable(PerRayData_radiance, prd_radiance, rtPayload,);
+rtDeclareVariable(PerRayData_radiance_iterative, prd_radiance_it, rtPayload, );
+
+// -----------------------------------------------------------------------------
+
+static __device__ __inline__ float3 TraceRay(float3 origin, float3 direction, int depth, float importance, float hit_depth, unsigned int flags, int last_lens_id)
+{
+ optix::Ray ray = optix::make_Ray(origin, direction, 0, 0.0f, RT_DEFAULT_MAX);
+ PerRayData_radiance prd;
+ prd.depth = depth;
+ prd.importance = importance;
+ prd.hit_depth = hit_depth;
+ prd.flags = flags;
+ prd.last_lens_id = last_lens_id;
+ 
+ rtTrace(top_object, ray, prd);
+ return prd.result;
+}
+
+static __device__ __inline__ float3 exp(const float3& x){
+ return make_float3(exp(x.x), exp(x.y), exp(x.z));
+}
+
+// -----------------------------------------------------------------------------
+
+RT_PROGRAM void closest_hit_radiance(){
+
+	unsigned int hit_lens = (prd_radiance.flags >> 1);
+	if(hit_lens == 0) prd_radiance.hit_depth = hit_depth;
+	prd_radiance.flags = prd_radiance.flags | 2;
+	prd_radiance.last_lens_id = lens_id;
+
+	// intersection vectors
+	const float3 n = normalize(rtTransformNormal(RT_OBJECT_TO_WORLD, shading_normal)); // normal
+	const float3 fhp = rtTransformPoint(RT_OBJECT_TO_WORLD, front_hit_point);
+	const float3 bhp = rtTransformPoint(RT_OBJECT_TO_WORLD, back_hit_point);
+	const float3 i = ray.direction; // incident direction
+	float3 t; // transmission direction
+	float3 r; // reflection direction
+
+	float reflection = 1.0f;
+	float3 result = make_float3(0.0f);
+
+	const int depth = prd_radiance.depth;
+
+	float3 beer_attenuation;
+	if(dot(n, ray.direction) > 0){
+		// Beer's law attenuation
+		beer_attenuation = exp(extinction_constant * (hit_depth / 100));
+	} else {
+		beer_attenuation = make_float3(1);
+	}
+
+	// refraction
+	if(depth < min(refraction_maxdepth, max_depth)){
+		if(refract(t, i, n, refraction_index)){
+			// check for external or internal reflection
+			float cos_theta = dot(i, n);
+			cos_theta = (cos_theta < 0.0f) * -cos_theta + (cos_theta >= 0.0f) * dot(t, n);
+			
+			reflection = fresnel_schlick(cos_theta, fresnel_exponent, fresnel_minimum, fresnel_maximum);
+
+			float importance = prd_radiance.importance * (1.0f-reflection) * optix::luminance(refraction_color * beer_attenuation);
+			float3 color = cutoff_color;
+			if(importance > importance_cutoff){
+				color = TraceRay(bhp, t, depth+1, importance, prd_radiance.hit_depth, prd_radiance.flags, prd_radiance.last_lens_id);
+			}
+			result +=(1.0f - reflection)* refraction_color * color;
+		}
+		// else TIR
+	} // else reflection==1 so refraction has 0 weight
+
+	// reflection
+	float3 color = cutoff_color;
+	if(depth < min(reflection_maxdepth, max_depth)){
+		r = reflect(i, n);
+
+		float importance = prd_radiance.importance * reflection * optix::luminance(reflection_color * beer_attenuation);
+		if(importance > importance_cutoff){
+			color = TraceRay(fhp, r, depth+1, importance, prd_radiance.hit_depth, prd_radiance.flags, prd_radiance.last_lens_id);
+		}
+	}
+	result += reflection * reflection_color * color;
+
+	result = result * beer_attenuation;
+
+	prd_radiance.result = result;
+}
+
+RT_PROGRAM void closest_hit_iterative()
+{
+	prd_radiance_it.hit_lens = 1;
+
+	const float3 w_out = -ray.direction;
+	float3 normal = normalize(rtTransformNormal(RT_OBJECT_TO_WORLD, shading_normal));
+
+	float cos_theta_i = optix::dot( w_out, normal );
+	float eta = ( cos_theta_i > 0.0f ) * refraction_index + ( cos_theta_i <= 0.0f ) * 1.0f / refraction_index;
+	normal =  ( cos_theta_i > 0.0f ) * normal + ( cos_theta_i <= 0.0f ) * -normal;
+	
+	float3 w_t;
+	const bool tir = !optix::refract( w_t, -w_out, normal, eta );
+	
+	const float3 w_in = (tir > 0) * optix::reflect( -w_out, normal ) + (tir <= 0) * w_t; 
+	const float3 fhp = rtTransformPoint(RT_OBJECT_TO_WORLD, front_hit_point);
+	const float3 bhp = rtTransformPoint(RT_OBJECT_TO_WORLD, back_hit_point);
+	
+	prd_radiance_it.origin = (tir > 0) * fhp + (tir <= 0) * bhp;
+	prd_radiance_it.direction = w_in; 
+	prd_radiance_it.done = !allowTir && tir;
+
+ // Note: we do not trace the ray for the next bounce here, we just set it up for
+ // the ray-gen program using per-ray data.
+}
\ No newline at end of file
diff --git a/Source/OptiX/Private/cuda/frame_material.cu b/Source/OptiX/Private/cuda/tmp/frame_material.cu
similarity index 97%
rename from Source/OptiX/Private/cuda/frame_material.cu
rename to Source/OptiX/Private/cuda/tmp/frame_material.cu
index ed30232bca8f77163174630d4d64992dca991e95..644fe03ab14429c8c10f57b86da18eae0e74f39b 100644
--- a/Source/OptiX/Private/cuda/frame_material.cu
+++ b/Source/OptiX/Private/cuda/tmp/frame_material.cu
@@ -1,49 +1,49 @@
-//------------------------------------------------------------------------------
-// Project Phoenix
-//
-// Copyright (c) 2017-2018 RWTH Aachen University, Germany,
-// Virtual Reality & Immersive Visualization Group.
-//------------------------------------------------------------------------------
-//                                 License
-//
-// Licensed under the 3-Clause BSD License (the "License");
-// you may not use this file except in compliance with the License.
-// See the file LICENSE for the full text.
-// You may obtain a copy of the License at
-//
-//     https://opensource.org/licenses/BSD-3-Clause
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//------------------------------------------------------------------------------
-
-#include <optix_world.h>
-#include "prd.h"
-
-rtDeclareVariable(PerRayData_radiance, prd_radiance, rtPayload, );
-rtDeclareVariable(PerRayData_radiance_iterative, prd_radiance_it, rtPayload, );
-rtTextureSampler<float4, 2> frameTexture;
-rtDeclareVariable(float2, texture_coord, attribute texture_coord, );
-rtDeclareVariable(float, hit_depth, rtIntersectionDistance, );
-rtDeclareVariable(optix::Ray, ray, rtCurrentRay, );
-
-RT_PROGRAM void closest_hit_radiance()
-{ 
-	if(texture_coord.x >= 0 && texture_coord.y >= 0){
-		prd_radiance.result = make_float3(tex2D(frameTexture, texture_coord.x, texture_coord.y)); 	
-	}else{
-		prd_radiance.result = make_float3(1.0f);
-	}
-	
-	prd_radiance.hit_depth = hit_depth;
-}
-
-RT_PROGRAM void closest_hit_iterative()
-{ 
-	float3 hit_point = ray.origin + hit_depth * ray.direction;
-	prd_radiance_it.origin = hit_point;
-	prd_radiance_it.done = true;
-}
+//------------------------------------------------------------------------------
+// Project Phoenix
+//
+// Copyright (c) 2017-2018 RWTH Aachen University, Germany,
+// Virtual Reality & Immersive Visualization Group.
+//------------------------------------------------------------------------------
+//                                 License
+//
+// Licensed under the 3-Clause BSD License (the "License");
+// you may not use this file except in compliance with the License.
+// See the file LICENSE for the full text.
+// You may obtain a copy of the License at
+//
+//     https://opensource.org/licenses/BSD-3-Clause
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//------------------------------------------------------------------------------
+
+#include <optix_world.h>
+#include "prd.h"
+
+rtDeclareVariable(PerRayData_radiance, prd_radiance, rtPayload, );
+rtDeclareVariable(PerRayData_radiance_iterative, prd_radiance_it, rtPayload, );
+rtTextureSampler<float4, 2> frameTexture;
+rtDeclareVariable(float2, texture_coord, attribute texture_coord, );
+rtDeclareVariable(float, hit_depth, rtIntersectionDistance, );
+rtDeclareVariable(optix::Ray, ray, rtCurrentRay, );
+
+RT_PROGRAM void closest_hit_radiance()
+{ 
+	if(texture_coord.x >= 0 && texture_coord.y >= 0){
+		prd_radiance.result = make_float3(tex2D(frameTexture, texture_coord.x, texture_coord.y)); 	
+	}else{
+		prd_radiance.result = make_float3(1.0f);
+	}
+	
+	prd_radiance.hit_depth = hit_depth;
+}
+
+RT_PROGRAM void closest_hit_iterative()
+{ 
+	float3 hit_point = ray.origin + hit_depth * ray.direction;
+	prd_radiance_it.origin = hit_point;
+	prd_radiance_it.done = true;
+}
diff --git a/Source/OptiX/Private/cuda/tmp/glass_iterative_camera.cu b/Source/OptiX/Private/cuda/tmp/glass_iterative_camera.cu
new file mode 100644
index 0000000000000000000000000000000000000000..e0754b8d479ae2e23a084f017888fb62c501fec4
--- /dev/null
+++ b/Source/OptiX/Private/cuda/tmp/glass_iterative_camera.cu
@@ -0,0 +1,76 @@
+/* 
+ * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of NVIDIA CORPORATION nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <optix.h>
+#include <optixu/optixu_math_namespace.h>
+#include "prd.h"
+#include "random.h"
+
+using namespace optix;
+
+rtDeclareVariable(float3, shading_normal, attribute shading_normal, ); 
+rtDeclareVariable(float3, front_hit_point, attribute front_hit_point, );
+rtDeclareVariable(float3, back_hit_point, attribute back_hit_point, );
+
+rtDeclareVariable(optix::Ray, ray, rtCurrentRay, );
+rtDeclareVariable(float, t_hit, rtIntersectionDistance, );
+
+rtDeclareVariable(int, allowTir, , );
+
+rtDeclareVariable(float, refraction_index, , );
+rtDeclareVariable(float, laserWaveLength, , );
+
+rtDeclareVariable(PerRayData_radiance_iterative, prd_radiance, rtPayload, );
+
+RT_PROGRAM void closest_hit_radiance()
+{
+	prd_radiance.hit_lens = 1;
+
+	const float3 w_out = -ray.direction;
+	float3 normal = normalize(rtTransformNormal(RT_OBJECT_TO_WORLD, shading_normal));
+
+	float cos_theta_i = optix::dot( w_out, normal );
+	float eta = ( cos_theta_i > 0.0f ) * refraction_index + ( cos_theta_i <= 0.0f ) * 1.0f / refraction_index;
+	normal =  ( cos_theta_i > 0.0f ) * normal + ( cos_theta_i <= 0.0f ) * -normal;
+	
+	float3 w_t;
+	const bool tir = !optix::refract( w_t, -w_out, normal, eta );
+	
+	const float3 w_in = (tir > 0) * optix::reflect( -w_out, normal ) + (tir <= 0) * w_t; 
+	const float3 fhp = rtTransformPoint(RT_OBJECT_TO_WORLD, front_hit_point);
+	const float3 bhp = rtTransformPoint(RT_OBJECT_TO_WORLD, back_hit_point);
+	
+	prd_radiance.origin = (tir > 0) * fhp + (tir <= 0) * bhp;
+	prd_radiance.direction = w_in; 
+	prd_radiance.done = !allowTir && tir;
+
+ // Note: we do not trace the ray for the next bounce here, we just set it up for
+ // the ray-gen program using per-ray data.
+}
+
+
diff --git a/Source/OptiX/Private/cuda/glass_perspective_camera.cu b/Source/OptiX/Private/cuda/tmp/glass_perspective_camera.cu
similarity index 97%
rename from Source/OptiX/Private/cuda/glass_perspective_camera.cu
rename to Source/OptiX/Private/cuda/tmp/glass_perspective_camera.cu
index 91ed1655d1bbdf504cd5803d9f0eb5db3946895c..a72b2a83229ab654dc59f952a0ed3bb7a9db8e43 100644
--- a/Source/OptiX/Private/cuda/glass_perspective_camera.cu
+++ b/Source/OptiX/Private/cuda/tmp/glass_perspective_camera.cu
@@ -1,146 +1,146 @@
-/* 
- * Copyright(c)2017 NVIDIA CORPORATION. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * * Neither the name of NVIDIA CORPORATION nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES(INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION)HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- *(INCLUDING NEGLIGENCE OR OTHERWISE)ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <optix.h>
-#include <optixu/optixu_math_namespace.h>
-#include "helpers.h"
-#include "prd.h"
-
-using namespace optix;
-
-rtDeclareVariable(rtObject, top_object, ,);
-rtDeclareVariable(float, scene_epsilon, ,);
-rtDeclareVariable(int, max_depth, ,);
-
-rtDeclareVariable(float3, shading_normal, attribute shading_normal,); 
-rtDeclareVariable(float3, front_hit_point, attribute front_hit_point,);
-rtDeclareVariable(float3, back_hit_point, attribute back_hit_point,);
-
-rtDeclareVariable(float, hit_depth, rtIntersectionDistance,);
-rtDeclareVariable(optix::Ray, ray, rtCurrentRay,);
-
-rtDeclareVariable(float, importance_cutoff, ,);
-rtDeclareVariable(float3, cutoff_color, ,);
-rtDeclareVariable(float, fresnel_exponent, ,);
-rtDeclareVariable(float, fresnel_minimum, ,);
-rtDeclareVariable(float, fresnel_maximum, ,);
-rtDeclareVariable(float, refraction_index, ,);
-rtDeclareVariable(int, refraction_maxdepth, ,);
-rtDeclareVariable(int, reflection_maxdepth, ,);
-rtDeclareVariable(float3, refraction_color, ,);
-rtDeclareVariable(float3, reflection_color, ,);
-rtDeclareVariable(float3, extinction_constant, ,);
-rtDeclareVariable(int, lens_id, ,);
-
-rtDeclareVariable(PerRayData_radiance, prd_radiance, rtPayload,);
-
-// -----------------------------------------------------------------------------
-
-static __device__ __inline__ float3 TraceRay(float3 origin, float3 direction, int depth, float importance, float hit_depth, unsigned int flags, int last_lens_id)
-{
- optix::Ray ray = optix::make_Ray(origin, direction, 0, 0.0f, RT_DEFAULT_MAX);
- PerRayData_radiance prd;
- prd.depth = depth;
- prd.importance = importance;
- prd.hit_depth = hit_depth;
- prd.flags = flags;
- prd.last_lens_id = last_lens_id;
- 
- rtTrace(top_object, ray, prd);
- return prd.result;
-}
-
-static __device__ __inline__ float3 exp(const float3& x){
- return make_float3(exp(x.x), exp(x.y), exp(x.z));
-}
-
-// -----------------------------------------------------------------------------
-
-RT_PROGRAM void closest_hit_radiance(){
-
-	unsigned int hit_lens = (prd_radiance.flags >> 1);
-	if(hit_lens == 0) prd_radiance.hit_depth = hit_depth;
-	prd_radiance.flags = prd_radiance.flags | 2;
-	prd_radiance.last_lens_id = lens_id;
-
-	// intersection vectors
-	const float3 n = normalize(rtTransformNormal(RT_OBJECT_TO_WORLD, shading_normal)); // normal
-	const float3 fhp = rtTransformPoint(RT_OBJECT_TO_WORLD, front_hit_point);
-	const float3 bhp = rtTransformPoint(RT_OBJECT_TO_WORLD, back_hit_point);
-	const float3 i = ray.direction; // incident direction
-	float3 t; // transmission direction
-	float3 r; // reflection direction
-
-	float reflection = 1.0f;
-	float3 result = make_float3(0.0f);
-
-	const int depth = prd_radiance.depth;
-
-	float3 beer_attenuation;
-	if(dot(n, ray.direction) > 0){
-		// Beer's law attenuation
-		beer_attenuation = exp(extinction_constant * (hit_depth / 100));
-	} else {
-		beer_attenuation = make_float3(1);
-	}
-
-	// refraction
-	if(depth < min(refraction_maxdepth, max_depth)){
-		if(refract(t, i, n, refraction_index)){
-			// check for external or internal reflection
-			float cos_theta = dot(i, n);
-			cos_theta = (cos_theta < 0.0f) * -cos_theta + (cos_theta >= 0.0f) * dot(t, n);
-			
-			reflection = fresnel_schlick(cos_theta, fresnel_exponent, fresnel_minimum, fresnel_maximum);
-
-			float importance = prd_radiance.importance * (1.0f-reflection) * optix::luminance(refraction_color * beer_attenuation);
-			float3 color = cutoff_color;
-			if(importance > importance_cutoff){
-				color = TraceRay(bhp, t, depth+1, importance, prd_radiance.hit_depth, prd_radiance.flags, prd_radiance.last_lens_id);
-			}
-			result +=(1.0f - reflection)* refraction_color * color;
-		}
-		// else TIR
-	} // else reflection==1 so refraction has 0 weight
-
-	// reflection
-	float3 color = cutoff_color;
-	if(depth < min(reflection_maxdepth, max_depth)){
-		r = reflect(i, n);
-
-		float importance = prd_radiance.importance * reflection * optix::luminance(reflection_color * beer_attenuation);
-		if(importance > importance_cutoff){
-			color = TraceRay(fhp, r, depth+1, importance, prd_radiance.hit_depth, prd_radiance.flags, prd_radiance.last_lens_id);
-		}
-	}
-	result += reflection * reflection_color * color;
-
-	result = result * beer_attenuation;
-
-	prd_radiance.result = result;
-}
+/* 
+ * Copyright(c)2017 NVIDIA CORPORATION. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of NVIDIA CORPORATION nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES(INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION)HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *(INCLUDING NEGLIGENCE OR OTHERWISE)ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <optix.h>
+#include <optixu/optixu_math_namespace.h>
+#include "helpers.h"
+#include "prd.h"
+
+using namespace optix;
+
+rtDeclareVariable(rtObject, top_object, ,);
+rtDeclareVariable(float, scene_epsilon, ,);
+rtDeclareVariable(int, max_depth, ,);
+
+rtDeclareVariable(float3, shading_normal, attribute shading_normal,); 
+rtDeclareVariable(float3, front_hit_point, attribute front_hit_point,);
+rtDeclareVariable(float3, back_hit_point, attribute back_hit_point,);
+
+rtDeclareVariable(float, hit_depth, rtIntersectionDistance,);
+rtDeclareVariable(optix::Ray, ray, rtCurrentRay,);
+
+rtDeclareVariable(float, importance_cutoff, ,);
+rtDeclareVariable(float3, cutoff_color, ,);
+rtDeclareVariable(float, fresnel_exponent, ,);
+rtDeclareVariable(float, fresnel_minimum, ,);
+rtDeclareVariable(float, fresnel_maximum, ,);
+rtDeclareVariable(float, refraction_index, ,);
+rtDeclareVariable(int, refraction_maxdepth, ,);
+rtDeclareVariable(int, reflection_maxdepth, ,);
+rtDeclareVariable(float3, refraction_color, ,);
+rtDeclareVariable(float3, reflection_color, ,);
+rtDeclareVariable(float3, extinction_constant, ,);
+rtDeclareVariable(int, lens_id, ,);
+
+rtDeclareVariable(PerRayData_radiance, prd_radiance, rtPayload,);
+
+// -----------------------------------------------------------------------------
+
+static __device__ __inline__ float3 TraceRay(float3 origin, float3 direction, int depth, float importance, float hit_depth, unsigned int flags, int last_lens_id)
+{
+ optix::Ray ray = optix::make_Ray(origin, direction, 0, 0.0f, RT_DEFAULT_MAX);
+ PerRayData_radiance prd;
+ prd.depth = depth;
+ prd.importance = importance;
+ prd.hit_depth = hit_depth;
+ prd.flags = flags;
+ prd.last_lens_id = last_lens_id;
+ 
+ rtTrace(top_object, ray, prd);
+ return prd.result;
+}
+
+static __device__ __inline__ float3 exp(const float3& x){
+ return make_float3(exp(x.x), exp(x.y), exp(x.z));
+}
+
+// -----------------------------------------------------------------------------
+
+RT_PROGRAM void closest_hit_radiance(){
+
+	unsigned int hit_lens = (prd_radiance.flags >> 1);
+	if(hit_lens == 0) prd_radiance.hit_depth = hit_depth;
+	prd_radiance.flags = prd_radiance.flags | 2;
+	prd_radiance.last_lens_id = lens_id;
+
+	// intersection vectors
+	const float3 n = normalize(rtTransformNormal(RT_OBJECT_TO_WORLD, shading_normal)); // normal
+	const float3 fhp = rtTransformPoint(RT_OBJECT_TO_WORLD, front_hit_point);
+	const float3 bhp = rtTransformPoint(RT_OBJECT_TO_WORLD, back_hit_point);
+	const float3 i = ray.direction; // incident direction
+	float3 t; // transmission direction
+	float3 r; // reflection direction
+
+	float reflection = 1.0f;
+	float3 result = make_float3(0.0f);
+
+	const int depth = prd_radiance.depth;
+
+	float3 beer_attenuation;
+	if(dot(n, ray.direction) > 0){
+		// Beer's law attenuation
+		beer_attenuation = exp(extinction_constant * (hit_depth / 100));
+	} else {
+		beer_attenuation = make_float3(1);
+	}
+
+	// refraction
+	if(depth < min(refraction_maxdepth, max_depth)){
+		if(refract(t, i, n, refraction_index)){
+			// check for external or internal reflection
+			float cos_theta = dot(i, n);
+			cos_theta = (cos_theta < 0.0f) * -cos_theta + (cos_theta >= 0.0f) * dot(t, n);
+			
+			reflection = fresnel_schlick(cos_theta, fresnel_exponent, fresnel_minimum, fresnel_maximum);
+
+			float importance = prd_radiance.importance * (1.0f-reflection) * optix::luminance(refraction_color * beer_attenuation);
+			float3 color = cutoff_color;
+			if(importance > importance_cutoff){
+				color = TraceRay(bhp, t, depth+1, importance, prd_radiance.hit_depth, prd_radiance.flags, prd_radiance.last_lens_id);
+			}
+			result +=(1.0f - reflection)* refraction_color * color;
+		}
+		// else TIR
+	} // else reflection==1 so refraction has 0 weight
+
+	// reflection
+	float3 color = cutoff_color;
+	if(depth < min(reflection_maxdepth, max_depth)){
+		r = reflect(i, n);
+
+		float importance = prd_radiance.importance * reflection * optix::luminance(reflection_color * beer_attenuation);
+		if(importance > importance_cutoff){
+			color = TraceRay(fhp, r, depth+1, importance, prd_radiance.hit_depth, prd_radiance.flags, prd_radiance.last_lens_id);
+		}
+	}
+	result += reflection * reflection_color * color;
+
+	result = result * beer_attenuation;
+
+	prd_radiance.result = result;
+}
diff --git a/Source/OptiX/Public/OptiXCameraActor.h b/Source/OptiX/Public/OptiXCameraActor.h
index 86e5336755612e10b37aeb8a882eed6e697abb0a..cbb36016a6d549fb05153881fbc22f9b85e36b34 100644
--- a/Source/OptiX/Public/OptiXCameraActor.h
+++ b/Source/OptiX/Public/OptiXCameraActor.h
@@ -1,100 +1,100 @@
-#pragma once
-
-#include "CoreMinimal.h"
-#include "UObject/ObjectMacros.h"
-#include "Runtime/Engine/Classes/Camera/PlayerCameraManager.h"
-#include "OptiXContext.h"
-#include "Runtime/Engine/Classes/Components/SceneCaptureComponent2D.h"
-#include "Runtime/Engine/Classes/Engine/TextureRenderTarget2D.h"
-#include "Runtime/Engine/Classes/Components/SceneCaptureComponentCube.h"
-#include "Engine/BlendableInterface.h"
-#include "Runtime/Engine/Classes/Components/PostProcessComponent.h"
-
-#include "OptiXCameraActor.generated.h"
-
-DECLARE_LOG_CATEGORY_EXTERN(OptiXPluginCameraActor, Log, All);
-
-
-UCLASS(Blueprintable, BlueprintType)
-class OPTIX_API UOptiXBlendable : public UObject, public IBlendableInterface
-{
-	GENERATED_BODY()
-
-public:
-
-	UOptiXBlendable(const FObjectInitializer& ObjectInitializer);
-
-
-	/** 0:no effect, 1:full effect */
-	UPROPERTY(interp, Category = OptiXBlendable, BlueprintReadWrite, meta = (UIMin = "0.0", UIMax = "1.0"))
-	float BlendWeight;
-
-	// Begin interface IBlendableInterface
-	virtual void OverrideBlendableSettings(class FSceneView& View, float InWeight) const override;
-	// End interface IBlendableInterface
-
-};
-
-UCLASS(hidecategories = (Input))
-class OPTIX_API AOptiXPlayerCameraManager : public APlayerCameraManager
-{
-	GENERATED_BODY()
-
-public:
-
-	AOptiXPlayerCameraManager(const FObjectInitializer& ObjectInitializer);
-
-
-	//AOptiXCameraActor(const FObjectInitializer& ObjectInitializer);
-
-
-	virtual void BeginPlay() override;
-	virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
-	virtual void Tick(float DeltaSeconds) override;
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXActor")
-	void Init();
-	
-	
-public:
-
-
-	UPROPERTY(BlueprintReadOnly, Category = OptiX)
-	TArray<UTextureRenderTarget2D*> CubemapRenderTargets;
-
-	UPROPERTY(BlueprintReadOnly, Category = OptiX)
-	USceneCaptureComponent2D* SceneCaptureComponent;
-
-	// Try the cubemap again
-
-	UPROPERTY(BlueprintReadOnly, Category = OptiX)
-	USceneCaptureComponentCube* SceneCaptureCubeComponent;
-
-	UPROPERTY(BlueprintReadOnly, Category = OptiX)
-	UTextureRenderTargetCube* CubeRenderTarget;
-
-	UPROPERTY(BlueprintReadOnly, Category = OptiX)
-	UPostProcessComponent* PostProcessComponent;
-
-	UPROPERTY(BlueprintReadOnly, Category = OptiX)
-	UMaterialInstanceDynamic* BlendableVR;
-
-	UPROPERTY(BlueprintReadOnly, Category = OptiX)
-	UMaterialInstanceDynamic* BlendableOrtho;
-
-
-	
-	FThreadSafeBool bCubemapCaptured = false;
-	
-private:
-
-
-	void CaptureCubemap();
-
-private:
-
-	uint32 CubemapSize = 1024;
-
-	uint32 C = 0;
-
+#pragma once
+
+#include "CoreMinimal.h"
+#include "UObject/ObjectMacros.h"
+#include "Runtime/Engine/Classes/Camera/PlayerCameraManager.h"
+//#include "OptiXContext.h"
+#include "Runtime/Engine/Classes/Components/SceneCaptureComponent2D.h"
+#include "Runtime/Engine/Classes/Engine/TextureRenderTarget2D.h"
+#include "Runtime/Engine/Classes/Components/SceneCaptureComponentCube.h"
+#include "Engine/BlendableInterface.h"
+#include "Runtime/Engine/Classes/Components/PostProcessComponent.h"
+
+#include "OptiXCameraActor.generated.h"
+
+DECLARE_LOG_CATEGORY_EXTERN(OptiXPluginCameraActor, Log, All);
+
+
+UCLASS(Blueprintable, BlueprintType)
+class OPTIX_API UOptiXBlendable : public UObject, public IBlendableInterface
+{
+	GENERATED_BODY()
+
+public:
+
+	UOptiXBlendable(const FObjectInitializer& ObjectInitializer);
+
+
+	/** 0:no effect, 1:full effect */
+	UPROPERTY(interp, Category = OptiXBlendable, BlueprintReadWrite, meta = (UIMin = "0.0", UIMax = "1.0"))
+	float BlendWeight;
+
+	// Begin interface IBlendableInterface
+	virtual void OverrideBlendableSettings(class FSceneView& View, float InWeight) const override;
+	// End interface IBlendableInterface
+
+};
+
+UCLASS(hidecategories = (Input))
+class OPTIX_API AOptiXPlayerCameraManager : public APlayerCameraManager
+{
+	GENERATED_BODY()
+
+public:
+
+	AOptiXPlayerCameraManager(const FObjectInitializer& ObjectInitializer);
+
+
+	//AOptiXCameraActor(const FObjectInitializer& ObjectInitializer);
+
+
+	virtual void BeginPlay() override;
+	virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
+	virtual void Tick(float DeltaSeconds) override;
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXActor")
+	void Init();
+	
+	
+public:
+
+
+	UPROPERTY(BlueprintReadOnly, Category = OptiX)
+	TArray<UTextureRenderTarget2D*> CubemapRenderTargets;
+
+	UPROPERTY(BlueprintReadOnly, Category = OptiX)
+	USceneCaptureComponent2D* SceneCaptureComponent;
+
+	// Try the cubemap again
+
+	UPROPERTY(BlueprintReadOnly, Category = OptiX)
+	USceneCaptureComponentCube* SceneCaptureCubeComponent;
+
+	UPROPERTY(BlueprintReadOnly, Category = OptiX)
+	UTextureRenderTargetCube* CubeRenderTarget;
+
+	UPROPERTY(BlueprintReadOnly, Category = OptiX)
+	UPostProcessComponent* PostProcessComponent;
+
+	UPROPERTY(BlueprintReadOnly, Category = OptiX)
+	UMaterialInstanceDynamic* BlendableVR;
+
+	UPROPERTY(BlueprintReadOnly, Category = OptiX)
+	UMaterialInstanceDynamic* BlendableOrtho;
+
+
+	
+	FThreadSafeBool bCubemapCaptured = false;
+	
+private:
+
+
+	void CaptureCubemap();
+
+private:
+
+	uint32 CubemapSize = 1024;
+
+	uint32 C = 0;
+
 };
\ No newline at end of file
diff --git a/Source/OptiX/Public/OptiXContextManager.h b/Source/OptiX/Public/OptiXContextManager.h
index 75528d9269447fdb7eb3a3d04097a1816ac26c7a..d36899518e2b57bcc19920716505d9698b6a4dd3 100644
--- a/Source/OptiX/Public/OptiXContextManager.h
+++ b/Source/OptiX/Public/OptiXContextManager.h
@@ -11,14 +11,16 @@
 #include "Materials/MaterialInstance.h"
 #include "Delegates/Delegate.h"
 
-#include "OptiXContext.h"
+//#include "OptiXContext.h"
+#include "OptiXIncludes.h"
+
 #include "OptiXObjectComponent.h"
 #include "OptiXLaserComponent.h"
 #include "OptiXLaserActor.h"
 #include "OptiXCameraActor.h"
 #include "StatsDefines.h"
 
-
+DECLARE_LOG_CATEGORY_EXTERN(OptiXContextManagerLog, Log, All);
 
 // Let's try some events!
 
@@ -36,8 +38,9 @@ DECLARE_MULTICAST_DELEGATE(FOnSceneChangedDelegate);
 #include "HideWindowsPlatformTypes.h"
 #endif
 
-// print cuda error helper:
-
+/**
+* Cuda error print function. Polls the latest cuda error and logs it. 
+*/
 inline void PrintLastCudaError(FString Msg)
 {
 	cudaError_t Err = cudaGetLastError();
@@ -46,54 +49,108 @@ inline void PrintLastCudaError(FString Msg)
 	}
 }
 
+/**
+* Struct storing the optix objects that typically form an unreal optix object component.
+*/
+struct FOptiXObjectData
+{
+	optix::Acceleration			OptiXAcceleration;
+	optix::Geometry				OptiXGeometry;
+	optix::GeometryGroup		OptiXGeometryGroup;
+	optix::GeometryInstance		OptiXGeometryInstance;
+	optix::Transform			OptiXTransform;
+	optix::Material				OptiXMaterial;
+	/**
+	* First and second program correspond to perspective and iterative trace for the optix geometry, while the third and fourth correspond to perspective and iterative
+	* programs for the optix material. Anyhit programs need to be added differently.
+	*/
+	TTuple<optix::Program, optix::Program, optix::Program, optix::Program>	OptiXPrograms;
+};
+
+/**
+* Struct storing the data needed to create an optix buffer. Used to prevent overlong constructors.
+*/
+struct FOptiXBufferData
+{
+	FString Name;
+	unsigned int Type;
+	RTformat Format;
+	RTsize BufferWidth = 0;
+	RTsize BufferHeight = 0;
+	RTsize BufferDepth = 0;
+};
+
+/**
+* Typdef for the callback function to update corresponding optix variables from a game-thread owned UObject in the scene.
+*/
+typedef TFunction<void(FOptiXObjectData* Data, TMap<FString, optix::Buffer>* Buffers, optix::TextureSampler TextureSampler)> OptiXObjectUpdateFunction;
+
+/**
+* Typdef for the callback function to update corresponding optix variables from a game-thread owned UObject in the scene. Additionally contains the RHICmdList as a parameter
+* so that textures and materials can be updated directly.
+*/
+typedef TFunction<void(FOptiXObjectData* Data, TMap<FString, optix::Buffer>* Buffers, optix::TextureSampler TextureSampler, FRHICommandListImmediate & RHICmdList)> OptiXObjectUpdateFunctionRHI;
+
+/**
+* Typdef for the callback function to initialize optix objects from the corresponding gamethread UObject.
+*/
+typedef TFunction<void(FOptiXObjectData* Data, TMap<FString, optix::Buffer>* Buffers, optix::TextureSampler TextureSampler)> OptiXObjectInitFunction;
+
+/**
+* Typdef for the callback function to update a cubemap for a lens. Additionally contains the RHICmdList as a parameter
+* so that textures and materials can be updated directly.
+*/
+typedef TFunction<void(optix::Buffer CubemapBuffer, FRHICommandListImmediate& RHICmdList)> CubemapUpdateFunction;
+
+/**
+* Typdef for the callback function to update general optix context variables.
+*/
+typedef TFunction<void(optix::Context Context)> OptiXContextUpdateFunction;
+
+/**
+* Typdef for the callback function executed after the laser trace finished.
+*/
+typedef TFunction<void(FOptiXObjectData* Data, TMap<FString, optix::Buffer>* Buffers, optix::TextureSampler TextureSampler, FRHICommandListImmediate & RHICmdList)> LaserTraceFinishedCallback;
+
+/**
+* Unique Id for a UObject in the scene. Used to map a UObject to a corresponding set of optix objects.
+*/
+typedef uint32 UniqueId;
+
+
+class OPTIX_API FOptiXContextUpdateManager : public FSceneViewExtensionBase
+{
+
+public:
+
+	// The auto register parameter is used to make sure this constructor is only called via the NewExtension function
+	FOptiXContextUpdateManager(const FAutoRegister& AutoRegister);
+
+	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 bool IsActiveThisFrame(class FViewport* InViewport) const override;
+	virtual int32 GetPriority() const override;
+
+	// ISceneViewExtension interface end
+	bool bIsActive = false;
+};
+
+
 
 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
+	// The auto register parameter 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();
+		// TODO
 	}
 
 	// ISceneViewExtension interface start, called by the render thread:
@@ -106,8 +163,9 @@ public:
 	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
+	virtual int32 GetPriority() const override;
 
+	// ISceneViewExtension interface end
 
 	void RenderOrthoPass();
 	
@@ -116,17 +174,8 @@ public:
 
 	void EndPlay()
 	{
-		//bEndPlay.AtomicSet(true);
-
-		//CleanupOptiXOnEnd();
-		//bCleanup.AtomicSet(true);
-		//bStartTracing.AtomicSet(false);
-		//bCleanup.AtomicSet(false);
-	}
-
-	UOptiXContext* GetOptiXContext()
-	{
-		return OptiXContext.Get();
+		bEndPlayReceived.AtomicSet(true);
+		Cleanup_GameThread();
 	}
 
 	UMaterialInstanceDynamic* GetOptiXMID() // Used to set up the post process
@@ -141,26 +190,6 @@ public:
 
 	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)
 	{
@@ -195,44 +224,52 @@ public:
 	{
 		WavelengthChangedEvent.Broadcast(WL);
 		//UE_LOG(LogTemp, Error, TEXT("LaserMaterialDynamic is invalid!"));
-
 	}
 
+	void ExecuteOptiXUpdate_PreLateUpdate(FRHICommandListImmediate & RHICmdList);
 
 public:
 	
-	FThreadSafeBool bStartTracing = false;
-	FThreadSafeBool bIsInitialized = false;
-	FThreadSafeBool bLaserIsInitialized = false;
-	FThreadSafeBool bSceneChanged = true;
-	FThreadSafeBool bIsTracing = false;
-	FThreadSafeBool bClearToLaunch = true;
-	FThreadSafeBool bCleanup = false;
+	FThreadSafeBool bEndPlayReceived = false;
+
 	FThreadSafeBool bValidCubemap = false;
+	FThreadSafeBool bIsInitializedCuda = false;
+	FThreadSafeBool bIsInitializedLaser = false;
+	FThreadSafeBool bIsInitializedAll = false;
+
+	FThreadSafeBool bSceneChanged = true;
 	FThreadSafeBool bRequestOrthoPass = false;
+
+	//FThreadSafeBool bStartTracing = false;
+	//FThreadSafeBool bIsInitialized = false;
+	//FThreadSafeBool bIsTracing = false;
+	//FThreadSafeBool bClearToLaunch = true;
+	//FThreadSafeBool bCleanup = false;
+	//FThreadSafeBool bRequestOrthoPass = false;
 	//FThreadSafeBool bEndPlay = false;
 
+	/**
+	* Delegate that broadcasts every time the laser trace finishes. Required to update the detector texture.
+	*/
 	FLaserTraceFinishedEvent LaserTraceFinishedEvent;
+
+	/**
+	* Delegate that broadcasts every time the wavelength changes. Required for recomputation of the refractive indices of the lenses. 
+	*/
 	FWavelengthChangedEvent WavelengthChangedEvent;
+
+	/**
+	* Delegate that broadcasts every time the scene changes, e.g. when a lens is moved. This should imply a new laser trace.
+	*/
 	FOnSceneChangedDelegate OnSceneChangedDelegate;
 
+	/**
+	* Path to the pre-compiled ptx files that contains the optix shaders.
+	*/
+	FString OptiXPTXDir;
 
-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;
+public:	
 
 	FMatrix OrthoMatrix;
 
@@ -243,496 +280,70 @@ private:
 	void InitPrograms();
 	void InitLaser();
 
-	void LaunchLaser();
+	void LaunchLaser(FRHICommandListImmediate & RHICmdList);
 
-	void InitCubemap();
-
-	void InitOptiXComponents(FRHICommandListImmediate & RHICmdList)
-	{
-		TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("FOptiXContextManager::InitOptiXComponents"))
-
-		// 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()
-	{
-		TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("FOptiXContextManager::UpdateOptiXComponentVariables"))
+	void LaunchStandardTrace(FRHICommandListImmediate& RHICmdList, FSceneViewFamily& InViewFamily);
 
-		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 CopyLaserCudaTexture(FRHICommandListImmediate & RHICmdList);
 
-	void RemovePendingChildrenFromGroups()
-	{
-		TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("FOptiXContextManager::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 InitCubemap();
 
-	void DestroyOptiXObjects()
-	{
-		TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("FOptiXContextManager::DestroyOptiXObjects"))
+	void CleanupCuda();
 
-		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 CleanupLocalOptiXObjects();
 
-	void UpdateRequestedCubemaps(FRHICommandListImmediate & RHICmdList)
-	{
-		// update only the first for now, shouldn't be more than 1 in queue anyway:
-		TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("FOptiXContextManager::UpdateRequestedCubemaps"))
+	void Cleanup_RenderThread();
 
-		if (!CubemapComponentsToUpdateQueue.IsEmpty())
-		{
-			UOptiXCubemapComponent* Comp;
-			if (CubemapComponentsToUpdateQueue.Dequeue(Comp))
-			{
-				Comp->UpdateCubemap(RHICmdList);
-			}
-		}
-	}
+	void Cleanup_GameThread();
 
 	void UpdateCubemapBuffer(FRHICommandListImmediate & RHICmdList);
-
-	void CleanupOptiXOnEnd()
-	{
-		TRACE_CPUPROFILER_EVENT_SCOPE(TEXT("FOptiXContextManager::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;
+	TSharedPtr<FOptiXContextUpdateManager, ESPMode::ThreadSafe> OptiXContextUpdateManager;
 
 	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;
-
+	/**
+	* Viewport width and height
+	*/
 	int32 Width;
 	int32 Height;
 
-	//FTexture2DRHIRef OutputTextureColorRightRef;
-	//FTexture2DRHIRef OutputTextureColorLeftRef;
-	//FTexture2DRHIRef OutputTextureDepthRightRef;
-	//FTexture2DRHIRef OutputTextureDepthLeftRef;
-	//
-	//FTexture2DRHIRef OutputTextureColorOrthoRef;
-	//FTexture2DRHIRef OutputTextureDepthOrthoRef;
-
+	/**
+	* Right eye color texture used for post processing. Cuda copies the optix results into this texture.
+	*/
 	TWeakObjectPtr<UTexture2D> OutputTexture;
+	/**
+	* Right eye depth texture used for post processing. Cuda copies the optix results into this texture.
+	*/
 	TWeakObjectPtr<UTexture2D> DepthTexture;
+
+	/**
+	* Left eye color texture used for post processing. Cuda copies the optix results into this texture.
+	*/
 	TWeakObjectPtr<UTexture2D> OutputTexture2;
+	/**
+	* Left eye depth texture used for post processing. Cuda copies the optix results into this texture.
+	*/
 	TWeakObjectPtr<UTexture2D> DepthTexture2;
 
+	/**
+	* Ortho pass texture used for post processing. Cuda copies the optix results into this texture.
+	* The ortho pass is used for single eye orthogonal rendering.
+	*/
 	TWeakObjectPtr<UTexture2D> OutputTextureOrtho;
 	TWeakObjectPtr<UTexture2D> DepthTextureOrtho;
 
-	UTexture2D* TestTexture;
-
+	/**
+	* Pointers to the post processing materials used to blend the optix results with the unreal scene.
+	*/
 	TWeakObjectPtr<UMaterialInstanceDynamic> DynamicMaterial;
 	TWeakObjectPtr<UMaterialInstanceDynamic> DynamicMaterialOrtho;
 	TWeakObjectPtr<UMaterial> RegularMaterial;
@@ -744,13 +355,13 @@ private:
 	// Laser stuff
 	// ---------------------------------------------------------------------------------------------------
 
-	FTexture2DRHIRef LaserIntersectionTextureRef;
-
 	TWeakObjectPtr<UTexture2D> LaserIntersectionTexture;
 	TWeakObjectPtr<UMaterial> LaserMaterial;
 	TWeakObjectPtr<UMaterialInstanceDynamic> LaserMaterialDynamic;
 
 
+
+
 public:
 
 	TQueue<TPair<uint32, TArray<FVector>>> LaserIntersectionQueue;
@@ -765,8 +376,6 @@ private:
 
 	FThreadSafeBool bTracingLaser;
 
-	FCriticalSection CriticalSection;
-
 	int32 LaserMaxDepth;
 	int32 LaserEntryPoint;
 	int32 LaserBufferSize;
@@ -779,23 +388,15 @@ private:
 	// 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:
-
+	/**
+	* Initialization function for Cuda. Needs to be called from the gamethread.
+	*/
 	void InitCUDADX();
 
-
-	//ID3D11Texture2D* D3D11Texture;
+	/**
+	* Cuda graphic resources associated with the corresponding unreal textures.
+	*/
 	cudaGraphicsResource* CudaResourceDepthLeft;
 	cudaGraphicsResource* CudaResourceDepthRight;
 	cudaGraphicsResource* CudaResourceColorLeft;
@@ -804,11 +405,277 @@ private:
 	cudaGraphicsResource* CudaResourceColorOrtho;
 	cudaGraphicsResource* CudaResourceDepthOrtho;
 
+	/**
+	* Cuda memory allocated and used to copy the optix results into the direct x textures.
+	*/
 	float* CudaLinearMemoryDepth;
 	float4* CudaLinearMemoryColor;
 	void* CudaLinearMemoryIntersections;
+
 	size_t Pitch; // fix me
 	size_t PitchLaser;
 
+	/**
+	* Cuda resource array used for easy mapping. Duplicate to above direct pointers.
+	*/
 	cudaGraphicsResource *Resources[7];
+
+	// Refactor stuff
+
+public:
+
+	/*
+	* Request functions used by UObjects to request the creation/destruction of the corresponding optix object.
+	* The objects are stored here as accessing them directly is not threadsafe. 
+	*/
+
+	////////////////////////////////////////////////////////////////
+	//  Request functions used by UObjects to request the creation/destruction of the corresponding optix object.
+	//	The objects are stored here as accessing them directly is not threadsafe.
+	////////////////////////////////////////////////////////////////
+
+	/**
+	* Requests a new optix::Buffer object to be created and associated with the calling object's Id. 
+	*
+	* @param ObjectId - The unique object Id this buffer should be associated with.
+	* @param BufferData - The FOptiXBufferData storing the parameters with which the buffer should be initialized.
+	*/
+	void RequestNewOptiXBuffer(UniqueId ObjectId, FOptiXBufferData BufferData);
+
+	/**
+	* Requests a new optix::Group object to be created and associated with the calling object's Id.
+	*
+	* @param ObjectId - The unique object Id this Group should be associated with.
+	* @warning Not Implemented yet!
+	*/
+	void RequestNewOptiXGroup(UniqueId ObjectId);
+
+	/**
+	* Requests a new optix::TextureSampler object to be created and associated with the calling object's Id.
+	*
+	* @param ObjectId - The unique object Id this TextureSampler should be associated with.
+	*/
+	void RequestNewOptiXTextureSampler(UniqueId ObjectId);
+
+	/**
+	* Requests the creation of a fully usable optix object used for targets and lenses. 
+	* The object consists of a optix::Geometry and optix::Material with respective perspective and iterative programs.
+	* Geometry and Material are combined in an optix::GeometryInstance which is added to a optix::GeometryGroup.
+	* A optix::Transform is created for the GeometryGroup and attached to the top object. This function only requests
+	* the creation of this object, which will then be executed on the next render thread tick.
+	*
+	* @param ObjectId - The unique object Id these objects should be associated with.
+	* @param Program - The name of the programs associated with the Geometry and Material. 
+	*/
+	void RequestNewOptiXObject(UniqueId ObjectId, FString Program);
+
+	/**
+	* Requests the destruction of all optix objects associated with the Id. 
+	*
+	* @param ObjectId - The unique object Id.
+	*/
+	void RequestDestroyOptiXObjects(UniqueId ObjectId);
+
+
+	////////////////////////////////////////////////////////////////
+	//   Enqueue functions used by UObjects to enqueue an update lambda function that is then executed by the rendering thread for threadsafety.
+	////////////////////////////////////////////////////////////////
+
+	/**
+	* Requests and enqueues an update of the cubemap for a lens. 
+	*
+	* @param ObjectId - The unique object Id for the lens which needs to be updated.
+	* @param UpdateFunction - The callback function that is called from the render thread to execute the cubemap update.
+	*/
+	void RequestLensCubemapUpdate(UniqueId ObjectId, CubemapUpdateFunction UpdateFunction);
+
+	/**
+	* Requests and enqueues the initialization of an optix object component.
+	*
+	* @param ObjectId - The unique object Id for the object component which needs to be initialized.
+	* @param InitFuntion - The callback function that is called from the render thread to execute the initialization.
+	*/
+	void EnqueueInitFunction(UniqueId ObjectId, OptiXObjectInitFunction InitFuntion);
+
+	/**
+	* Requests and enqueues the update of an optix object.
+	*
+	* @param ObjectId - The unique object Id for the object requesting the update.
+	* @param UpdateFunction - The callback function that is called from the render thread to execute the update.
+	*/
+	void EnqueueUpdateFunction(UniqueId ObjectId, OptiXObjectUpdateFunction UpdateFunction);
+
+	/**
+	* Requests and enqueues a general optix context update.
+	*
+	* @param UpdateFunction - The callback function that is called from the render thread to execute the update.
+	*/
+	void EnqueueContextUpdateFunction(OptiXContextUpdateFunction UpdateFunction);
+
+	/**
+	* Requests and enqueues the update of an optix object. The update function gets called with the RHICmdList for texture manipulation.
+	*
+	* @param ObjectId - The unique object Id for the object requesting the update.
+	* @param UpdateFunction - The callback function that is called from the render thread with the RHICmdList to execute the update.
+	*/
+	void EnqueueUpdateFunctionRHI(UniqueId ObjectId, OptiXObjectUpdateFunctionRHI UpdateFunction);
+
+	/**
+	* Registers a callback to be called each time after a laser trace has finished
+	*
+	* @param ObjectId - The unique object Id for the object registering the callback.
+	* @param Callback - The callback function that is called from the render thread with the RHICmdList and respective laser buffers.
+	*/
+	void RegisterLaserTraceCallback(UniqueId ObjectId, LaserTraceFinishedCallback Callback);
+
+	/**
+	* Updates the laser position/orientations variables that get modified by the controller late update in case the laser is attached to the motion controller
+	*
+	* @param LateUpdateTransform - The newly updated transform.
+	*/
+	void LaserPositionLateUpdate_RenderThread(const FTransform LateUpdateTransform);
+
+	/**
+	* Updates the laser position/orientations variables that get modified by the controller late update in case the laser is attached to the motion controller
+	*
+	* @param LateUpdateTransform - The newly updated transform.
+	*/
+	void ObjectPositionLateUpdate_RenderThread(UniqueId ObjectId, const FMatrix LateUpdateTransform);
+
+private:
+
+	/*
+	Creation/Destruction/Update functions that are called by the context manager if a UObject previously requested them. 
+	*/
+	void CreateNewOptiXObject(UniqueId ObjectId, FString Program);
+	void CreateNewOptiXBuffer(UniqueId ObjectId, FOptiXBufferData BufferData);
+	void CreateNewOptiXTextureSampler(UniqueId ObjectId);
+	void DestroyOptiXObjects(UniqueId ObjectId);
+
+	void ExecuteOptiXUpdate(UniqueId ObjectId, OptiXObjectUpdateFunction UpdateFunction);
+	void ExecuteOptiXUpdateRHI(UniqueId ObjectId, FRHICommandListImmediate& RHICmdList, OptiXObjectUpdateFunctionRHI UpdateFunction);
+	void ExecuteContextUpdate(OptiXContextUpdateFunction UpdateFunction);
+	   
+	void InitializeOptiXObject(UniqueId ObjectId, OptiXObjectInitFunction InitFunction);
+
+	void UpdateCubemap(UniqueId ObjectId, FRHICommandListImmediate & RHICmdList, CubemapUpdateFunction UpdateFunction);
+
+	/**
+	* Functions that parse the respective queues to see if any request has been queued by a game-thread UObject. If there are any in the queues, 
+	* the respective Creation/Destruction/Update functions are executed.
+	*/
+	void ParseCreationQueue();
+	void ParseInitQueue();
+	void ParseUpdateQueue(FRHICommandListImmediate & RHICmdList);
+	void ParseDestroyQueue();
+	void ParseCubemapUpdateQueue(FRHICommandListImmediate & RHICmdList);
+
+
+private:
+	/**
+	* Queues to guarantee thread-safety between the optix native objects and the corresponding UObjects that represent them in the unreal scene. 
+	*/
+	TQueue<UniqueId>					OptiXObjectsToDestroy;
+	TQueue<TPair<UniqueId, FString>>	OptiXObjectsToCreate;
+	TQueue<TPair<UniqueId, OptiXObjectInitFunction>> OptiXObjectInitFunctions;
+	TQueue<TPair<UniqueId, OptiXObjectUpdateFunction>>	OptiXObjectUpdateFunctions;
+	TQueue<TPair<UniqueId, OptiXObjectUpdateFunctionRHI>>	OptiXObjectUpdateFunctionsRHI;
+
+	TQueue<TPair<UniqueId, FOptiXBufferData>>	OptiXBuffersToCreate;
+	TQueue<UniqueId>	OptiXTextureSamplersToCreate;
+	TQueue<TPair<UniqueId, CubemapUpdateFunction>>	CubemapsToUpdate;
+	TQueue<OptiXContextUpdateFunction>	OptiXContextUpdateQueue;
+
+	/**
+	* Map storing callbacks that are executed as soon as the laser trace finishes.
+	* Could probably be used via delegates/events as well.
+	*/
+	TMap<UniqueId, LaserTraceFinishedCallback> LaserTraceFinishedCallbacks;
+
+
+	////////////////////////////////////////////////////////////////
+	//   OptiX API objects
+	////////////////////////////////////////////////////////////////
+
+	/**
+	* Maps which store the optix objects mapped to a unique object id as keys.
+	* Currently, multiple named buffers can be associated with one UObject, while only one group, sampler and object collection is supported.
+	*/
+	TMap<UniqueId, TMap<FString, optix::Buffer>>	OptiXBuffers;
+	TMap<UniqueId, optix::Group>					OptiXGroups;
+	TMap<UniqueId, optix::TextureSampler>			OptiXTextureSamplers;
+	TMap<UniqueId, FOptiXObjectData>				OptiXObjectData;
+
+	// Context Manager local objects
+
+	/**
+	* The optix context is the core handle on the whole optix framework. It's used to create and manipulate all other objects and
+	* is the main entry point into the optix trace.
+	*/
+	optix::Context NativeContext;
+
+	/**
+	* The ray generation program is the main optix device shader program. 
+	* It generates the rays and executes the trace, writing the result in the respective buffers.
+	*/
+	optix::Program RayGenerationProgram;
+
+	/**
+	* The miss program is executed on the device in case a ray misses any optix object. Generally, a cubemap is used to look up
+	* environment data.
+	*/
+	optix::Program MissProgram;
+
+	/**
+	* The exception program is executed when optix exceptions are enabled and is used only for debugging. Printing needs to be explicitly enabled as well
+	* to actually print the exceptions. 
+	*
+	* @warning The rtPrints executed by optix will NOT print to UE_LOG! They will be streamed to the standard cout, which requires executing the unreal executable
+	* via the command line!
+	*/
+	optix::Program ExceptionProgram;
+
+	/**
+	* The top group of the optix scenegraph. This is the group that will be traced on, so all other scene objects need to be children.
+	*/
+	optix::Group TopObject;
+
+	/**
+	* The main acceleration of the top-level scenegraph. Each group can have a custom acceleration, this is the initial acceleration structure.
+	*/
+	optix::Acceleration TopAcceleration;
+
+	/**
+	* The main output buffer for color values. OptiX writes the color result into the first 3 float components, followed by a 4th component denoting the hit value.
+	* If nothing has been hit for a given pixel, the post process material picks the unreal scene layer. 
+	*/
+	optix::Buffer OutputBuffer;
+
+	/**
+	* The main output buffer for the depth value, storing the depth as a single float per pixel.
+	*/
+	optix::Buffer OutputDepthBuffer;
+
+	// Cubemap stuff
+
+	/**
+	* ContextManager local optix buffer and sampler that handle the initial cubemap. 
+	*/
+	optix::TextureSampler	CubemapSampler;
+	optix::Buffer			CubemapBuffer;
+
+	/**
+	* optix buffer storing the texture sampler ids (integers) corresponding to a certain lens. 
+	* The number of cubemaps is limited to 10, so ids have to be recycled. The ids are used as indices to the buffer
+	* for quick and easy access in the optix shaders.
+	*/
+	optix::Buffer			CubemapsInputBuffer;
+
+
+	// Laser Part
+
+	optix::Buffer  LaserOutputBuffer;
+	optix::Program LaserRayGenerationProgram;
+	optix::Program LaserMissProgram;
+	optix::Program LaserExceptionProgram;
 };
\ No newline at end of file
diff --git a/Source/OptiX/Public/OptiXCubemapLateUpdateComponent.h b/Source/OptiX/Public/OptiXCubemapLateUpdateComponent.h
new file mode 100644
index 0000000000000000000000000000000000000000..f4a1c5f7f6800321d6493348205d919cc6af5132
--- /dev/null
+++ b/Source/OptiX/Public/OptiXCubemapLateUpdateComponent.h
@@ -0,0 +1,34 @@
+// Fill out your copyright notice in the Description page of Project Settings.
+
+#pragma once
+
+#include "CoreMinimal.h"
+#include "Components/PrimitiveComponent.h"
+#include "OptiXContextManager.h"
+
+#include "OptiXCubemapLateUpdateComponent.generated.h"
+
+/**
+ * Literally only here to update the lenses on applylateupdate, as the scene capture component is a USceneCompoenent and NOT 
+ * a UPrimitiveComponent and can therefore not receive the lateupdate. This is incredibly annoying. 
+ */
+UCLASS(Blueprintable, hidecategories = (Object), meta = (BlueprintSpawnableComponent))
+class OPTIX_API UOptiXCubemapLateUpdateComponent : public UPrimitiveComponent
+{
+	GENERATED_BODY()
+	
+public:
+
+	virtual FPrimitiveSceneProxy* CreateSceneProxy() override;
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXCubemapLateUpdateComponent")
+	void LinkOptiXComponent(UOptiXCubemapComponent* OptiXComponent);
+
+	//UFUNCTION(BlueprintPure, BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXCubemapLateUpdateComponent")
+	const uint32* GetOptiXComponentId() const
+	{
+		return &OptiXComponentId;
+	}
+
+	uint32 OptiXComponentId;
+};
diff --git a/Source/OptiX/Public/OptiXDeclarations.h b/Source/OptiX/Public/OptiXDeclarations.h
deleted file mode 100644
index c3ce6c81399dcccd50f5f4e64ffe196da4910a84..0000000000000000000000000000000000000000
--- a/Source/OptiX/Public/OptiXDeclarations.h
+++ /dev/null
@@ -1,55 +0,0 @@
-#pragma once
-/*
-
-See optix_declarations.h
-
-This defines the same enums as UENUMS to be used in blueprints. I hope this actually works.
-
-*/
-
-#include "CoreMinimal.h"
-#include "UObject/ObjectMacros.h"
-#include "Engine/EngineTypes.h"
-
-//
-//
-//UENUM()
-//enum class URTformat : int32
-//{
-//	RT_FORMAT_UNKNOWN = 0x100,				/*!< Format unknown       */
-//	RT_FORMAT_FLOAT,                        /*!< Float                */
-//	RT_FORMAT_FLOAT2,                       /*!< sizeof(float)*2      */
-//	RT_FORMAT_FLOAT3,                       /*!< sizeof(float)*3      */
-//	RT_FORMAT_FLOAT4,                       /*!< sizeof(float)*4      */
-//	RT_FORMAT_BYTE,                         /*!< BYTE                 */
-//	RT_FORMAT_BYTE2,                        /*!< sizeof(CHAR)*2       */
-//	RT_FORMAT_BYTE3,                        /*!< sizeof(CHAR)*3       */
-//	RT_FORMAT_BYTE4,                        /*!< sizeof(CHAR)*4       */
-//	RT_FORMAT_UNSIGNED_BYTE,                /*!< UCHAR                */
-//	RT_FORMAT_UNSIGNED_BYTE2,               /*!< sizeof(UCHAR)*2      */
-//	RT_FORMAT_UNSIGNED_BYTE3,               /*!< sizeof(UCHAR)*3      */
-//	RT_FORMAT_UNSIGNED_BYTE4,               /*!< sizeof(UCHAR)*4      */
-//	RT_FORMAT_SHORT,                        /*!< SHORT                */
-//	RT_FORMAT_SHORT2,                       /*!< sizeof(SHORT)*2      */
-//	RT_FORMAT_SHORT3,                       /*!< sizeof(SHORT)*3      */
-//	RT_FORMAT_SHORT4,                       /*!< sizeof(SHORT)*4      */
-//	RT_FORMAT_UNSIGNED_SHORT,               /*!< USHORT               */
-//	RT_FORMAT_UNSIGNED_SHORT2,              /*!< sizeof(USHORT)*2     */
-//	RT_FORMAT_UNSIGNED_SHORT3,              /*!< sizeof(USHORT)*3     */
-//	RT_FORMAT_UNSIGNED_SHORT4,              /*!< sizeof(USHORT)*4     */
-//	RT_FORMAT_INT,                          /*!< INT                  */
-//	RT_FORMAT_INT2,                         /*!< sizeof(INT)*2        */
-//	RT_FORMAT_INT3,                         /*!< sizeof(INT)*3        */
-//	RT_FORMAT_INT4,                         /*!< sizeof(INT)*4        */
-//	RT_FORMAT_UNSIGNED_INT,                 /*!< sizeof(UINT)         */
-//	RT_FORMAT_UNSIGNED_INT2,                /*!< sizeof(UINT)*2       */
-//	RT_FORMAT_UNSIGNED_INT3,                /*!< sizeof(UINT)*3       */
-//	RT_FORMAT_UNSIGNED_INT4,                /*!< sizeof(UINT)*4       */
-//	RT_FORMAT_USER,                         /*!< User Format          */
-//	RT_FORMAT_BUFFER_ID,                    /*!< Buffer Id            */
-//	RT_FORMAT_PROGRAM_ID,                   /*!< Program Id           */
-//	RT_FORMAT_HALF,                         /*!< half float           */
-//	RT_FORMAT_HALF2,                        /*!< sizeof(half float)*2 */
-//	RT_FORMAT_HALF3,                        /*!< sizeof(half float)*3 */
-//	RT_FORMAT_HALF4                         /*!< sizeof(half float)*4 */
-//};
\ No newline at end of file
diff --git a/Source/OptiX/Public/OptiXLaserComponent.h b/Source/OptiX/Public/OptiXLaserComponent.h
index c8a4306927a6124bffd24b83e399f328e1e4935e..4088ba9dd1289fd717684ccddbed5ab8da991065 100644
--- a/Source/OptiX/Public/OptiXLaserComponent.h
+++ b/Source/OptiX/Public/OptiXLaserComponent.h
@@ -1,160 +1,146 @@
-// Fill out your copyright notice in the Description page of Project Settings.
-
-#pragma once
-
-#include "CoreMinimal.h"
-#include "Components/SceneComponent.h"
-#include "Runtime/Engine/Classes/Engine/Texture2D.h"
-
-#include "OptiXContext.h"
-
-#include "OptiXLaserComponent.generated.h"
-
-
-UENUM(BlueprintType)
-enum class EPatternTypes : uint8
-{
-	CROSS	UMETA(DisplayName = "Cross"),
-	POINTER	UMETA(DisplayName = "Pointer"),
-	CIRCLE	UMETA(DisplayName = "Circle"),
-	QUAD	UMETA(DisplayName = "Quad"),
-};
-
-
-UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
-class OPTIX_API UOptiXLaserComponent : public USceneComponent
-{
-	GENERATED_BODY()
-
-public:	
-	// Sets default values for this component's properties
-	UOptiXLaserComponent();
-	~UOptiXLaserComponent()
-	{
-		CleanOptiXObjects();
-	}
-
-protected:
-	// Called when the game starts
-	virtual void BeginPlay() override;
-	virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
-
-public:	
-
-	virtual void OnUpdateTransform(EUpdateTransformFlags UpdateTransformFlags, ETeleportType Teleport = ETeleportType::None) override;
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXLaserComponent")
-	void CleanOptiXObjects()
-	{
-		//FOptiXModule::Get().GetOptiXContextManager()->bLaserIsInitialized.AtomicSet(true);
-
-		UE_LOG(LogTemp, Warning, TEXT("OptiX Laser Component Cleaning up")); // TODO
-	}
-
-	void UpdateOptiXContextVariables();
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXLaserComponent")
-	void Init();
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXLaserComponent")
-	void UpdateLaserPosition();
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXLaserComponent")
-	void SetRayTIR(bool Active);
-
-	UFUNCTION(BlueprintPure, BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXLaserComponent")
-	bool GetRayTIR() const;
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXLaserComponent")
-	void SetTargetBufferWrite(bool Flag); // Top naming...
-
-	UFUNCTION(BlueprintPure, BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXLaserComponent")
-	bool GetTargetBufferWrite() const;
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXLaserComponent")
-	void SetTargetColorMode(bool Flag);
-
-	UFUNCTION(BlueprintPure, BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXLaserComponent")
-	bool GetTargetColorMode() const;
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXLaserComponent")
-	void SetWavelength(float WL);
-
-	UFUNCTION(BlueprintPure, BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXLaserComponent")
-	float GetWavelength() const;
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXLaserComponent")
-	void SetLaserWidth(float Width);
-
-	UFUNCTION(BlueprintPure, BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXLaserComponent")
-	float GetLaserWidth() const;
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXLaserComponent")
-	void SetLaserPattern(EPatternTypes Pattern);
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXLaserComponent")
-	void PreparePatternChange(EPatternTypes Pattern);
-
-	UFUNCTION(BlueprintPure, BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXLaserComponent")
-	EPatternTypes GetLaserPattern() const;
-
-public:
-
-	UPROPERTY(BlueprintReadOnly, Category = OptiX)
-	UOptiXContext* OptiXContext;	
-
-	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = OptiX)
-	int32 LaserMaxDepth;
-
-	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = OptiX)
-	int32 LaserBufferSize;
-
-	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = OptiX)
-	int32 LaserBufferWidth;
-
-	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = OptiX)
-	int32 LaserBufferHeight;
-
-	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = OptiX)
-	int32 LaserTracesPerFrame;
-
-	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = OptiX)
-	int32 LaserEntryPoint;
-
-	UPROPERTY(BlueprintReadOnly, Category = OptiX)
-	TArray<int32> LaserIndices;
-
-	UPROPERTY(BlueprintReadOnly, Category = OptiX)
-	TArray<FColor> LaserIndexColorMap;
-
-	UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category = OptiX)
-	TMap<EPatternTypes, UTexture2D*> Patterns;
-
-	UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category = OptiX)
-	TMap<EPatternTypes, UTexture2D*> PatternDirections;
-
-	TArray<FString> PatternNames = { "Cross", "Pointer", "Circle", "Quad" };
-
-	UPROPERTY(BlueprintReadWrite, EditAnywhere, BlueprintGetter = GetRayTIR, BlueprintSetter = SetRayTIR) // todo
-	bool RayTIR;
-
-	UPROPERTY(BlueprintReadWrite, EditAnywhere, BlueprintGetter = GetTargetBufferWrite, BlueprintSetter = SetTargetBufferWrite) // todo
-	bool TargetBufferWrite;
-
-	UPROPERTY(BlueprintReadWrite, EditAnywhere, BlueprintGetter = GetTargetColorMode, BlueprintSetter = SetTargetColorMode) // todo
-	bool TargetColorMode;
-
-	UPROPERTY(BlueprintReadWrite, EditAnywhere, BlueprintGetter = GetWavelength, BlueprintSetter = SetWavelength) // todo
-	float Wavelength;
-
-	UPROPERTY(BlueprintReadWrite, EditAnywhere, BlueprintGetter = GetLaserWidth, BlueprintSetter = SetLaserWidth) // todo
-	float LaserWidth;
-
-	UPROPERTY(BlueprintReadWrite, EditAnywhere, BlueprintGetter = GetLaserPattern, BlueprintSetter = SetLaserPattern) // todo
-	EPatternTypes CurrentLaserPattern;
-
-private:
-	FThreadSafeBool bUpdateQueued = true;	
-	FThreadSafeBool bPatternChanged = true;
-
-};
+// Fill out your copyright notice in the Description page of Project Settings.
+
+#pragma once
+
+#include "CoreMinimal.h"
+#include "Components/PrimitiveComponent.h"
+#include "Runtime/Engine/Classes/Engine/Texture2D.h"
+#include "PrimitiveSceneProxy.h"
+
+//#include "OptiXContext.h"
+
+#include "OptiXLaserComponent.generated.h"
+
+
+UENUM(BlueprintType)
+enum class EPatternTypes : uint8
+{
+	CROSS	UMETA(DisplayName = "Cross"),
+	POINTER	UMETA(DisplayName = "Pointer"),
+	CIRCLE	UMETA(DisplayName = "Circle"),
+	QUAD	UMETA(DisplayName = "Quad"),
+};
+
+
+UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
+class OPTIX_API UOptiXLaserComponent : public UPrimitiveComponent
+{
+	GENERATED_BODY()
+
+public:	
+	// Sets default values for this component's properties
+	UOptiXLaserComponent();
+	~UOptiXLaserComponent()
+	{
+		CleanOptiXObjects();
+	}
+
+protected:
+	// Called when the game starts
+	virtual void BeginPlay() override;
+	virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
+
+public:	
+
+	virtual void OnUpdateTransform(EUpdateTransformFlags UpdateTransformFlags, ETeleportType Teleport = ETeleportType::None) override;
+
+	virtual FPrimitiveSceneProxy* CreateSceneProxy() override;
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXLaserComponent")
+	void CleanOptiXObjects();
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXLaserComponent")
+	void UpdateLaserPosition();
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXLaserComponent")
+	void SetRayTIR(bool Active);
+
+	UFUNCTION(BlueprintPure, BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXLaserComponent")
+	bool GetRayTIR() const;
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXLaserComponent")
+	void SetTargetBufferWrite(bool Flag); // Top naming...
+
+	UFUNCTION(BlueprintPure, BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXLaserComponent")
+	bool GetTargetBufferWrite() const;
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXLaserComponent")
+	void SetTargetColorMode(bool Flag);
+
+	UFUNCTION(BlueprintPure, BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXLaserComponent")
+	bool GetTargetColorMode() const;
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXLaserComponent")
+	void SetWavelength(float WL);
+
+	UFUNCTION(BlueprintPure, BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXLaserComponent")
+	float GetWavelength() const;
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXLaserComponent")
+	void SetLaserWidth(float Width);
+
+	UFUNCTION(BlueprintPure, BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXLaserComponent")
+	float GetLaserWidth() const;
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXLaserComponent")
+	void SetLaserPattern(EPatternTypes Pattern);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXLaserComponent")
+	void PreparePatternChange(EPatternTypes Pattern);
+
+	UFUNCTION(BlueprintPure, BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXLaserComponent")
+	EPatternTypes GetLaserPattern() const;
+
+public:	
+
+	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = OptiX)
+	int32 LaserMaxDepth;
+
+	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = OptiX)
+	int32 LaserBufferSize;
+
+	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = OptiX)
+	int32 LaserBufferWidth;
+
+	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = OptiX)
+	int32 LaserBufferHeight;
+
+	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = OptiX)
+	int32 LaserTracesPerFrame;
+
+	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = OptiX)
+	int32 LaserEntryPoint;
+
+	UPROPERTY(BlueprintReadOnly, Category = OptiX)
+	TArray<int32> LaserIndices;
+
+	UPROPERTY(BlueprintReadOnly, Category = OptiX)
+	TArray<FColor> LaserIndexColorMap;
+
+	UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category = OptiX)
+	TMap<EPatternTypes, UTexture2D*> Patterns;
+
+	UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category = OptiX)
+	TMap<EPatternTypes, UTexture2D*> PatternDirections;
+
+	TArray<FString> PatternNames = { "Cross", "Pointer", "Circle", "Quad" };
+
+	UPROPERTY(BlueprintReadWrite, EditAnywhere, BlueprintGetter = GetRayTIR, BlueprintSetter = SetRayTIR) // todo
+	bool RayTIR;
+
+	UPROPERTY(BlueprintReadWrite, EditAnywhere, BlueprintGetter = GetTargetBufferWrite, BlueprintSetter = SetTargetBufferWrite) // todo
+	bool TargetBufferWrite;
+
+	UPROPERTY(BlueprintReadWrite, EditAnywhere, BlueprintGetter = GetTargetColorMode, BlueprintSetter = SetTargetColorMode) // todo
+	bool TargetColorMode;
+
+	UPROPERTY(BlueprintReadWrite, EditAnywhere, BlueprintGetter = GetWavelength, BlueprintSetter = SetWavelength) // todo
+	float Wavelength;
+
+	UPROPERTY(BlueprintReadWrite, EditAnywhere, BlueprintGetter = GetLaserWidth, BlueprintSetter = SetLaserWidth) // todo
+	float LaserWidth;
+
+	UPROPERTY(BlueprintReadWrite, EditAnywhere, BlueprintGetter = GetLaserPattern, BlueprintSetter = SetLaserPattern) // todo
+	EPatternTypes CurrentLaserPattern;
+
+};
diff --git a/Source/OptiX/Public/OptiXLaserTargetComponent.h b/Source/OptiX/Public/OptiXLaserTargetComponent.h
index 23b017674b6ec4fceefe5105f9a60f8b2997c4c2..b956bd8978b1d2d218c3bf1601c5218cc9fe5578 100644
--- a/Source/OptiX/Public/OptiXLaserTargetComponent.h
+++ b/Source/OptiX/Public/OptiXLaserTargetComponent.h
@@ -1,81 +1,52 @@
-// Fill out your copyright notice in the Description page of Project Settings.
-
-#pragma once
-
-#include "CoreMinimal.h"
-#include "OptiXObjectComponent.h"
-#include "OptiXBuffer.h"
-#include "OptiXLaserTargetComponent.generated.h"
-
-/**
- *  
- */
-UCLASS(Blueprintable, hidecategories = (Object), meta = (BlueprintSpawnableComponent)) // TODO Many things
-class OPTIX_API UOptiXLaserTargetComponent : public UOptiXObjectComponent
-{
-	GENERATED_BODY()
-
-public:
-	UOptiXLaserTargetComponent(const FObjectInitializer& ObjectInitializer);
-	
-	virtual void UpdateOptiXComponentVariables() override;
-
-	/* OptiXObjectComponent Interface Start */
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXComponent")
-	virtual void UpdateOptiXComponent() override;
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXComponent")
-	virtual void InitOptiXGeometry() override;
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXComponent")
-	virtual void InitOptiXMaterial() override;
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXComponent")
-	virtual void InitOptiXGroups() override;
-
-	virtual void CleanOptiXComponent() override;
-	/*OptiXObjectComponent Interface End*/
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXComponent")
-	float GetMaxFromBuffer();
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXComponent")
-	void UpdateBufferData();
-
-	/* Standard Component Interface Start */
-	//virtual void BeginPlay() override;
-	//virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
-	//virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;
-	/* Standard Component Interface End */
-
-public:
-
-	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "OptiX")
-	bool bIsColorMode;
-
-	UPROPERTY(BlueprintReadOnly, Category = "OptiX")
-	UOptiXTransform* OptiXTransform;
-
-	UPROPERTY(BlueprintReadOnly, Category = "OptiX")
-	UOptiXAcceleration* OptiXAcceleration;
-
-	UPROPERTY(BlueprintReadOnly, Category = "OptiX")
-	UOptiXBuffer* TargetBuffer;
-
-	UPROPERTY(BlueprintReadOnly, Category = "OptiX")
-	UOptiXBuffer* TargetBufferMax;
-
-	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "OptiX")
-	float TargetRes;
-
-	// Think about this later a bit - is there even a reason to save it like this?
-	// It seems much easier to have optix write the already correct colors in the buffer and then just do a FMemory:MemCpy?
-	TArray<FColor, TFixedAllocator<512 * 512>> ColorData; // Needs to be FColor so we can do an easy mem copy
-
-	float HighlightColorValue = 0.8f;
-
-	FColor HighlightColor;
-
-	TArray<FColor, TFixedAllocator<256>> ColorLUT;
-	UTexture2D* LUTTexture;
-};
+// Fill out your copyright notice in the Description page of Project Settings.
+
+#pragma once
+
+#include "CoreMinimal.h"
+#include "OptiXObjectComponent.h"
+#include "OptiXLaserTargetComponent.generated.h"
+
+/**
+ *  
+ */
+UCLASS(Blueprintable, hidecategories = (Object), meta = (BlueprintSpawnableComponent)) // TODO Many things
+class OPTIX_API UOptiXLaserTargetComponent : public UOptiXObjectComponent
+{
+	GENERATED_BODY()
+
+public:
+	UOptiXLaserTargetComponent(const FObjectInitializer& ObjectInitializer);
+	
+	virtual void BeginPlay() override;
+
+	/*OptiXObjectComponent Interface End*/
+
+	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXComponent")
+	//float GetMaxFromBuffer();
+
+	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXComponent")
+	//void UpdateBufferData();
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXComponent")
+	void ClearOptiXBuffer();
+
+
+public:
+
+	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "OptiX")
+	bool bIsColorMode;
+	
+	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "OptiX")
+	float TargetRes;
+
+	// Think about this later a bit - is there even a reason to save it like this?
+	// It seems much easier to have optix write the already correct colors in the buffer and then just do a FMemory:MemCpy?
+	TArray<FColor, TFixedAllocator<512 * 512>> ColorData; // Needs to be FColor so we can do an easy mem copy
+
+	float HighlightColorValue = 0.8f;
+
+	FColor HighlightColor;
+
+	TArray<FColor, TFixedAllocator<256>> ColorLUT;
+	UTexture2D* LUTTexture;
+};
diff --git a/Source/OptiX/Public/OptiXLensComponent.h b/Source/OptiX/Public/OptiXLensComponent.h
index b6953a3755e871fe5d1ff673f85a0f82f0c882bf..80e2ee17fb461d497311ccdc7718c94d242098ab 100644
--- a/Source/OptiX/Public/OptiXLensComponent.h
+++ b/Source/OptiX/Public/OptiXLensComponent.h
@@ -1,205 +1,143 @@
-// Fill out your copyright notice in the Description page of Project Settings.
-
-#pragma once
-
-#include "CoreMinimal.h"
-#include "OptiXObjectComponent.h"
-#include "OptiXGlassDefinitions.h"
-
-#include "OptiXLensComponent.generated.h"
-
-DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnLensRadiusChanged, float, Radius);
-DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnLensThicknessChanged, float, Thickness);
-
-
-
-///**
-// * Glass Type Enum
-// */
-//UENUM(BlueprintType)
-//enum class EGlassType : uint8 // TODO fix descriptions
-//{
-//	BK7 = 0					UMETA(DisplayName = "BK7"),
-//	SF5 = 1					UMETA(DisplayName = "SF5"),
-//	SF11 = 2				UMETA(DisplayName = "SF11"),
-//	FUSED_SILICA = 3		UMETA(DisplayName = "Fused silicia"),
-//	SK16 = 4				UMETA(DisplayName = "SK16"),
-//	F2 = 5					UMETA(DisplayName = "F2")
-//};
-
-/**
- * Lens Component
- */
-UCLASS(Blueprintable, hidecategories = (Object), meta = (BlueprintSpawnableComponent)) // TODO Many things
-class OPTIX_API UOptiXLensComponent : public UOptiXCubemapComponent
-{
-	GENERATED_BODY()
-	
-public:
-
-	UOptiXLensComponent(const FObjectInitializer& ObjectInitializer);
-
-	virtual void BeginPlay() override;
-
-	// UOptiXObjectComponent Interface Start
-
-	virtual void UpdateOptiXComponentVariables() override;
-	
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXComponent")
-	virtual void UpdateOptiXComponent() override;
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXComponent")
-	virtual void InitOptiXGeometry() override;
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXComponent")
-	virtual void InitOptiXMaterial() override;
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXComponent")
-	virtual void InitOptiXGroups() override;
-
-	virtual void CleanOptiXComponent() override;
-	// UOptiXObjectComponent Interface End
-
-	virtual void InitCubemap(FRHICommandListImmediate & RHICmdList) override;
-
-	virtual void UpdateCubemap(FRHICommandListImmediate & RHICmdList) override;
-
-
-	// This sadly only works in the editor itself, leave it for now
-	//virtual void PostEditChangeProperty(FPropertyChangedEvent & PropertyChangedEvent) override;
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXLensComponent")
-	void InitFromData(const FLensData& Data);
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXLensComponent")
-		void SetThickness(float Thickness);
-	UFUNCTION(BlueprintPure, BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXLensComponent")
-		float GetThickness() const;
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXLensComponent")
-		void SetRadius1(float Radius);
-	UFUNCTION(BlueprintPure, BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXLensComponent")
-		float GetRadius1() const;
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXLensComponent")
-		void SetRadius2(float Radius);
-	UFUNCTION(BlueprintPure, BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXLensComponent")
-		float GetRadius2() const;
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXLensComponent")
-		void SetLensRadius(float Radius);
-	UFUNCTION(BlueprintPure, BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXLensComponent")
-		float GetLensRadius() const;
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXLensComponent")
-		void SetLensType1(ELensSideType Type);
-	UFUNCTION(BlueprintPure, BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXLensComponent")
-		ELensSideType GetLensType1() const;
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXLensComponent")
-		void SetLensType2(ELensSideType Type);
-	UFUNCTION(BlueprintPure, BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXLensComponent")
-		ELensSideType GetLensType2() const;
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXLensComponent")
-	void SetGlassType(FString Type);
-
-	UFUNCTION(BlueprintPure, BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXLensComponent")
-	FString GetGlassType() const;
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXLensComponent")
-		void SetWavelength(float WL);
-	UFUNCTION(BlueprintPure, BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXLensComponent")
-		float GetWavelength() const;
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXLensComponent") // TODO
-	void MarkDirty();
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXLensComponent") // TODO
-	TArray<FString> GetGlassDefinitionNames();
-
-	UFUNCTION()
-	void OnWavelengthChangedEvent(float WL);
-
-	// Event callbacks:
-	UPROPERTY(BlueprintAssignable, Category = "OptiXLensComponent")
-	FOnLensRadiusChanged OnLensRadiusChanged;
-
-	UPROPERTY(BlueprintAssignable, Category = "OptiXLensComponent")
-	FOnLensThicknessChanged OnLensThicknessChanged;
-
-public:
-
-	// Lens Properties
-	// Let's try some more Unreal magic with the BlueprintGetter=GetterFunctionName and BlueprintSetter=SetterFunctionName
-	// functions!
-
-	UPROPERTY(BlueprintReadWrite, EditAnywhere, BlueprintGetter=GetThickness, BlueprintSetter=SetThickness) // todo
-	float LensThickness;
-
-	UPROPERTY(BlueprintReadWrite, EditAnywhere, BlueprintGetter=GetRadius1, BlueprintSetter=SetRadius1)
-	float Radius1;
-
-	UPROPERTY(BlueprintReadWrite, EditAnywhere, BlueprintGetter=GetRadius2, BlueprintSetter=SetRadius2)
-	float Radius2; // todo fix name
-
-	UPROPERTY(BlueprintReadWrite, EditAnywhere, BlueprintGetter=GetLensRadius, BlueprintSetter=SetLensRadius)
-	float LensRadius; // todo fix name
-
-	UPROPERTY(BlueprintReadWrite, EditAnywhere, BlueprintGetter=GetLensType1, BlueprintSetter=SetLensType1)
-	ELensSideType LensType1;
-
-	UPROPERTY(BlueprintReadWrite, EditAnywhere, BlueprintGetter=GetLensType2, BlueprintSetter=SetLensType2)
-	ELensSideType LensType2; // todo fix names again gah
-
-	UPROPERTY(BlueprintReadWrite, EditAnywhere, BlueprintGetter=GetGlassType, BlueprintSetter=SetGlassType)
-	FString GlassType;
-
-	// Wavelength in NM
-	UPROPERTY(BlueprintReadWrite, EditAnywhere, BlueprintGetter=GetWavelength, BlueprintSetter=SetWavelength)
-	float CurrentWavelength;
-
-
-
-	// Helper functions
-	float GetCylinderLength(float Thickness) const;
-
-private:
-
-	// Not sure if we need to even save them here.
-	UPROPERTY()
-	UOptiXTransform* OptiXTransform;
-
-	UPROPERTY()
-	UOptiXAcceleration* OptiXAcceleration;
-
-	UPROPERTY()
-	UOptiXBuffer* CubemapBuffer;
-
-	UPROPERTY()
-	UOptiXTextureSampler* CubemapSampler;
-
-	void RecalculateBoundingBox();
-
-
-
-
-	// Okay, for some crazy reason glass definitions have been originally saved here... TODOOOOO
-	//struct GlassDefinition
-	//{
-	//	FVector B;
-	//	FVector C;
-	//	GlassDefinition(FVector b, FVector c) : B(b), C(c)
-	//	{}
-	//};
-
-	//const TArray<GlassDefinition> GlassDefinitions =
-	//{
-	//	GlassDefinition(FVector(1.03961212f, 0.231792344f, 1.01046945f), FVector(0.00600069867f, 0.0200179144f, 103.560653f)),	// BK7
-	//	GlassDefinition(FVector(1.52481889f, 0.187085527f, 1.42729015f), FVector(0.011254756f, 0.0588995392f, 129.141675f)),	// SF5
-	//	GlassDefinition(FVector(1.73759695f, 0.313747346f, 1.89878101f), FVector(0.013188707f, 0.0623068142f, 155.23629f)),		// SF11
-	//	GlassDefinition(FVector(0.6961663f, 0.4079426f, 0.8974794f), FVector(0.0684043f, 0.1162414f, 9.896161f)),				// Fused S.
-	//	GlassDefinition(FVector(1.34317774f, 0.241144399f, 0.994317969f), FVector(0.00704687339f, 0.0229005f, 92.7508526f)),	// SK16
-	//	GlassDefinition(FVector(1.34533359f, 0.209073176f, 0.937357162f), FVector(0.00997743871f, 0.0470450767f, 111.886764f)),	// F2
-	//};
-};
+// Fill out your copyright notice in the Description page of Project Settings.
+
+#pragma once
+
+#include "CoreMinimal.h"
+#include "OptiXObjectComponent.h"
+#include "OptiXGlassDefinitions.h"
+
+#include "OptiXLensComponent.generated.h"
+
+DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnLensRadiusChanged, float, Radius);
+DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnLensThicknessChanged, float, Thickness);
+
+
+
+///**
+// * Glass Type Enum
+// */
+//UENUM(BlueprintType)
+//enum class EGlassType : uint8 // TODO fix descriptions
+//{
+//	BK7 = 0					UMETA(DisplayName = "BK7"),
+//	SF5 = 1					UMETA(DisplayName = "SF5"),
+//	SF11 = 2				UMETA(DisplayName = "SF11"),
+//	FUSED_SILICA = 3		UMETA(DisplayName = "Fused silicia"),
+//	SK16 = 4				UMETA(DisplayName = "SK16"),
+//	F2 = 5					UMETA(DisplayName = "F2")
+//};
+
+/**
+ * Lens Component
+ */
+UCLASS(Blueprintable, hidecategories = (Object), meta = (BlueprintSpawnableComponent)) // TODO Many things
+class OPTIX_API UOptiXLensComponent : public UOptiXCubemapComponent
+{
+	GENERATED_BODY()
+	
+public:
+
+	UOptiXLensComponent(const FObjectInitializer& ObjectInitializer);
+
+	virtual void BeginPlay() override;
+
+	// UOptiXObjectComponent Interface End
+
+	// This sadly only works in the editor itself, leave it for now
+	//virtual void PostEditChangeProperty(FPropertyChangedEvent & PropertyChangedEvent) override;
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXLensComponent")
+	void InitFromData(const FLensData& Data);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXLensComponent")
+		void SetThickness(float Thickness);
+	UFUNCTION(BlueprintPure, BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXLensComponent")
+		float GetThickness() const;
+
+	UFUNCTION(BlueprintPure, BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXLensComponent")
+		float GetThicknessForCylinderLength(float Length) const;
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXLensComponent")
+		void SetRadius1(float Radius);
+	UFUNCTION(BlueprintPure, BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXLensComponent")
+		float GetRadius1() const;
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXLensComponent")
+		void SetRadius2(float Radius);
+	UFUNCTION(BlueprintPure, BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXLensComponent")
+		float GetRadius2() const;
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXLensComponent")
+		void SetLensRadius(float Radius);
+	UFUNCTION(BlueprintPure, BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXLensComponent")
+		float GetLensRadius() const;
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXLensComponent")
+		void SetLensType1(ELensSideType Type);
+	UFUNCTION(BlueprintPure, BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXLensComponent")
+		ELensSideType GetLensType1() const;
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXLensComponent")
+		void SetLensType2(ELensSideType Type);
+	UFUNCTION(BlueprintPure, BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXLensComponent")
+		ELensSideType GetLensType2() const;
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXLensComponent")
+	void SetGlassType(FString Type);
+
+	UFUNCTION(BlueprintPure, BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXLensComponent")
+	FString GetGlassType() const;
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXLensComponent")
+		void SetWavelength(float WL);
+	UFUNCTION(BlueprintPure, BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXLensComponent")
+		float GetWavelength() const;
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXLensComponent") // TODO
+	TArray<FString> GetGlassDefinitionNames();
+
+	UFUNCTION()
+	void OnWavelengthChangedEvent(float WL);
+
+	// Event callbacks:
+	UPROPERTY(BlueprintAssignable, Category = "OptiXLensComponent")
+	FOnLensRadiusChanged OnLensRadiusChanged;
+
+	UPROPERTY(BlueprintAssignable, Category = "OptiXLensComponent")
+	FOnLensThicknessChanged OnLensThicknessChanged;
+
+public:
+
+	// Lens Properties
+	// Let's try some more Unreal magic with the BlueprintGetter=GetterFunctionName and BlueprintSetter=SetterFunctionName
+	// functions!
+
+	UPROPERTY(BlueprintReadWrite, EditAnywhere, BlueprintGetter=GetThickness, BlueprintSetter=SetThickness) // todo
+	float LensThickness;
+
+	UPROPERTY(BlueprintReadWrite, EditAnywhere, BlueprintGetter=GetRadius1, BlueprintSetter=SetRadius1)
+	float Radius1;
+
+	UPROPERTY(BlueprintReadWrite, EditAnywhere, BlueprintGetter=GetRadius2, BlueprintSetter=SetRadius2)
+	float Radius2; // todo fix name
+
+	UPROPERTY(BlueprintReadWrite, EditAnywhere, BlueprintGetter=GetLensRadius, BlueprintSetter=SetLensRadius)
+	float LensRadius; // todo fix name
+
+	UPROPERTY(BlueprintReadWrite, EditAnywhere, BlueprintGetter=GetLensType1, BlueprintSetter=SetLensType1)
+	ELensSideType LensType1;
+
+	UPROPERTY(BlueprintReadWrite, EditAnywhere, BlueprintGetter=GetLensType2, BlueprintSetter=SetLensType2)
+	ELensSideType LensType2; // todo fix names again gah
+
+	UPROPERTY(BlueprintReadWrite, EditAnywhere, BlueprintGetter=GetGlassType, BlueprintSetter=SetGlassType)
+	FString GlassType;
+
+	// Wavelength in NM
+	UPROPERTY(BlueprintReadWrite, EditAnywhere, BlueprintGetter=GetWavelength, BlueprintSetter=SetWavelength)
+	float CurrentWavelength;
+
+	// Helper functions
+	float GetCylinderLength(float Thickness) const;
+
+};
diff --git a/Source/OptiX/Public/OptiXModule.h b/Source/OptiX/Public/OptiXModule.h
index cacb573a7caea71905b9f1f7000ee771b9cb0483..c0d92508e9fac58b11aa9f2c0e0d5098c664de72 100644
--- a/Source/OptiX/Public/OptiXModule.h
+++ b/Source/OptiX/Public/OptiXModule.h
@@ -36,11 +36,6 @@ public:
 
 	void Init();
 
-	UOptiXContext* GetContext()
-	{
-		return GetOptiXContextManager()->GetOptiXContext();
-	}
-
 	TMap<FString, FGlassDefinition>& GetGlassDefinitions()
 	{
 		return GlassDefinitionsMap;
diff --git a/Source/OptiX/Public/OptiXObjectComponent.h b/Source/OptiX/Public/OptiXObjectComponent.h
index 87d15c4a5020fe79a258117a8a27fd279427798b..f451748d0b8c9ee973ea661b973286cd2689ab1c 100644
--- a/Source/OptiX/Public/OptiXObjectComponent.h
+++ b/Source/OptiX/Public/OptiXObjectComponent.h
@@ -1,191 +1,87 @@
-# pragma once
-
-#include "CoreMinimal.h"
-#include "UObject/ObjectMacros.h"
-#include "Components/PrimitiveComponent.h"
-#include "Runtime/Engine/Classes/Components/SceneCaptureComponentCube.h"
-
-#include "OptiXContext.h"
-#include "OptiXComponentInterface.h"
-
-#include "OptiXObjectComponent.generated.h"
-
-
-// The interface is sadly useless as unreal doesn't let me do what's possible in standard c++.
-
-UCLASS(abstract) //Blueprintable, hidecategories = (Object), meta=(BlueprintSpawnableComponent)) // TODO Many things
-class OPTIX_API UOptiXObjectComponent : public USceneComponent, public IOptiXComponentInterface
-{
-	GENERATED_BODY()
-
-public:
-
-	// UObject interface
-
-	UOptiXObjectComponent(const FObjectInitializer& ObjectInitializer);
-
-
-	virtual void OnUnregister() override;
-
-	//virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;
-
-
-	// End of UObject interface
-
-	// Begin UActorComponent interface
-	virtual void BeginPlay() override;
-	virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
-	// End UActorComponent interface
-
-	// USceneComponent interface
-	virtual void OnUpdateTransform(EUpdateTransformFlags UpdateTransformFlags, ETeleportType Teleport = ETeleportType::None) override;
-
-	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXComponent")
-	void InitOptiXComponent(FRHICommandListImmediate & RHICmdList) override;
-
-	virtual void RegisterOptiXComponent() override;
-
-	virtual void QueueOptiXContextUpdate() override;
-
-	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXComponent")
-	virtual void CleanOptiXComponent() override;
-
-	virtual void SetUpdateQueued(bool UpdateQueued) override;
-
-	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXComponent")
-	virtual void UpdateOptiXComponent() override {};
-
-	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXComponent")
-	virtual void InitOptiXGeometry() override {};
-
-	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXComponent")
-	virtual void InitOptiXMaterial() override {};
-
-	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXComponent")
-	virtual void InitOptiXGroups() override {};
-
-	FString OptiXPTXDir;
-
-public:
-
-	UPROPERTY(BlueprintReadOnly)
-	UOptiXContext* OptiXContext;
-
-	UPROPERTY(BlueprintReadOnly)
-	UOptiXGeometryGroup* OptiXGeometryGroup;
-
-	UPROPERTY(BlueprintReadOnly)
-	UOptiXGeometryInstance* OptiXGeometryInstance;
-
-	UPROPERTY(BlueprintReadOnly)
-	UOptiXGeometry* OptiXGeometry;
-
-	UPROPERTY(BlueprintReadOnly)
-	UOptiXMaterial* OptiXMaterial;
-
-protected:
-
-	UPROPERTY(BlueprintReadOnly)
-	bool bIsInitialized = false;
-
-	FThreadSafeBool bUpdateQueued = false;
-};
-
-
-UCLASS(abstract) //Blueprintable, hidecategories = (Object), meta=(BlueprintSpawnableComponent)) // TODO Many things
-class OPTIX_API UOptiXCubemapComponent : public USceneCaptureComponentCube, public IOptiXComponentInterface
-{
-	GENERATED_BODY()
-
-public:
-
-	// UObject interface
-
-	UOptiXCubemapComponent(const FObjectInitializer& ObjectInitializer);
-
-
-	virtual void OnUnregister() override;
-
-	// End of UObject interface
-
-	// Begin UActorComponent interface
-	virtual void BeginPlay() override;
-	virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
-	// End UActorComponent interface
-
-	// USceneComponent interface
-	virtual void OnUpdateTransform(EUpdateTransformFlags UpdateTransformFlags, ETeleportType Teleport = ETeleportType::None) override;
-
-	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXComponent")
-	void InitOptiXComponent(FRHICommandListImmediate & RHICmdList) override;
-
-
-	virtual void RegisterOptiXComponent() override;
-
-	virtual void QueueOptiXContextUpdate() override;
-
-	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXComponent")
-	virtual void CleanOptiXComponent() override;
-
-	virtual void SetUpdateQueued(bool UpdateQueued) override;
-
-	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXComponent")
-	virtual void UpdateOptiXComponent() override {};
-
-	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXComponent")
-	virtual void InitOptiXGeometry() override {};
-
-	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXComponent")
-	virtual void InitOptiXMaterial() override {};
-
-	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXComponent")
-	virtual void InitOptiXGroups() override {};
-
-	virtual void InitCubemap(FRHICommandListImmediate & RHICmdList) {};
-	virtual void UpdateCubemap(FRHICommandListImmediate & RHICmdList) {};
-
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXComponent")
-	void RequestCubemapUpdate();
-
-
-	FString OptiXPTXDir;
-
-public:
-
-	UPROPERTY(BlueprintReadOnly)
-	UOptiXContext* OptiXContext;
-
-	UPROPERTY(BlueprintReadOnly)
-	UOptiXGeometryGroup* OptiXGeometryGroup;
-
-	UPROPERTY(BlueprintReadOnly)
-	UOptiXGeometryInstance* OptiXGeometryInstance;
-
-	UPROPERTY(BlueprintReadOnly)
-	UOptiXGeometry* OptiXGeometry;
-
-	UPROPERTY(BlueprintReadOnly)
-	UOptiXMaterial* OptiXMaterial;
-
-	UPROPERTY(BlueprintReadOnly)
-	int32 OptiXCubemapId;
-
-	// Cubemap Unreal Stuff
-
-	UPROPERTY(BlueprintReadOnly, Category = OptiX)
-	UTextureRenderTargetCube* CubeRenderTarget;
-
-	FThreadSafeBool bCubemapCaptured = false;
-
-protected:
-
-	UPROPERTY(BlueprintReadOnly)
-	bool bIsInitialized = false;
-
-	FThreadSafeBool bUpdateQueued = false;
-};
-
-
-
-
+# pragma once
+
+#include "CoreMinimal.h"
+#include "UObject/ObjectMacros.h"
+#include "Components/PrimitiveComponent.h"
+#include "Runtime/Engine/Classes/Components/SceneCaptureComponentCube.h"
+
+//#include "OptiXContext.h"
+//#include "OptiXComponentInterface.h"
+
+#include "OptiXObjectComponent.generated.h"
+
+
+// The interface is sadly useless as unreal doesn't let me do what's possible in standard c++.
+
+UCLASS(abstract) //Blueprintable, hidecategories = (Object), meta=(BlueprintSpawnableComponent)) // TODO Many things
+class OPTIX_API UOptiXObjectComponent : public UPrimitiveComponent
+{
+	GENERATED_BODY()
+
+public:
+
+	// UObject interface
+
+	UOptiXObjectComponent(const FObjectInitializer& ObjectInitializer);
+
+	virtual FPrimitiveSceneProxy* CreateSceneProxy() override;
+
+
+	// End of UObject interface
+
+	// Begin UActorComponent interface
+	virtual void BeginPlay() override;
+	virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
+	// End UActorComponent interface
+
+		//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXComponent")
+	void CleanOptiXComponent();
+
+	// USceneComponent interface
+	virtual void OnUpdateTransform(EUpdateTransformFlags UpdateTransformFlags, ETeleportType Teleport = ETeleportType::None) override;
+};
+
+
+UCLASS(abstract) //Blueprintable, hidecategories = (Object), meta=(BlueprintSpawnableComponent)) // TODO Many things
+class OPTIX_API UOptiXCubemapComponent : public USceneCaptureComponentCube
+{
+	GENERATED_BODY()
+
+public:
+
+	// UObject interface
+
+	UOptiXCubemapComponent(const FObjectInitializer& ObjectInitializer);
+
+	// End of UObject interface
+
+	// Begin UActorComponent interface
+	virtual void BeginPlay() override;
+	virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
+	// End UActorComponent interface
+
+	// USceneComponent interface
+	virtual void OnUpdateTransform(EUpdateTransformFlags UpdateTransformFlags, ETeleportType Teleport = ETeleportType::None) override;
+
+	//UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXComponent")
+	void CleanOptiXComponent();	
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXCubemapComponent")
+	virtual void RequestCubemapUpdate();
+
+public:
+
+	UPROPERTY(BlueprintReadOnly)
+	int32 OptiXCubemapId;
+
+	// Cubemap Unreal Stuff
+
+	UPROPERTY(BlueprintReadOnly, Category = OptiX)
+	UTextureRenderTargetCube* CubeRenderTarget;
+
+	FThreadSafeBool bCubemapCaptured = false;
+};
+
+
+
+
diff --git a/Source/OptiX/Public/OptiXTargetComponent.h b/Source/OptiX/Public/OptiXTargetComponent.h
index 3e56c2c93fae1aaa0ca36ad3aa73dfbe5ec3a867..2ed3499dc4d156dc11239cecfee8305bb9a860e0 100644
--- a/Source/OptiX/Public/OptiXTargetComponent.h
+++ b/Source/OptiX/Public/OptiXTargetComponent.h
@@ -1,80 +1,55 @@
-// Fill out your copyright notice in the Description page of Project Settings.
-
-#pragma once
-
-#include "CoreMinimal.h"
-#include "OptiXObjectComponent.h"
-#include "OptiXTargetComponent.generated.h"
-
-/**
- * 
- */
-
-UENUM(BlueprintType)
-enum class ETexturePattern : uint8
-{
-	TP_BLACK	UMETA(DisplayName = "Black"),
-	TP_CIRCLES	UMETA(DisplayName = "Circles"),
-	TP_CHECKER	UMETA(DisplayName = "Checker"),
-	TP_GRID		UMETA(DisplayName = "Grid"),
-};
-
-
-UCLASS(Blueprintable, hidecategories = (Object), meta = (BlueprintSpawnableComponent)) // TODO Many things
-class OPTIX_API UOptiXTargetComponent : public UOptiXObjectComponent
-{
-	GENERATED_BODY()
-
-public:
-
-	UOptiXTargetComponent(const FObjectInitializer& ObjectInitializer);
-
-	virtual void BeginPlay() override;
-	
-	virtual void UpdateOptiXComponentVariables() override;
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXComponent")
-	virtual void UpdateOptiXComponent() override;
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXComponent")
-	virtual void InitOptiXGeometry() override;
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXComponent")
-	virtual void InitOptiXMaterial() override;
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXComponent")
-	virtual void InitOptiXGroups() override;
-
-	virtual void CleanOptiXComponent() override;
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXTargetComponent")
-	void SetSize(FVector NewSize);
-
-	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXTargetComponent")
-	FVector GetSize();
-
-
-public:
-
-	FIntPoint TextureSize;
-
-	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "OptiXTargetComponent")
-	FVector TargetSize;
-
-	UPROPERTY(BlueprintReadWrite, EditAnywhere)
-	ETexturePattern CurrentTexturePattern;
-
-private:
-
-	UPROPERTY()
-	UOptiXTransform* OptiXTransform;
-
-	UPROPERTY()
-	UOptiXAcceleration* OptiXAcceleration;
-
-	UPROPERTY()
-	UOptiXBuffer* TextureBuffer;
-
-	UPROPERTY()
-	UTexture2D* Texture;
-};
+// Fill out your copyright notice in the Description page of Project Settings.
+
+#pragma once
+
+#include "CoreMinimal.h"
+#include "OptiXObjectComponent.h"
+#include "OptiXTargetComponent.generated.h"
+
+/**
+ * 
+ */
+
+UENUM(BlueprintType)
+enum class ETexturePattern : uint8
+{
+	TP_BLACK	UMETA(DisplayName = "Black"),
+	TP_CIRCLES	UMETA(DisplayName = "Circles"),
+	TP_CHECKER	UMETA(DisplayName = "Checker"),
+	TP_GRID		UMETA(DisplayName = "Grid"),
+};
+
+
+UCLASS(Blueprintable, hidecategories = (Object), meta = (BlueprintSpawnableComponent)) // TODO Many things
+class OPTIX_API UOptiXTargetComponent : public UOptiXObjectComponent
+{
+	GENERATED_BODY()
+
+public:
+
+	UOptiXTargetComponent(const FObjectInitializer& ObjectInitializer);
+
+	virtual void BeginPlay() override;
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXTargetComponent")
+	void SetSize(FVector NewSize);
+
+	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXTargetComponent")
+	FVector GetSize();
+
+
+public:
+
+	FIntPoint TextureSize;
+
+	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "OptiXTargetComponent")
+	FVector TargetSize;
+
+	UPROPERTY(BlueprintReadWrite, EditAnywhere)
+	ETexturePattern CurrentTexturePattern;
+
+private:
+
+	UPROPERTY()
+	UTexture2D* Texture;
+};
diff --git a/Source/OptiX/Public/OptiXVRPawn.h b/Source/OptiX/Public/OptiXVRPawn.h
index 111f301317b55f1c67231291c4becc9cad7591a3..a8e181766206871d01d4e0736782a6fec4cbe6cd 100644
--- a/Source/OptiX/Public/OptiXVRPawn.h
+++ b/Source/OptiX/Public/OptiXVRPawn.h
@@ -5,6 +5,8 @@
 #include "CoreMinimal.h"
 #include "GameFramework/Pawn.h"
 #include "Components/SceneCaptureComponent2D.h"
+#include "Camera/CameraComponent.h"
+
 #include "OptiXVRPawn.generated.h"
 
 
@@ -84,4 +86,8 @@ public:
 
 	UPROPERTY(BlueprintReadWrite, EditAnywhere)
 	float Damping = 0.1f;
+
+	// Hacky but who cares, BP write into this
+	UPROPERTY(BlueprintReadWrite, EditAnywhere)
+	FVector HMDLocation;
 };
diff --git a/Source/OptiX/Public/OutlineStaticMeshComponent.h b/Source/OptiX/Public/OutlineStaticMeshComponent.h
new file mode 100644
index 0000000000000000000000000000000000000000..6ae4fc366ec2bb692042b943d1e58827e7745bac
--- /dev/null
+++ b/Source/OptiX/Public/OutlineStaticMeshComponent.h
@@ -0,0 +1,19 @@
+// Fill out your copyright notice in the Description page of Project Settings.
+
+#pragma once
+
+#include "CoreMinimal.h"
+#include "Components/StaticMeshComponent.h"
+#include "OutlineStaticMeshComponent.generated.h"
+
+/**
+ * 
+ */
+UCLASS(ClassGroup = (Rendering, Common), hidecategories = (Object, Activation, "Components|Activation"), ShowCategories = (Mobility), editinlinenew, meta = (BlueprintSpawnableComponent))
+class OPTIX_API UOutlineStaticMeshComponent : public UStaticMeshComponent
+{
+	GENERATED_BODY()
+
+	virtual FPrimitiveSceneProxy* CreateSceneProxy() override;
+
+};
diff --git a/Source/OptiX/Public/SelectableActorBase.h b/Source/OptiX/Public/SelectableActorBase.h
index 068d93a2ab701d56fce54fe9d74b7523d1f05bb0..f31db63a006bd6a218b4f1c1732d61d5060ac7be 100644
--- a/Source/OptiX/Public/SelectableActorBase.h
+++ b/Source/OptiX/Public/SelectableActorBase.h
@@ -3,17 +3,20 @@
 #pragma once
 
 #include "CoreMinimal.h"
+#include "UObject/ObjectMacros.h"
 #include "Engine/StaticMeshActor.h"
-#include "Components/WidgetComponent.h"
+#include "GameFramework/Actor.h"
 
+#include "Components/WidgetComponent.h"
+#include "OptiXVRPawn.h"
 
 #include "SelectableActorBase.generated.h"
 
 /**
  * 
  */
-UCLASS()
-class OPTIX_API ASelectableActorBase : public AStaticMeshActor
+UCLASS(hidecategories = (Input), showcategories = ("Input|MouseInput", "Input|TouchInput"), ConversionRoot, ComponentWrapperClass, meta = (ChildCanTick))
+class OPTIX_API ASelectableActorBase : public AActor
 {
 	GENERATED_BODY()
 
@@ -24,6 +27,15 @@ public:
 	virtual void BeginPlay() override;
 	virtual void Tick(float DeltaTime) override;
 
+	virtual void Serialize(FArchive& Ar) override;
+
+	/** Returns StaticMeshComponent subobject **/
+	class UStaticMeshComponent* GetStaticMeshComponent() const { return StaticMeshComponent; }
+
+	/** Function to change mobility type */
+	UFUNCTION(BlueprintCallable, Category = Mobility)
+	void SetMobility(EComponentMobility::Type InMobility);
+
 	UFUNCTION(BlueprintCallable, /*meta = (BlueprintProtected)*/ Category = "OptiXActor")
 	void SetScaleV(FRotator Rot);
 	
@@ -63,10 +75,11 @@ public:
 	UFUNCTION(BlueprintNativeEvent)
 	void OnOverlapEnd(UPrimitiveComponent* OverlappedComp, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex);
 
-
-
 public:
 
+	UPROPERTY(BlueprintReadOnly, VisibleAnywhere)
+	AOptiXVRPawn* OptiXVRPawn;
+
 	UPROPERTY(BlueprintReadWrite, EditAnywhere)
 	USceneComponent* Gizmo;
 
@@ -141,4 +154,16 @@ public:
 
 	UPROPERTY(BlueprintReadWrite, EditAnywhere)
 	UStaticMeshComponent* Socket;
+
+private:
+	UPROPERTY(Category = StaticMeshActor, VisibleAnywhere, BlueprintReadOnly, meta = (ExposeFunctionCategories = "Mesh,Rendering,Physics,Components|StaticMesh", AllowPrivateAccess = "true"))
+	class UStaticMeshComponent* StaticMeshComponent;
+
+
+protected:
+
+	//~ Begin UObject Interface.
+	virtual FString GetDetailedInfoInternal() const override;
+
+
 };