diff --git a/Data/Shaders/Mesh/Mesh.frag b/Data/Shaders/Mesh/Mesh.frag
index 183e6756889380be8279b06cbc625a9951444024..72a9daef6d2e5aafedcbfea8edc2e8ca88eabb03 100644
--- a/Data/Shaders/Mesh/Mesh.frag
+++ b/Data/Shaders/Mesh/Mesh.frag
@@ -1,5 +1,11 @@
 #version 420 core
 
+layout(std140, binding = 1) uniform LightData
+{
+	uint pointLightCount;
+	vec4 pointLightPos[10];
+} lightData;
+
 in FragData
 {
 	vec3 wsPosition;
@@ -7,11 +13,13 @@ in FragData
 	vec2 uv;
 } fragData;
 
-vec3 lightPos = vec3(4.0, 5.0, 6.0);
-
 void main()
 {
-	vec3 pointToLight = normalize(lightPos - fragData.wsPosition);
-	float test = max(dot(pointToLight, fragData.wsNormal), 0);
+	float test = 0.0;
+	for (int i = 0; i < lightData.pointLightCount; i++)
+	{
+		vec3 pointToLight = normalize(lightData.pointLightPos[i].xyz - fragData.wsPosition);
+		test += max(dot(pointToLight, fragData.wsNormal), 0);
+	}
 	gl_FragColor = vec4(test, test, test, test);
 }
diff --git a/external/DMath b/external/DMath
index 0d9c06d9e19a54a8747147a370d5e73dfe616220..a17ca749764c26300ffaf2d8ffa13da38cc4d630 160000
--- a/external/DMath
+++ b/external/DMath
@@ -1 +1 @@
-Subproject commit 0d9c06d9e19a54a8747147a370d5e73dfe616220
+Subproject commit a17ca749764c26300ffaf2d8ffa13da38cc4d630
diff --git a/src/Engine/Application.cpp b/src/Engine/Application.cpp
index 9663b05cdf649442834d0f3e532c55eb96256ee9..72df58ef66bdbc665017983b5d6eba0ec7e7a694 100644
--- a/src/Engine/Application.cpp
+++ b/src/Engine/Application.cpp
@@ -53,8 +53,8 @@ namespace Engine
 				data = std::make_unique<Data>();
 				data->isRunning = true;
 
