From 4a866fdcd4838945079391b74e59a0c19daf0bb2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nils=20Petter=20Sk=C3=A5lerud?= <np_skalerud@hotmail.com>
Date: Sun, 24 Mar 2019 12:29:31 +0100
Subject: [PATCH] Added support for colored point lights. Updated RenderSystem,
 shaders and components for colored light support. Tried working on the
 Utility::Color struct, still WIP.
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Nils Petter Skålerud <np_skalerud@hotmail.com>
---
 Data/Shaders/Mesh/Mesh.frag          | 21 ++++----
 Data/Shaders/Mesh/Mesh.vert          |  2 +-
 src/Engine/Application.cpp           |  2 -
 src/Engine/Components/PointLight.cpp |  3 +-
 src/Engine/Components/PointLight.hpp |  2 +
 src/Engine/Engine.cpp                |  4 ++
 src/Engine/Renderer/OpenGL.cpp       | 26 +++++++--
 src/Engine/Renderer/Renderer.hpp     | 13 ++---
 src/Engine/Systems/RenderSystem.cpp  |  7 ++-
 src/Engine/Utility/Color.hpp         | 81 ++++++++++++++++++++++++++--
 10 files changed, 130 insertions(+), 31 deletions(-)

diff --git a/Data/Shaders/Mesh/Mesh.frag b/Data/Shaders/Mesh/Mesh.frag
index 9adfd48..8c4156b 100644
--- a/Data/Shaders/Mesh/Mesh.frag
+++ b/Data/Shaders/Mesh/Mesh.frag
@@ -2,13 +2,15 @@
 
 layout(std140, binding = 0) uniform CameraData
 {
-	vec4 wsPosition;
+	vec3 wsPosition;
 	mat4 viewProjection;
 } cameraData;
 
 layout(std140, binding = 1) uniform LightData
 {
+	vec4 ambientLight;
 	uint pointLightCount;
+	vec4 pointLightIntensity[10];
 	vec4 pointLightPos[10];
 } lightData;
 
@@ -23,26 +25,25 @@ layout(location = 0) out vec4 frag_color;
 
 void main()
 {
-	vec3 pointToCamera = cameraData.wsPosition.xyz - fragData.wsPosition;
+	vec3 pointToCamera = cameraData.wsPosition - fragData.wsPosition;
 	vec3 pointToCameraDir = normalize(pointToCamera);
 
-	float test = 0.0;
+	vec3 diffuse;
+	vec3 specular;
 	for (int i = 0; i < lightData.pointLightCount; i++)
 	{
 		vec3 pointToLight = lightData.pointLightPos[i].xyz - fragData.wsPosition;
 		vec3 pointToLightDir = normalize(pointToLight);
 		
-		float diff = max(0, dot(pointToLightDir, fragData.wsNormal));
-		test += diff;
+		diffuse += max(0, dot(pointToLightDir, fragData.wsNormal)) * vec3(lightData.pointLightIntensity[i]);
 		
 		vec3 lightToPointDir = -pointToLightDir;
 		
 		vec3 reflectDir = reflect(lightToPointDir, fragData.wsNormal);
 		
-		float spec = pow(max(dot(pointToCameraDir, reflectDir), 0.0), 50);
-		
-		test += spec;
-		
+		const float coefficient = 50;
+		specular += pow(max(dot(pointToCameraDir, reflectDir), 0.0), coefficient) * vec3(1);
 	}
-	frag_color = vec4(test);
+	
+	frag_color = vec4(vec3(lightData.ambientLight) + diffuse + specular, 1.0);
 }
diff --git a/Data/Shaders/Mesh/Mesh.vert b/Data/Shaders/Mesh/Mesh.vert
index af8162a..0c2a91e 100644
--- a/Data/Shaders/Mesh/Mesh.vert
+++ b/Data/Shaders/Mesh/Mesh.vert
@@ -6,7 +6,7 @@ layout(location = 2) in vec3 vtxNormal;
 
 layout(std140, binding = 0) uniform CameraData
 {
-	vec4 wsPosition;
+	vec3 wsPosition;
 	mat4 viewProjection;
 } cameraData;
 
