From a2ec7dabd48a70ea69623406ddd0f8f97af403c8 Mon Sep 17 00:00:00 2001 From: hachem Date: Tue, 12 Aug 2025 18:12:37 +0200 Subject: [add]: Start of a basic rendering backend --- src/Rendering/IndexBuffer.cpp | 17 +++++++ src/Rendering/IndexBuffer.h | 18 ++++++++ src/Rendering/Renderer.cpp | 63 ++++++++++++++++++++++++++ src/Rendering/Renderer.h | 100 +++++++++++++++++++++++++++++++++++++++++ src/Rendering/Shader.cpp | 66 +++++++++++++++++++++++++++ src/Rendering/Shader.h | 46 +++++++++++++++++++ src/Rendering/VertexArray.cpp | 28 ++++++++++++ src/Rendering/VertexArray.h | 26 +++++++++++ src/Rendering/VertexBuffer.cpp | 17 +++++++ src/Rendering/VertexBuffer.h | 73 ++++++++++++++++++++++++++++++ 10 files changed, 454 insertions(+) create mode 100644 src/Rendering/IndexBuffer.cpp create mode 100644 src/Rendering/IndexBuffer.h create mode 100644 src/Rendering/Renderer.cpp create mode 100644 src/Rendering/Renderer.h create mode 100644 src/Rendering/Shader.cpp create mode 100644 src/Rendering/Shader.h create mode 100644 src/Rendering/VertexArray.cpp create mode 100644 src/Rendering/VertexArray.h create mode 100644 src/Rendering/VertexBuffer.cpp create mode 100644 src/Rendering/VertexBuffer.h (limited to 'src/Rendering') diff --git a/src/Rendering/IndexBuffer.cpp b/src/Rendering/IndexBuffer.cpp new file mode 100644 index 0000000..d8854d3 --- /dev/null +++ b/src/Rendering/IndexBuffer.cpp @@ -0,0 +1,17 @@ +#include "IndexBuffer.h" +#include "Renderer.h" +#include "Platform/OpenGL/OpenGLIndexBuffer.h" + +namespace Donut +{ + IndexBuffer* IndexBuffer::Create(const uint32_t* indices, uint32_t count) + { + switch (Renderer::GetAPI()) + { + case RendererAPI::API::OpenGL: + return new OpenGLIndexBuffer(indices, count); + default: + return nullptr; + } + } +}; diff --git a/src/Rendering/IndexBuffer.h b/src/Rendering/IndexBuffer.h new file mode 100644 index 0000000..0729d95 --- /dev/null +++ b/src/Rendering/IndexBuffer.h @@ -0,0 +1,18 @@ +#pragma once + +#include + +namespace Donut +{ + class IndexBuffer + { + public: + virtual ~IndexBuffer() = default; + + virtual void Bind() const = 0; + virtual void Unbind() const = 0; + virtual uint32_t GetCount() const = 0; + + static IndexBuffer* Create(const uint32_t* indices, uint32_t count); + }; +}; diff --git a/src/Rendering/Renderer.cpp b/src/Rendering/Renderer.cpp new file mode 100644 index 0000000..7b75a18 --- /dev/null +++ b/src/Rendering/Renderer.cpp @@ -0,0 +1,63 @@ +#include "Renderer.h" +#include "Platform/OpenGL/OpenGLRendererAPI.h" +#include +#include + +namespace Donut { + + Scope RendererAPI::Create() { + switch (s_API) { + case API::OpenGL: + return std::make_unique(); + default: + return nullptr; + } + } + + RendererAPI::API RendererAPI::s_API = RendererAPI::API::OpenGL; + + Renderer::SceneData* Renderer::s_SceneData = new Renderer::SceneData; + + void Renderer::Init() { + RenderCommand::Init(); + } + + void Renderer::Shutdown() { + delete s_SceneData; + } + + void Renderer::OnWindowResize(uint32_t width, uint32_t height) { + RenderCommand::SetViewport(0, 0, width, height); + } + + void Renderer::BeginScene() { + // Set up scene data + s_SceneData->ViewProjectionMatrix = glm::ortho(-1.0f, 1.0f, -1.0f, 1.0f, -1.0f, 1.0f); + } + + void Renderer::EndScene() { + // Clean up scene data + } + + void Renderer::Submit(const std::shared_ptr& shader, + const std::shared_ptr& vertexArray, + const glm::mat4& transform) { + shader->Bind(); + shader->SetMat4("u_ViewProjection", s_SceneData->ViewProjectionMatrix); + shader->SetMat4("u_Transform", transform); + + vertexArray->Bind(); + RenderCommand::DrawIndexed(vertexArray); + } + + Scope RenderCommand::s_RendererAPI = RendererAPI::Create(); + + void Renderer::SetClearColor(const glm::vec4& color) { + RenderCommand::SetClearColor(color); + } + + void Renderer::Clear() { + RenderCommand::Clear(); + } + +} diff --git a/src/Rendering/Renderer.h b/src/Rendering/Renderer.h new file mode 100644 index 0000000..29f66a5 --- /dev/null +++ b/src/Rendering/Renderer.h @@ -0,0 +1,100 @@ +#pragma once + +#include "VertexArray.h" +#include "Shader.h" +#include +#include + +namespace Donut +{ + template + using Scope = std::unique_ptr; + + template + constexpr Scope CreateScope(Args&& ... args) + { + return std::make_unique(std::forward(args)...); + } + + class RendererAPI + { + public: + enum class API + { + None = 0, + OpenGL = 1, + Vulkan = 2, + }; + + public: + virtual ~RendererAPI() = default; + + virtual void Init() = 0; + virtual void SetViewport(uint32_t x, uint32_t y, uint32_t width, uint32_t height) = 0; + virtual void SetClearColor(const glm::vec4& color) = 0; + virtual void Clear() = 0; + + virtual void DrawIndexed(const std::shared_ptr& vertexArray, uint32_t indexCount = 0) = 0; + + inline static API GetAPI() { return s_API; } + static Scope Create(); + + private: + static API s_API; + }; + + class RenderCommand + { + public: + inline static void Init() { + s_RendererAPI->Init(); + } + + inline static void SetViewport(uint32_t x, uint32_t y, uint32_t width, uint32_t height) { + s_RendererAPI->SetViewport(x, y, width, height); + } + + inline static void SetClearColor(const glm::vec4& color) { + s_RendererAPI->SetClearColor(color); + } + + inline static void Clear() { + s_RendererAPI->Clear(); + } + + inline static void DrawIndexed(const std::shared_ptr& vertexArray, uint32_t indexCount = 0) { + s_RendererAPI->DrawIndexed(vertexArray, indexCount); + } + + private: + static Scope s_RendererAPI; + }; + + class Renderer + { + public: + static void Init(); + static void Shutdown(); + + static void OnWindowResize(uint32_t width, uint32_t height); + + static void BeginScene(); + static void EndScene(); + + static void Submit(const std::shared_ptr& shader, + const std::shared_ptr& vertexArray, + const glm::mat4& transform = glm::mat4(1.0f)); + + static void SetClearColor(const glm::vec4& color); + static void Clear(); + + inline static RendererAPI::API GetAPI() { return RendererAPI::GetAPI(); } + private: + struct SceneData + { + glm::mat4 ViewProjectionMatrix; + }; + + static SceneData* s_SceneData; + }; +}; diff --git a/src/Rendering/Shader.cpp b/src/Rendering/Shader.cpp new file mode 100644 index 0000000..b055fe4 --- /dev/null +++ b/src/Rendering/Shader.cpp @@ -0,0 +1,66 @@ +#include "Shader.h" +#include "Renderer.h" +#include "Platform/OpenGL/OpenGLShader.h" +#include + +namespace Donut +{ + Shader* Shader::Create(const std::string& filepath) + { + switch (Renderer::GetAPI()) + { + case RendererAPI::API::OpenGL: + return new OpenGLShader(filepath); + default: + return nullptr; + } + } + + Shader* Shader::Create(const std::string& name, const std::string& vertexSrc, const std::string& fragmentSrc) + { + switch (Renderer::GetAPI()) + { + case RendererAPI::API::OpenGL: + return new OpenGLShader(name, vertexSrc, fragmentSrc); + default: + return nullptr; + } + } + + void ShaderLibrary::Add(const std::shared_ptr& shader) + { + auto& name = shader->GetName(); + Add(name, shader); + } + + void ShaderLibrary::Add(const std::string& name, const std::shared_ptr& shader) + { + m_Shaders[name] = shader; + } + + std::shared_ptr ShaderLibrary::Load(const std::string& filepath) + { + auto shader = std::shared_ptr(Shader::Create(filepath)); + Add(shader); + return shader; + } + + std::shared_ptr ShaderLibrary::Load(const std::string& name, const std::string& filepath) + { + auto shader = std::shared_ptr(Shader::Create(filepath)); + Add(name, shader); + return shader; + } + + std::shared_ptr ShaderLibrary::Get(const std::string& name) + { + if (Exists(name)) + return m_Shaders[name]; + return nullptr; + } + + bool ShaderLibrary::Exists(const std::string& name) const + { + return m_Shaders.find(name) != m_Shaders.end(); + } +}; diff --git a/src/Rendering/Shader.h b/src/Rendering/Shader.h new file mode 100644 index 0000000..a6b287a --- /dev/null +++ b/src/Rendering/Shader.h @@ -0,0 +1,46 @@ +#pragma once + +#include +#include +#include +#include + +namespace Donut +{ + class Shader + { + public: + virtual ~Shader() = default; + + virtual void Bind() const = 0; + virtual void Unbind() const = 0; + + virtual void SetInt(const std::string& name, int value) = 0; + virtual void SetIntArray(const std::string& name, int* values, uint32_t count) = 0; + virtual void SetFloat(const std::string& name, float value) = 0; + virtual void SetFloat3(const std::string& name, const glm::vec3& value) = 0; + virtual void SetFloat4(const std::string& name, const glm::vec4& value) = 0; + virtual void SetMat4(const std::string& name, const glm::mat4& value) = 0; + + virtual const std::string& GetName() const = 0; + + static Shader* Create(const std::string& filepath); + static Shader* Create(const std::string& name, const std::string& vertexSrc, const std::string& fragmentSrc); + }; + + class ShaderLibrary + { + public: + void Add(const std::shared_ptr& shader); + void Add(const std::string& name, const std::shared_ptr& shader); + std::shared_ptr Load(const std::string& filepath); + std::shared_ptr Load(const std::string& name, const std::string& filepath); + + std::shared_ptr Get(const std::string& name); + + bool Exists(const std::string& name) const; + + private: + std::unordered_map> m_Shaders; + }; +}; diff --git a/src/Rendering/VertexArray.cpp b/src/Rendering/VertexArray.cpp new file mode 100644 index 0000000..87db8fb --- /dev/null +++ b/src/Rendering/VertexArray.cpp @@ -0,0 +1,28 @@ +#include "VertexArray.h" +#include "Renderer.h" +#include "Platform/OpenGL/OpenGLVertexArray.h" + +namespace Donut +{ + uint32_t VertexBufferElement::GetSizeOfType(uint32_t type) + { + switch (type) + { + case 0x1406: return 4; // GL_FLOAT + case 0x1405: return 4; // GL_UNSIGNED_INT + case 0x1401: return 1; // GL_UNSIGNED_BYTE + default: return 0; + } + } + + VertexArray* VertexArray::Create() + { + switch (Renderer::GetAPI()) + { + case RendererAPI::API::OpenGL: + return new OpenGLVertexArray(); + default: + return nullptr; + } + } +}; diff --git a/src/Rendering/VertexArray.h b/src/Rendering/VertexArray.h new file mode 100644 index 0000000..3c8254e --- /dev/null +++ b/src/Rendering/VertexArray.h @@ -0,0 +1,26 @@ +#pragma once + +#include "VertexBuffer.h" +#include "IndexBuffer.h" +#include +#include + +namespace Donut +{ + class VertexArray + { + public: + virtual ~VertexArray() = default; + + virtual void Bind() const = 0; + virtual void Unbind() const = 0; + + virtual void AddVertexBuffer(const std::shared_ptr& vertexBuffer) = 0; + virtual void SetIndexBuffer(const std::shared_ptr& indexBuffer) = 0; + + virtual const std::vector>& GetVertexBuffers() const = 0; + virtual const std::shared_ptr& GetIndexBuffer() const = 0; + + static VertexArray* Create(); + }; +}; diff --git a/src/Rendering/VertexBuffer.cpp b/src/Rendering/VertexBuffer.cpp new file mode 100644 index 0000000..bd9c0f9 --- /dev/null +++ b/src/Rendering/VertexBuffer.cpp @@ -0,0 +1,17 @@ +#include "VertexBuffer.h" +#include "Renderer.h" +#include "Platform/OpenGL/OpenGLVertexBuffer.h" + +namespace Donut +{ + VertexBuffer* VertexBuffer::Create(const void* data, uint32_t size) + { + switch (Renderer::GetAPI()) + { + case RendererAPI::API::OpenGL: + return new OpenGLVertexBuffer(data, size); + default: + return nullptr; + } + } +}; diff --git a/src/Rendering/VertexBuffer.h b/src/Rendering/VertexBuffer.h new file mode 100644 index 0000000..807e1be --- /dev/null +++ b/src/Rendering/VertexBuffer.h @@ -0,0 +1,73 @@ +#pragma once + +#include +#include + +namespace Donut +{ + struct VertexBufferElement + { + uint32_t type; + uint32_t count; + uint8_t normalized; + uint32_t offset; + + static uint32_t GetSizeOfType(uint32_t type); + }; + + class VertexBufferLayout + { + public: + VertexBufferLayout() = default; + ~VertexBufferLayout() = default; + + template + void Push(uint32_t count) + { + static_assert(false); + } + + template<> + void Push(uint32_t count) + { + m_Elements.push_back({ 0x1406, count, 0, m_Stride }); // GL_FLOAT + m_Stride += count * VertexBufferElement::GetSizeOfType(0x1406); + } + + template<> + void Push(uint32_t count) + { + m_Elements.push_back({ 0x1405, count, 0, m_Stride }); // GL_UNSIGNED_INT + m_Stride += count * VertexBufferElement::GetSizeOfType(0x1405); + } + + template<> + void Push(uint32_t count) + { + m_Elements.push_back({ 0x1401, count, 1, m_Stride }); // GL_UNSIGNED_BYTE + m_Stride += count * VertexBufferElement::GetSizeOfType(0x1401); + } + + inline const std::vector& GetElements() const { return m_Elements; } + inline uint32_t GetStride() const { return m_Stride; } + + private: + std::vector m_Elements; + uint32_t m_Stride = 0; + }; + + class VertexBuffer + { + public: + virtual ~VertexBuffer() = default; + + virtual void Bind() const = 0; + virtual void Unbind() const = 0; + virtual void SetData(const void* data, uint32_t size) = 0; + + virtual const VertexBufferLayout& GetLayout() const = 0; + virtual void SetLayout(const VertexBufferLayout& layout) = 0; + + static VertexBuffer* Create(const void* data, uint32_t size); + }; +}; -- cgit v1.3