aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorhachem <im@hachem.wtf>2025-08-12 18:12:37 +0200
committerhachem <im@hachem.wtf>2025-08-12 18:12:37 +0200
commita2ec7dabd48a70ea69623406ddd0f8f97af403c8 (patch)
tree52d71b51753b88473607f5e97f8bc15bdb5ad7d3 /src
parent16dff443789c7f1461b46ce52966972ae14c042b (diff)
[add]: Start of a basic rendering backend
Diffstat (limited to 'src')
-rw-r--r--src/Core/Application.cpp54
-rw-r--r--src/Core/Application.h13
-rw-r--r--src/Core/Window.cpp10
-rw-r--r--src/Platform/OpenGL/OpenGLIndexBuffer.cpp28
-rw-r--r--src/Platform/OpenGL/OpenGLIndexBuffer.h22
-rw-r--r--src/Platform/OpenGL/OpenGLRendererAPI.cpp34
-rw-r--r--src/Platform/OpenGL/OpenGLRendererAPI.h19
-rw-r--r--src/Platform/OpenGL/OpenGLShader.cpp224
-rw-r--r--src/Platform/OpenGL/OpenGLShader.h47
-rw-r--r--src/Platform/OpenGL/OpenGLVertexArray.cpp55
-rw-r--r--src/Platform/OpenGL/OpenGLVertexArray.h40
-rw-r--r--src/Platform/OpenGL/OpenGLVertexBuffer.cpp34
-rw-r--r--src/Platform/OpenGL/OpenGLVertexBuffer.h25
-rw-r--r--src/Rendering/IndexBuffer.cpp17
-rw-r--r--src/Rendering/IndexBuffer.h18
-rw-r--r--src/Rendering/Renderer.cpp63
-rw-r--r--src/Rendering/Renderer.h100
-rw-r--r--src/Rendering/Shader.cpp66
-rw-r--r--src/Rendering/Shader.h46
-rw-r--r--src/Rendering/VertexArray.cpp28
-rw-r--r--src/Rendering/VertexArray.h26
-rw-r--r--src/Rendering/VertexBuffer.cpp17
-rw-r--r--src/Rendering/VertexBuffer.h73
23 files changed, 1057 insertions, 2 deletions
diff --git a/src/Core/Application.cpp b/src/Core/Application.cpp
index 9ca060c..98d1de7 100644
--- a/src/Core/Application.cpp
+++ b/src/Core/Application.cpp
@@ -1,5 +1,14 @@
#include "Application.h"
+
+#include "Rendering/Renderer.h"
+#include "Rendering/VertexArray.h"
+#include "Rendering/VertexBuffer.h"
+#include "Rendering/IndexBuffer.h"
+#include "Rendering/Shader.h"
+
#include <iostream>
+#include <glm/glm.hpp>
+#include <glm/gtc/matrix_transform.hpp>
namespace Donut
{
@@ -73,8 +82,39 @@ namespace Donut
});
}
- void Application::OnInit() { }
- void Application::OnShutdown() { }
+ void Application::OnInit()
+ {
+ Renderer::Init();
+
+ float vertices[3 * 7] =
+ {
+ -0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f,
+ 0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f,
+ 0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f
+ };
+
+ uint32_t indices[3] = { 0, 1, 2 };
+
+ m_VertexArray = std::shared_ptr<VertexArray>(VertexArray::Create());
+ m_VertexBuffer = std::shared_ptr<VertexBuffer>(VertexBuffer::Create(vertices, sizeof(vertices)));
+
+ VertexBufferLayout layout;
+ layout.Push<float>(3);
+ layout.Push<float>(4);
+ m_VertexBuffer->SetLayout(layout);
+
+ m_VertexArray->AddVertexBuffer(m_VertexBuffer);
+
+ m_IndexBuffer = std::shared_ptr<IndexBuffer>(IndexBuffer::Create(indices, 3));
+ m_VertexArray->SetIndexBuffer(m_IndexBuffer);
+
+ m_Shader = std::shared_ptr<Shader>(Shader::Create("assets/Basic.glsl"));
+ }
+
+ void Application::OnShutdown()
+ {
+ Renderer::Shutdown();
+ }
void Application::OnUpdate()
{
@@ -82,5 +122,15 @@ namespace Donut
void Application::OnRender()
{
+ Renderer::SetClearColor({ 0.1f, 0.1f, 0.1f, 1.0f });
+ Renderer::Clear();
+
+ Renderer::BeginScene();
+
+ glm::mat4 viewProjection = glm::ortho(-1.0f, 1.0f, -1.0f, 1.0f, -1.0f, 1.0f);
+
+ Renderer::Submit(m_Shader, m_VertexArray, glm::mat4(1.0f));
+
+ Renderer::EndScene();
}
}
diff --git a/src/Core/Application.h b/src/Core/Application.h
index fca4c42..b8c9d49 100644
--- a/src/Core/Application.h
+++ b/src/Core/Application.h
@@ -7,6 +7,14 @@
namespace Donut
{
+ class VertexArray;
+ class VertexBuffer;
+ class IndexBuffer;
+ class Shader;
+};
+
+namespace Donut
+{
class Application
{
public:
@@ -30,6 +38,11 @@ namespace Donut
bool m_Running;
bool m_Minimized;
+ std::shared_ptr<VertexArray> m_VertexArray;
+ std::shared_ptr<VertexBuffer> m_VertexBuffer;
+ std::shared_ptr<IndexBuffer> m_IndexBuffer;
+ std::shared_ptr<Shader> m_Shader;
+
static Application* s_Instance;
};
} \ No newline at end of file
diff --git a/src/Core/Window.cpp b/src/Core/Window.cpp
index 13025cf..440aeb1 100644
--- a/src/Core/Window.cpp
+++ b/src/Core/Window.cpp
@@ -1,6 +1,7 @@
#include "Window.h"
#include <cstdint>
#include <iostream>
+#include <glad/glad.h>
namespace Donut
{
@@ -42,6 +43,15 @@ namespace Donut
}
glfwMakeContextCurrent(m_Window);
+
+ // Initialize GLAD
+ if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
+ {
+ std::cout << "Failed to initialize GLAD!" << std::endl;
+ glfwTerminate();
+ return;
+ }
+
glfwSetWindowUserPointer(m_Window, this);
glfwSetErrorCallback(GLFWErrorCallback);
diff --git a/src/Platform/OpenGL/OpenGLIndexBuffer.cpp b/src/Platform/OpenGL/OpenGLIndexBuffer.cpp
new file mode 100644
index 0000000..7faee62
--- /dev/null
+++ b/src/Platform/OpenGL/OpenGLIndexBuffer.cpp
@@ -0,0 +1,28 @@
+#include "OpenGLIndexBuffer.h"
+#include <glad/glad.h>
+
+namespace Donut
+{
+ OpenGLIndexBuffer::OpenGLIndexBuffer(const uint32_t* indices, uint32_t count)
+ : m_Count(count)
+ {
+ glCreateBuffers(1, &m_RendererID);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_RendererID);
+ glBufferData(GL_ELEMENT_ARRAY_BUFFER, count * sizeof(uint32_t), indices, GL_STATIC_DRAW);
+ }
+
+ OpenGLIndexBuffer::~OpenGLIndexBuffer()
+ {
+ glDeleteBuffers(1, &m_RendererID);
+ }
+
+ void OpenGLIndexBuffer::Bind() const
+ {
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_RendererID);
+ }
+
+ void OpenGLIndexBuffer::Unbind() const
+ {
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+ }
+};
diff --git a/src/Platform/OpenGL/OpenGLIndexBuffer.h b/src/Platform/OpenGL/OpenGLIndexBuffer.h
new file mode 100644
index 0000000..0de8fb2
--- /dev/null
+++ b/src/Platform/OpenGL/OpenGLIndexBuffer.h
@@ -0,0 +1,22 @@
+#pragma once
+
+#include "Rendering/IndexBuffer.h"
+
+namespace Donut
+{
+ class OpenGLIndexBuffer
+ : public IndexBuffer
+ {
+ public:
+ OpenGLIndexBuffer(const uint32_t* indices, uint32_t count);
+ virtual ~OpenGLIndexBuffer();
+
+ virtual void Bind() const override;
+ virtual void Unbind() const override;
+ virtual uint32_t GetCount() const override { return m_Count; }
+
+ private:
+ uint32_t m_RendererID;
+ uint32_t m_Count;
+ };
+};
diff --git a/src/Platform/OpenGL/OpenGLRendererAPI.cpp b/src/Platform/OpenGL/OpenGLRendererAPI.cpp
new file mode 100644
index 0000000..c1c2e9b
--- /dev/null
+++ b/src/Platform/OpenGL/OpenGLRendererAPI.cpp
@@ -0,0 +1,34 @@
+#include "OpenGLRendererAPI.h"
+#include <glad/glad.h>
+
+namespace Donut
+{
+ void OpenGLRendererAPI::Init()
+ {
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glEnable(GL_DEPTH_TEST);
+ }
+
+ void OpenGLRendererAPI::SetViewport(uint32_t x, uint32_t y, uint32_t width, uint32_t height)
+ {
+ glViewport(x, y, width, height);
+ }
+
+ void OpenGLRendererAPI::SetClearColor(const glm::vec4& color)
+ {
+ glClearColor(color.r, color.g, color.b, color.a);
+ }
+
+ void OpenGLRendererAPI::Clear()
+ {
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+ }
+
+ void OpenGLRendererAPI::DrawIndexed(const std::shared_ptr<VertexArray>& vertexArray, uint32_t indexCount)
+ {
+ uint32_t count = indexCount ? indexCount : vertexArray->GetIndexBuffer()->GetCount();
+ glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_INT, nullptr);
+ glBindTexture(GL_TEXTURE_2D, 0);
+ }
+};
diff --git a/src/Platform/OpenGL/OpenGLRendererAPI.h b/src/Platform/OpenGL/OpenGLRendererAPI.h
new file mode 100644
index 0000000..33547c0
--- /dev/null
+++ b/src/Platform/OpenGL/OpenGLRendererAPI.h
@@ -0,0 +1,19 @@
+#pragma once
+
+#include "Rendering/Renderer.h"
+#include <glad/glad.h>
+
+namespace Donut
+{
+ class OpenGLRendererAPI
+ : public RendererAPI
+ {
+ public:
+ virtual void Init() override;
+ virtual void SetViewport(uint32_t x, uint32_t y, uint32_t width, uint32_t height) override;
+ virtual void SetClearColor(const glm::vec4& color) override;
+ virtual void Clear() override;
+
+ virtual void DrawIndexed(const std::shared_ptr<VertexArray>& vertexArray, uint32_t indexCount = 0) override;
+ };
+};
diff --git a/src/Platform/OpenGL/OpenGLShader.cpp b/src/Platform/OpenGL/OpenGLShader.cpp
new file mode 100644
index 0000000..bb75f3d
--- /dev/null
+++ b/src/Platform/OpenGL/OpenGLShader.cpp
@@ -0,0 +1,224 @@
+#include "OpenGLShader.h"
+#include <glad/glad.h>
+#include <glm/gtc/type_ptr.hpp>
+#include <fstream>
+#include <iostream>
+
+namespace Donut
+{
+ static uint32_t ShaderTypeFromString(const std::string& type)
+ {
+ if (type == "vertex")
+ return GL_VERTEX_SHADER;
+ if (type == "fragment" || type == "pixel")
+ return GL_FRAGMENT_SHADER;
+ return 0;
+ }
+
+ OpenGLShader::OpenGLShader(const std::string& filepath)
+ {
+ std::string source = ReadFile(filepath);
+ auto shaderSources = PreProcess(source);
+ Compile(shaderSources);
+
+ auto lastSlash = filepath.find_last_of("/\\");
+ lastSlash = lastSlash == std::string::npos ? 0 : lastSlash + 1;
+ auto lastDot = filepath.rfind('.');
+ auto count = lastDot == std::string::npos ? filepath.size() - lastSlash : lastDot - lastSlash;
+ m_Name = filepath.substr(lastSlash, count);
+ }
+
+ OpenGLShader::OpenGLShader(const std::string& name, const std::string& vertexSrc, const std::string& fragmentSrc)
+ : m_Name(name)
+ {
+ std::unordered_map<uint32_t, std::string> sources;
+ sources[GL_VERTEX_SHADER] = vertexSrc;
+ sources[GL_FRAGMENT_SHADER] = fragmentSrc;
+ Compile(sources);
+ }
+
+ OpenGLShader::~OpenGLShader()
+ {
+ glDeleteProgram(m_RendererID);
+ }
+
+ std::string OpenGLShader::ReadFile(const std::string& filepath)
+ {
+ std::string result;
+ std::ifstream in(filepath, std::ios::in | std::ios::binary);
+ if (in) {
+ in.seekg(0, std::ios::end);
+ size_t size = in.tellg();
+ if (size != -1) {
+ result.resize(size);
+ in.seekg(0, std::ios::beg);
+ in.read(&result[0], size);
+ }
+ }
+ return result;
+ }
+
+ std::unordered_map<uint32_t, std::string> OpenGLShader::PreProcess(const std::string& source)
+ {
+ std::unordered_map<uint32_t, std::string> shaderSources;
+
+ const char* typeToken = "#type";
+ size_t typeTokenLength = strlen(typeToken);
+ size_t pos = source.find(typeToken, 0);
+ while (pos != std::string::npos) {
+ size_t eol = source.find_first_of("\r\n", pos);
+ size_t begin = pos + typeTokenLength + 1;
+ std::string type = source.substr(begin, eol - begin);
+
+ size_t nextLinePos = source.find_first_not_of("\r\n", eol);
+ pos = source.find(typeToken, nextLinePos);
+ shaderSources[ShaderTypeFromString(type)] = (pos == std::string::npos) ? source.substr(nextLinePos) :
+ source.substr(nextLinePos, pos - nextLinePos);
+ }
+
+ return shaderSources;
+ }
+
+ void OpenGLShader::Compile(const std::unordered_map<uint32_t, std::string>& shaderSources)
+ {
+ uint32_t program = glCreateProgram();
+ std::vector<uint32_t> glShaderIDs(shaderSources.size());
+ for (auto& kv : shaderSources)
+ {
+ uint32_t type = kv.first;
+ const std::string& source = kv.second;
+
+ uint32_t shader = glCreateShader(type);
+ const char* sourceCStr = source.c_str();
+ glShaderSource(shader, 1, &sourceCStr, 0);
+ glCompileShader(shader);
+
+ int isCompiled = 0;
+ glGetShaderiv(shader, GL_COMPILE_STATUS, &isCompiled);
+ if (isCompiled == GL_FALSE)
+ {
+ int maxLength = 0;
+ glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &maxLength);
+ std::vector<char> infoLog(maxLength);
+ glGetShaderInfoLog(shader, maxLength, &maxLength, &infoLog[0]);
+ glDeleteShader(shader);
+ std::cout << "Shader compilation failure!" << std::endl << infoLog.data() << std::endl;
+ return;
+ }
+ glAttachShader(program, shader);
+ glShaderIDs.push_back(shader);
+ }
+
+ m_RendererID = program;
+ glLinkProgram(m_RendererID);
+
+ int isLinked = 0;
+ glGetProgramiv(m_RendererID, GL_LINK_STATUS, (int*)&isLinked);
+ if (isLinked == GL_FALSE)
+ {
+ int maxLength = 0;
+ glGetProgramiv(m_RendererID, GL_INFO_LOG_LENGTH, &maxLength);
+ std::vector<char> infoLog(maxLength);
+ glGetProgramInfoLog(m_RendererID, maxLength, &maxLength, &infoLog[0]);
+ glDeleteProgram(m_RendererID);
+ for (auto id : glShaderIDs)
+ glDeleteShader(id);
+ std::cout << "Shader link failure!" << std::endl << infoLog.data() << std::endl;
+ return;
+ }
+
+ for (auto id : glShaderIDs)
+ {
+ glDetachShader(m_RendererID, id);
+ glDeleteShader(id);
+ }
+ }
+
+ void OpenGLShader::Bind() const
+ {
+ glUseProgram(m_RendererID);
+ }
+
+ void OpenGLShader::Unbind() const
+ {
+ glUseProgram(0);
+ }
+
+ void OpenGLShader::SetInt(const std::string& name, int value)
+ {
+ UploadUniformInt(name, value);
+ }
+
+ void OpenGLShader::SetIntArray(const std::string& name, int* values, uint32_t count)
+ {
+ UploadUniformIntArray(name, values, count);
+ }
+
+ void OpenGLShader::SetFloat(const std::string& name, float value)
+ {
+ UploadUniformFloat(name, value);
+ }
+
+ void OpenGLShader::SetFloat3(const std::string& name, const glm::vec3& value)
+ {
+ UploadUniformFloat3(name, value);
+ }
+
+ void OpenGLShader::SetFloat4(const std::string& name, const glm::vec4& value)
+ {
+ UploadUniformFloat4(name, value);
+ }
+
+ void OpenGLShader::SetMat4(const std::string& name, const glm::mat4& value)
+ {
+ UploadUniformMat4(name, value);
+ }
+
+ void OpenGLShader::UploadUniformInt(const std::string& name, int value)
+ {
+ int location = glGetUniformLocation(m_RendererID, name.c_str());
+ glUniform1i(location, value);
+ }
+
+ void OpenGLShader::UploadUniformIntArray(const std::string& name, int* values, uint32_t count)
+ {
+ int location = glGetUniformLocation(m_RendererID, name.c_str());
+ glUniform1iv(location, count, values);
+ }
+
+ void OpenGLShader::UploadUniformFloat(const std::string& name, float value)
+ {
+ int location = glGetUniformLocation(m_RendererID, name.c_str());
+ glUniform1f(location, value);
+ }
+
+ void OpenGLShader::UploadUniformFloat2(const std::string& name, const glm::vec2& value)
+ {
+ int location = glGetUniformLocation(m_RendererID, name.c_str());
+ glUniform2f(location, value.x, value.y);
+ }
+
+ void OpenGLShader::UploadUniformFloat3(const std::string& name, const glm::vec3& value)
+ {
+ int location = glGetUniformLocation(m_RendererID, name.c_str());
+ glUniform3f(location, value.x, value.y, value.z);
+ }
+
+ void OpenGLShader::UploadUniformFloat4(const std::string& name, const glm::vec4& value)
+ {
+ int location = glGetUniformLocation(m_RendererID, name.c_str());
+ glUniform4f(location, value.x, value.y, value.z, value.w);
+ }
+
+ void OpenGLShader::UploadUniformMat3(const std::string& name, const glm::mat3& matrix)
+ {
+ int location = glGetUniformLocation(m_RendererID, name.c_str());
+ glUniformMatrix3fv(location, 1, GL_FALSE, glm::value_ptr(matrix));
+ }
+
+ void OpenGLShader::UploadUniformMat4(const std::string& name, const glm::mat4& matrix)
+ {
+ int location = glGetUniformLocation(m_RendererID, name.c_str());
+ glUniformMatrix4fv(location, 1, GL_FALSE, glm::value_ptr(matrix));
+ }
+};
diff --git a/src/Platform/OpenGL/OpenGLShader.h b/src/Platform/OpenGL/OpenGLShader.h
new file mode 100644
index 0000000..2ebde12
--- /dev/null
+++ b/src/Platform/OpenGL/OpenGLShader.h
@@ -0,0 +1,47 @@
+#pragma once
+
+#include "Rendering/Shader.h"
+#include <unordered_map>
+#include <glm/glm.hpp>
+
+namespace Donut
+{
+ class OpenGLShader
+ : public Shader
+ {
+ public:
+ OpenGLShader(const std::string& filepath);
+ OpenGLShader(const std::string& name, const std::string& vertexSrc, const std::string& fragmentSrc);
+ virtual ~OpenGLShader();
+
+ virtual void Bind() const override;
+ virtual void Unbind() const override;
+
+ virtual void SetInt(const std::string& name, int value) override;
+ virtual void SetIntArray(const std::string& name, int* values, uint32_t count) override;
+ virtual void SetFloat(const std::string& name, float value) override;
+ virtual void SetFloat3(const std::string& name, const glm::vec3& value) override;
+ virtual void SetFloat4(const std::string& name, const glm::vec4& value) override;
+ virtual void SetMat4(const std::string& name, const glm::mat4& value) override;
+
+ virtual const std::string& GetName() const override { return m_Name; }
+
+ void UploadUniformInt(const std::string& name, int value);
+ void UploadUniformIntArray(const std::string& name, int* values, uint32_t count);
+ void UploadUniformFloat(const std::string& name, float value);
+ void UploadUniformFloat2(const std::string& name, const glm::vec2& value);
+ void UploadUniformFloat3(const std::string& name, const glm::vec3& value);
+ void UploadUniformFloat4(const std::string& name, const glm::vec4& value);
+ void UploadUniformMat3(const std::string& name, const glm::mat3& matrix);
+ void UploadUniformMat4(const std::string& name, const glm::mat4& matrix);
+
+ private:
+ std::string ReadFile(const std::string& filepath);
+ std::unordered_map<uint32_t, std::string> PreProcess(const std::string& source);
+ void Compile(const std::unordered_map<uint32_t, std::string>& shaderSources);
+
+ private:
+ uint32_t m_RendererID;
+ std::string m_Name;
+ };
+};
diff --git a/src/Platform/OpenGL/OpenGLVertexArray.cpp b/src/Platform/OpenGL/OpenGLVertexArray.cpp
new file mode 100644
index 0000000..f172b9f
--- /dev/null
+++ b/src/Platform/OpenGL/OpenGLVertexArray.cpp
@@ -0,0 +1,55 @@
+#include <glad/glad.h>
+#include "OpenGLVertexArray.h"
+#include "Rendering/VertexBuffer.h"
+#include "Rendering/IndexBuffer.h"
+
+namespace Donut
+{
+ OpenGLVertexArray::OpenGLVertexArray()
+ {
+ glCreateVertexArrays(1, &m_RendererID);
+ }
+
+ OpenGLVertexArray::~OpenGLVertexArray()
+ {
+ glDeleteVertexArrays(1, &m_RendererID);
+ }
+
+ void OpenGLVertexArray::Bind() const
+ {
+ glBindVertexArray(m_RendererID);
+ }
+
+ void OpenGLVertexArray::Unbind() const
+ {
+ glBindVertexArray(0);
+ }
+
+ void OpenGLVertexArray::AddVertexBuffer(const std::shared_ptr<VertexBuffer>& vertexBuffer)
+ {
+ glBindVertexArray(m_RendererID);
+ vertexBuffer->Bind();
+
+ const auto& layout = vertexBuffer->GetLayout();
+ for (const auto& element : layout.GetElements())
+ {
+ glEnableVertexAttribArray(m_VertexBufferIndex);
+ glVertexAttribPointer(m_VertexBufferIndex,
+ element.count,
+ element.type,
+ element.normalized ? GL_TRUE : GL_FALSE,
+ layout.GetStride(),
+ (const void*)element.offset);
+ m_VertexBufferIndex++;
+ }
+
+ m_VertexBuffers.push_back(vertexBuffer);
+ }
+
+ void OpenGLVertexArray::SetIndexBuffer(const std::shared_ptr<IndexBuffer>& indexBuffer)
+ {
+ glBindVertexArray(m_RendererID);
+ indexBuffer->Bind();
+ m_IndexBuffer = indexBuffer;
+ }
+};
diff --git a/src/Platform/OpenGL/OpenGLVertexArray.h b/src/Platform/OpenGL/OpenGLVertexArray.h
new file mode 100644
index 0000000..6783140
--- /dev/null
+++ b/src/Platform/OpenGL/OpenGLVertexArray.h
@@ -0,0 +1,40 @@
+#pragma once
+
+#include "Rendering/VertexArray.h"
+#include <vector>
+#include <memory>
+
+namespace Donut
+{
+ class VertexBuffer;
+ class IndexBuffer;
+
+ class OpenGLVertexArray
+ : public VertexArray
+ {
+ public:
+ OpenGLVertexArray();
+ virtual ~OpenGLVertexArray();
+
+ virtual void Bind() const override;
+ virtual void Unbind() const override;
+
+ virtual void AddVertexBuffer(const std::shared_ptr<VertexBuffer>& vertexBuffer) override;
+ virtual void SetIndexBuffer(const std::shared_ptr<IndexBuffer>& indexBuffer) override;
+
+ virtual const std::vector<std::shared_ptr<VertexBuffer>>& GetVertexBuffers() const override
+ {
+ return m_VertexBuffers;
+ }
+
+ virtual const std::shared_ptr<IndexBuffer>& GetIndexBuffer() const override
+ {
+ return m_IndexBuffer;
+ }
+ private:
+ uint32_t m_RendererID;
+ uint32_t m_VertexBufferIndex = 0;
+ std::vector<std::shared_ptr<VertexBuffer>> m_VertexBuffers;
+ std::shared_ptr<IndexBuffer> m_IndexBuffer;
+ };
+};
diff --git a/src/Platform/OpenGL/OpenGLVertexBuffer.cpp b/src/Platform/OpenGL/OpenGLVertexBuffer.cpp
new file mode 100644
index 0000000..56080c7
--- /dev/null
+++ b/src/Platform/OpenGL/OpenGLVertexBuffer.cpp
@@ -0,0 +1,34 @@
+#include "OpenGLVertexBuffer.h"
+#include "Rendering/VertexBuffer.h"
+#include <glad/glad.h>
+
+namespace Donut
+{
+ OpenGLVertexBuffer::OpenGLVertexBuffer(const void* data, uint32_t size)
+ {
+ glCreateBuffers(1, &m_RendererID);
+ glBindBuffer(GL_ARRAY_BUFFER, m_RendererID);
+ glBufferData(GL_ARRAY_BUFFER, size, data, GL_STATIC_DRAW);
+ }
+
+ OpenGLVertexBuffer::~OpenGLVertexBuffer()
+ {
+ glDeleteBuffers(1, &m_RendererID);
+ }
+
+ void OpenGLVertexBuffer::Bind() const
+ {
+ glBindBuffer(GL_ARRAY_BUFFER, m_RendererID);
+ }
+
+ void OpenGLVertexBuffer::Unbind() const
+ {
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ }
+
+ void OpenGLVertexBuffer::SetData(const void* data, uint32_t size)
+ {
+ glBindBuffer(GL_ARRAY_BUFFER, m_RendererID);
+ glBufferSubData(GL_ARRAY_BUFFER, 0, size, data);
+ }
+};
diff --git a/src/Platform/OpenGL/OpenGLVertexBuffer.h b/src/Platform/OpenGL/OpenGLVertexBuffer.h
new file mode 100644
index 0000000..491af6f
--- /dev/null
+++ b/src/Platform/OpenGL/OpenGLVertexBuffer.h
@@ -0,0 +1,25 @@
+#pragma once
+
+#include "Rendering/VertexBuffer.h"
+
+namespace Donut
+{
+ class OpenGLVertexBuffer
+ : public VertexBuffer
+ {
+ public:
+ OpenGLVertexBuffer(const void* data, uint32_t size);
+ virtual ~OpenGLVertexBuffer();
+
+ virtual void Bind() const override;
+ virtual void Unbind() const override;
+ virtual void SetData(const void* data, uint32_t size) override;
+
+ virtual const VertexBufferLayout& GetLayout() const override { return m_Layout; }
+ virtual void SetLayout(const VertexBufferLayout& layout) override { m_Layout = layout; }
+
+ private:
+ uint32_t m_RendererID;
+ VertexBufferLayout m_Layout;
+ };
+};
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 <cstdint>
+
+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 <memory>
+#include <glm/gtc/matrix_transform.hpp>
+
+namespace Donut {
+
+ Scope<RendererAPI> RendererAPI::Create() {
+ switch (s_API) {
+ case API::OpenGL:
+ return std::make_unique<OpenGLRendererAPI>();
+ 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>& shader,
+ const std::shared_ptr<VertexArray>& 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<RendererAPI> 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 <glm/glm.hpp>
+#include <memory>
+
+namespace Donut
+{
+ template<typename T>
+ using Scope = std::unique_ptr<T>;
+
+ template<typename T, typename ... Args>
+ constexpr Scope<T> CreateScope(Args&& ... args)
+ {
+ return std::make_unique<T>(std::forward<Args>(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>& vertexArray, uint32_t indexCount = 0) = 0;
+
+ inline static API GetAPI() { return s_API; }
+ static Scope<RendererAPI> 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>& vertexArray, uint32_t indexCount = 0) {
+ s_RendererAPI->DrawIndexed(vertexArray, indexCount);
+ }
+
+ private:
+ static Scope<RendererAPI> 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>& shader,
+ const std::shared_ptr<VertexArray>& 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 <memory>
+
+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>& shader)
+ {
+ auto& name = shader->GetName();
+ Add(name, shader);
+ }
+
+ void ShaderLibrary::Add(const std::string& name, const std::shared_ptr<Shader>& shader)
+ {
+ m_Shaders[name] = shader;
+ }
+
+ std::shared_ptr<Shader> ShaderLibrary::Load(const std::string& filepath)
+ {
+ auto shader = std::shared_ptr<Shader>(Shader::Create(filepath));
+ Add(shader);
+ return shader;
+ }
+
+ std::shared_ptr<Shader> ShaderLibrary::Load(const std::string& name, const std::string& filepath)
+ {
+ auto shader = std::shared_ptr<Shader>(Shader::Create(filepath));
+ Add(name, shader);
+ return shader;
+ }
+
+ std::shared_ptr<Shader> 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 <string>
+#include <unordered_map>
+#include <memory>
+#include <glm/glm.hpp>
+
+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>& shader);
+ void Add(const std::string& name, const std::shared_ptr<Shader>& shader);
+ std::shared_ptr<Shader> Load(const std::string& filepath);
+ std::shared_ptr<Shader> Load(const std::string& name, const std::string& filepath);
+
+ std::shared_ptr<Shader> Get(const std::string& name);
+
+ bool Exists(const std::string& name) const;
+
+ private:
+ std::unordered_map<std::string, std::shared_ptr<Shader>> 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 <memory>
+#include <vector>
+
+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>& vertexBuffer) = 0;
+ virtual void SetIndexBuffer(const std::shared_ptr<IndexBuffer>& indexBuffer) = 0;
+
+ virtual const std::vector<std::shared_ptr<VertexBuffer>>& GetVertexBuffers() const = 0;
+ virtual const std::shared_ptr<IndexBuffer>& 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 <cstdint>
+#include <vector>
+
+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<typename T>
+ void Push(uint32_t count)
+ {
+ static_assert(false);
+ }
+
+ template<>
+ void Push<float>(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>(uint32_t count)
+ {
+ m_Elements.push_back({ 0x1405, count, 0, m_Stride }); // GL_UNSIGNED_INT
+ m_Stride += count * VertexBufferElement::GetSizeOfType(0x1405);
+ }
+
+ template<>
+ void Push<uint8_t>(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<VertexBufferElement>& GetElements() const { return m_Elements; }
+ inline uint32_t GetStride() const { return m_Stride; }
+
+ private:
+ std::vector<VertexBufferElement> 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);
+ };
+};