From fa792a362da1f2c59d43a6b3ccf8bb6a25b17ab0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nils=20Petter=20Sk=C3=A5lerud?= <np_skalerud@hotmail.com>
Date: Fri, 19 Apr 2019 10:53:27 +0200
Subject: [PATCH] =?UTF-8?q?Signed-off-by:=20Nils=20Petter=20Sk=C3=A5lerud?=
 =?UTF-8?q?=20<np=5Fskalerud@hotmail.com>?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 data/Shaders/Mesh/Mesh.frag                   |   7 +-
 data/Shaders/Sprite/sprite.frag               |  10 -
 data/Shaders/Sprite/sprite.vert               |  17 --
 external/DMath                                |   2 +-
 include/DEngine/AssetManager/AssetManager.hpp |   4 +-
 include/DEngine/Components/Camera.hpp         |   2 +-
 include/DEngine/Components/PointLight.hpp     |   1 +
 include/DEngine/SceneObject.hpp               |   3 +-
 include/InputRotate.hpp                       |  21 ++
 include/SinusMovement.hpp                     |   2 +
 src/Engine/Components/Camera.cpp              |   4 +-
 src/Engine/Components/PointLight.cpp          |   5 +
 src/Engine/Engine.cpp                         |  91 +++++-
 src/Engine/LoadGLTFScene.cpp                  |  59 ++--
 src/Engine/LoadGLTFScene.hpp                  |   4 +-
 src/Engine/Renderer/OpenGL.cpp                |  49 +++-
 src/Engine/Renderer/Renderer.cpp              |  18 +-
 src/Engine/SceneObject.cpp                    | 273 +++++++++++-------
 src/Engine/Systems/RenderSystem.cpp           |  33 +--
 src/InputRotate.cpp                           |  35 +++
 src/SinusMovement.cpp                         |   4 +-
 21 files changed, 422 insertions(+), 222 deletions(-)
 delete mode 100644 data/Shaders/Sprite/sprite.frag
 delete mode 100644 data/Shaders/Sprite/sprite.vert
 create mode 100644 include/InputRotate.hpp
 create mode 100644 src/InputRotate.cpp

diff --git a/data/Shaders/Mesh/Mesh.frag b/data/Shaders/Mesh/Mesh.frag
index a2370ad..73cf64c 100644
--- a/data/Shaders/Mesh/Mesh.frag
+++ b/data/Shaders/Mesh/Mesh.frag
@@ -36,14 +36,17 @@ void main()
 	vec3 pointToCamera = cameraData.wsPosition - fragData.wsPosition;
 	vec3 pointToCameraDir = normalize(pointToCamera);
 
+	vec3 ambient;
 	vec3 diffuse;
 	vec3 specular;
 	for (int i = 0; i < lightData.pointLightCount; i++)
 	{
 		vec3 pointToLight = lightData.pointLightPos[i].xyz - fragData.wsPosition;
-		
 		float distance = length(pointToLight);
 		float attenuation = 1.0 / (constant + linear * distance + quadratic * (distance * distance));
+	
+		ambient += attenuation * lightData.pointLightIntensity[i].xyz * 0.1f;
+		
 		
 		vec3 pointToLightDir = normalize(pointToLight);
 		
@@ -58,7 +61,7 @@ void main()
 		specular += vec3(pow(max(dot(pointToCameraDir, reflectDir), 0.0), coefficient) * lightData.pointLightIntensity[i] * attenuation);
 	}
 	
-	vec3 resultIntensity = diffuse * color + specular;
+	vec3 resultIntensity = (ambient + diffuse)  * color + specular;
 	vec3 resultColor = resultIntensity;
 	frag_color = vec4(resultColor, 1.0);
 }
diff --git a/data/Shaders/Sprite/sprite.frag b/data/Shaders/Sprite/sprite.frag
deleted file mode 100644
index 8ecd5b0..0000000
--- a/data/Shaders/Sprite/sprite.frag
+++ /dev/null
@@ -1,10 +0,0 @@
-#version 330
-
-in vec2 fragUV;
-
-uniform sampler2D sampler;
-
-void main()
-{	
-	gl_FragColor = texture(sampler, fragUV);
-}
diff --git a/data/Shaders/Sprite/sprite.vert b/data/Shaders/Sprite/sprite.vert
deleted file mode 100644
index bb53e55..0000000
--- a/data/Shaders/Sprite/sprite.vert
+++ /dev/null
@@ -1,17 +0,0 @@
-#version 330
-
-in vec3 position;
-in vec2 texCoord;
-in vec3 normal;
-
-out vec2 fragUV;
-
-uniform mat4 model;
-uniform mat4 viewProjection;
-
-void main()
-{
-	gl_Position = viewProjection * model * vec4(position, 1.0);
-	
-	fragUV = texCoord;
-}
diff --git a/external/DMath b/external/DMath
index 221eadc..30717a4 160000
--- a/external/DMath
+++ b/external/DMath
@@ -1 +1 @@
-Subproject commit 221eadc75e3ec0dfd0a244084a234fac24062312
+Subproject commit 30717a477868d3dcc8ce82f55c2f4d78236d4227
diff --git a/include/DEngine/AssetManager/AssetManager.hpp b/include/DEngine/AssetManager/AssetManager.hpp
index 7103c16..576b2b1 100644
--- a/include/DEngine/AssetManager/AssetManager.hpp
+++ b/include/DEngine/AssetManager/AssetManager.hpp
@@ -15,8 +15,8 @@ namespace Engine
 		struct MeshInfo
 		{
 			std::string path;
-			size_t meshIndex;
-			size_t primitiveIndex;
+			size_t meshIndex = 0;
+			size_t primitiveIndex = 0;
 
 			bool operator==(const MeshInfo& right) const;
 		};
diff --git a/include/DEngine/Components/Camera.hpp b/include/DEngine/Components/Camera.hpp
index 1e62bd2..232ee03 100644
--- a/include/DEngine/Components/Camera.hpp
+++ b/include/DEngine/Components/Camera.hpp
@@ -25,7 +25,7 @@ namespace Engine
 			static constexpr float defaultFovY = 50.f;
 			static constexpr float defaultOrtographicWidth = 10.f;
 			static constexpr float defaultZNear = 0.1f;
-			static constexpr float defaultZFar = 100.f;
+			static constexpr float defaultZFar = 10000.f;
 			static constexpr ProjectionMode defaultProjectionMode = ProjectionMode::Perspective;
 
 			explicit Camera(SceneObject& owningObject);
