hachem.wtf
aboutsummaryrefslogtreecommitdiff
path: root/src/rendering
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
commit50cdd344a3ed87c75a67739e2ffd34762e9b0895 (patch)
tree2a4a107e92687236c6676296281b89e14f8eac01 /src/rendering
parentdbe642e5e26cf2bd99218f727157b58c7fed286e (diff)
feat: start of a basic rendering backend
Diffstat (limited to 'src/rendering')
-rw-r--r--src/rendering/index_buffer.cpp17
-rw-r--r--src/rendering/index_buffer.h18
-rw-r--r--src/rendering/renderer.cpp61
-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/vertex_array.cpp28
-rw-r--r--src/rendering/vertex_array.h26
-rw-r--r--src/rendering/vertex_buffer.cpp17
-rw-r--r--src/rendering/vertex_buffer.h73
10 files changed, 452 insertions, 0 deletions
diff --git a/src/rendering/index_buffer.cpp b/src/rendering/index_buffer.cpp
new file mode 100644
index 0000000..d4bd9c0
--- /dev/null
+++ b/src/rendering/index_buffer.cpp
@@ -0,0 +1,17 @@
+#include "index_buffer.h"
+#include "renderer.h"
+#include "platform/opengl/opengl_index_buffer.h"
+
+namespace Donut
+{
+ IndexBuffer* IndexBuffer::create(const uint32_t* indices, uint32_t count)
+ {
+ switch (Renderer::get_api())
+ {
+ case RendererAPI::API::OpenGL:
+ return new OpenGLIndexBuffer(indices, count);
+ default:
+ return nullptr;
+ }
+ }
+};
diff --git a/src/rendering/index_buffer.h b/src/rendering/index_buffer.h
new file mode 100644
index 0000000..3003676
--- /dev/null
+++ b/src/rendering/index_buffer.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 get_count() 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..1da5034
--- /dev/null
+++ b/src/rendering/renderer.cpp
@@ -0,0 +1,61 @@
+#include "renderer.h"
+#include "platform/opengl/opengl_renderer_api.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_scene_data = new Renderer::SceneData;
+
+ void Renderer::init() {
+ RenderCommand::init();
+ }
+
+ void Renderer::shutdown() {
+ delete s_scene_data;
+ }
+
+ void Renderer::on_window_resize(uint32_t width, uint32_t height) {
+ RenderCommand::set_viewport(0, 0, width, height);
+ }
+
+ void Renderer::begin_scene() {
+ s_scene_data->ViewProjectionMatrix = glm::ortho(-1.0f, 1.0f, -1.0f, 1.0f, -1.0f, 1.0f);
+ }
+
+ void Renderer::end_scene() {
+ }
+
+ void Renderer::submit(const std::shared_ptr<Shader>& shader,
+ const std::shared_ptr<VertexArray>& vertex_array,
+ const glm::mat4& transform) {
+ shader->bind();
+ shader->set_mat4("u_ViewProjection", s_scene_data->ViewProjectionMatrix);
+ shader->set_mat4("u_Transform", transform);
+
+ vertex_array->bind();
+ RenderCommand::draw_indexed(vertex_array);
+ }
+
+ Scope<RendererAPI> RenderCommand::s_renderer_api = RendererAPI::create();
+
+ void Renderer::set_clear_color(const glm::vec4& color) {
+ RenderCommand::set_clear_color(color);
+ }
+
+ void Renderer::clear() {
+ RenderCommand::clear();
+ }
+
+}
diff --git a/src/rendering/renderer.h b/src/rendering/renderer.h
new file mode 100644
index 0000000..fd61914
--- /dev/null
+++ b/src/rendering/renderer.h
@@ -0,0 +1,100 @@
+#pragma once
+
+#include "vertex_array.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> create_scope(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 set_viewport(uint32_t x, uint32_t y, uint32_t width, uint32_t height) = 0;
+ virtual void set_clear_color(const glm::vec4& color) = 0;
+ virtual void clear() = 0;
+
+ virtual void draw_indexed(const std::shared_ptr<VertexArray>& vertex_array, uint32_t index_count = 0) = 0;
+
+ inline static API get_api() { return s_api; }
+ static Scope<RendererAPI> create();
+
+ private:
+ static API s_api;
+ };
+
+ class RenderCommand
+ {
+ public:
+ inline static void init() {
+ s_renderer_api->init();
+ }
+
+ inline static void set_viewport(uint32_t x, uint32_t y, uint32_t width, uint32_t height) {
+ s_renderer_api->set_viewport(x, y, width, height);
+ }
+
+ inline static void set_clear_color(const glm::vec4& color) {
+ s_renderer_api->set_clear_color(color);
+ }
+
+ inline static void clear() {
+ s_renderer_api->clear();
+ }
+
+ inline static void draw_indexed(const std::shared_ptr<VertexArray>& vertex_array, uint32_t index_count = 0) {
+ s_renderer_api->draw_indexed(vertex_array, index_count);
+ }
+
+ private:
+ static Scope<RendererAPI> s_renderer_api;
+ };
+
+ class Renderer
+ {
+ public:
+ static void init();
+ static void shutdown();
+
+ static void on_window_resize(uint32_t width, uint32_t height);
+
+ static void begin_scene();
+ static void end_scene();
+
+ static void submit(const std::shared_ptr<Shader>& shader,
+ const std::shared_ptr<VertexArray>& vertex_array,
+ const glm::mat4& transform = glm::mat4(1.0f));
+
+ static void set_clear_color(const glm::vec4& color);
+ static void clear();
+
+ inline static RendererAPI::API get_api() { return RendererAPI::get_api(); }
+ private:
+ struct SceneData
+ {
+ glm::mat4 ViewProjectionMatrix;
+ };
+
+ static SceneData* s_scene_data;
+ };
+};
diff --git a/src/rendering/shader.cpp b/src/rendering/shader.cpp
new file mode 100644
index 0000000..10f6c49
--- /dev/null
+++ b/src/rendering/shader.cpp
@@ -0,0 +1,66 @@
+#include "shader.h"
+#include "renderer.h"
+#include "platform/opengl/opengl_shader.h"
+#include <memory>
+
+namespace Donut
+{
+ Shader* Shader::create(const std::string& filepath)
+ {
+ switch (Renderer::get_api())
+ {
+ case RendererAPI::API::OpenGL:
+ return new OpenGLShader(filepath);
+ default:
+ return nullptr;
+ }
+ }
+
+ Shader* Shader::create(const std::string& name, const std::string& vertex_src, const std::string& fragment_src)
+ {
+ switch (Renderer::get_api())
+ {
+ case RendererAPI::API::OpenGL:
+ return new OpenGLShader(name, vertex_src, fragment_src);
+ default:
+ return nullptr;
+ }
+ }
+
+ void ShaderLibrary::add(const std::shared_ptr<Shader>& shader)
+ {
+ auto& name = shader->get_name();
+ 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..d9128f6
--- /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 set_int(const std::string& name, int value) = 0;
+ virtual void set_int_array(const std::string& name, int* values, uint32_t count) = 0;
+ virtual void set_float(const std::string& name, float value) = 0;
+ virtual void set_float3(const std::string& name, const glm::vec3& value) = 0;
+ virtual void set_float4(const std::string& name, const glm::vec4& value) = 0;
+ virtual void set_mat4(const std::string& name, const glm::mat4& value) = 0;
+
+ virtual const std::string& get_name() const = 0;
+
+ static Shader* create(const std::string& filepath);
+ static Shader* create(const std::string& name, const std::string& vertex_src, const std::string& fragment_src);
+ };
+
+ 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/vertex_array.cpp b/src/rendering/vertex_array.cpp
new file mode 100644
index 0000000..48eeb5a
--- /dev/null
+++ b/src/rendering/vertex_array.cpp
@@ -0,0 +1,28 @@
+#include "vertex_array.h"
+#include "renderer.h"
+#include "platform/opengl/opengl_vertex_array.h"
+
+namespace Donut
+{
+ uint32_t VertexBufferElement::get_size_of_type(uint32_t type)
+ {
+ switch (type)
+ {
+ case 0x1406: return 4;
+ case 0x1405: return 4;
+ case 0x1401: return 1;
+ default: return 0;
+ }
+ }
+
+ VertexArray* VertexArray::create()
+ {
+ switch (Renderer::get_api())
+ {
+ case RendererAPI::API::OpenGL:
+ return new OpenGLVertexArray();
+ default:
+ return nullptr;
+ }
+ }
+};
diff --git a/src/rendering/vertex_array.h b/src/rendering/vertex_array.h
new file mode 100644
index 0000000..b51db84
--- /dev/null
+++ b/src/rendering/vertex_array.h
@@ -0,0 +1,26 @@
+#pragma once
+
+#include "vertex_buffer.h"
+#include "index_buffer.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 add_vertex_buffer(const std::shared_ptr<VertexBuffer>& vertex_buffer) = 0;
+ virtual void set_index_buffer(const std::shared_ptr<IndexBuffer>& index_buffer) = 0;
+
+ virtual const std::vector<std::shared_ptr<VertexBuffer>>& get_vertex_buffers() const = 0;
+ virtual const std::shared_ptr<IndexBuffer>& get_index_buffer() const = 0;
+
+ static VertexArray* create();
+ };
+};
diff --git a/src/rendering/vertex_buffer.cpp b/src/rendering/vertex_buffer.cpp
new file mode 100644
index 0000000..a349e78
--- /dev/null
+++ b/src/rendering/vertex_buffer.cpp
@@ -0,0 +1,17 @@
+#include "vertex_buffer.h"
+#include "renderer.h"
+#include "platform/opengl/opengl_vertex_buffer.h"
+
+namespace Donut
+{
+ VertexBuffer* VertexBuffer::create(const void* data, uint32_t size)
+ {
+ switch (Renderer::get_api())
+ {
+ case RendererAPI::API::OpenGL:
+ return new OpenGLVertexBuffer(data, size);
+ default:
+ return nullptr;
+ }
+ }
+};
diff --git a/src/rendering/vertex_buffer.h b/src/rendering/vertex_buffer.h
new file mode 100644
index 0000000..1d0b621
--- /dev/null
+++ b/src/rendering/vertex_buffer.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 get_size_of_type(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 });
+ m_stride += count * VertexBufferElement::get_size_of_type(0x1406);
+ }
+
+ template<>
+ void push<uint32_t>(uint32_t count)
+ {
+ m_elements.push_back({ 0x1405, count, 0, m_stride });
+ m_stride += count * VertexBufferElement::get_size_of_type(0x1405);
+ }
+
+ template<>
+ void push<uint8_t>(uint32_t count)
+ {
+ m_elements.push_back({ 0x1401, count, 1, m_stride });
+ m_stride += count * VertexBufferElement::get_size_of_type(0x1401);
+ }
+
+ inline const std::vector<VertexBufferElement>& get_elements() const { return m_elements; }
+ inline uint32_t get_stride() 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 set_data(const void* data, uint32_t size) = 0;
+
+ virtual const VertexBufferLayout& get_layout() const = 0;
+ virtual void set_layout(const VertexBufferLayout& layout) = 0;
+
+ static VertexBuffer* create(const void* data, uint32_t size);
+ };
+};