diff --git a/src/Engine/Asset.cpp b/src/Engine/Asset.cpp index 5a956ace6a267b1da7c9e3d5588c9ac8264baa88..71458652f5638e4f1aa2430e2e5ac02310b42769 100644 --- a/src/Engine/Asset.cpp +++ b/src/Engine/Asset.cpp @@ -150,6 +150,11 @@ Asset::TextureDocument Asset::LoadTextureDocument(Sprite texture) return TextureDocument(std::move(createInfo)); } +Engine::Renderer::MeshDocument Asset::LoadMesh(size_t i) +{ + return Engine::Renderer::MeshDocument(); +} + static Asset::MeshDocument::IndexType ToIndexType(fx::gltf::Accessor::ComponentType componentType) { switch (componentType) diff --git a/src/Engine/Asset.hpp b/src/Engine/Asset.hpp index 6fabdec161c59d54c0242788ab965c18a18753f2..b350dbb76028bba95a15e19ac752864a316f052f 100644 --- a/src/Engine/Asset.hpp +++ b/src/Engine/Asset.hpp @@ -8,6 +8,8 @@ #include <vector> #include <array> +#include "Renderer/MeshDocument.hpp" + namespace Asset { constexpr std::string_view textureFolderPath = "Data/Textures/"; @@ -29,6 +31,8 @@ namespace Asset MeshDocument LoadMeshDocument(Mesh mesh); MeshDocument LoadMeshDocument(const std::string& path); TextureDocument LoadTextureDocument(Sprite texture); + + Engine::Renderer::MeshDocument LoadMesh(size_t i); } class Asset::MeshDocument @@ -80,7 +84,6 @@ public: const uint8_t* GetDataPtr(Attribute type) const; Data GetData(Attribute type) const; -private: std::vector<uint8_t> byteArray; std::array<Data, static_cast<size_t>(Attribute::COUNT)> data; IndexType indexType; diff --git a/src/Engine/Engine.cpp b/src/Engine/Engine.cpp index 38ccf4f182eb76f663110f23d23662e403e7b8cf..3485afaa8eaade7e4de8b876a4e5d0c3d2485006 100644 --- a/src/Engine/Engine.cpp +++ b/src/Engine/Engine.cpp @@ -23,6 +23,8 @@ #include <iostream> +std::vector<std::unique_ptr<Engine::Scene>> Engine::Core::scenes; + class ScriptTest : public Engine::Components::ScriptBase { using ParentType = Engine::Components::ScriptBase; @@ -52,7 +54,28 @@ void rendererDebugCallback(std::string_view message) std::cout << "Renderer log: " << message << std::endl; } -std::vector<std::unique_ptr<Engine::Scene>> Engine::Core::scenes; +namespace Engine +{ + void InitializeRenderer() + { + // Initialize renderer + Renderer::InitInfo rendererInitInfo; + + rendererInitInfo.preferredAPI = Renderer::API::OpenGL; + + // Debug info + rendererInitInfo.debugInitInfo.useDebugging = true; + rendererInitInfo.debugInitInfo.errorMessageCallback = rendererDebugCallback; + + rendererInitInfo.surfaceDimensions = Application::GetWindowSize(); + rendererInitInfo.surfaceHandle = Application::Core::GetMainWindowHandle(); + + rendererInitInfo.assetLoadCreateInfo.meshLoader = &Asset::LoadMesh; + + rendererInitInfo.openGLInitInfo.glSwapBuffers = &Application::Core::GL_SwapWindow; + Renderer::Core::Initialize(rendererInitInfo); + } +} void Engine::Core::Run() { @@ -61,14 +84,7 @@ void Engine::Core::Run() Input::Core::Initialize(); Physics2D::Core::Initialize(); - // Initialize renderer - Renderer::CreateInfo rendererCreateInfo; - rendererCreateInfo.preferredAPI = Renderer::API::OpenGL; - rendererCreateInfo.surfaceDimensions = Application::GetWindowSize(); - rendererCreateInfo.surfaceHandle = Application::Core::GetMainWindowHandle(); - rendererCreateInfo.debugCreateInfo.errorMessageCallback = rendererDebugCallback; - rendererCreateInfo.openGLCreateInfo.glSwapBuffers = Application::Core::GL_SwapWindow; - Renderer::Core::Initialize(std::move(rendererCreateInfo)); + InitializeRenderer(); // Create scene and make viewport 0 point to scene 0. diff --git a/src/Engine/Renderer/MeshDocument.hpp b/src/Engine/Renderer/MeshDocument.hpp new file mode 100644 index 0000000000000000000000000000000000000000..501fd3e5eca3b2755afd778dde962356e229b40c --- /dev/null +++ b/src/Engine/Renderer/MeshDocument.hpp @@ -0,0 +1,99 @@ +#pragma once + +#include <cstddef> +#include <array> + +namespace Engine +{ + namespace Renderer + { + class MeshDocument + { + public: + using PositionType = std::array<float, 3>; + using UVType = std::array<float, 2>; + using NormalType = std::array<float, 3>; + using TangentType = std::array<float, 3>; + + enum class IndexType + { + UInt16, + UInt32 + }; + + static uint8_t ToByteSize(IndexType type); + + struct DataInfo + { + size_t byteOffset; + size_t byteLength; + }; + + enum class Attribute + { + Position, + TexCoord, + Normal, + Tangent, + Index, + COUNT + }; + + struct CreateInfo + { + std::vector<uint8_t> byteArray; + DataInfo posData; + DataInfo uvData; + DataInfo normalData; + DataInfo tangentData; + DataInfo indexData; + IndexType indexType; + }; + + MeshDocument(CreateInfo&& createInfo); + MeshDocument() = default; + + DataInfo GetData(Attribute attr) const; + const uint8_t* GetDataPtr(Attribute attr) const; + + IndexType GetIndexType() const; + uint32_t GetIndexCount() const; + + size_t GetTotalByteLength() const; + + IndexType indexType; + std::vector<uint8_t> byteArray; + std::array<DataInfo, static_cast<size_t>(Attribute::COUNT)> data; + }; + + inline MeshDocument::DataInfo MeshDocument::GetData(Attribute attr) const + { + return data.at(static_cast<size_t>(attr)); + } + + inline const uint8_t* MeshDocument::GetDataPtr(Attribute attr) const + { + return byteArray.data() + GetData(attr).byteOffset; + } + + inline MeshDocument::IndexType MeshDocument::GetIndexType() const + { + return indexType; + } + + inline uint32_t MeshDocument::GetIndexCount() const + { + return uint32_t( GetData( Attribute::Index).byteLength / ToByteSize(GetIndexType() ) ); + } + + inline size_t MeshDocument::GetTotalByteLength() const + { + return data.size(); + } + + inline uint8_t MeshDocument::ToByteSize(IndexType type) + { + return type == IndexType::UInt16 ? uint8_t(2) : uint8_t(4); + } + } +} \ No newline at end of file diff --git a/src/Engine/Renderer/OpenGL.cpp b/src/Engine/Renderer/OpenGL.cpp index b9fb42d355c478c1c21b19814ced71433aaba64b..9459f736a7b7985b01fa466f11a4f9d76aa81830 100644 --- a/src/Engine/Renderer/OpenGL.cpp +++ b/src/Engine/Renderer/OpenGL.cpp @@ -1,9 +1,8 @@ #include "Renderer.hpp" #include "RendererData.hpp" +#include "MeshDocument.hpp" #include "OpenGL.hpp" -#include "../Asset.hpp" - #include "GL/glew.h" #include <cassert> @@ -36,7 +35,7 @@ namespace Engine struct LightDataUBO; void UpdateVBODatabase(Data& data, const std::vector<MeshID>& loadQueue); - std::optional<VBO> VBOFromPath(const std::string& path); + std::optional<VBO> VBOFromPath(size_t id); void UpdateIBODatabase(Data& data, const std::vector<SpriteID>& loadQueue); Data& GetAPIData(); @@ -51,504 +50,499 @@ namespace Engine void GLDebugOutputCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message, const void *userParam); } } -} -struct Engine::Renderer::OpenGL::CameraDataUBO -{ - Math::Vector3D wsPosition; - float padding1; - Math::Matrix<4, 4, float> viewProjection; -}; + struct Renderer::OpenGL::CameraDataUBO + { + 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; -}; - -struct Engine::Renderer::OpenGL::VertexBufferObject -{ - enum class Attribute + struct Renderer::OpenGL::LightDataUBO { - Position, - TexCoord, - Normal, - Index, - COUNT + Math::Vector4D ambientLight; + uint32_t pointLightCount; + std::array<uint32_t, 3> padding1; + std::array<Math::Vector4D, 10> pointLightIntensity; + std::array<Math::Vector4D, 10> pointLightPos; }; - - void DeallocateDeviceBuffers(); - GLuint vertexArrayObject; - std::array<GLuint, static_cast<size_t>(Attribute::COUNT)> attributeBuffers; - uint32_t numIndices; - GLenum indexType; -}; + struct Renderer::OpenGL::VertexBufferObject + { + enum class Attribute + { + Position, + TexCoord, + Normal, + Index, + COUNT + }; + + void DeallocateDeviceBuffers(); + + GLuint vertexArrayObject; + std::array<GLuint, static_cast<size_t>(Attribute::COUNT)> attributeBuffers; + uint32_t numIndices; + GLenum indexType; + }; -struct Engine::Renderer::OpenGL::ImageBufferObject -{ - void DeallocateDeviceBuffers(); - GLuint texture; -}; + struct Renderer::OpenGL::ImageBufferObject + { + void DeallocateDeviceBuffers(); + GLuint texture; + }; -struct Engine::Renderer::OpenGL::Data -{ - std::function<void(void*)> glSwapBuffers; + struct Renderer::OpenGL::Data + { + std::function<void(void*)> glSwapBuffers; - std::unordered_map<MeshID, VBO> vboDatabase; - VBO quadVBO; + std::unordered_map<MeshID, VBO> vboDatabase; + VBO quadVBO; - std::unordered_map<SpriteID, IBO> iboDatabase; + std::unordered_map<SpriteID, IBO> iboDatabase; - GLuint cameraDataUBO; - GLuint lightDataUBO; - GLuint samplerObject; + GLuint cameraDataUBO; + GLuint lightDataUBO; + GLuint samplerObject; - GLuint spriteProgram; - GLint spriteModelUniform; - GLint spriteSamplerUniform; + GLuint spriteProgram; + GLint spriteModelUniform; + GLint spriteSamplerUniform; - GLuint meshProgram; - GLint meshModelUniform; -}; + GLuint meshProgram; + GLint meshModelUniform; + }; -Engine::Renderer::OpenGL::Data& Engine::Renderer::OpenGL::GetAPIData() { return std::any_cast<Data&>(Core::GetAPIData()); } + Renderer::OpenGL::Data& Renderer::OpenGL::GetAPIData() { return std::any_cast<Data&>(Core::GetAPIData()); } -static std::string LoadShader(const std::string& fileName) -{ - std::ifstream file; - file.open((fileName).c_str()); + static std::string LoadShader(const std::string& fileName) + { + std::ifstream file; + file.open((fileName).c_str()); - std::string output; - std::string line; + std::string output; + std::string line; - if (file.is_open()) - { - while (file.good()) + if (file.is_open()) { - getline(file, line); - output.append(line + "\n"); + while (file.good()) + { + getline(file, line); + output.append(line + "\n"); + } + } + else + { + Renderer::LogDebugMessage("Unable to load shader : " + fileName); } - } - else - { - if (Engine::Renderer::Core::GetData().debugData.errorMessageCallback) - Engine::Renderer::Core::GetData().debugData.errorMessageCallback("Unable to load shader : " + fileName); + return output; } - return output; -} - -static void CheckShaderError(GLuint shader, GLuint flag, bool isProgram, const std::string& errorMessage) -{ - GLint success = 0; - GLchar error[1024] = { 0 }; - - if (isProgram) - glGetProgramiv(shader, flag, &success); - else - glGetShaderiv(shader, flag, &success); - - if (success == GL_FALSE) + static void CheckShaderError(GLuint shader, GLuint flag, bool isProgram, const std::string& errorMessage) { + GLint success = 0; + GLchar error[1024] = { 0 }; + if (isProgram) - glGetProgramInfoLog(shader, sizeof(error), NULL, error); + glGetProgramiv(shader, flag, &success); else - glGetShaderInfoLog(shader, sizeof(error), NULL, error); + glGetShaderiv(shader, flag, &success); - if (Engine::Renderer::Core::GetData().debugData.errorMessageCallback) - Engine::Renderer::Core::GetData().debugData.errorMessageCallback(errorMessage + ": '" + error); - } -} - -static GLuint CreateShader(const std::string& text, GLuint type) -{ - GLuint shader = glCreateShader(type); + if (success == GL_FALSE) + { + if (isProgram) + glGetProgramInfoLog(shader, sizeof(error), NULL, error); + else + glGetShaderInfoLog(shader, sizeof(error), NULL, error); - if (shader == 0) - { - if (Engine::Renderer::Core::GetData().debugData.errorMessageCallback) - Engine::Renderer::Core::GetData().debugData.errorMessageCallback("Error compiling shader type " + type); + Renderer::LogDebugMessage(errorMessage + ": '" + error); + } } - const GLchar* p[1]; - p[0] = text.c_str(); - GLint lengths[1]; - lengths[0] = static_cast<GLint>(text.length()); - - glShaderSource(shader, 1, p, lengths); - glCompileShader(shader); - - std::string test = "Error compiling "; - if (type == GL_VERTEX_SHADER) - test += "vertex"; - else if (type == GL_FRAGMENT_SHADER) - test += "fragment"; - test += " shader"; - CheckShaderError(shader, GL_COMPILE_STATUS, false, test); + static GLuint CreateShader(const std::string& text, GLuint type) + { + GLuint shader = glCreateShader(type); - return shader; -} + if (shader == 0) + Renderer::LogDebugMessage("Error compiling shader type " + type); -void Engine::Renderer::OpenGL::LoadSpriteShader(Data& data) -{ - // Create shader - data.spriteProgram = glCreateProgram(); + const GLchar* p[1]; + p[0] = text.c_str(); + GLint lengths[1]; + lengths[0] = static_cast<GLint>(text.length()); - std::array<GLuint, 2> shaders{}; - shaders[0] = CreateShader(LoadShader("Data/Shaders/Sprite/sprite.vert"), GL_VERTEX_SHADER); - shaders[1] = CreateShader(LoadShader("Data/Shaders/Sprite/sprite.frag"), GL_FRAGMENT_SHADER); + glShaderSource(shader, 1, p, lengths); + glCompileShader(shader); - for (unsigned int i = 0; i < 2; i++) - glAttachShader(data.spriteProgram, shaders[i]); + std::string test = "Error compiling "; + if (type == GL_VERTEX_SHADER) + test += "vertex"; + else if (type == GL_FRAGMENT_SHADER) + test += "fragment"; + test += " shader"; + CheckShaderError(shader, GL_COMPILE_STATUS, false, test); - glLinkProgram(data.spriteProgram); - CheckShaderError(data.spriteProgram, GL_LINK_STATUS, true, "Error linking shader program"); + return shader; + } - glValidateProgram(data.spriteProgram); - CheckShaderError(data.spriteProgram, GL_LINK_STATUS, true, "Invalid shader program"); + void Renderer::OpenGL::LoadSpriteShader(Data& data) + { + // Create shader + data.spriteProgram = glCreateProgram(); - for (unsigned int i = 0; i < 2; i++) - glDeleteShader(shaders[i]); + std::array<GLuint, 2> shaders{}; + shaders[0] = CreateShader(LoadShader("Data/Shaders/Sprite/sprite.vert"), GL_VERTEX_SHADER); + shaders[1] = CreateShader(LoadShader("Data/Shaders/Sprite/sprite.frag"), GL_FRAGMENT_SHADER); - // Grab uniforms - data.spriteModelUniform = glGetUniformLocation(data.spriteProgram, "model"); + for (unsigned int i = 0; i < 2; i++) + glAttachShader(data.spriteProgram, shaders[i]); - data.spriteSamplerUniform = glGetUniformLocation(data.spriteProgram, "sampler"); -} + glLinkProgram(data.spriteProgram); + CheckShaderError(data.spriteProgram, GL_LINK_STATUS, true, "Error linking shader program"); -void Engine::Renderer::OpenGL::LoadMeshShader(Engine::Renderer::OpenGL::Data &data) -{ - // Create shader - data.meshProgram = glCreateProgram(); + glValidateProgram(data.spriteProgram); + CheckShaderError(data.spriteProgram, GL_LINK_STATUS, true, "Invalid 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); + for (unsigned int i = 0; i < 2; i++) + glDeleteShader(shaders[i]); - for (unsigned int i = 0; i < 2; i++) - glAttachShader(data.meshProgram, shader[i]); + // Grab uniforms + data.spriteModelUniform = glGetUniformLocation(data.spriteProgram, "model"); - glLinkProgram(data.meshProgram); - CheckShaderError(data.meshProgram, GL_LINK_STATUS, true, "Error linking shader program"); + data.spriteSamplerUniform = glGetUniformLocation(data.spriteProgram, "sampler"); + } - glValidateProgram(data.meshProgram); - CheckShaderError(data.meshProgram, GL_LINK_STATUS, true, "Invalid shader program"); + void Renderer::OpenGL::LoadMeshShader(Engine::Renderer::OpenGL::Data &data) + { + // Create shader + data.meshProgram = glCreateProgram(); - for (unsigned int i = 0; i < 2; i++) - glDeleteShader(shader[i]); + 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); - // Grab uniforms - data.meshModelUniform = glGetUniformLocation(data.meshProgram, "model"); + for (unsigned int i = 0; i < 2; i++) + glAttachShader(data.meshProgram, shader[i]); - glUniformBlockBinding(data.meshProgram, 1, 1); -} + glLinkProgram(data.meshProgram); + CheckShaderError(data.meshProgram, GL_LINK_STATUS, true, "Error linking shader program"); -void Engine::Renderer::OpenGL::CreateStandardUBOs(Data& data) -{ - std::array<GLuint, 2> buffers; - glGenBuffers(2, buffers.data()); + glValidateProgram(data.meshProgram); + CheckShaderError(data.meshProgram, GL_LINK_STATUS, true, "Invalid shader program"); - data.cameraDataUBO = buffers[0]; - data.lightDataUBO = buffers[1]; + for (unsigned int i = 0; i < 2; i++) + glDeleteShader(shader[i]); - // 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)); + // Grab uniforms + data.meshModelUniform = glGetUniformLocation(data.meshProgram, "model"); - // 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)); -} + glUniformBlockBinding(data.meshProgram, 1, 1); + } -void Engine::Renderer::OpenGL::GLDebugOutputCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message, const void *userParam) -{ - Core::GetData().debugData.errorMessageCallback(message); -} + void Renderer::OpenGL::CreateStandardUBOs(Data& data) + { + std::array<GLuint, 2> buffers; + glGenBuffers(2, buffers.data()); -void Engine::Renderer::OpenGL::Initialize(std::any& apiData, CreateInfo&& createInfo) -{ - auto glInitResult = glewInit(); - assert(glInitResult == 0); + data.cameraDataUBO = buffers[0]; + data.lightDataUBO = buffers[1]; - apiData = std::make_any<Data>(); - Data& data = std::any_cast<Data&>(apiData); + // 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)); - data.glSwapBuffers = std::move(createInfo.glSwapBuffers); + // 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)); + } - // Initialize debug stuff - if (Core::GetData().debugData.errorMessageCallback) + void Renderer::OpenGL::GLDebugOutputCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message, const void *userParam) { - GLint flags; - glGetIntegerv(GL_CONTEXT_FLAGS, &flags); - if (flags & GL_CONTEXT_FLAG_DEBUG_BIT) - { - glEnable(GL_DEBUG_OUTPUT); - glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); - glDebugMessageCallback(&GLDebugOutputCallback, nullptr); - glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, nullptr, GL_TRUE); - } - else - Core::GetData().debugData.errorMessageCallback("Error. Couldn't make GL Debug Output"); + LogDebugMessage(message); } - - - CreateStandardUBOs(data); - - // Gen sampler - glGenSamplers(1, &data.samplerObject); - glSamplerParameteri(data.samplerObject, GL_TEXTURE_WRAP_S, GL_REPEAT); - glSamplerParameteri(data.samplerObject, GL_TEXTURE_WRAP_T, GL_REPEAT); - glSamplerParameteri(data.samplerObject, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glSamplerParameteri(data.samplerObject, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - // Load sprite VBO - auto quadVBOOpt = VBOFromPath(static_cast<std::string>(Renderer::Setup::assetPath) + "/Meshes/SpritePlane/SpritePlane.gltf"); - if (quadVBOOpt.has_value()) - data.quadVBO = quadVBOOpt.value(); - else - assert(false); - - glEnable(GL_DEPTH_TEST); - - glEnable(GL_CULL_FACE); - glCullFace(GL_BACK); + void Renderer::OpenGL::Initialize(std::any& apiData, const InitInfo& createInfo) + { + auto glInitResult = glewInit(); + assert(glInitResult == 0); - //glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + apiData = std::make_any<Data>(); + Data& data = std::any_cast<Data&>(apiData); + data.glSwapBuffers = std::move(createInfo.glSwapBuffers); + // Initialize debug stuff + if constexpr (Setup::enableDebugging) + { + if (Core::GetData().debugData.useDebugging) + { + GLint flags; + glGetIntegerv(GL_CONTEXT_FLAGS, &flags); + if (flags & GL_CONTEXT_FLAG_DEBUG_BIT) + { + glEnable(GL_DEBUG_OUTPUT); + glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); + glDebugMessageCallback(&GLDebugOutputCallback, nullptr); + glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, nullptr, GL_TRUE); + } + else + LogDebugMessage("Error. Couldn't make GL Debug Output"); + } + } + + + CreateStandardUBOs(data); + + // Gen sampler + glGenSamplers(1, &data.samplerObject); + glSamplerParameteri(data.samplerObject, GL_TEXTURE_WRAP_S, GL_REPEAT); + glSamplerParameteri(data.samplerObject, GL_TEXTURE_WRAP_T, GL_REPEAT); + glSamplerParameteri(data.samplerObject, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glSamplerParameteri(data.samplerObject, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + // Load sprite VBO + /* + auto quadVBOOpt = VBOFromPath(static_cast<std::string>(Renderer::Setup::assetPath) + "/Meshes/SpritePlane/SpritePlane.gltf"); + if (quadVBOOpt.has_value()) + data.quadVBO = quadVBOOpt.value(); + else + assert(false); + */ - //LoadSpriteShader(data); - LoadMeshShader(data); -} + glEnable(GL_DEPTH_TEST); -void Engine::Renderer::OpenGL::Terminate(std::any& apiData) -{ - Data& data = std::any_cast<Data&>(apiData); + glEnable(GL_CULL_FACE); + glCullFace(GL_BACK); - data.quadVBO.DeallocateDeviceBuffers(); - for (auto& vboItem : data.vboDatabase) - vboItem.second.DeallocateDeviceBuffers(); + //glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - for (auto& iboItem : data.vboDatabase) - iboItem.second.DeallocateDeviceBuffers(); - glDeleteProgram(data.spriteProgram); - glDeleteProgram(data.meshProgram); - //delete static_cast<Data*>(apiData); - //apiData = nullptr; -} + //LoadSpriteShader(data); + LoadMeshShader(data); + } -void Engine::Renderer::OpenGL::PrepareRenderingEarly(const std::vector<SpriteID>& spriteLoadQueue, const std::vector<MeshID>& meshLoadQueue) -{ - Data& data = GetAPIData(); + void Renderer::OpenGL::Terminate(std::any& apiData) + { + Data& data = std::any_cast<Data&>(apiData); - UpdateIBODatabase(data, spriteLoadQueue); - UpdateVBODatabase(data, meshLoadQueue); + data.quadVBO.DeallocateDeviceBuffers(); + for (auto& vboItem : data.vboDatabase) + vboItem.second.DeallocateDeviceBuffers(); - const auto& renderGraph = Core::GetRenderGraph(); + for (auto& iboItem : data.vboDatabase) + iboItem.second.DeallocateDeviceBuffers(); - // Update ambient light - constexpr GLintptr ambientLightOffset = offsetof(LightDataUBO, LightDataUBO::ambientLight); - glNamedBufferSubData(data.lightDataUBO, ambientLightOffset, sizeof(renderGraph.ambientLight), renderGraph.ambientLight.Data()); + glDeleteProgram(data.spriteProgram); + glDeleteProgram(data.meshProgram); - // 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); + //delete static_cast<Data*>(apiData); + //apiData = nullptr; + } - // 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()); -} + void Renderer::OpenGL::PrepareRenderingEarly(const std::vector<SpriteID>& spriteLoadQueue, const std::vector<MeshID>& meshLoadQueue) + { + Data& data = GetAPIData(); + + UpdateIBODatabase(data, spriteLoadQueue); + UpdateVBODatabase(data, meshLoadQueue); + + 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()); + } -void Engine::Renderer::OpenGL::PrepareRenderingLate() -{ - Data& data = GetAPIData(); - - const auto& renderGraphTransform = Core::GetRenderGraphTransform(); - - // 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; - constexpr GLintptr pointLightPosDataOffset = offsetof(LightDataUBO, LightDataUBO::pointLightPos); - glNamedBufferSubData(data.lightDataUBO, pointLightPosDataOffset, byteLength, posData.data()); - - auto& viewport = Renderer::GetViewport(0); - - // Update camera UBO - auto& cameraInfo = Renderer::Core::GetCameraInfo(); - 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()); - - auto viewMatrix = cameraInfo.GetModel(viewport.GetDimensions().GetAspectRatio()); - constexpr GLintptr cameraViewProjectionDataOffset = offsetof(CameraDataUBO, CameraDataUBO::viewProjection); - glBufferSubData(GL_UNIFORM_BUFFER, cameraViewProjectionDataOffset, sizeof(viewMatrix), viewMatrix.Data()); -} - -void Engine::Renderer::OpenGL::Draw() -{ - Data& data = GetAPIData(); + void Renderer::OpenGL::PrepareRenderingLate() + { + Data& data = GetAPIData(); + + const auto& renderGraphTransform = Core::GetRenderGraphTransform(); + + // 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; + constexpr GLintptr pointLightPosDataOffset = offsetof(LightDataUBO, LightDataUBO::pointLightPos); + glNamedBufferSubData(data.lightDataUBO, pointLightPosDataOffset, byteLength, posData.data()); + + auto& viewport = Renderer::GetViewport(0); + + // Update camera UBO + auto& cameraInfo = Renderer::Core::GetCameraInfo(); + 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()); + + auto viewMatrix = cameraInfo.GetModel(viewport.GetDimensions().GetAspectRatio()); + constexpr GLintptr cameraViewProjectionDataOffset = offsetof(CameraDataUBO, CameraDataUBO::viewProjection); + glBufferSubData(GL_UNIFORM_BUFFER, cameraViewProjectionDataOffset, sizeof(viewMatrix), viewMatrix.Data()); + } - glClearColor(0.25f, 0.f, 0.f, 1.f); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + void Renderer::OpenGL::Draw() + { + Data& data = GetAPIData(); + 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); + const auto& renderGraph = Core::GetRenderGraph(); + const auto& renderGraphTransform = Core::GetRenderGraphTransform(); - auto& viewport = Renderer::GetViewport(0); + Draw_SpritePass(data, renderGraph.sprites, renderGraphTransform.sprites); + Draw_MeshPass(data, renderGraph.meshes, renderGraphTransform.meshes); - data.glSwapBuffers(viewport.GetSurfaceHandle()); -} + auto& viewport = Renderer::GetViewport(0); -void Engine::Renderer::OpenGL::Draw_SpritePass(const Data& data, - const std::vector<SpriteID>& sprites, - const std::vector<Math::Matrix4x4>& transforms) -{ - auto& viewport = Renderer::GetViewport(0); + data.glSwapBuffers(viewport.GetSurfaceHandle()); + } - // Sprite render pass - if (!sprites.empty()) + void Renderer::OpenGL::Draw_SpritePass(const Data& data, + const std::vector<SpriteID>& sprites, + const std::vector<Math::Matrix4x4>& transforms) { - glUseProgram(data.spriteProgram); + auto& viewport = Renderer::GetViewport(0); - glProgramUniform1ui(data.spriteProgram, data.spriteSamplerUniform, 0); - glBindSampler(0, data.samplerObject); + // Sprite render pass + if (!sprites.empty()) + { + glUseProgram(data.spriteProgram); - const auto& spriteVBO = data.quadVBO; - glBindVertexArray(spriteVBO.vertexArrayObject); + glProgramUniform1ui(data.spriteProgram, data.spriteSamplerUniform, 0); + glBindSampler(0, data.samplerObject); - for (size_t i = 0; i < sprites.size(); i++) - { - glProgramUniformMatrix4fv(data.spriteProgram, data.spriteModelUniform, 1, GL_FALSE, transforms[i].data.data()); + const auto& spriteVBO = data.quadVBO; + glBindVertexArray(spriteVBO.vertexArrayObject); - glActiveTexture(GL_TEXTURE0); - const IBO& ibo = data.iboDatabase.at(sprites[i]); - glBindTexture(GL_TEXTURE_2D, ibo.texture); + for (size_t i = 0; i < sprites.size(); i++) + { + glProgramUniformMatrix4fv(data.spriteProgram, data.spriteModelUniform, 1, GL_FALSE, transforms[i].data.data()); + + glActiveTexture(GL_TEXTURE0); + const IBO& ibo = data.iboDatabase.at(sprites[i]); + glBindTexture(GL_TEXTURE_2D, ibo.texture); - glDrawElements(GL_TRIANGLES, spriteVBO.numIndices, spriteVBO.indexType, nullptr); + glDrawElements(GL_TRIANGLES, spriteVBO.numIndices, spriteVBO.indexType, nullptr); + } } } -} -void Engine::Renderer::OpenGL::Draw_MeshPass(const Engine::Renderer::OpenGL::Data &data, - const std::vector<Engine::Renderer::MeshID> &meshes, - const std::vector<Math::Matrix4x4> &transforms) -{ - auto& viewport = Renderer::GetViewport(0); - - if (!meshes.empty()) + void Renderer::OpenGL::Draw_MeshPass(const Engine::Renderer::OpenGL::Data &data, + const std::vector<Engine::Renderer::MeshID> &meshes, + const std::vector<Math::Matrix4x4> &transforms) { - glUseProgram(data.meshProgram); + auto& viewport = Renderer::GetViewport(0); - for (size_t i = 0; i < meshes.size(); i++) + if (!meshes.empty()) { - glProgramUniformMatrix4fv(data.meshProgram, data.meshModelUniform, 1, GL_FALSE, transforms[i].data.data()); + glUseProgram(data.meshProgram); + + for (size_t i = 0; i < meshes.size(); i++) + { + glProgramUniformMatrix4fv(data.meshProgram, data.meshModelUniform, 1, GL_FALSE, transforms[i].data.data()); - const VBO& vbo = data.vboDatabase.at(meshes[i]); - glBindVertexArray(vbo.vertexArrayObject); + const VBO& vbo = data.vboDatabase.at(meshes[i]); + glBindVertexArray(vbo.vertexArrayObject); - glDrawElements(GL_TRIANGLES, vbo.numIndices, vbo.indexType, nullptr); + glDrawElements(GL_TRIANGLES, vbo.numIndices, vbo.indexType, nullptr); + } } } -} - -void Engine::Renderer::OpenGL::UpdateVBODatabase(Data& data, const std::vector<MeshID>& loadQueue) -{ - for (const auto& id : loadQueue) + void Renderer::OpenGL::UpdateVBODatabase(Data& data, const std::vector<MeshID>& loadQueue) { - std::string path = Asset::GetPath(static_cast<Asset::Mesh>(id)); - - auto vboOpt = VBOFromPath(path); - assert(vboOpt.has_value()); + for (const auto& id : loadQueue) + { + auto vboOpt = VBOFromPath(static_cast<size_t>(id)); + assert(vboOpt.has_value()); - data.vboDatabase.insert({ id, vboOpt.value() }); + data.vboDatabase.insert({ id, vboOpt.value() }); + } } -} -void Engine::Renderer::OpenGL::UpdateIBODatabase(Data& data, const std::vector<SpriteID>& loadQueue) -{ - glActiveTexture(GL_TEXTURE0); - for (const auto& id : loadQueue) + void Renderer::OpenGL::UpdateIBODatabase(Data& data, const std::vector<SpriteID>& loadQueue) { - auto texDocument = Asset::LoadTextureDocument(static_cast<Asset::Sprite>(id)); + glActiveTexture(GL_TEXTURE0); + for (const auto& id : loadQueue) + { + /*auto texDocument = Asset::LoadTextureDocument(static_cast<Asset::Sprite>(id)); - IBO ibo; + IBO ibo; - glGenTextures(1, &ibo.texture); - glBindTexture(GL_TEXTURE_2D, ibo.texture); + glGenTextures(1, &ibo.texture); + glBindTexture(GL_TEXTURE_2D, ibo.texture); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texDocument.GetDimensions().width, texDocument.GetDimensions().height, 0, GL_RGBA, GL_UNSIGNED_BYTE, texDocument.GetData()); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texDocument.GetDimensions().width, texDocument.GetDimensions().height, 0, GL_RGBA, GL_UNSIGNED_BYTE, texDocument.GetData()); - data.iboDatabase.insert({ id, ibo }); + data.iboDatabase.insert({ id, ibo });*/ + } } -} -void Engine::Renderer::OpenGL::VBO::DeallocateDeviceBuffers() -{ - glDeleteBuffers(static_cast<GLint>(attributeBuffers.size()), attributeBuffers.data()); - glDeleteVertexArrays(1, &vertexArrayObject); -} + void Renderer::OpenGL::VBO::DeallocateDeviceBuffers() + { + glDeleteBuffers(static_cast<GLint>(attributeBuffers.size()), attributeBuffers.data()); + glDeleteVertexArrays(1, &vertexArrayObject); + } -void Engine::Renderer::OpenGL::IBO::ImageBufferObject::DeallocateDeviceBuffers() -{ - glDeleteTextures(1, &texture); -} + void Renderer::OpenGL::IBO::ImageBufferObject::DeallocateDeviceBuffers() + { + glDeleteTextures(1, &texture); + } -std::optional<Engine::Renderer::OpenGL::VBO> Engine::Renderer::OpenGL::VBOFromPath(const std::string& path) -{ - using namespace Asset; - auto meshDocument = LoadMeshDocument(path); + std::optional<Renderer::OpenGL::VBO> Renderer::OpenGL::VBOFromPath(size_t id) + { + const auto meshDocument = Core::GetData().assetLoadData.meshLoader(id); - VBO vbo; + VBO vbo; - vbo.indexType = meshDocument.GetIndexType() == MeshDocument::IndexType::Uint16 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT; - vbo.numIndices = meshDocument.GetIndexCount(); + vbo.indexType = meshDocument.GetIndexType() == MeshDocument::IndexType::UInt16 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT; + vbo.numIndices = meshDocument.GetIndexCount(); - glGenVertexArrays(1, &vbo.vertexArrayObject); - glBindVertexArray(vbo.vertexArrayObject); + glGenVertexArrays(1, &vbo.vertexArrayObject); + glBindVertexArray(vbo.vertexArrayObject); - glGenBuffers(static_cast<GLint>(vbo.attributeBuffers.size()), vbo.attributeBuffers.data()); + glGenBuffers(static_cast<GLint>(vbo.attributeBuffers.size()), vbo.attributeBuffers.data()); - glBindBuffer(GL_ARRAY_BUFFER, vbo.attributeBuffers[static_cast<size_t>(VBO::Attribute::Position)]); - glBufferData(GL_ARRAY_BUFFER, meshDocument.GetData(MeshDocument::Attribute::Position).byteLength, meshDocument.GetDataPtr(Asset::MeshDocument::Attribute::Position), GL_STATIC_DRAW); - glEnableVertexAttribArray(static_cast<size_t>(VBO::Attribute::Position)); - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0); + glBindBuffer(GL_ARRAY_BUFFER, vbo.attributeBuffers[static_cast<size_t>(VBO::Attribute::Position)]); + glBufferData(GL_ARRAY_BUFFER, meshDocument.GetData(MeshDocument::Attribute::Position).byteLength, meshDocument.GetDataPtr(MeshDocument::Attribute::Position), GL_STATIC_DRAW); + glEnableVertexAttribArray(static_cast<size_t>(VBO::Attribute::Position)); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0); - glBindBuffer(GL_ARRAY_BUFFER, vbo.attributeBuffers[static_cast<size_t>(VBO::Attribute::TexCoord)]); - glBufferData(GL_ARRAY_BUFFER, meshDocument.GetData(MeshDocument::Attribute::TexCoord).byteLength, meshDocument.GetDataPtr(Asset::MeshDocument::Attribute::TexCoord), GL_STATIC_DRAW); - glEnableVertexAttribArray(static_cast<size_t>(VBO::Attribute::TexCoord)); - glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, 0); + glBindBuffer(GL_ARRAY_BUFFER, vbo.attributeBuffers[static_cast<size_t>(VBO::Attribute::TexCoord)]); + glBufferData(GL_ARRAY_BUFFER, meshDocument.GetData(MeshDocument::Attribute::TexCoord).byteLength, meshDocument.GetDataPtr(MeshDocument::Attribute::TexCoord), GL_STATIC_DRAW); + glEnableVertexAttribArray(static_cast<size_t>(VBO::Attribute::TexCoord)); + glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, 0); - glBindBuffer(GL_ARRAY_BUFFER, vbo.attributeBuffers[static_cast<size_t>(VBO::Attribute::Normal)]); - glBufferData(GL_ARRAY_BUFFER, meshDocument.GetData(MeshDocument::Attribute::Normal).byteLength, meshDocument.GetDataPtr(Asset::MeshDocument::Attribute::Normal), GL_STATIC_DRAW); - glEnableVertexAttribArray(static_cast<size_t>(VBO::Attribute::Normal)); - glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, 0); + glBindBuffer(GL_ARRAY_BUFFER, vbo.attributeBuffers[static_cast<size_t>(VBO::Attribute::Normal)]); + glBufferData(GL_ARRAY_BUFFER, meshDocument.GetData(MeshDocument::Attribute::Normal).byteLength, meshDocument.GetDataPtr(MeshDocument::Attribute::Normal), GL_STATIC_DRAW); + glEnableVertexAttribArray(static_cast<size_t>(VBO::Attribute::Normal)); + glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, 0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo.attributeBuffers[static_cast<size_t>(VBO::Attribute::Index)]); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, meshDocument.GetData(Asset::MeshDocument::Attribute::Index).byteLength, meshDocument.GetDataPtr(Asset::MeshDocument::Attribute::Index), GL_STATIC_DRAW); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo.attributeBuffers[static_cast<size_t>(VBO::Attribute::Index)]); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, meshDocument.GetData(MeshDocument::Attribute::Index).byteLength, meshDocument.GetDataPtr(MeshDocument::Attribute::Index), GL_STATIC_DRAW); - return vbo; + return vbo; + } } \ No newline at end of file diff --git a/src/Engine/Renderer/OpenGL.hpp b/src/Engine/Renderer/OpenGL.hpp index 901d5ebf85f8b4f39f56d2a07b0850b422d55500..e7f51e2e6a1ee24c2302fe2f5ceb54c3e86659d4 100644 --- a/src/Engine/Renderer/OpenGL.hpp +++ b/src/Engine/Renderer/OpenGL.hpp @@ -11,7 +11,7 @@ namespace Engine { namespace OpenGL { - void Initialize(std::any& apiData, CreateInfo&& createInfo); + void Initialize(std::any& apiData, const InitInfo& createInfo); void Terminate(std::any& apiData); void PrepareRenderingEarly(const std::vector<SpriteID>& spriteLoadQueue, const std::vector<MeshID>& meshLoadQueue); void PrepareRenderingLate(); diff --git a/src/Engine/Renderer/OpenGLCreateInfo.hpp b/src/Engine/Renderer/OpenGLCreateInfo.hpp index 30809c3375be71f417801dfe7a553f0ae3bfb751..d4c764f15c76107c7f9d89cf7f297dfbb1e78138 100644 --- a/src/Engine/Renderer/OpenGLCreateInfo.hpp +++ b/src/Engine/Renderer/OpenGLCreateInfo.hpp @@ -1,5 +1,6 @@ #pragma once +#include "Typedefs.hpp" #include <functional> namespace Engine @@ -8,10 +9,12 @@ namespace Engine { namespace OpenGL { - struct CreateInfo + struct InitInfo { std::function<void(void*)> glSwapBuffers; }; + + bool IsValid(const InitInfo& initInfo, ErrorMessageCallbackPFN callback); } } } \ No newline at end of file diff --git a/src/Engine/Renderer/Renderer.cpp b/src/Engine/Renderer/Renderer.cpp index 8cdecf09a849b61a75f3a24316b7141dfdc46f15..4677f1a36b2c4911443f1a93ef0deec48668292e 100644 --- a/src/Engine/Renderer/Renderer.cpp +++ b/src/Engine/Renderer/Renderer.cpp @@ -16,226 +16,331 @@ namespace Engine static std::unique_ptr<Data> data; void UpdateAssetReferences(Data& data, const RenderGraph& oldRG, const RenderGraph* newRG); + + bool IsValid(const InitInfo& createInfo, ErrorMessageCallbackPFN callback); } } -} -const Engine::Renderer::Core::Data& Engine::Renderer::Core::GetData() -{ - return *data; -} + bool Renderer::Core::IsValid(const InitInfo& createInfo, ErrorMessageCallbackPFN callback) + { + const auto& DebugMessage = [callback](const char* message) + { + if (callback) + callback(message); + }; -Engine::Renderer::Viewport& Engine::Renderer::NewViewport(Utility::ImgDim dimensions, void* surfaceHandle) -{ - Core::data->viewports.emplace_back(std::make_unique<Viewport>(dimensions, surfaceHandle)); - return *Core::data->viewports.back(); -} + if (createInfo.surfaceHandle == nullptr) + { + DebugMessage("Error. InitInfo needs a window/surface handle."); + return false; + } -size_t Engine::Renderer::GetViewportCount() { return Core::data->viewports.size(); } + if (createInfo.surfaceDimensions[0] == 0 || createInfo.surfaceDimensions[1] == 1) + { + DebugMessage("Error. InitInfo::surfaceDimensions can't have any dimension(s) with value 0."); + return false; + } -Engine::Renderer::Viewport& Engine::Renderer::GetViewport(size_t index) { return *Core::data->viewports[index]; } + // Asset load stuff + if (createInfo.assetLoadCreateInfo.meshLoader == nullptr) + { + DebugMessage("Error. MeshLoader pointer in initialization cannot be nullptr."); + return false; + } -Engine::Renderer::API Engine::Renderer::GetActiveAPI() -{ - if (Core::data) - return Core::data->activeAPI; - else - return API::None; -} + // Debug stuff + if (createInfo.debugInitInfo.useDebugging == true) + { + const DebugCreateInfo& debugInfo = createInfo.debugInitInfo; + if (debugInfo.errorMessageCallback == nullptr) + { + DebugMessage("Error. DebugCreateInfo::errorMessageCallback cannot be nullptr when DebugCreateInfo::enableDebug is true."); + return false; + } + } + + switch (createInfo.preferredAPI) + { + case API::OpenGL: + if (IsValid(createInfo.openGLInitInfo, createInfo.debugInitInfo.errorMessageCallback) == true) + break; + else + return false; + default: + DebugMessage("Error. InitInfo::preferredAPI can't be set to 'API::None'"); + return false; + } -std::any& Engine::Renderer::Core::GetAPIData() { return data->apiData; } + return true; + } -bool Engine::Renderer::Core::Initialize(CreateInfo&& createInfo) -{ - Core::data = std::make_unique<Data>(); - Data& data = *Core::data; + bool Renderer::OpenGL::IsValid(const InitInfo& initInfo, ErrorMessageCallbackPFN callback) + { + const auto& DebugMessage = [callback](const char* message) + { + if (callback) + callback(message); + }; - data.activeAPI = createInfo.preferredAPI; + if (initInfo.glSwapBuffers == nullptr) + { + DebugMessage("Error. Renderer::OpenGL::InitInfo must point to a valid function."); + return false; + } - data.debugData = std::move(createInfo.debugCreateInfo); + return true; + } - NewViewport(createInfo.surfaceDimensions, createInfo.surfaceHandle); + const Renderer::Core::Data& Engine::Renderer::Core::GetData() + { + return *data; + } - switch (data.activeAPI) + Renderer::Viewport& Engine::Renderer::NewViewport(Utility::ImgDim dimensions, void* surfaceHandle) { - case API::OpenGL: - OpenGL::Initialize(data.apiData, std::move(createInfo.openGLCreateInfo)); - data.Draw = OpenGL::Draw; - data.PrepareRenderingEarly = OpenGL::PrepareRenderingEarly; - data.PrepareRenderingLate = OpenGL::PrepareRenderingLate; - break; - default: - break; + Core::data->viewports.emplace_back(std::make_unique<Viewport>(dimensions, surfaceHandle)); + return *Core::data->viewports.back(); } - return true; -} + size_t Renderer::GetViewportCount() { return Core::data->viewports.size(); } -void Engine::Renderer::Core::Terminate() -{ - switch (GetActiveAPI()) + Renderer::Viewport& Renderer::GetViewport(size_t index) { return *Core::data->viewports[index]; } + + Renderer::API Renderer::GetActiveAPI() { - case API::OpenGL: - OpenGL::Terminate(data->apiData); - break; - default: - break; + if (Core::data) + return Core::data->activeAPI; + else + return API::None; } - data = nullptr; -} + std::any& Renderer::Core::GetAPIData() { return data->apiData; } -void Engine::Renderer::Core::PrepareRenderingEarly(RenderGraph& renderGraphInput) -{ - Data& data = *Core::data; + bool Renderer::Core::Initialize(const InitInfo& createInfo) + { + if constexpr (Setup::enableDebugging) + { + if (createInfo.debugInitInfo.useDebugging) + { + bool valid = IsValid(createInfo, createInfo.debugInitInfo.errorMessageCallback); + if (!valid) + LogDebugMessage("Error. InitInfo is not valid."); + assert(valid); + } + } - auto& renderGraph = data.renderGraph; + Core::data = std::make_unique<Data>(); + Data& data = *Core::data; - UpdateAssetReferences(data, renderGraph, &renderGraphInput); + // Debug info + if constexpr (Setup::enableDebugging) + { + data.debugData = createInfo.debugInitInfo; + } - std::swap(renderGraph, renderGraphInput); + data.activeAPI = createInfo.preferredAPI; - if (!data.loadSpriteQueue.empty() || !data.loadMeshQueue.empty()) - data.debugData.errorMessageCallback("Loading sprite/mesh resource(s)..."); - data.PrepareRenderingEarly(data.loadSpriteQueue, data.loadMeshQueue); + data.assetLoadData = createInfo.assetLoadCreateInfo; - data.loadSpriteQueue.clear(); - data.unloadSpriteQueue.clear(); - data.loadMeshQueue.clear(); - data.unloadMeshQueue.clear(); -} + NewViewport(createInfo.surfaceDimensions, createInfo.surfaceHandle); -void Engine::Renderer::Core::PrepareRenderingLate(RenderGraphTransform &input) -{ - const auto& renderGraph = data->renderGraph; - auto& renderGraphTransform = data->renderGraphTransform; + switch (data.activeAPI) + { + case API::OpenGL: + OpenGL::Initialize(data.apiData, createInfo.openGLInitInfo); + data.Draw = OpenGL::Draw; + data.PrepareRenderingEarly = OpenGL::PrepareRenderingEarly; + data.PrepareRenderingLate = OpenGL::PrepareRenderingLate; + break; + default: + break; + } - assert(IsCompatible(renderGraph, input)); + return true; + } - std::swap(renderGraphTransform, input); + void Renderer::Core::Terminate() + { + switch (GetActiveAPI()) + { + case API::OpenGL: + OpenGL::Terminate(data->apiData); + break; + default: + break; + } - data->PrepareRenderingLate(); -} + data = nullptr; + } -void Engine::Renderer::Core::Draw() -{ - data->Draw(); -} + void Renderer::Core::PrepareRenderingEarly(RenderGraph& renderGraphInput) + { + Data& data = *Core::data; -const Engine::Renderer::RenderGraph &Engine::Renderer::Core::GetRenderGraph() -{ - return data->renderGraph; -} + auto& renderGraph = data.renderGraph; -const Engine::Renderer::RenderGraphTransform &Engine::Renderer::Core::GetRenderGraphTransform() -{ - return data->renderGraphTransform; -} + UpdateAssetReferences(data, renderGraph, &renderGraphInput); -const Engine::Renderer::CameraInfo &Engine::Renderer::Core::GetCameraInfo() -{ - return data->cameraInfo; -} + std::swap(renderGraph, renderGraphInput); -void Engine::Renderer::Core::SetCameraInfo(const CameraInfo &input) -{ - data->cameraInfo = input; -} + if (!data.loadSpriteQueue.empty() || !data.loadMeshQueue.empty()) + LogDebugMessage("Loading sprite/mesh resource(s)..."); + data.PrepareRenderingEarly(data.loadSpriteQueue, data.loadMeshQueue); -Engine::Renderer::SceneData::SceneData() -{ - sceneID = Core::data->sceneIDCounter; - Core::data->sceneIDCounter++; -} - -Engine::Renderer::Viewport::Viewport(Utility::ImgDim dimensions, void* surfaceHandle) : - sceneRef(nullptr), - cameraIndex(0), - dimensions(dimensions), - surfaceHandle(surfaceHandle) -{ -} + data.loadSpriteQueue.clear(); + data.unloadSpriteQueue.clear(); + data.loadMeshQueue.clear(); + data.unloadMeshQueue.clear(); + } -Utility::ImgDim Engine::Renderer::Viewport::GetDimensions() const { return dimensions; } + void Renderer::Core::PrepareRenderingLate(RenderGraphTransform &input) + { + Data& data = *Core::data; -size_t Engine::Renderer::Viewport::GetCameraIndex() const { return cameraIndex; } + const auto& renderGraph = data.renderGraph; + auto& renderGraphTransform = data.renderGraphTransform; -void* Engine::Renderer::Viewport::GetSurfaceHandle() { return surfaceHandle; } + if constexpr (Setup::enableDebugging) + { + if (data.debugData.useDebugging) + { + bool compatible = IsCompatible(renderGraph, input); + if (!compatible) + { + LogDebugMessage("Error. Newly submitted RenderGraphTransform is not compatible with previously submitted RenderGraph."); + assert(false); + } + } + } -void Engine::Renderer::Viewport::SetSceneRef(const Engine::Renderer::SceneType* scene) -{ - sceneRef = scene; -} + std::swap(renderGraphTransform, input); -bool Engine::Renderer::IsCompatible(const RenderGraph &renderGraph, const RenderGraphTransform &transforms) -{ - if (renderGraph.sprites.size() != transforms.sprites.size()) - return false; + data.PrepareRenderingLate(); + } - if (renderGraph.meshes.size() != transforms.meshes.size()) - return false; + void Renderer::Core::Draw() + { + data->Draw(); + } - if (renderGraph.pointLights.size() != transforms.pointLights.size()) - return false; + const Renderer::RenderGraph &Renderer::Core::GetRenderGraph() + { + return data->renderGraph; + } - return true; -} + const Renderer::RenderGraphTransform &Renderer::Core::GetRenderGraphTransform() + { + return data->renderGraphTransform; + } -void Engine::Renderer::Core::UpdateAssetReferences(Data& data, const RenderGraph& oldRG, const RenderGraph* newRG) -{ - // Add new references - if (newRG) + const Renderer::CameraInfo &Renderer::Core::GetCameraInfo() { - // Sprites - for(const auto& item : newRG->sprites) - { - auto& referenceCount = data.spriteReferences[item]; - referenceCount++; - if (referenceCount == 1) - data.loadSpriteQueue.emplace_back(item); - } + return data->cameraInfo; + } - // Meshes - for (const auto& item : newRG->meshes) - { - auto& referenceCount = data.meshReferences[item]; - referenceCount++; - if (referenceCount == 1) - data.loadMeshQueue.emplace_back(item); - } + void Renderer::Core::SetCameraInfo(const CameraInfo &input) + { + data->cameraInfo = input; } - // Remove existing references - for (const auto& item : oldRG.sprites) + Renderer::Viewport::Viewport(Utility::ImgDim dimensions, void* surfaceHandle) : + sceneRef(nullptr), + cameraIndex(0), + dimensions(dimensions), + surfaceHandle(surfaceHandle) { - auto iterator = data.spriteReferences.find(item); - iterator->second--; - if (iterator->second <= 0) + } + + Utility::ImgDim Renderer::Viewport::GetDimensions() const { return dimensions; } + + size_t Renderer::Viewport::GetCameraIndex() const { return cameraIndex; } + + void* Renderer::Viewport::GetSurfaceHandle() { return surfaceHandle; } + + void Renderer::Viewport::SetSceneRef(const Renderer::SceneType* scene) + { + sceneRef = scene; + } + + bool Renderer::IsCompatible(const RenderGraph &renderGraph, const RenderGraphTransform &transforms) + { + if (renderGraph.sprites.size() != transforms.sprites.size()) + return false; + + if (renderGraph.meshes.size() != transforms.meshes.size()) + return false; + + if (renderGraph.pointLights.size() != transforms.pointLights.size()) + return false; + + return true; + } + + void Renderer::LogDebugMessage(std::string_view message) + { + if constexpr (Setup::enableDebugging) { - data.unloadSpriteQueue.emplace_back(item); - data.spriteReferences.erase(iterator); + const Core::Data& data = *Core::data; + if (data.debugData.useDebugging) + data.debugData.errorMessageCallback(message); } } - for (const auto& item : oldRG.meshes) + void Renderer::Core::UpdateAssetReferences(Data& data, const RenderGraph& oldRG, const RenderGraph* newRG) { - auto iterator = data.meshReferences.find(item); - iterator->second--; - if (iterator->second <= 0) + // Add new references + if (newRG) + { + // Sprites + for (const auto& item : newRG->sprites) + { + auto& referenceCount = data.spriteReferences[item]; + referenceCount++; + if (referenceCount == 1) + data.loadSpriteQueue.emplace_back(item); + } + + // Meshes + for (const auto& item : newRG->meshes) + { + auto& referenceCount = data.meshReferences[item]; + referenceCount++; + if (referenceCount == 1) + data.loadMeshQueue.emplace_back(item); + } + } + + // Remove existing references + for (const auto& item : oldRG.sprites) + { + auto iterator = data.spriteReferences.find(item); + iterator->second--; + if (iterator->second <= 0) + { + data.unloadSpriteQueue.emplace_back(item); + data.spriteReferences.erase(iterator); + } + } + + for (const auto& item : oldRG.meshes) { - data.unloadMeshQueue.emplace_back(item); - data.meshReferences.erase(iterator); + auto iterator = data.meshReferences.find(item); + iterator->second--; + if (iterator->second <= 0) + { + data.unloadMeshQueue.emplace_back(item); + data.meshReferences.erase(iterator); + } } } -} -Math::Matrix4x4 Engine::Renderer::CameraInfo::GetModel(float aspectRatio) const -{ - using namespace Math::LinTran3D; - if (projectMode == ProjectionMode::Perspective) + Math::Matrix4x4 Renderer::CameraInfo::GetModel(float aspectRatio) const { - switch (GetActiveAPI()) + using namespace Math::LinTran3D; + if (projectMode == ProjectionMode::Perspective) { + switch (GetActiveAPI()) + { case API::OpenGL: return Perspective<float>(Math::API3D::OpenGL, fovY, aspectRatio, zNear, zFar) * transform; case API::Vulkan: @@ -243,16 +348,16 @@ Math::Matrix4x4 Engine::Renderer::CameraInfo::GetModel(float aspectRatio) const default: assert(false); return {}; + } } - } - else if (projectMode == ProjectionMode::Orthographic) - { - const float& right = orthoWidth / 2; - const float& left = -right; - const float& top = orthoWidth / aspectRatio / 2; - const float& bottom = -top; - switch (GetActiveAPI()) + else if (projectMode == ProjectionMode::Orthographic) { + const float& right = orthoWidth / 2; + const float& left = -right; + const float& top = orthoWidth / aspectRatio / 2; + const float& bottom = -top; + switch (GetActiveAPI()) + { case API::OpenGL: return Orthographic<float>(Math::API3D::OpenGL, left, right, bottom, top, zNear, zFar); case API::Vulkan: @@ -260,10 +365,11 @@ Math::Matrix4x4 Engine::Renderer::CameraInfo::GetModel(float aspectRatio) const default: assert(false); return {}; + } } - } - // Function should NOT reach here. - assert(false); - return {}; + // Function should NOT reach here. + assert(false); + return {}; + } } \ No newline at end of file diff --git a/src/Engine/Renderer/Renderer.hpp b/src/Engine/Renderer/Renderer.hpp index cdfcf978bf6c55726f887d366c61e161498f1776..a7242b18ca8b3c5c6f8bbbc03d3d4803a8999d4b 100644 --- a/src/Engine/Renderer/Renderer.hpp +++ b/src/Engine/Renderer/Renderer.hpp @@ -20,7 +20,7 @@ namespace Engine namespace Renderer { using SceneType = Setup::SceneType; - + Viewport& NewViewport(Utility::ImgDim dimensions, void* surfaceHandle); size_t GetViewportCount(); Viewport& GetViewport(size_t index); @@ -29,9 +29,12 @@ namespace Engine bool IsCompatible(const RenderGraph& renderGraph, const RenderGraphTransform& transforms); + // This call is thread-safe if ErrorMessageCallback supplied to InitInfo is. + void LogDebugMessage(std::string_view message); + namespace Core { - bool Initialize(CreateInfo&& createInfo); + bool Initialize(const InitInfo& createInfo); void PrepareRenderingEarly(RenderGraph& renderGraphInput); void PrepareRenderingLate(RenderGraphTransform& sceneData); void Draw(); @@ -53,18 +56,26 @@ namespace Engine struct Renderer::DebugCreateInfo { - std::function<void(std::string_view)> errorMessageCallback; + bool useDebugging = false; + ErrorMessageCallbackPFN errorMessageCallback = nullptr; + }; + + struct Renderer::AssetLoadCreateInfo + { + using MeshLoaderPFN = MeshDocument(*)(size_t); + MeshLoaderPFN meshLoader = nullptr; }; - struct Renderer::CreateInfo + struct Renderer::InitInfo { API preferredAPI = API::None; Utility::ImgDim surfaceDimensions; void* surfaceHandle = nullptr; - DebugCreateInfo debugCreateInfo; + AssetLoadCreateInfo assetLoadCreateInfo; + DebugCreateInfo debugInitInfo; - OpenGL::CreateInfo openGLCreateInfo; + OpenGL::InitInfo openGLInitInfo; }; struct Renderer::RenderGraph @@ -83,16 +94,6 @@ namespace Engine std::vector<Math::Vector<3, float>> pointLights; }; - class Renderer::SceneData - { - public: - SceneData(); - - size_t GetSceneID() const; - private: - size_t sceneID; - }; - struct Renderer::CameraInfo { enum class ProjectionMode diff --git a/src/Engine/Renderer/RendererData.hpp b/src/Engine/Renderer/RendererData.hpp index 37d25cdc733e0499bbfec92bdc14f7b8afb8330c..f83cdff303c868835f356b30bbdb55325e111172 100644 --- a/src/Engine/Renderer/RendererData.hpp +++ b/src/Engine/Renderer/RendererData.hpp @@ -19,8 +19,6 @@ namespace Engine RenderGraphTransform renderGraphTransform; CameraInfo cameraInfo; - size_t sceneIDCounter = 0; - API activeAPI = API::None; std::unordered_map<MeshID, size_t> meshReferences; @@ -37,8 +35,10 @@ namespace Engine std::function<void(const std::vector<SpriteID>&, const std::vector<MeshID>&)> PrepareRenderingEarly; std::function<void(void)> PrepareRenderingLate; + AssetLoadCreateInfo assetLoadData; DebugCreateInfo debugData; + std::any apiData = nullptr; }; diff --git a/src/Engine/Renderer/Setup.hpp b/src/Engine/Renderer/Setup.hpp index c7d6cd402419adf41b14e58ae34c3bc2b47a6f62..a065681f2afa850fcfd0b8fbae4805416a925d0a 100644 --- a/src/Engine/Renderer/Setup.hpp +++ b/src/Engine/Renderer/Setup.hpp @@ -12,6 +12,8 @@ namespace Engine { using SceneType = Engine::Scene; + constexpr bool enableDebugging = true; + constexpr std::string_view assetPath = "Data/DRenderer"; } } diff --git a/src/Engine/Renderer/Typedefs.hpp b/src/Engine/Renderer/Typedefs.hpp index 9410bd065c11f7efab678c6859ba7a670eae4233..f2c34df31bf14a605d36ebbcc0fa9674c8dff8d0 100644 --- a/src/Engine/Renderer/Typedefs.hpp +++ b/src/Engine/Renderer/Typedefs.hpp @@ -1,6 +1,7 @@ #pragma once #include <cstdint> +#include <functional> namespace Engine { @@ -11,15 +12,21 @@ namespace Engine using AssetIntegerType = uint32_t; } + using ErrorMessageCallbackPFN = std::function<void(std::string_view)>; + enum class SpriteID : Core::AssetIntegerType {}; enum class MeshID : Core::AssetIntegerType {}; struct DebugCreateInfo; - struct CreateInfo; + struct AssetLoadCreateInfo; + struct InitInfo; + + class MeshDocument; + + enum class API; class Viewport; - class SceneData; struct RenderGraph; struct RenderGraphTransform; struct CameraInfo; diff --git a/src/Engine/Utility/ImgDim.hpp b/src/Engine/Utility/ImgDim.hpp index c5c02f68cc6642fb34033ea0cecc90d5aec4af02..06de4af8121a8692c94573a718f315d12bb4ff0b 100644 --- a/src/Engine/Utility/ImgDim.hpp +++ b/src/Engine/Utility/ImgDim.hpp @@ -3,6 +3,7 @@ #include <string> #include <sstream> #include <utility> +#include <cassert> namespace Utility { @@ -18,6 +19,11 @@ namespace Utility void Swap(); std::string ToString() const; + + constexpr ValueType& At(size_t i); + constexpr const ValueType& At(size_t i) const; + constexpr ValueType& operator[](size_t i); + constexpr const ValueType& operator[](size_t i) const; }; constexpr float ImgDim::GetAspectRatio() const { return static_cast<float>(width) / static_cast<float>(height); } @@ -30,5 +36,35 @@ namespace Utility out << '(' << width << ", " << height << ')'; return out.str(); } + + constexpr ImgDim::ValueType& ImgDim::At(size_t i) + { + return const_cast<ValueType&>(std::as_const(*this).At(i)); + } + + const constexpr ImgDim::ValueType& ImgDim::At(size_t i) const + { + assert(i >= 0 && i < 2); + switch (i) + { + case 0: + return width; + case 1: + return height; + default: + assert(false); + return width; + } + } + + constexpr ImgDim::ValueType& ImgDim::operator[](size_t i) + { + return At(i); + } + + constexpr const ImgDim::ValueType& ImgDim::operator[](size_t i) const + { + return At(i); + } }