diff --git a/include/DEngine/Components/PointLight.hpp b/include/DEngine/Components/PointLight.hpp
index 4495e75..e529d79 100644
--- a/include/DEngine/Components/PointLight.hpp
+++ b/include/DEngine/Components/PointLight.hpp
@@ -26,6 +26,7 @@ namespace Engine
 
 			[[nodiscard]] Math::Matrix<4, 3> GetModel_Reduced(Space space) const;
 			[[nodiscard]] Math::Matrix4x4 GetModel(Space space) const;
+			[[nodiscard]] Math::Vector<3, float> GetPosition(Space space) const;
 		};
 	}
 }
\ No newline at end of file
diff --git a/include/DEngine/SceneObject.hpp b/include/DEngine/SceneObject.hpp
index b02983d..8bd21bb 100644
--- a/include/DEngine/SceneObject.hpp
+++ b/include/DEngine/SceneObject.hpp
@@ -43,6 +43,7 @@ namespace Engine
 		[[nodiscard]] Scene& GetScene();
 
 		[[nodiscard]] SceneObject* GetParent() const;
+		void SetParent(SceneObject* newParent);
 
 		template<typename T>
 		decltype(auto) AddComponent();
@@ -71,7 +72,7 @@ namespace Engine
 	private:
 		std::reference_wrapper<Scene> sceneRef;
 		SceneObject* parent = nullptr;
-		std::vector<SceneObject*> children;
+		std::vector<std::reference_wrapper<SceneObject>> children;
 		std::unordered_map<std::type_index, std::vector<size_t>> components;
 		std::unordered_map<std::type_index, size_t> singletonComponents;
 	};
diff --git a/include/InputRotate.hpp b/include/InputRotate.hpp
new file mode 100644
index 0000000..91eb9ec
--- /dev/null
+++ b/include/InputRotate.hpp
@@ -0,0 +1,21 @@
+#pragma once
+
+#include "DEngine/Components/ScriptBase.hpp"
+
+#include "DMath/Vector/Vector.hpp"
+
+namespace Assignment02
+{
+	class InputRotate : public Engine::Components::ScriptBase
+	{
+	public:
+		using ParentType = ScriptBase;
+
+		explicit InputRotate(Engine::SceneObject& owningObject);
+
+	protected:
+		void SceneStart() override;
+
+		void Tick() override;
+	};
+}
\ No newline at end of file
diff --git a/include/SinusMovement.hpp b/include/SinusMovement.hpp
index aace0dc..724025a 100644
--- a/include/SinusMovement.hpp
+++ b/include/SinusMovement.hpp
@@ -14,6 +14,8 @@ namespace Assignment02
 		explicit SinusMovement(Engine::SceneObject& owningObject);
 
 		Math::Vector3D startPos{};
+		float movementMultiplier = 7.5f;
+		float timeMultiplier = 25.f;
 
 	protected:
 		void SceneStart() override;
diff --git a/src/Engine/Components/Camera.cpp b/src/Engine/Components/Camera.cpp
index 254f6da..0cb2c19 100644
--- a/src/Engine/Components/Camera.cpp
+++ b/src/Engine/Components/Camera.cpp
@@ -81,9 +81,7 @@ namespace Engine
 			if (space == Space::Local)
 				return localPos;
 			else if (space == Space::World)
-			{
-				return GetSceneObject().GetPosition(space);
-			}
+				return Multiply_Reduced(GetSceneObject().GetModel_Reduced(space), localPos);
 			else
 			{
 				assert(false && "Invalid enum value.");
diff --git a/src/Engine/Components/PointLight.cpp b/src/Engine/Components/PointLight.cpp
index 3163059..952b3fd 100644
--- a/src/Engine/Components/PointLight.cpp
+++ b/src/Engine/Components/PointLight.cpp
@@ -33,5 +33,10 @@ namespace Engine
 			using namespace Math::LinTran3D;
 			return AsMat4(GetModel_Reduced(space));
 		}
+
+		Math::Vector<3, float> PointLight::GetPosition(Space space) const
+		{
+			return Math::LinTran3D::GetTranslation(GetModel_Reduced(space));
+		}
 	}
 }
\ No newline at end of file
diff --git a/src/Engine/Engine.cpp b/src/Engine/Engine.cpp
index 710e49e..bf80032 100644
--- a/src/Engine/Engine.cpp
+++ b/src/Engine/Engine.cpp
@@ -15,6 +15,7 @@
 #include "DEngine/Components/PointLight.hpp"
 
 #include "SinusMovement.hpp"
+#include "InputRotate.hpp"
 
 #include "Systems/RenderSystem.hpp"
 
@@ -41,16 +42,22 @@ namespace Engine
 		rendererInitInfo.preferredAPI = Renderer::API::OpenGL;
 
 		// Debug info
+		// Whether we want to enable debugging in the rendering system
+		// And the error callback method we want to use.
 		rendererInitInfo.debugInitInfo.useDebugging = true;
 		rendererInitInfo.debugInitInfo.errorMessageCallback = rendererDebugCallback;
 
+		// Dimensions and handle to a surface we have generated to render onto.
 		rendererInitInfo.surfaceDimensions = Application::GetWindowSize();
 		rendererInitInfo.surfaceHandle = Application::Core::GetMainWindowHandle();
 
+		// Set function pointer to our decoupled asset loaders.
 		rendererInitInfo.assetLoadCreateInfo.meshLoader = &AssMan::GetRendererMeshDoc;
 		rendererInitInfo.assetLoadCreateInfo.assetLoadEnd = &AssMan::Renderer_AssetLoadEndEvent;
 		rendererInitInfo.assetLoadCreateInfo.textureLoader = &LoadTexture;
 
+		// Function pointer to the Application systems GL_SwapBuffer function.
+		// This one goes to GLFW3's swap buffer function.
 		rendererInitInfo.openGLInitInfo.glSwapBuffers = &Application::Core::GL_SwapWindow;
 		Renderer::Core::Initialize(rendererInitInfo);
 	}
@@ -69,46 +76,102 @@ void Engine::Core::Run()
 	Scene& scene1 = Engine::NewScene();
 	Renderer::GetViewport(0).SetSceneRef(&scene1);
 
+	// Add our cube model to the asset manager
+	AssMan::MeshInfo meshInfo;
+	meshInfo.path = "data/Meshes/Cube/Cube.gltf";
+	size_t cubeMesh = AssMan::AddMesh(std::move(meshInfo));
+
+	// Create camera Object
+	// SceneObjects are guaranteed to be in the same place in memory always. No need for soft-references.
 	auto& objCamera = scene1.NewSceneObject();
 	objCamera.localPosition.z = -5.f;