diff --git a/src/Engine/Application.cpp b/src/Engine/Application.cpp
index 72df58e..a30f9e5 100644
--- a/src/Engine/Application.cpp
+++ b/src/Engine/Application.cpp
@@ -23,8 +23,6 @@ namespace Engine
 				Application::API3D activeAPI;
 
 				void* windowHandle = nullptr;
-
-				
 			};
 
 			static std::unique_ptr<Data> data;
diff --git a/src/Engine/Components/PointLight.cpp b/src/Engine/Components/PointLight.cpp
index da60b31..9f42003 100644
--- a/src/Engine/Components/PointLight.cpp
+++ b/src/Engine/Components/PointLight.cpp
@@ -11,7 +11,8 @@ namespace Engine
 		PointLight::PointLight(SceneObject& owningObject) :
 			ParentType(owningObject),
 			positionOffset(),
-			intensity(1)
+			intensity(1),
+			color{1.f, 1.f, 1.f}
 		{
 		}
 
diff --git a/src/Engine/Components/PointLight.hpp b/src/Engine/Components/PointLight.hpp
index 5bbe42c..edf6078 100644
--- a/src/Engine/Components/PointLight.hpp
+++ b/src/Engine/Components/PointLight.hpp
@@ -6,6 +6,7 @@
 #include "DMath/Vector/Vector.hpp"
 #include "DMath/Matrix/Matrix.hpp"
 