-				glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
-				glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
+				glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
+				glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
 				GLFWwindow* window = glfwCreateWindow(defaultWindowSize.width, defaultWindowSize.height, "My Title", NULL, NULL);
 				if (!window)
 				{
@@ -133,6 +133,15 @@ Engine::Input::Raw::Button Engine::Application::Core::APIKeyToButton(int32_t api
 	case GLFW_KEY_LEFT_CONTROL:
 		return Button::LeftCtrl;
 
+	case GLFW_KEY_UP:
+		return Button::Up;
+	case GLFW_KEY_DOWN:
+		return Button::Down;
+	case GLFW_KEY_LEFT:
+		return Button::Left;
+	case GLFW_KEY_RIGHT:
+		return Button::Right;
+
 	case GLFW_KEY_A:
 		return Button::A;
 	case GLFW_KEY_B:
diff --git a/src/Engine/Engine.cpp b/src/Engine/Engine.cpp
index ac5b7a5317e5c9fa81afb2073b6b312c81cdbd00..5b001717dc6a4afcd278b60a39158c63507c6154 100644
--- a/src/Engine/Engine.cpp
+++ b/src/Engine/Engine.cpp
@@ -69,8 +69,8 @@ void Engine::Core::Run()
 
 
 	auto& sceneObject1 = scene1.NewSceneObject();
-	auto& sprite1 = sceneObject1.AddComponent<Components::MeshRenderer>().first.get();
-	sprite1.SetMesh(Asset::Mesh::Helmet);
+	auto& mesh1 = sceneObject1.AddComponent<Components::MeshRenderer>().first.get();
+	mesh1.SetMesh(Asset::Mesh::Helmet);
 
 	auto& mesh2 = sceneObject1.AddComponent<Components::MeshRenderer>().first.get();
 	mesh2.SetMesh(Asset::Mesh::Cube);
@@ -80,9 +80,19 @@ void Engine::Core::Run()
 	auto& camera = objCamera.AddComponent<Components::Camera>().first.get();
 	camera.positionOffset.z = 5.f;
 
-	auto& obj3 = scene1.NewSceneObject();
-	obj3.transform.localPosition = { 5.f, 5.f, 10.f };
-	Components::PointLight& light1 = obj3.AddComponent<Components::PointLight>().first.get();
+	auto& lightObj = scene1.NewSceneObject();
+	lightObj.transform.localPosition = { 2.5f, 2.5f, 2.5f };
+	Components::PointLight& light1 = lightObj.AddComponent<Components::PointLight>().first.get();
+	auto& mesh3 = lightObj.AddComponent<Components::MeshRenderer>().first.get();
+	mesh3.SetMesh(Asset::Mesh::Cube);
+	mesh3.scale = { 0.1f, 0.1f, 0.1f };
+
+	auto& obj4 = scene1.NewSceneObject();
+	obj4.transform.localPosition = { 0.f, -7.5f, -10.f };
+	Components::PointLight& light3 = obj4.AddComponent<Components::PointLight>().first.get();
+	auto& mesh4 = obj4.AddComponent<Components::MeshRenderer>().first.get();
+	mesh4.SetMesh(Asset::Mesh::Cube);
+	mesh4.scale = { 0.1f, 0.1f, 0.1f };
 
 
 	Renderer::RenderGraph graph;
@@ -109,6 +119,15 @@ void Engine::Core::Run()
 			camera.positionOffset += Math::Vector3D::Down() * speed * scene1.GetTimeData().GetDeltaTime();
 		camera.LookAt({ 0, 0, 0 });
 
+		if (Input::Raw::GetValue(Input::Raw::Button::Up))
+			lightObj.transform.localPosition.z += speed * scene1.GetTimeData().GetDeltaTime();
+		if (Input::Raw::GetValue(Input::Raw::Button::Down))
+			lightObj.transform.localPosition.z -= speed * scene1.GetTimeData().GetDeltaTime();
+		if (Input::Raw::GetValue(Input::Raw::Button::Left))
+			lightObj.transform.localPosition.x -= speed * scene1.GetTimeData().GetDeltaTime();
+		if (Input::Raw::GetValue(Input::Raw::Button::Right))
+			lightObj.transform.localPosition.x += speed * scene1.GetTimeData().GetDeltaTime();
+
 		if (Input::Raw::GetEventType(Input::Raw::Button::C) == Input::EventType::Pressed)
 		{
 			scene1.Clear();
diff --git a/src/Engine/Renderer/OpenGL.cpp b/src/Engine/Renderer/OpenGL.cpp
index 5cd066160f9b28561f7b12b5fa83a92abfbb02fa..065f8be0db7ffad6a4ecfa77090d58f250d0b3ab 100644
--- a/src/Engine/Renderer/OpenGL.cpp
+++ b/src/Engine/Renderer/OpenGL.cpp
@@ -44,8 +44,11 @@ namespace Engine
 			void Draw_SpritePass(const Data& data, const std::vector<SpriteID>& sprites, const std::vector<Math::Matrix4x4>& transforms);
 			void Draw_MeshPass(const Data& data, const std::vector<MeshID>& meshes, const std::vector<Math::Matrix4x4>& transforms);
 
+			void CreateStandardUBOs(Data& data);
 			void LoadSpriteShader(Data& data);
 			void LoadMeshShader(Data& data);
+
+			inline void PrintGLError(const char* string = "");
 		}
 	}
 }
@@ -58,7 +61,8 @@ struct Engine::Renderer::OpenGL::CameraDataUBO
 struct Engine::Renderer::OpenGL::LightDataUBO
 {
 	uint32_t pointLightCount;
-	std::array<Math::Vector4D, 10> pointLights;
+	std::array<uint32_t, 3> padding;
+	std::array<Math::Vector4D, 10> pointLightPos;
 };
 
 struct Engine::Renderer::OpenGL::VertexBufferObject
@@ -96,6 +100,7 @@ struct Engine::Renderer::OpenGL::Data
 	std::unordered_map<SpriteID, IBO> iboDatabase;
 
 	GLuint cameraDataUBO;
+	GLuint lightDataUBO;
 	GLuint samplerObject;
 
 	GLuint spriteProgram;
@@ -104,8 +109,6 @@ struct Engine::Renderer::OpenGL::Data
 
 	GLuint meshProgram;
 	GLint meshModelUniform;