+	// Add a component to our SceneObject (similiar to Unity's GameObject)
+	// This function returns a soft-reference to the component (.first) and a hard-reference (.second.get()).
+	// We use hard-references, but components may move in memory over the lifetime of the program
+	// so soft-references are usually preferred.
 	auto& camera = objCamera.AddComponent<Components::Camera>().second.get();
-	camera.zFar = 10000.f;
+	camera.rotation = camera.rotation;
 	objCamera.AddComponent<Components::FreeLook>();
 
+	// Light object 1
 	auto& lightObj = scene1.NewSceneObject();
 	lightObj.localPosition = { 0.f, 1.f, 0.f };
+	lightObj.localScale = { 0.1f, 0.1f, 0.1f };
 	Components::PointLight& light1 = lightObj.AddComponent<Components::PointLight>().second.get();
-	light1.color = { 1.f, 1.f, 1.f };
-	light1.intensity = 2.f;
-	lightObj.AddComponent<Assignment02::SinusMovement>();
-
-	auto& obj4 = scene1.NewSceneObject();
-	obj4.localPosition = { 0.f, -7.5f, -10.f };
-	//Components::PointLight& light3 = obj4.AddComponent<Components::PointLight>().second.get();
-
-
-	LoadGLTFScene(scene1, "Data/Sponza2/Sponza.gltf");
-
-	const auto& meshCompVector = scene1.GetAllComponents<Components::MeshRenderer>();
-
+	light1.color = { 1.f, 0.5f, 0.5f };
+	light1.intensity = 0.5f;
+	auto& sinus1 = lightObj.AddComponent<Assignment02::SinusMovement>();
+	auto& mesh1 = lightObj.AddComponent<Components::MeshRenderer>().second.get();
+	mesh1.mesh = cubeMesh;
+	mesh1.texture = 0;
+
+
+	// Light object 2
+	auto& lightObj2 = scene1.NewSceneObject();
+	lightObj2.localPosition = { 0.f, 5.f, 3.f };
+	lightObj2.localScale = { 0.1f, 0.1f, 0.1f };
+	auto& mesh2 = lightObj2.AddComponent<Components::MeshRenderer>().second.get();
+	mesh2.mesh = cubeMesh;
+	mesh2.texture = 0;
+	auto& sinus2 = lightObj2.AddComponent<Assignment02::SinusMovement>();
+	sinus2.timeMultiplier = 15.f;
+	sinus2.movementMultiplier = -sinus2.movementMultiplier;
+	Components::PointLight& light2 = lightObj2.AddComponent<Components::PointLight>().second.get();
+	light2.color = { 0.5f, 1.f, 0.5f };
+	light2.intensity = 0.5f;
+
+
+	// Light object 3
+	auto& lightObj3 = scene1.NewSceneObject();
+	lightObj3.localPosition = { 0.f, 5.f, -3.5f };
+	lightObj3.localScale = { 0.1f, 0.1f, 0.1f };
+	auto& mesh3 = lightObj3.AddComponent<Components::MeshRenderer>().second.get();
+	mesh3.mesh = cubeMesh;
+	mesh3.texture = 0;
+	auto& sinus3 = lightObj3.AddComponent<Assignment02::SinusMovement>();
+	sinus3.timeMultiplier = 15.f;
+	Components::PointLight& light3 = lightObj3.AddComponent<Components::PointLight>().second.get();
+	light3.color = { 0.5f, 0.5f, 1.f };
+	light3.intensity = 0.5f;
+
+	// Load the GLTF scene, with a reference to the SceneObject we want to add it to
+	auto& rootObj = scene1.NewSceneObject();
+	rootObj.AddComponent<Assignment02::InputRotate>();
+	LoadGLTFScene(rootObj, "data/Sponza2/Sponza.gltf");
+
+	lightObj.SetParent(&rootObj);
+	lightObj2.SetParent(&rootObj);
+	lightObj3.SetParent(&rootObj);
+
+	// Not optimal solution. These are the RenderGraph struct we can work with. 
+	// Ideally they should belong to Rendering system
 	Renderer::RenderGraph graph;
 	Renderer::RenderGraphTransform graphTransform;
 
 
 	scene1.Scripts_SceneStart();
+	// Checks for any window events, like input etc and updates the Input system.
 	while (Application::Core::UpdateEvents(), Application::IsRunning())
 	{
+		// Calls all the custom script components' Tick function.
 		scene1.ScriptTick();
 
+		// Build the RenderGraph we want to submit to the rendering system
 		RenderSystem::BuildRenderGraph(scene1, graph);
+		// Submit built RenderGraph
 		Renderer::Core::PrepareRenderingEarly(graph);
 
+		// Update camera-info in the renderer by using the Camera-component we have made.
 		Renderer::Core::SetCameraInfo(GetRendererCameraInfo(camera));
+		// Build the positional data for the RenderGraph.
 		RenderSystem::BuildRenderGraphTransform(scene1, graphTransform);
+		// Submit the positional data for the RenderGraph
 		Renderer::Core::PrepareRenderingLate(graphTransform);
 
+		// Draw the most recently submitted RenderGraph
 		Renderer::Core::Draw();
 
+		// Various End-of-Tick events
 		Input::Core::ClearValues();
 		Time::Core::TickEnd(scene1.GetTimeData());
 	}