+#include "../Utility/Color.hpp"
 
 namespace Engine
 {
@@ -20,6 +21,7 @@ namespace Engine
 			~PointLight();
 
 			float intensity;
+			Math::Vector3D color;
 			Math::Vector3D positionOffset;
 
 			[[nodiscard]] Math::Matrix<4, 3> GetModel_Reduced(Space space) const;
diff --git a/src/Engine/Engine.cpp b/src/Engine/Engine.cpp
index a89788a..27a9e38 100644
--- a/src/Engine/Engine.cpp
+++ b/src/Engine/Engine.cpp
@@ -56,11 +56,14 @@ void Engine::Core::Run()
 	Input::Core::Initialize();
 	Physics2D::Core::Initialize();
 
+
 	Renderer::CreateInfo rendererCreateInfo;
 	rendererCreateInfo.preferredAPI = Renderer::API::OpenGL;
 	rendererCreateInfo.surfaceDimensions = Application::GetWindowSize();
 	rendererCreateInfo.surfaceHandle = Application::Core::GetMainWindowHandle();
+
 	rendererCreateInfo.openGLCreateInfo.glSwapBuffers = Application::Core::GL_SwapWindow;
+
 	Renderer::Core::Initialize(std::move(rendererCreateInfo));
 
 	// Create scene and make viewport 0 point to scene 0.
@@ -89,6 +92,7 @@ void Engine::Core::Run()
 	auto& lightObj = scene1.NewSceneObject();
 	lightObj.transform.localPosition = { 2.5f, 2.5f, 2.5f };
 	Components::PointLight& light1 = lightObj.AddComponent<Components::PointLight>().first.get();
+	light1.color = { 1.f, 0.5f, 0.f };
 	auto& mesh3 = lightObj.AddComponent<Components::MeshRenderer>().first.get();
 	mesh3.SetMesh(Asset::Mesh::Cube);
 	mesh3.scale = { 0.1f, 0.1f, 0.1f };
diff --git a/src/Engine/Renderer/OpenGL.cpp b/src/Engine/Renderer/OpenGL.cpp
index 8648cc9..13e5bcd 100644
--- a/src/Engine/Renderer/OpenGL.cpp
+++ b/src/Engine/Renderer/OpenGL.cpp
@@ -55,14 +55,17 @@ namespace Engine
 
 struct Engine::Renderer::OpenGL::CameraDataUBO
 {
-	Math::Vector4D wsPosition;
+	Math::Vector3D wsPosition;
+	float padding1;
 	Math::Matrix<4, 4, float> viewProjection;
 };
 
 struct Engine::Renderer::OpenGL::LightDataUBO
 {
+	Math::Vector4D ambientLight;
 	uint32_t pointLightCount;
 	std::array<uint32_t, 3> padding1;
+	std::array<Math::Vector4D, 10> pointLightIntensity;
 	std::array<Math::Vector4D, 10> pointLightPos;
 };
 
@@ -306,6 +309,9 @@ void Engine::Renderer::OpenGL::Initialize(std::any& apiData, CreateInfo&& create
 	glEnable(GL_CULL_FACE);
 	glCullFace(GL_BACK);
 
+	//glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+
+
 
 	//LoadSpriteShader(data);
 	LoadMeshShader(data);
@@ -338,11 +344,25 @@ void Engine::Renderer::OpenGL::PrepareRenderingEarly(const std::vector<SpriteID>
 	UpdateIBODatabase(data, spriteLoadQueue);
 	UpdateVBODatabase(data, meshLoadQueue);
 
-	// Update light count
 	const auto& renderGraph = Core::GetRenderGraph();
+
+	// Update ambient light
+	constexpr GLintptr ambientLightOffset = offsetof(LightDataUBO, LightDataUBO::ambientLight);
+	glNamedBufferSubData(data.lightDataUBO, ambientLightOffset, sizeof(renderGraph.ambientLight), renderGraph.ambientLight.Data());
+
+	// Update light count
 	auto pointLightCount = static_cast<uint32_t>(renderGraph.pointLights.size());
 	constexpr GLintptr pointLightCountDataOffset = offsetof(LightDataUBO, LightDataUBO::pointLightCount);
 	glNamedBufferSubData(data.lightDataUBO, pointLightCountDataOffset, sizeof(pointLightCount), &pointLightCount);
+
+	// Update intensities
+	const size_t elements = Math::Min(10, renderGraph.pointLights.size());
+	std::array<Math::Vector4D, 10> intensityData;
+	for (size_t i = 0; i < elements; i++)
+		intensityData[i] = renderGraph.pointLights[i].AsVec4();
+	size_t byteLength = sizeof(Math::Vector4D) * elements;
+	constexpr GLintptr pointLightIntensityOffset = offsetof(LightDataUBO, LightDataUBO::pointLightIntensity);
+	glNamedBufferSubData(data.lightDataUBO, pointLightIntensityOffset, byteLength, intensityData.data());
 }
 
 bool testing = false;
@@ -365,7 +385,7 @@ void Engine::Renderer::OpenGL::PrepareRenderingLate()
 
 	// Update camera UBO
 	auto& cameraInfo = Renderer::Core::GetCameraInfo();
-	const Math::Vector4D& cameraWSPosition = cameraInfo.worldSpacePos.AsVec4();
+	const Math::Vector3D& cameraWSPosition = cameraInfo.worldSpacePos;
 	constexpr GLintptr cameraWSPositionDataOffset = offsetof(CameraDataUBO, CameraDataUBO::wsPosition);
 	glBindBuffer(GL_UNIFORM_BUFFER, data.cameraDataUBO);
 	glBufferSubData(GL_UNIFORM_BUFFER, cameraWSPositionDataOffset, sizeof(cameraWSPosition), cameraWSPosition.Data());
diff --git a/src/Engine/Renderer/Renderer.hpp b/src/Engine/Renderer/Renderer.hpp
index 22d9a53..98987a3 100644
--- a/src/Engine/Renderer/Renderer.hpp
+++ b/src/Engine/Renderer/Renderer.hpp
@@ -5,10 +5,9 @@
 #include "OpenGLCreateInfo.hpp"
 
 #include "../Utility/ImgDim.hpp"
-#include "../Utility/Color.hpp"
 
 #include "DMath/Vector/Vector.hpp"
-#include "DMath/UnitQuaternion.hpp"
+#include "DMath/Matrix/Matrix.hpp"
 
 #include <memory>
 #include <vector>
@@ -59,19 +58,17 @@ namespace Engine
 		API preferredAPI = API::None;
 		Utility::ImgDim surfaceDimensions{};
 		void* surfaceHandle = nullptr;
+		std::function<void(std::string_view)> errorMessageCallback;
 		OpenGL::CreateInfo openGLCreateInfo{};
 	};
 
-	struct Renderer::PointLight
-	{
-		float intensity;
-	};
-
 	struct Renderer::RenderGraph
 	{
 		std::vector<SpriteID> sprites;
 		std::vector<MeshID> meshes;
-		std::vector<PointLight> pointLights;
+		
+		Math::Vector3D ambientLight;
+		std::vector<Math::Vector<3, float>> pointLights;
 	};
 
 	struct Renderer::RenderGraphTransform
diff --git a/src/Engine/Systems/RenderSystem.cpp b/src/Engine/Systems/RenderSystem.cpp
index d48089d..be48bf5 100644
--- a/src/Engine/Systems/RenderSystem.cpp
+++ b/src/Engine/Systems/RenderSystem.cpp
@@ -42,7 +42,12 @@ namespace Engine
 			const auto& pointLightComponents = *pointLightComponentsPtr;
 			graph.pointLights.resize(pointLightComponents.size());
 			for (size_t i = 0; i < pointLightComponents.size(); i++)
-				graph.pointLights[i] = Renderer::PointLight{ pointLightComponents[i].intensity };
+			{
+				Math::Vector3D color = pointLightComponents[i].color;
+				for (auto& element : color)
+					element = Math::Clamp(element, 0.f, 1.f) * pointLightComponents[i].intensity;
+				graph.pointLights[i] = color;
+			}
 		}
 	}
 