-
-	
 };
 
 Engine::Renderer::OpenGL::Data& Engine::Renderer::OpenGL::GetData() { return std::any_cast<Data&>(Core::GetAPIData()); }
@@ -232,7 +235,44 @@ void Engine::Renderer::OpenGL::LoadMeshShader(Engine::Renderer::OpenGL::Data &da
 	// Grab uniforms
 	data.meshModelUniform = glGetUniformLocation(data.meshProgram, "model");
 
-	glUniformBlockBinding(data.meshProgram, 0, 0);
+	auto test = glGetUniformBlockIndex(data.meshProgram, "LightData");
+	glUniformBlockBinding(data.meshProgram, 1, 1);
+}
+
+inline void Engine::Renderer::OpenGL::PrintGLError(const char* string)
+{
+	if constexpr (enableDebug)
+	{
+		auto errorEnum = glGetError();
+		if (errorEnum != 0)
+		{
+			auto errorString = glewGetErrorString(errorEnum);
+			std::cout << string << errorString << std::endl;
+		}
+	}
+}
+
+void Engine::Renderer::OpenGL::CreateStandardUBOs(Data& data)
+{
+	std::array<GLuint, 2> buffers;
+	glGenBuffers(2, buffers.data());
+
+	PrintGLError("Making buffers for standard UBOs: ");
+
+	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));
+	PrintGLError("Making Camera UBO: ");
+
+	// Make light ubo
+	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));
+	PrintGLError("Making LightData UBO: ");
 }
 
 void Engine::Renderer::OpenGL::Initialize(std::any& apiData, CreateInfo&& createInfo)