diff --git a/src/Engine/LoadGLTFScene.cpp b/src/Engine/LoadGLTFScene.cpp
index 4ee83f9..8d636fa 100644
--- a/src/Engine/LoadGLTFScene.cpp
+++ b/src/Engine/LoadGLTFScene.cpp
@@ -10,39 +10,48 @@
 
 namespace Engine
 {
-	bool LoadGLTFScene(Scene& scene, std::filesystem::path path)
+	bool LoadGLTFScene(SceneObject& obj, std::filesystem::path path)
 	{
 		auto gltfDoc = fx::gltf::LoadFromText(path.string());
 
+		Scene& scene = obj.GetScene();
+
+		// Generate one sceneObject for all our primitives to be attached to.
 		auto& sceneObj = scene.NewSceneObject();
+		sceneObj.SetParent(&obj);
+
+		// Software currently only supports one node with several primitives attached.
+		// Found no sample files to test with multiple nodes.
+		// Multiple nodes would mean multiple SceneObjects.
 
 		sceneObj.localScale = { gltfDoc.nodes[0].scale[0], gltfDoc.nodes[0].scale[1], gltfDoc.nodes[0].scale[2], };
 
-		for (size_t meshIndex = 0; meshIndex < gltfDoc.meshes.size(); meshIndex++)
-		{
-			const auto& mesh = gltfDoc.meshes[meshIndex];
+		// Grabs the GLTF mesh node 0 uses.
+		const auto& mesh = gltfDoc.meshes[gltfDoc.nodes[0].mesh];
 			
-			for (size_t primitiveIndex = 0; primitiveIndex < mesh.primitives.size(); primitiveIndex++)
-			{
-				const auto& primitive = mesh.primitives[primitiveIndex];
-
-				auto& compRef = sceneObj.AddComponent<Components::MeshRenderer>().second.get();
-
-				AssetManager::MeshInfo meshInfo{};
-				meshInfo.path = path.string();
-				meshInfo.meshIndex = meshIndex;
-				meshInfo.primitiveIndex = primitiveIndex;
-
-				size_t meshID = AssetManager::AddMesh(std::move(meshInfo));
-				compRef.SetMesh(meshID);
-
-				size_t baseColorTexIndex = gltfDoc.materials[primitive.material].pbrMetallicRoughness.baseColorTexture.index;
-				AssetManager::TextureInfo textureInfo{};
-				textureInfo.path = path.parent_path().string() + '/' + gltfDoc.images[baseColorTexIndex].uri;
-				
-				size_t textureID = AssetManager::AddTexture(std::move(textureInfo));
-				compRef.texture = textureID;
-			}
+		// Iterates through the primitives in this mesh and adds it to the AssetManager, then adds it as a component on the SceneObject
+		for (size_t primitiveIndex = 0; primitiveIndex < mesh.primitives.size(); primitiveIndex++)
+		{
+			const auto& primitive = mesh.primitives[primitiveIndex];
+
+			auto& compRef = sceneObj.AddComponent<Components::MeshRenderer>().second.get();
+
+			AssetManager::MeshInfo meshInfo{};
+			meshInfo.path = path.string();
+			meshInfo.meshIndex = gltfDoc.nodes[0].mesh;
+			meshInfo.primitiveIndex = primitiveIndex;
+
+			size_t meshID = AssetManager::AddMesh(std::move(meshInfo));
+			compRef.SetMesh(meshID);
+
+			// Adds the BaseColor (Diffuse) texture associated with this primitive, to the AssetManager
+			// and then references it in the MeshRenderer component.
+			size_t baseColorTexIndex = gltfDoc.materials[primitive.material].pbrMetallicRoughness.baseColorTexture.index;
+			AssetManager::TextureInfo textureInfo{};
+			textureInfo.path = path.parent_path().string() + '/' + gltfDoc.images[baseColorTexIndex].uri;
+
+			size_t textureID = AssetManager::AddTexture(std::move(textureInfo));
+			compRef.texture = textureID;
 		}
 
 		return true;
diff --git a/src/Engine/LoadGLTFScene.hpp b/src/Engine/LoadGLTFScene.hpp
index 3a4371c..bd1dedc 100644
--- a/src/Engine/LoadGLTFScene.hpp
+++ b/src/Engine/LoadGLTFScene.hpp
@@ -5,7 +5,7 @@
 
 namespace Engine
 {
-	class Scene;
+	class SceneObject;
 
-	bool LoadGLTFScene(Scene& scene, std::filesystem::path path);
+	bool LoadGLTFScene(SceneObject& scene, std::filesystem::path path);
 }
\ No newline at end of file
diff --git a/src/Engine/Renderer/OpenGL.cpp b/src/Engine/Renderer/OpenGL.cpp
index d8a93cb..7c2fada 100644
--- a/src/Engine/Renderer/OpenGL.cpp
+++ b/src/Engine/Renderer/OpenGL.cpp
@@ -215,11 +215,12 @@ namespace Engine
 		data.spriteSamplerUniform = glGetUniformLocation(data.spriteProgram, "sampler");
 	}
 
-	void Renderer::OpenGL::LoadMeshShader(Engine::Renderer::OpenGL::Data &data)
+	void Renderer::OpenGL::LoadMeshShader(Data &data)
 	{
 		// Create shader
 		data.meshProgram = glCreateProgram();
 
+		// Links the shader files to the shader program.
 		std::array<GLuint, 2> shader{};
 		shader[0] = CreateShader(LoadShader("Data/Shaders/Mesh/Mesh.vert"), GL_VERTEX_SHADER);
 		shader[1] = CreateShader(LoadShader("Data/Shaders/Mesh/Mesh.frag"), GL_FRAGMENT_SHADER);
@@ -239,9 +240,6 @@ namespace Engine
 		// Grab uniforms
 		data.meshModelUniform = glGetUniformLocation(data.meshProgram, "model");
 		data.meshTextureUniform = glGetUniformLocation(data.meshProgram, "texture");
-
-
-		glUniformBlockBinding(data.meshProgram, 1, 1);
 	}
 
 	void Renderer::OpenGL::CreateStandardUBOs(Data& data)
@@ -249,15 +247,14 @@ namespace Engine
 		std::array<GLuint, 2> buffers;
 		glGenBuffers(2, buffers.data());
 
+		// Make camera ubo, bind it to 0
 		data.cameraDataUBO = buffers[0];
-		data.lightDataUBO = buffers[1];
-
-		// Make camera ubo
 		glBindBuffer(GL_UNIFORM_BUFFER, data.cameraDataUBO);
 		glNamedBufferData(data.cameraDataUBO, sizeof(CameraDataUBO), nullptr, GL_DYNAMIC_DRAW);
 		glBindBufferRange(GL_UNIFORM_BUFFER, 0, data.cameraDataUBO, 0, sizeof(CameraDataUBO));
 
-		// Make light ubo
+		// Make light ubo, bind it to 1
+		data.lightDataUBO = buffers[1];
 		glBindBuffer(GL_UNIFORM_BUFFER, data.lightDataUBO);
 		glNamedBufferData(data.lightDataUBO, sizeof(LightDataUBO), nullptr, GL_DYNAMIC_DRAW);
 		glBindBufferRange(GL_UNIFORM_BUFFER, 1, data.lightDataUBO, 0, sizeof(LightDataUBO));
@@ -270,9 +267,11 @@ namespace Engine
 
     void Renderer::OpenGL::Initialize(std::any& apiData, const InitInfo& createInfo)
 	{
+		// Initializes GLEW
 		auto glInitResult = glewInit();
 		assert(glInitResult == 0);
 
+		// Allocates the memory associated with the OpenGL rendering.
 		apiData = std::make_any<Data>();
 		Data& data = std::any_cast<Data&>(apiData);
 
@@ -298,9 +297,10 @@ namespace Engine
 			}
 		}
 
+		// Creates UBO buffers for camera and lighting data.
 		CreateStandardUBOs(data);
 
-		// Gen sampler
+		// We only use 1 Sampler Object in this project. We generate it here and set its parameters.
 		glGenSamplers(1, &data.samplerObject);
 		glSamplerParameteri(data.samplerObject, GL_TEXTURE_WRAP_S, GL_REPEAT);
 		glSamplerParameteri(data.samplerObject, GL_TEXTURE_WRAP_T, GL_REPEAT);
@@ -311,20 +311,21 @@ namespace Engine
 		glSamplerParameteri(data.samplerObject, GL_TEXTURE_LOD_BIAS, 0);
 		glBindSampler(0, data.samplerObject);
 
+		// Basic OpenGL settings.
 		glEnable(GL_DEPTH_TEST);
-
 		glEnable(GL_CULL_FACE);
 		glCullFace(GL_BACK);
 
 		//glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
 
-		// Load default texture
+		// Load default texture, this texture will ordinarily be used if the renderer can't find the one it's supposed to use.
 		auto loadResult = DTex::LoadFromFile(std::string{ Setup::assetPath } + "/DRenderer/Textures/02.ktx");
 		assert(loadResult.GetResultInfo() == DTex::ResultInfo::Success && "Couldn't load the default texture for DRenderer.");
 		data.testIBO = GetIBOFromTexDoc(loadResult.GetValue()).value();
 
 
 		//LoadSpriteShader(data);
+		// Loads the mesh shader and initializes it.
 		LoadMeshShader(data);
 	}
 
