From b8438ad3e7746487d660f59a08e3e0de93e89cd3 Mon Sep 17 00:00:00 2001 From: Riyyi Date: Mon, 11 Jan 2021 15:59:29 +0100 Subject: [PATCH] Convert Renderer2D to singleton pattern --- inferno/src/inferno/application.cpp | 15 +- inferno/src/inferno/render/renderer.cpp | 217 +++++++++++++----------- inferno/src/inferno/render/renderer.h | 99 ++++++----- 3 files changed, 181 insertions(+), 150 deletions(-) diff --git a/inferno/src/inferno/application.cpp b/inferno/src/inferno/application.cpp index e73a5b7..3bd2121 100644 --- a/inferno/src/inferno/application.cpp +++ b/inferno/src/inferno/application.cpp @@ -46,7 +46,8 @@ namespace Inferno { m_cameraO = std::make_shared(); m_cameraP = std::make_shared(); - Renderer2D::initialize(); + Renderer2D* renderer2D = new Renderer2D(); + renderer2D->initialize(); // Load assets @@ -56,7 +57,7 @@ namespace Inferno { Application::~Application() { - Renderer2D::destroy(); + Renderer2D::the().destroy(); TextureManager::the().destroy(); ShaderManager::the().destroy(); // Input::destroy(); @@ -102,13 +103,13 @@ namespace Inferno { RenderCommand::clearColor({ 0.2f, 0.3f, 0.3f, 1.0f }); RenderCommand::clear(); - Renderer2D::beginScene(m_cameraP); // camera, lights, environment + Renderer2D::the().beginScene(m_cameraP); // camera, lights, environment - Renderer2D::drawQuad(std::make_shared(cube), colors); - Renderer2D::drawQuad(std::make_shared(cube2), { 0.5f, 0.6f, 0.8f, 1.0f }, m_texture); - Renderer2D::drawQuad(std::make_shared(cube3), { 1.0f, 1.0f, 1.0f, 1.0f }, m_texture2); + Renderer2D::the().drawQuad(std::make_shared(cube), colors); + Renderer2D::the().drawQuad(std::make_shared(cube2), { 0.5f, 0.6f, 0.8f, 1.0f }, m_texture); + Renderer2D::the().drawQuad(std::make_shared(cube3), { 1.0f, 1.0f, 1.0f, 1.0f }, m_texture2); - Renderer2D::endScene(); + Renderer2D::the().endScene(); m_window->render(); diff --git a/inferno/src/inferno/render/renderer.cpp b/inferno/src/inferno/render/renderer.cpp index 35d0c11..ab001d8 100644 --- a/inferno/src/inferno/render/renderer.cpp +++ b/inferno/src/inferno/render/renderer.cpp @@ -3,6 +3,7 @@ #include +#include "inferno/assertions.h" #include "inferno/component/transform.h" #include "inferno/render/buffer.h" #include "inferno/render/camera.h" @@ -37,68 +38,129 @@ namespace Inferno { // ----------------------------------------- - std::shared_ptr Renderer2D::s_camera = nullptr; - QuadBatch* Renderer2D::s_quadBatch; + uint32_t Renderer::m_supportedTextureUnitPerBatch = 0; + + void Renderer::initialize() + { + // Get amount of texture units supported by the GPU + uint32_t constTextureUnitCount = textureUnitPerBatch; + uint32_t gpuTextureUnitCount = RenderCommand::textureUnitAmount(); + m_supportedTextureUnitPerBatch = std::min(constTextureUnitCount, gpuTextureUnitCount); + + // Create texture unit samplers + int32_t samplers[textureUnitPerBatch]; + for (uint32_t i = 0; i < textureUnitPerBatch; i++) { + samplers[i] = i; + } + + // Create shader + m_shader = ShaderManager::the().load("assets/glsl/batch-quad"); + m_shader->bind(); + m_shader->setInt("u_textures", samplers, textureUnitPerBatch); + m_shader->unbind(); + } + + void Renderer::destroy() + { + } + + uint32_t Renderer::addTextureUnit(std::shared_ptr texture) + { + if (texture == nullptr) { + return 0; + } + + // Create a new batch if the texture unit limit has been reached + if (m_textureUnitIndex >= m_supportedTextureUnitPerBatch) { + nextBatch(); + } + + // If texure was already added + for (uint32_t i = 1; i < m_textureUnitIndex; i++) { + if (m_textureUnits[i] == texture) { + return i; + } + } + + // Add texture + uint32_t textureUnitIndex = m_textureUnitIndex; + m_textureUnits[textureUnitIndex] = texture; + m_textureUnitIndex++; + + return textureUnitIndex; + } + + void Renderer::bind() + { + m_shader->bind(); + + for (uint32_t i = 1; i < m_textureUnitIndex; i++) { + m_textureUnits[i]->bind(i); + } + + m_vertexArray->bind(); + } + + void Renderer::unbind() + { + m_vertexArray->unbind(); + + for (uint32_t i = 1; i < m_textureUnitIndex; i++) { + m_textureUnits[i]->unbind(); + } + + m_shader->unbind(); + } + +// ----------------------------------------- + + Renderer2D* Renderer2D::s_instance = nullptr; void Renderer2D::initialize() { - s_quadBatch = new QuadBatch(); + ASSERT(!s_instance, "ShaderManager already exists!"); + s_instance = this; + + Renderer::initialize(); // CPU // ----------------------------------------- // Create array for storing quads vertices - s_quadBatch->vertexBufferBase = std::unique_ptr(new QuadVertex[QuadBatch::vertexCount]); - s_quadBatch->vertexBufferPtr = s_quadBatch->vertexBufferBase.get(); + m_vertexBufferBase = std::unique_ptr(new QuadVertex[vertexCount]); + m_vertexBufferPtr = m_vertexBufferBase.get(); // Set default quad vertex positions - s_quadBatch->vertexPositions[0] = { -0.5f, -0.5f, 0.0f, 1.0f }; - s_quadBatch->vertexPositions[1] = { 0.5f, -0.5f, 0.0f, 1.0f }; - s_quadBatch->vertexPositions[2] = { 0.5f, 0.5f, 0.0f, 1.0f }; - s_quadBatch->vertexPositions[3] = { -0.5f, 0.5f, 0.0f, 1.0f }; - - // Create texture unit samplers - int32_t samplers[s_quadBatch->textureUnitPerBatch]; - for (uint32_t i = 0; i < s_quadBatch->textureUnitPerBatch; i++) { - samplers[i] = i; - } - - // Get amount of texture units supported by the GPU - uint32_t constTextureUnitCount = QuadBatch::textureUnitPerBatch; - uint32_t gpuTextureUnitCount = RenderCommand::textureUnitAmount(); - s_quadBatch->supportedTextureUnitPerBatch = std::min(constTextureUnitCount, gpuTextureUnitCount); + m_vertexPositions[0] = { -0.5f, -0.5f, 0.0f, 1.0f }; + m_vertexPositions[1] = { 0.5f, -0.5f, 0.0f, 1.0f }; + m_vertexPositions[2] = { 0.5f, 0.5f, 0.0f, 1.0f }; + m_vertexPositions[3] = { -0.5f, 0.5f, 0.0f, 1.0f }; // Texture unit 0 is reserved for no texture - s_quadBatch->textureUnits[0] = nullptr; + m_textureUnits[0] = nullptr; // GPU // ----------------------------------------- - // Create shader - s_quadBatch->shader = ShaderManager::the().load("assets/glsl/batch-quad"); - s_quadBatch->shader->bind(); - s_quadBatch->shader->setInt("u_textures", samplers, s_quadBatch->textureUnitPerBatch); - s_quadBatch->shader->unbind(); - // Create vertex array - s_quadBatch->vertexArray = std::make_shared(); + m_vertexArray = std::make_shared(); // Create vertex buffer - auto vertexBuffer = std::make_shared(sizeof(QuadVertex) * QuadBatch::vertexCount); + auto vertexBuffer = std::make_shared(sizeof(QuadVertex) * vertexCount); vertexBuffer->setLayout({ { BufferElementType::Vec3, "a_position" }, { BufferElementType::Vec4, "a_color" }, { BufferElementType::Vec2, "a_textureCoordinates" }, { BufferElementType::Float, "a_textureIndex" }, }); - s_quadBatch->vertexArray->addVertexBuffer(std::move(vertexBuffer)); + m_vertexArray->addVertexBuffer(std::move(vertexBuffer)); // Generate indices - uint32_t* indices = new uint32_t[QuadBatch::indexCount]; + uint32_t* indices = new uint32_t[indexCount]; uint32_t offset = 0; - for (uint32_t i = 0; i < QuadBatch::indexCount; i += QuadBatch::indexPerQuad) { + for (uint32_t i = 0; i < indexCount; i += indexPerQuad) { indices[i + 0] = offset + 0; indices[i + 1] = offset + 1; indices[i + 2] = offset + 2; @@ -106,12 +168,12 @@ namespace Inferno { indices[i + 4] = offset + 3; indices[i + 5] = offset + 0; - offset += QuadBatch::vertexPerQuad; + offset += vertexPerQuad; } // Create index buffer - auto indexBuffer = std::make_shared(indices, sizeof(uint32_t) * QuadBatch::indexCount); - s_quadBatch->vertexArray->setIndexBuffer(indexBuffer); + auto indexBuffer = std::make_shared(indices, sizeof(uint32_t) * indexCount); + m_vertexArray->setIndexBuffer(indexBuffer); delete[] indices; dbg(Log::Info) << "Renderer2D initialized"; @@ -119,7 +181,8 @@ namespace Inferno { void Renderer2D::destroy() { - delete s_quadBatch; + delete s_instance; + s_instance = nullptr; } void Renderer2D::beginScene(const std::shared_ptr& camera) @@ -150,7 +213,7 @@ namespace Inferno { void Renderer2D::drawQuad(std::shared_ptr transform, glm::mat4 color, std::shared_ptr texture) { // Create a new batch if the quad limit has been reached - if (s_quadBatch->quadCount >= QuadBatch::quads) { + if (m_quadIndex >= quadCount) { nextBatch(); } @@ -161,91 +224,43 @@ namespace Inferno { uint32_t textureUnitIndex = addTextureUnit(texture); // Add the quads 4 vertices - for (uint32_t i = 0; i < QuadBatch::vertexPerQuad; i++) { - s_quadBatch->vertexBufferPtr->position = transform->transform() * s_quadBatch->vertexPositions[i]; - s_quadBatch->vertexBufferPtr->color = color[i]; - s_quadBatch->vertexBufferPtr->textureCoordinates = textureCoordinates[i]; - s_quadBatch->vertexBufferPtr->textureIndex = (float)textureUnitIndex; - s_quadBatch->vertexBufferPtr++; - } - - s_quadBatch->quadCount++; - } - - uint32_t Renderer2D::addTextureUnit(std::shared_ptr texture) - { - if (texture == nullptr) { - return 0; - } - - // Create a new batch if the texture unit limit has been reached - if (s_quadBatch->textureUnitIndex >= s_quadBatch->supportedTextureUnitPerBatch) { - nextBatch(); - } - - // If texure was already added - for (uint32_t i = 1; i < s_quadBatch->textureUnitIndex; i++) { - if (s_quadBatch->textureUnits[i] == texture) { - return i; - } - } - - // Add texture - uint32_t textureUnitIndex = s_quadBatch->textureUnitIndex; - s_quadBatch->textureUnits[textureUnitIndex] = texture; - s_quadBatch->textureUnitIndex++; - - return textureUnitIndex; - } - - void Renderer2D::bind() - { - s_quadBatch->shader->bind(); - - for (uint32_t i = 1; i < s_quadBatch->textureUnitIndex; i++) { - s_quadBatch->textureUnits[i]->bind(i); - } - - s_quadBatch->vertexArray->bind(); - } - - void Renderer2D::unbind() - { - s_quadBatch->vertexArray->unbind(); - - for (uint32_t i = 1; i < s_quadBatch->textureUnitIndex; i++) { - s_quadBatch->textureUnits[i]->unbind(); + for (uint32_t i = 0; i < vertexPerQuad; i++) { + m_vertexBufferPtr->position = transform->transform() * m_vertexPositions[i]; + m_vertexBufferPtr->color = color[i]; + m_vertexBufferPtr->textureCoordinates = textureCoordinates[i]; + m_vertexBufferPtr->textureIndex = (float)textureUnitIndex; + m_vertexBufferPtr++; } - s_quadBatch->shader->unbind(); + m_quadIndex++; } void Renderer2D::flush() { - if (s_quadBatch->quadCount == 0) { + if (m_quadIndex == 0) { return; } // Upload vertex data to GPU - s_quadBatch->vertexArray->getVertexBuffers().at(0)->uploadData( - s_quadBatch->vertexBufferBase.get(), - s_quadBatch->quadCount * QuadBatch::vertexPerQuad * sizeof(QuadVertex)); + m_vertexArray->getVertexBuffers().at(0)->uploadData( + m_vertexBufferBase.get(), + quadCount * vertexPerQuad * sizeof(QuadVertex)); bind(); // Render - s_quadBatch->shader->setFloat("u_projectionView", s_camera->projection() * s_camera->transform()->transform()); - RenderCommand::drawIndexed(s_quadBatch->vertexArray, s_quadBatch->quadCount * QuadBatch::indexPerQuad); + m_shader->setFloat("u_projectionView", s_camera->projection() * s_camera->transform()->transform()); + RenderCommand::drawIndexed(m_vertexArray, quadCount * indexPerQuad); unbind(); } void Renderer2D::startBatch() { - s_quadBatch->quadCount = 0; - s_quadBatch->vertexBufferPtr = s_quadBatch->vertexBufferBase.get(); + m_quadIndex = 0; + m_vertexBufferPtr = m_vertexBufferBase.get(); - s_quadBatch->textureUnitIndex = 1; + m_textureUnitIndex = 1; } void Renderer2D::nextBatch() diff --git a/inferno/src/inferno/render/renderer.h b/inferno/src/inferno/render/renderer.h index 631c382..a07abac 100644 --- a/inferno/src/inferno/render/renderer.h +++ b/inferno/src/inferno/render/renderer.h @@ -15,7 +15,6 @@ namespace Inferno { class Shader; class Texture; class Transform; - class VertexBuffer; class VertexArray; struct QuadVertex { @@ -25,70 +24,86 @@ namespace Inferno { float textureIndex = 0; // @Todo get int to pass to fragment correctly }; - struct QuadBatch { +// ----------------------------------------- + + class RenderCommand { + public: + static void clear(); + static void clearColor(const glm::vec4& color); + + static void drawIndexed(const std::shared_ptr& vertexArray, uint32_t indexCount = 0); + + static int32_t textureUnitAmount(); + }; + +// ----------------------------------------- + + class Renderer { + public: static const uint32_t vertexPerQuad = 4; static const uint32_t indexPerQuad = 6; - static const uint32_t quads = 1000; - static const uint32_t vertexCount = quads * vertexPerQuad; - static const uint32_t indexCount = quads * indexPerQuad; static const uint32_t textureUnitPerBatch = 32; - // CPU quad vertices - uint32_t quadCount = 0; - std::unique_ptr vertexBufferBase = nullptr; - QuadVertex* vertexBufferPtr = nullptr; + protected: + virtual void initialize() = 0; + virtual void destroy() = 0; - // Default quad vertex positions - glm::vec4 vertexPositions[vertexPerQuad]; + uint32_t addTextureUnit(std::shared_ptr texture); + + void bind(); + void unbind(); + virtual void flush() = 0; + virtual void startBatch() = 0; + virtual void nextBatch() = 0; + + uint32_t m_quadIndex = 0; // Texture units - uint32_t supportedTextureUnitPerBatch = 0; - uint32_t textureUnitIndex = 1; - std::array, textureUnitPerBatch> textureUnits; + static uint32_t m_supportedTextureUnitPerBatch; + uint32_t m_textureUnitIndex = 1; + std::array, textureUnitPerBatch> m_textureUnits; // GPU objects - std::shared_ptr shader = nullptr; - std::shared_ptr vertexArray = nullptr; + std::shared_ptr m_shader = nullptr; + std::shared_ptr m_vertexArray = nullptr; }; // ----------------------------------------- - class RenderCommand { + class Renderer2D final : public Renderer { public: - static void clear(); - static void clearColor(const glm::vec4& color); + static const uint32_t quadCount = 1000; + static const uint32_t vertexCount = quadCount * vertexPerQuad; + static const uint32_t indexCount = quadCount * indexPerQuad; - static void drawIndexed(const std::shared_ptr& vertexArray, uint32_t indexCount = 0); + void initialize() override; + void destroy() override; - static int32_t textureUnitAmount(); - }; + void beginScene(const std::shared_ptr& camera); + void endScene(); -// ----------------------------------------- + void drawQuad(std::shared_ptr transform, glm::vec4 color); + void drawQuad(std::shared_ptr transform, glm::mat4 color); + void drawQuad(std::shared_ptr transform, glm::vec4 color, std::shared_ptr texture); + void drawQuad(std::shared_ptr transform, glm::mat4 color, std::shared_ptr texture); - class Renderer2D { - public: - static void initialize(); - static void destroy(); + static inline Renderer2D& the() { return *s_instance; } - static void beginScene(const std::shared_ptr& camera); - static void endScene(); + private: + void flush() override; + void startBatch() override; + void nextBatch() override; - static void drawQuad(std::shared_ptr transform, glm::vec4 color); - static void drawQuad(std::shared_ptr transform, glm::mat4 color); - static void drawQuad(std::shared_ptr transform, glm::vec4 color, std::shared_ptr texture); - static void drawQuad(std::shared_ptr transform, glm::mat4 color, std::shared_ptr texture); + std::shared_ptr s_camera; - private: - static uint32_t addTextureUnit(std::shared_ptr texture); + // CPU quad vertices + std::unique_ptr m_vertexBufferBase = nullptr; + QuadVertex* m_vertexBufferPtr = nullptr; - static void bind(); - static void unbind(); - static void flush(); - static void startBatch(); - static void nextBatch(); + // Default quad vertex positions + glm::vec4 m_vertexPositions[vertexPerQuad]; - static std::shared_ptr s_camera; - static QuadBatch* s_quadBatch; + static Renderer2D* s_instance; }; }