diff --git a/src/Engine/Utility/Color.hpp b/src/Engine/Utility/Color.hpp
index c8b305b..673d2fa 100644
--- a/src/Engine/Utility/Color.hpp
+++ b/src/Engine/Utility/Color.hpp
@@ -1,15 +1,33 @@
 #pragma once
 
+#include <cstdint>
+#include <cassert>
+
 namespace Utility
 {
 	struct Color
 	{
-		static constexpr unsigned char length = 4;
+	public:
+		static constexpr uint8_t length = 4;
+
+		using ValueType = float;
+
+		ValueType r;
+		ValueType g;
+		ValueType b;
+		ValueType a;
+
+		constexpr void Clamp();
+		constexpr Color GetClamped() const;
+		
+		constexpr void Normalize();
+		constexpr Color GetNormalized() const;
+
+		constexpr ValueType& At(size_t i);
+		constexpr const ValueType& At(size_t i) const;
 
-		float r;
-		float g;
-		float y;
-		float x;
+		constexpr ValueType& operator[](size_t i);
+		constexpr const ValueType& operator[](size_t i) const;
 
 		static constexpr Color Black();
 		static constexpr Color White();
@@ -19,6 +37,59 @@ namespace Utility
 		static constexpr Color Blue();
 	};
 
+	constexpr void Color::Clamp()
+	{
+		for (size_t i = 0; i < length; i++)
+		{
+			ValueType& element = At(i);
+			if (element < 0)
+				element = 0;
+			else if (element > 1)
+				element = 1;
+		}
+	}
+
+	constexpr Color Color::GetClamped() const
+	{
+		Color newColor = *this;
+		newColor.Clamp();
+		return newColor;
+	}
+
+	constexpr Color::ValueType& Color::At(size_t i)
+	{
+		return const_cast<ValueType&>(std::as_const(*this).At(i));
+	}
+
+	constexpr const Color::ValueType& Color::At(size_t i) const
+	{
+		assert(0 <= i && i < length);
+		switch (i)
+		{
+		case 0:
+			return r;
+		case 1:
+			return g;
+		case 2:
+			return b;
+		case 3:
+			return a;
+		default:
+			assert(false);
+			return r;
+		}
+	}
+
+	constexpr Color::ValueType& Color::operator[](size_t i)
+	{
+		return At(i);
+	}
+
+	constexpr const Color::ValueType& Color::operator[](size_t i) const
+	{
+		return At(i);
+	}
+
 	constexpr Color Color::Black() { return { 0, 0, 0, 1 }; }
 
 	constexpr Color Color::White() { return { 1, 1, 1, 1 }; }
-- 
GitLab