@@ -350,12 +351,18 @@ namespace Engine
 	{
 		Data& data = GetAPIData();
 
+		// Loads any needed texture into the unordered_map of IBOs in Data.
 		UpdateIBODatabase(data, spriteLoadQueue);
+		// Loads any needed meshes into the unordered_map of VBOs in Data.
 		UpdateVBODatabase(data, meshLoadQueue);
+		// Sends signal that the renderer is done loading assets to render this frame.
+		// This helps the AssetManager know when it can discard loaded assets in CPU memory.
 		Core::GetData().assetLoadData.assetLoadEnd();
 
 		const auto& renderGraph = Core::GetRenderGraph();
 
+		// Below we load all light intensities, colors etc. onto our Camera UBO.
+
 		// Update ambient light
 		constexpr GLintptr ambientLightOffset = offsetof(LightDataUBO, LightDataUBO::ambientLight);
 		glNamedBufferSubData(data.lightDataUBO, ambientLightOffset, sizeof(renderGraph.ambientLight), renderGraph.ambientLight.data());
@@ -385,6 +392,8 @@ namespace Engine
 
 		const auto& renderGraphTransform = Core::GetRenderGraphTransform();
 
+		// Below we load all non-drawcall positional data onto OpenGL. This includes light- and camera positional data.
+
 		// Update lights positions
 		const size_t elements = Math::Min(10, renderGraphTransform.pointLights.size());
 		std::array<std::array<float, 4>, 10> posData;
@@ -423,11 +432,13 @@ namespace Engine
 		const auto& renderGraph = Core::GetRenderGraph();
 		const auto& renderGraphTransform = Core::GetRenderGraphTransform();
 
-		Draw_SpritePass(data, renderGraph.sprites, renderGraphTransform.sprites);
+		//Draw_SpritePass(data, renderGraph.sprites, renderGraphTransform.sprites);
+		// Here our Mesh rendering-pass begins and ends.
 		Draw_MeshPass(data, renderGraph.meshes, renderGraphTransform.meshes);
 
 		auto& viewport = Renderer::GetViewport(0);
 
+		// At the end of the drawing process, we grab the surface handle we drew on and swap the GL Buffers.
 		data.glSwapBuffers(viewport.GetSurfaceHandle());
 	}
 
@@ -473,13 +484,18 @@ namespace Engine
 
 			glProgramUniform1ui(data.meshProgram, data.meshTextureUniform, 0);
 
+			// Iterates over all Mesh-components to be drawn
 			for (size_t i = 0; i < meshes.size(); i++)
 			{
+				// Updates the model matrix
 				glProgramUniformMatrix4fv(data.meshProgram, data.meshModelUniform, 1, GL_FALSE, transforms[i].data());
 
+				// Find the correct vertex array object and binds it.
 				const VBO& vbo = data.vboDatabase.at(meshes[i].meshID);
 				glBindVertexArray(vbo.vertexArrayObject);
 
+				// Finds the correct texture object and binds it. If we couldn't find it,
+				// then we bind the default texture for the renderer. And log an error output.
 				glActiveTexture(GL_TEXTURE0);
 				auto iboIterator = data.iboDatabase.find(meshes[i].diffuseID);
 				if (iboIterator == data.iboDatabase.end())
@@ -493,6 +509,7 @@ namespace Engine
 				else
 					glBindTexture(GL_TEXTURE_2D, iboIterator->second.texture);
 
+				// We draw elements using information we got from our VBO
 				glDrawElements(GL_TRIANGLES, vbo.numIndices, vbo.indexType, nullptr);
 			}
 		}
