diff options
| author | hachem <im@hachem.wtf> | 2025-08-12 18:12:37 +0200 |
|---|---|---|
| committer | hachem <im@hachem.wtf> | 2025-08-12 18:12:37 +0200 |
| commit | 50cdd344a3ed87c75a67739e2ffd34762e9b0895 (patch) | |
| tree | 2a4a107e92687236c6676296281b89e14f8eac01 /src/rendering | |
| parent | dbe642e5e26cf2bd99218f727157b58c7fed286e (diff) | |
feat: start of a basic rendering backend
Diffstat (limited to 'src/rendering')
| -rw-r--r-- | src/rendering/index_buffer.cpp | 17 | ||||
| -rw-r--r-- | src/rendering/index_buffer.h | 18 | ||||
| -rw-r--r-- | src/rendering/renderer.cpp | 61 | ||||
| -rw-r--r-- | src/rendering/renderer.h | 100 | ||||
| -rw-r--r-- | src/rendering/shader.cpp | 66 | ||||
| -rw-r--r-- | src/rendering/shader.h | 46 | ||||
| -rw-r--r-- | src/rendering/vertex_array.cpp | 28 | ||||
| -rw-r--r-- | src/rendering/vertex_array.h | 26 | ||||
| -rw-r--r-- | src/rendering/vertex_buffer.cpp | 17 | ||||
| -rw-r--r-- | src/rendering/vertex_buffer.h | 73 |
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); + }; +}; |