@@ -245,11 +285,7 @@ void Engine::Renderer::OpenGL::Initialize(std::any& apiData, CreateInfo&& create
 
 	data.glSwapBuffers = std::move(createInfo.glSwapBuffers);
 
-	// Make camera ubo
-	glGenBuffers(1, &data.cameraDataUBO);
-	glBindBuffer(GL_UNIFORM_BUFFER, data.cameraDataUBO);
-	glBufferData(GL_UNIFORM_BUFFER, sizeof(CameraDataUBO), nullptr, GL_DYNAMIC_DRAW);
-	glBindBufferRange(GL_UNIFORM_BUFFER, 0, data.cameraDataUBO, 0, sizeof(CameraDataUBO));
+	CreateStandardUBOs(data);
 
 	// Gen sampler
 	glGenSamplers(1, &data.samplerObject);
@@ -265,22 +301,16 @@ void Engine::Renderer::OpenGL::Initialize(std::any& apiData, CreateInfo&& create
 	else
 		assert(false);
 
-
-
 	glEnable(GL_DEPTH_TEST);
 
 	glEnable(GL_CULL_FACE);
 	glCullFace(GL_BACK);
 
+
 	//LoadSpriteShader(data);
 	LoadMeshShader(data);
 
-	if constexpr (enableDebug)
-	{
-		auto errorEnum = glGetError();
-		if (errorEnum != 0)
-			std::cout << glewGetErrorString(errorEnum) << std::endl;
-	}
+	PrintGLError("End of GL init: ");
 }
 
 void Engine::Renderer::OpenGL::Terminate(std::any& apiData)
@@ -303,43 +333,56 @@ void Engine::Renderer::OpenGL::Terminate(std::any& apiData)
 
 void Engine::Renderer::OpenGL::PrepareRenderingEarly(const std::vector<SpriteID>& spriteLoadQueue, const std::vector<MeshID>& meshLoadQueue)
 {
-	UpdateIBODatabase(GetData(), spriteLoadQueue);
-	UpdateVBODatabase(GetData(), meshLoadQueue);
-}
+	Data& data = GetData();
 
-void Engine::Renderer::OpenGL::PrepareRenderingLate()
-{
-	// Update lights positions
+	UpdateIBODatabase(data, spriteLoadQueue);
+	UpdateVBODatabase(data, meshLoadQueue);
+
+	// Update light count
+	const auto& renderGraph = Core::GetRenderGraph();
+	uint32_t pointLightCount = renderGraph.pointLights.size();
+	glNamedBufferSubData(data.lightDataUBO, 0, sizeof(uint32_t), &pointLightCount);
 }
 
-void Engine::Renderer::OpenGL::Draw()
+void Engine::Renderer::OpenGL::PrepareRenderingLate()
 {
 	Data& data = GetData();
 
-	glClearColor(1.f, 0.f, 0.f, 1.f);
-	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+	const auto& renderGraphTransform = Core::GetRenderGraphTransform();
 
-	auto& viewport = Renderer::GetViewport(0);
+	// Update lights positions
+	const size_t elements = Math::Min(10, renderGraphTransform.pointLights.size());
+	std::array<Math::Vector4D, 10> posData;
+	for (size_t i = 0; i < elements; i++)
+		posData[i] = renderGraphTransform.pointLights[i].AsVec4();
+	size_t byteLength = sizeof(Math::Vector4D) * elements;
+
+	glNamedBufferSubData(data.lightDataUBO, sizeof(uint32_t) * 4, byteLength, posData.data());
 
+	auto& viewport = Renderer::GetViewport(0);
 
 	auto& cameraInfo = Renderer::Core::GetCameraInfo();
 	auto viewMatrix = cameraInfo.GetModel(viewport.GetDimensions().GetAspectRatio());
 	glNamedBufferSubData(data.cameraDataUBO, 0, sizeof(CameraDataUBO::viewProjection), viewMatrix.data.data());
+}
+
+void Engine::Renderer::OpenGL::Draw()
+{
+	Data& data = GetData();
+
+	glClearColor(0.25f, 0.f, 0.f, 1.f);
+	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 
 
 	const auto& renderGraph = Core::GetRenderGraph();
 	const auto& renderGraphTransform = Core::GetRenderGraphTransform();
 
-
 	Draw_SpritePass(data, renderGraph.sprites, renderGraphTransform.sprites);
 	Draw_MeshPass(data, renderGraph.meshes, renderGraphTransform.meshes);
 
-	if constexpr (enableDebug)
-	{
-		auto errorEnum = glGetError();
-		if (errorEnum != 0)
-			std::cout << glewGetErrorString(errorEnum) << std::endl;
-	}
+	PrintGLError("End of GL tick: ");
+
+	auto& viewport = Renderer::GetViewport(0);
 
 	data.glSwapBuffers(viewport.GetSurfaceHandle());
 }
diff --git a/src/Engine/Renderer/Renderer.cpp b/src/Engine/Renderer/Renderer.cpp
index ce93f8ad7bfe8b279ec478e56cf1da838924755d..97aef6c8d07ec283d17e2a4b51169a212070c774 100644
--- a/src/Engine/Renderer/Renderer.cpp
+++ b/src/Engine/Renderer/Renderer.cpp
@@ -109,20 +109,22 @@ void Engine::Renderer::Core::Terminate()
 
 void Engine::Renderer::Core::PrepareRenderingEarly(RenderGraph& renderGraphInput)
 {
-    auto& renderGraph = data->renderGraph;
+	Data& data = *Core::data;
 
-	UpdateAssetReferences(*data, renderGraph, &renderGraphInput);
+    auto& renderGraph = data.renderGraph;
+
+	UpdateAssetReferences(data, renderGraph, &renderGraphInput);
 
 	std::swap(renderGraph, renderGraphInput);
 
-	if (!data->loadSpriteQueue.empty() || !data->loadMeshQueue.empty())
+	if (!data.loadSpriteQueue.empty() || !data.loadMeshQueue.empty())
 		std::cout << "Loading sprite/mesh resource(s)..." << std::endl;
-	data->PrepareRenderingEarly(data->loadSpriteQueue, data->loadMeshQueue);
+	data.PrepareRenderingEarly(data.loadSpriteQueue, data.loadMeshQueue);
 
-	data->loadSpriteQueue.clear();
-	data->unloadSpriteQueue.clear();
-	data->loadMeshQueue.clear();
-	data->unloadMeshQueue.clear();
+	data.loadSpriteQueue.clear();
+	data.unloadSpriteQueue.clear();
+	data.loadMeshQueue.clear();
+	data.unloadMeshQueue.clear();
 }
 
 void Engine::Renderer::Core::PrepareRenderingLate(RenderGraphTransform &input)
@@ -133,6 +135,8 @@ void Engine::Renderer::Core::PrepareRenderingLate(RenderGraphTransform &input)
 	assert(IsCompatible(renderGraph, input));
 
 	std::swap(renderGraphTransform, input);
+
+	data->PrepareRenderingLate();
 }
 
 void Engine::Renderer::Core::Draw()