@@ -531,9 +548,11 @@ namespace Engine
 	{
 		IBO ibo;
 
+		// Grabs the OpenGL data from the DTex::TexDoc structure.
 		GLenum target = DTex::ToGLTarget(input.GetTextureType());
 		GLint format = DTex::ToGLFormat(input.GetPixelFormat());
 		GLenum type = DTex::ToGLType(input.GetPixelFormat());
+
 		if (target == 0 || format == 0)
 		{
 			LogDebugMessage("Error. Texture can not be used in OpenGL.");
@@ -544,9 +563,11 @@ namespace Engine
 
 		glBindTexture(target, ibo.texture);
 
+		// Sets mipmapping parameters.
 		glTexParameteri(target, GL_TEXTURE_BASE_LEVEL, 0);
 		glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, GLint(input.GetMipLevels() - 1));
 
+		// Iterates over mipmap-levels and loads all image data onto OpenGL.
 		for (GLint level = 0; level < GLint(input.GetMipLevels()); level++)
 		{
 			GLsizei width = GLsizei(input.GetDimensions(level).width);
@@ -584,6 +605,8 @@ namespace Engine
 
 		VBO vbo;
 
+		// Here we load the metadata from our Renderer::MeshDocument struct
+
 		vbo.indexType = ToGLType(meshDocument.GetIndexType());
 		vbo.numIndices = meshDocument.GetIndexCount();
 
@@ -592,6 +615,8 @@ namespace Engine
 
 		glGenBuffers(GLint(vbo.attributeBuffers.size()), vbo.attributeBuffers.data());
 
+		// Below we move all the mesh-data onto the GPU on a per-attribute basis.
+
 		glBindBuffer(GL_ARRAY_BUFFER, vbo.attributeBuffers[size_t(VBO::Attribute::Position)]);
 		glBufferData(GL_ARRAY_BUFFER, meshDocument.GetByteLength(MeshDocument::Attribute::Position), meshDocument.GetDataPtr(MeshDocument::Attribute::Position), GL_STATIC_DRAW);
 		glEnableVertexAttribArray(size_t(VBO::Attribute::Position));
diff --git a/src/Engine/Renderer/Renderer.cpp b/src/Engine/Renderer/Renderer.cpp
index bb26924..c9c797c 100644
--- a/src/Engine/Renderer/Renderer.cpp
+++ b/src/Engine/Renderer/Renderer.cpp
@@ -125,6 +125,9 @@ namespace Engine
 
 	bool Renderer::Core::Initialize(const InitInfo& createInfo)
 	{
+		// Checks if the supplies InitInfo struct provides all the necessary info.
+		// This only happens if debugging is enabled.
+		// This doesn't happen at all when compiling in release mode.
 		if constexpr (Setup::enableDebugging)
 		{
 			if (createInfo.debugInitInfo.useDebugging)
@@ -149,15 +152,17 @@ namespace Engine
 
 		data.assetLoadData = createInfo.assetLoadCreateInfo;
 
+		// Creates a new viewport
 		NewViewport(createInfo.surfaceDimensions, createInfo.surfaceHandle);
 
+		// Initializes correct function pointers based on the preferred 3D API
 		switch (data.activeAPI)
 		{
 		case API::OpenGL:
 			OpenGL::Initialize(data.apiData, createInfo.openGLInitInfo);
-			data.Draw = OpenGL::Draw;
-			data.PrepareRenderingEarly = OpenGL::PrepareRenderingEarly;
-			data.PrepareRenderingLate = OpenGL::PrepareRenderingLate;
+			data.Draw = &OpenGL::Draw;
+			data.PrepareRenderingEarly = &OpenGL::PrepareRenderingEarly;
+			data.PrepareRenderingLate = &OpenGL::PrepareRenderingLate;
 			break;
 		default:
 			break;
@@ -186,14 +191,21 @@ namespace Engine
 
 		auto& renderGraph = data.renderGraph;
 
+		// Moves through the RenderGraph and tracks what assets are referenced
+		// to know which assets need to be loaded and which can be unloaded.
+		// Assets to be loaded/unloaded are stored in the data.load* queues.
 		UpdateAssetReferences(data, renderGraph, &renderGraphInput);
 
+		// Swaps the resources of the user's rendergraph and the one the renderer owns.
+		// This allows you to reuse allocated memory.
 		std::swap(renderGraph, renderGraphInput);
 
+		// Logs a message whenever textures or mesh assets need to be loaded.
 		if (!data.loadTextureQueue.empty() || !data.loadMeshQueue.empty())
 			LogDebugMessage("Loading sprite/mesh resource(s)...");
 		data.PrepareRenderingEarly(data.loadTextureQueue, data.loadMeshQueue);
 
+		// Clears all the load-asset queues.
 		data.loadTextureQueue.clear();
 		data.unloadTextureQueue.clear();
 		data.loadMeshQueue.clear();
diff --git a/src/Engine/SceneObject.cpp b/src/Engine/SceneObject.cpp
index f8fb6ad..c97575b 100644
--- a/src/Engine/SceneObject.cpp
+++ b/src/Engine/SceneObject.cpp
@@ -5,128 +5,201 @@
 #include "DMath/LinearTransform2D.hpp"
 #include "DMath/LinearTransform3D.hpp"
 
-Engine::SceneObject::SceneObject(Scene& owningScene, size_t indexInScene) : 
-	sceneRef(owningScene)
+namespace Engine
 {
-}
+	SceneObject::SceneObject(Scene& owningScene, size_t indexInScene) :
+		sceneRef(owningScene)
+	{
+	}
 
-Engine::SceneObject::~SceneObject()
-{
-	
-}
+	SceneObject::~SceneObject()
+	{
 
-Engine::Scene& Engine::SceneObject::GetScene() 
-{
-	return sceneRef.get();
-}
+	}
 
-Engine::SceneObject* Engine::SceneObject::GetParent() const { return parent; }
+	Scene& SceneObject::GetScene()
+	{
+		return sceneRef.get();
+	}
 
-Math::Vector3D Engine::SceneObject::GetPosition(Space space) const
-{
-	if (space == Space::Local)
-		return localPosition;
-	else
+	SceneObject* SceneObject::GetParent() const { return parent; }
+
+	void SceneObject::SetParent(SceneObject* newParent)
 	{
-		if (parent == nullptr)
+		if (parent == newParent)
+			return;
+
+		// Clean up old parent
+		if (parent != nullptr)
+		{
+			auto& parentChildVector = parent->children;
+			for (size_t i = 0; i < parentChildVector.size(); i++)
+			{
+				if (this == &parentChildVector[i].get())
+				{
+					parentChildVector[i] = parentChildVector.back();
+					parentChildVector.pop_back();
+					break;
+				}
+			}
+		}
+
+		parent = newParent;
+
+		// Add reference to new parent
+		if (parent != nullptr)
+			parent->children.emplace_back(*this);
+	}
+
+	Math::Vector3D SceneObject::GetPosition(Space space) const
+	{
+		using namespace Math::LinTran3D;
+
+		if (space == Space::Local)
 			return localPosition;
 		else
 		{
-			assert(false);
+			if (parent == nullptr)
+				return localPosition;
+			else
+				return Multiply_Reduced(parent->GetModel_Reduced(space), localPosition);
+		}
+	}
+
+	Math::Matrix<4, 3> SceneObject::GetModel_Reduced(Space space) const
+	{
+		using namespace Math::LinTran3D;
+
+		auto localModel = Multiply_Reduced(Rotate_Reduced(localRotation), Scale_Reduced(localScale));
+		Math::LinTran3D::AddTranslation(localModel, localPosition);
+
+		if (space == Space::Local || parent == nullptr)
+			return localModel;
+		else if (space == Space::World)
+			return Multiply_Reduced(parent->GetModel_Reduced(space), localModel);
+		else
+		{
+			assert(false && "Error. Undefined enum value.");
 			return {};
 		}
 	}
-}
 
-Math::Matrix<4, 3> Engine::SceneObject::GetModel_Reduced(Space space) const
-{
-	const auto& scaleModel = Math::LinTran3D::Scale_Reduced(localScale);
-	const auto& rotateModel = Math::LinTran3D::Rotate_Reduced(localRotation);
-	auto localModel = Math::LinTran3D::Multiply_Reduced(scaleModel, rotateModel);
-	Math::LinTran3D::AddTranslation(localModel, localPosition);
-	return localModel;
-}
-
-Math::Matrix<3, 2> Engine::SceneObject::GetModel2D_Reduced(Space space) const
-{
-	const auto& scaleModel = Math::LinTran2D::Scale_Reduced(localScale.x, localScale.y);
-	const auto& rotate = Math::LinTran2D::Rotate_Reduced(localRotation);
-	auto localModel = Math::LinTran2D::Multiply_Reduced(scaleModel, rotate);
-	Math::LinTran2D::AddTranslation(localModel, localPosition.x, localPosition.y);
-	return localModel;
-}
-
-Math::Matrix2x2 Engine::SceneObject::GetRotationModel2D(Space space) const
-{
-	return Math::Matrix2x2();
-}
+	Math::Matrix<3, 2> SceneObject::GetModel2D_Reduced(Space space) const
+	{
+		using namespace Math::LinTran2D;
 
-Math::Matrix<3, 3, float> Engine::SceneObject::GetRotationModel(Space space) const
-{
-	using namespace Math::LinearTransform3D;
+		auto localModel = Multiply_Reduced(Scale_Reduced(localScale.AsVec2()), Rotate_Reduced(localRotation));
+		AddTranslation(localModel, localPosition.AsVec2());
 
-	auto localModel = Rotate(localRotation);
-	if (space == Space::Local || parent == nullptr)
-		return localModel;
-	else
-		return parent->GetRotationModel(space) * localModel;
-}
+		if (space == Space::Local || parent == nullptr)
+			return localModel;
+		else if (space == Space::World)
+			return Multiply_Reduced(parent->GetModel2D_Reduced(space), localModel);
+		else
+		{
+			assert(false && "Error. Undefined enum value.");
+			return {};
+		}
+	}
 
-Math::Vector<3, float> Engine::SceneObject::GetForwardVector(Space space) const
-{
-	Math::UnitQuaternion<float> quat = localRotation;
+	Math::Matrix2x2 SceneObject::GetRotationModel2D(Space space) const
+	{
+		return Math::Matrix2x2();
+	}
+
+	Math::Matrix<3, 3, float> SceneObject::GetRotationModel(Space space) const
+	{
+		using namespace Math::LinTran3D;
 
-	const auto & s = quat.GetS();
-	const auto & x = quat.GetX();
-	const auto & y = quat.GetY();
-	const auto & z = quat.GetZ();
+		auto localModel = Rotate(localRotation);
+		if (space == Space::Local || parent == nullptr)
+			return localModel;
+		else if (space == Space::World)
+			return parent->GetRotationModel(space) * localModel;
+		else
+		{
+			assert(false && "Error. Undefined enum value.");
+			return {};
+		}
+	}
 
-	return
-	Math::Vector<3, float>
+	Math::Vector<3, float> SceneObject::GetForwardVector(Space space) const
 	{
-		2 * x* z + 2 * y * s, 
-		2 * y* z - 2 * x * s, 
-		1 - 2 * Math::Sqrd(x) - 2 * Math::Sqrd(y)
-	};
-}
+		const auto& s = localRotation.GetS();
+		const auto& x = localRotation.GetX();
+		const auto& y = localRotation.GetY();
+		const auto& z = localRotation.GetZ();
 
-Math::Vector<3, float> Engine::SceneObject::GetUpVector(Space space) const
-{
-	Math::UnitQuaternion<float> quat = localRotation;
+		Math::Vector<3, float> localForwardVector
+		{
+			2 * x * z + 2 * y * s,
+			2 * y * z - 2 * x * s,
+			1 - 2 * Math::Sqrd(x) - 2 * Math::Sqrd(y)
+		};
+
+		if (space == Space::Local || parent == nullptr)
+			return localForwardVector;
+		else if (space == Space::World)
+			return parent->GetRotationModel(space) * localForwardVector;
+		else
+		{
+			assert(false && "Error. Undefined enum value.");
+			return {};
+		}
+	}
+
+	Math::Vector<3, float> SceneObject::GetUpVector(Space space) const
+	{
+		const auto& s = localRotation.GetS();
+		const auto& x = localRotation.GetX();
+		const auto& y = localRotation.GetY();
+		const auto& z = localRotation.GetZ();
 
-	const auto & s = quat.GetS();
-	const auto & x = quat.GetX();
-	const auto & y = quat.GetY();
-	const auto & z = quat.GetZ();
+		Math::Vector<3, float> localUpVector
+		{
+			2 * x * y - 2 * z * s,
+			1 - 2 * Math::Sqrd(x) - 2 * Math::Sqrd(z),
+			2 * y * z + 2 * x * s
+		};
+
+		if (space == Space::Local || parent == nullptr)
+			return localUpVector;
+		else if (space == Space::World)
+			return parent->GetRotationModel(space) * localUpVector;
+		else
+		{
+			assert(false && "Error. Undefined enum value.");
+			return {};
+		}
+	}
 
-	return
-	Math::Vector<3, float>
+	Math::Vector<3, float> SceneObject::GetRightVector(Space space) const
 	{
-		2 * x* y - 2 * z * s,
-		1 - 2 * Math::Sqrd(x) - 2 * Math::Sqrd(z), 
-		2 * y* z + 2 * x * s
-	};
-}
+		const auto& s = localRotation.GetS();
+		const auto& x = localRotation.GetX();
+		const auto& y = localRotation.GetY();
+		const auto& z = localRotation.GetZ();
 
-Math::Vector<3, float> Engine::SceneObject::GetRightVector(Space space) const
-{
-	Math::UnitQuaternion<float> quat = localRotation;
-
-	const auto& s = quat.GetS();
-	const auto& x = quat.GetX();
-	const auto& y = quat.GetY();
-	const auto& z = quat.GetZ();
-
-	return 
-	Math::Vector<3, float>
-	{ 
-		1 - 2 * Math::Sqrd(y) - 2 * Math::Sqrd(z), 
-		2 * x * y + 2 * z * s,
-		2 * x * z - 2 * y * s 
-	};
-}
-
-void Engine::Destroy(SceneObject& sceneObject)
-{
-	Core::Destroy(sceneObject);
+		Math::Vector<3, float> localRightVector
+		{
+			1 - 2 * Math::Sqrd(y) - 2 * Math::Sqrd(z),
+			2 * x * y + 2 * z * s,
+			2 * x * z - 2 * y * s
+		};
+
+		if (space == Space::Local || parent == nullptr)
+			return localRightVector;
+		else if (space == Space::World)
+			return parent->GetRotationModel(space) * localRightVector;
+		else
+		{
+			assert(false && "Error. Undefined enum value.");
+			return {};
+		}
+	}
+
+	void Engine::Destroy(SceneObject & sceneObject)
+	{
+		Core::Destroy(sceneObject);
+	}
 }
\ No newline at end of file
diff --git a/src/Engine/Systems/RenderSystem.cpp b/src/Engine/Systems/RenderSystem.cpp
index 5afbc6e..8cfd17b 100644
--- a/src/Engine/Systems/RenderSystem.cpp
+++ b/src/Engine/Systems/RenderSystem.cpp
@@ -12,19 +12,7 @@ namespace Engine
 {
 	void RenderSystem::BuildRenderGraph(const Scene& scene, Renderer::RenderGraph& graph)
 	{
-		auto spriteComponentsPtr = scene.GetAllComponents<Components::SpriteRenderer>();
-		if (spriteComponentsPtr == nullptr)
-			graph.sprites.clear();
-		else
-		{
-			const auto& spriteComponents = *spriteComponentsPtr;
-			graph.sprites.resize(spriteComponents.size());
-			for (size_t i = 0; i < spriteComponents.size(); i++)
-			{
-				const auto& spriteComponent = spriteComponents[i];
-			}
-		}
-
+		// Copies all the MeshID and TextureID data (no positional data) from the components into the RenderGraph
 		auto meshComponentsPtr = scene.GetAllComponents<Components::MeshRenderer>();
 		if (meshComponentsPtr == nullptr)
 			graph.meshes.clear();
@@ -44,6 +32,7 @@ namespace Engine
 			}
 		}
 
+		// Loads all PointLight data (no positional data) onto the RenderGraph struct.
 		auto pointLightComponentsPtr = scene.GetAllComponents<Components::PointLight>();
 		if (pointLightComponentsPtr == nullptr)
 			graph.pointLightIntensities.clear();
@@ -63,17 +52,9 @@ namespace Engine
 
 	void RenderSystem::BuildRenderGraphTransform(const Scene& scene, Renderer::RenderGraphTransform& transforms)
 	{
-		auto spriteComponentsPtr = scene.GetAllComponents<Components::SpriteRenderer>();
-		if (spriteComponentsPtr == nullptr)
-			transforms.sprites.clear();
-		else
-		{
-			const auto& spriteComponents = *spriteComponentsPtr;
-			transforms.sprites.resize(spriteComponents.size());
-			for (size_t i = 0; i < spriteComponents.size(); i++)
-				transforms.sprites[i] = spriteComponents[i].GetModel(Space::World).data;
-		}
-
+		// Copies all the Mesh-components' positional data onto the RenderGraphTransform struct.
+		// This copies a full 4x4 matrix, it's faster because everything has
+		// to be converted to that format to move up the parent SceneObject chain anyways
 		auto meshComponentsPtr = scene.GetAllComponents<Components::MeshRenderer>();
 		if (meshComponentsPtr == nullptr)
 			transforms.meshes.clear();
@@ -85,6 +66,7 @@ namespace Engine
 				transforms.meshes[i] = meshComponents[i].GetModel(Space::World).data;
 		}
 
+		// Loads all the PointLight components' positional data over to the RenderGraphTransform
 		auto pointLightComponentsPtr = scene.GetAllComponents<Components::PointLight>();
 		if (pointLightComponentsPtr == nullptr)
 			transforms.pointLights.clear();
@@ -94,8 +76,7 @@ namespace Engine
 			transforms.pointLights.resize(pointLightComponents.size());
 			for (size_t i = 0; i < pointLightComponents.size(); i++)
 			{
-				const auto& model = pointLightComponents[i].GetModel_Reduced(Space::World);
-				const Math::Vector3D& position = Math::LinTran3D::GetTranslation(model);
+				const auto& position = pointLightComponents[i].GetPosition(Space::World);
 				transforms.pointLights[i] = { position.x, position.y, position.z };
 			}
 		}
diff --git a/src/InputRotate.cpp b/src/InputRotate.cpp
new file mode 100644
index 0000000..d477024
--- /dev/null
+++ b/src/InputRotate.cpp
@@ -0,0 +1,35 @@
+#include "InputRotate.hpp"
+
+#include "DEngine/SceneObject.hpp"
+#include "DEngine/Scene.hpp"
+
+#include "DMath/Trigonometric.hpp"
+
+#include "DEngine/Input/InputRaw.hpp"
+
+namespace Assignment02
+{
+	InputRotate::InputRotate(Engine::SceneObject& owner) :
+		ParentType(owner)
+	{
+
+	}
+
+	void InputRotate::SceneStart()
+	{
+		ParentType::SceneStart();
+	}
+
+	void InputRotate::Tick()
+	{
+		ParentType::Tick();
+
+		const auto& scene = GetSceneObject().GetScene();
+		float deltaTime = scene.GetTimeData().GetDeltaTime();
+
+		if (Engine::Input::Raw::GetValue(Engine::Input::Raw::Button::Up))
+			GetSceneObject().localRotation = Math::UnitQuaternion<float>({ 0.f, 0.f, 10.f * deltaTime }) * GetSceneObject().localRotation;
+		if (Engine::Input::Raw::GetValue(Engine::Input::Raw::Button::Down))
+			GetSceneObject().localRotation = Math::UnitQuaternion<float>({ 0.f, 0.f, -10.f * deltaTime }) * GetSceneObject().localRotation;
+	}
+}
\ No newline at end of file
diff --git a/src/SinusMovement.cpp b/src/SinusMovement.cpp
index 3d69eab..852062e 100644
--- a/src/SinusMovement.cpp
+++ b/src/SinusMovement.cpp
@@ -30,8 +30,6 @@ namespace Assignment02
 
 		float time = scene.GetTimeData().GetTimeSinceSceneStart();
 
-		float timeMultiplier = 25.f;
-		float moveMagnitudeMultipler = 7.5f;
-		GetSceneObject().localPosition.x = startPos.x + Math::Sin(time * timeMultiplier) * moveMagnitudeMultipler;
+		GetSceneObject().localPosition.x = startPos.x + Math::Sin(time * timeMultiplier) * movementMultiplier;
 	}
 }
\ No newline at end of file
-- 
GitLab