aboutsummaryrefslogtreecommitdiff
path: root/src/rendering
diff options
context:
space:
mode:
authorhachem <im@hachem.wtf>2026-08-20 02:27:02 +0200
committerhachem <im@hachem.wtf>2026-08-20 02:40:07 +0200
commit5b361d81dbd2af0d0e99b9eb1adebea76ff05db0 (patch)
tree34db1df17e8c7248aeeb92156d635d31c2484e3f /src/rendering
parente3abaaf59777258ba06705135a0cafcb5918ad12 (diff)
[chore]: MASSIVE refactor + more vulkan bs
Diffstat (limited to 'src/rendering')
-rw-r--r--src/rendering/framebuffer.cpp17
-rw-r--r--src/rendering/framebuffer.h65
-rw-r--r--src/rendering/index_buffer.cpp21
-rw-r--r--src/rendering/index_buffer.h18
-rw-r--r--src/rendering/renderer.cpp64
-rw-r--r--src/rendering/renderer.h158
-rw-r--r--src/rendering/shader.cpp84
-rw-r--r--src/rendering/shader.h58
-rw-r--r--src/rendering/texture.cpp68
-rw-r--r--src/rendering/texture.h42
-rw-r--r--src/rendering/texture_manager.cpp34
-rw-r--r--src/rendering/texture_manager.h19
-rw-r--r--src/rendering/uniform_buffer.cpp23
-rw-r--r--src/rendering/uniform_buffer.h18
-rw-r--r--src/rendering/vertex_array.cpp32
-rw-r--r--src/rendering/vertex_array.h28
-rw-r--r--src/rendering/vertex_buffer.cpp21
-rw-r--r--src/rendering/vertex_buffer.h73
18 files changed, 843 insertions, 0 deletions
diff --git a/src/rendering/framebuffer.cpp b/src/rendering/framebuffer.cpp
new file mode 100644
index 0000000..089c31e
--- /dev/null
+++ b/src/rendering/framebuffer.cpp
@@ -0,0 +1,17 @@
+#include "framebuffer.h"
+#include "renderer.h"
+
+#include "platform/opengl/opengl_framebuffer.h"
+
+namespace Donut
+{
+ auto Framebuffer::create(const FramebufferSpecification& spec) -> Ref<Framebuffer>
+ {
+ switch (Renderer::get_api())
+ {
+ case RendererAPI::API::OpenGL: return create_ref<OpenGLFramebuffer>(spec);
+ }
+
+ return nullptr;
+ }
+};
diff --git a/src/rendering/framebuffer.h b/src/rendering/framebuffer.h
new file mode 100644
index 0000000..a01a81b
--- /dev/null
+++ b/src/rendering/framebuffer.h
@@ -0,0 +1,65 @@
+#pragma once
+
+#include "core/memory.h"
+#include "texture.h"
+
+namespace Donut
+{
+ enum class FramebufferTextureFormat
+ {
+ None = 0,
+
+ RGBA8,
+ RED_INTEGER,
+
+ DEPTH24STENCIL8,
+
+ Depth = DEPTH24STENCIL8
+ };
+
+ struct FramebufferTextureSpecification
+ {
+ FramebufferTextureSpecification() = default;
+ FramebufferTextureSpecification(FramebufferTextureFormat format)
+ : texture_format(format) {}
+
+ FramebufferTextureFormat texture_format = FramebufferTextureFormat::None;
+ };
+
+ struct FramebufferAttachmentSpecification
+ {
+ FramebufferAttachmentSpecification() = default;
+ FramebufferAttachmentSpecification(std::initializer_list<FramebufferTextureSpecification> attachments)
+ : attachments(attachments) {}
+
+ std::vector<FramebufferTextureSpecification> attachments;
+ };
+
+ struct FramebufferSpecification
+ {
+ uint32_t Width = 0, Height = 0;
+ FramebufferAttachmentSpecification attachments;
+ uint32_t Samples = 1;
+
+ bool SwapChainTarget = false;
+ };
+
+ class Framebuffer
+ {
+ public:
+ virtual ~Framebuffer() = default;
+
+ virtual auto bind() -> void = 0;
+ virtual auto unbind() -> void = 0;
+
+ virtual auto resize(uint32_t width, uint32_t height) -> void = 0;
+ virtual auto read_pixel(uint32_t attachment_index, int x, int y) -> int = 0;
+
+ virtual auto clear_attachment(uint32_t attachment_index, int value) -> void = 0;
+ virtual auto get_color_attachment_renderer_id(uint32_t index = 0) const -> uint32_t = 0;
+
+ virtual auto get_specification() const -> const FramebufferSpecification& = 0;
+
+ static auto create(const FramebufferSpecification& spec) -> Ref<Framebuffer>;
+ };
+};
diff --git a/src/rendering/index_buffer.cpp b/src/rendering/index_buffer.cpp
new file mode 100644
index 0000000..9603c72
--- /dev/null
+++ b/src/rendering/index_buffer.cpp
@@ -0,0 +1,21 @@
+#include "index_buffer.h"
+#include "renderer.h"
+
+#include "platform/opengl/opengl_index_buffer.h"
+#include "platform/vulkan/vulkan_index_buffer.h"
+
+namespace Donut
+{
+ auto IndexBuffer::create(const uint32_t* indices, uint32_t count) -> IndexBuffer*
+ {
+ switch (Renderer::get_api())
+ {
+ case RendererAPI::API::OpenGL:
+ return new OpenGLIndexBuffer(indices, count);
+ case RendererAPI::API::Vulkan:
+ return new VulkanIndexBuffer((uint32_t*)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..8389f2d
--- /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 auto bind() const -> void = 0;
+ virtual auto unbind() const -> void = 0;
+ virtual auto get_count() const -> uint32_t = 0;
+
+ static auto create(const uint32_t* indices, uint32_t count) -> IndexBuffer*;
+ };
+};
diff --git a/src/rendering/renderer.cpp b/src/rendering/renderer.cpp
new file mode 100644
index 0000000..28b7962
--- /dev/null
+++ b/src/rendering/renderer.cpp
@@ -0,0 +1,64 @@
+#include "renderer.h"
+
+#include "platform/opengl/opengl_renderer_api.h"
+#include "platform/vulkan/vulkan_renderer_api.h"
+
+#include <glm/gtc/matrix_transform.hpp>
+
+namespace Donut
+{
+ auto RendererAPI::create() -> Scope<RendererAPI>
+ {
+ switch (s_api)
+ {
+ case API::OpenGL:
+ return create_scope<OpenGLRendererAPI>();
+ case API::Vulkan:
+ return create_scope<VulkanRendererAPI>();
+ default:
+ return nullptr;
+ }
+ }
+
+ RendererAPI::API RendererAPI::s_api = RendererAPI::API::OpenGL;
+
+ auto Renderer::init() -> void
+ {
+ RenderCommand::init();
+ RenderCommand::enable_depth_test();
+ }
+
+ auto Renderer::shutdown() -> void
+ {
+ }
+
+ auto Renderer::on_window_resize(uint32_t width, uint32_t height) -> void
+ {
+ RenderCommand::set_viewport(0, 0, width, height);
+ }
+
+ auto Renderer::submit(const Ref<Shader>& shader,
+ const Ref<VertexArray>& vertex_array,
+ const glm::mat4& transform,
+ const glm::mat4& view_projection) -> void
+ {
+ shader->bind();
+ shader->set_mat4("u_ViewProjection", view_projection);
+ shader->set_mat4("u_Transform", transform);
+
+ vertex_array->bind();
+ RenderCommand::draw_indexed(vertex_array);
+ }
+
+ Scope<RendererAPI> RenderCommand::s_renderer_api = RendererAPI::create();
+
+ auto Renderer::set_clear_color(const glm::vec4& color) -> void
+ {
+ RenderCommand::set_clear_color(color);
+ }
+
+ auto Renderer::clear() -> void
+ {
+ RenderCommand::clear();
+ }
+};
diff --git a/src/rendering/renderer.h b/src/rendering/renderer.h
new file mode 100644
index 0000000..189723d
--- /dev/null
+++ b/src/rendering/renderer.h
@@ -0,0 +1,158 @@
+#pragma once
+
+#include "core/memory.h"
+#include "vertex_array.h"
+#include "shader.h"
+#include "framebuffer.h"
+
+#include <glm/glm.hpp>
+
+namespace Donut
+{
+ class RendererAPI
+ {
+ public:
+ enum class API
+ {
+ None = 0,
+ OpenGL = 1,
+ Vulkan = 2,
+ };
+
+ public:
+ virtual ~RendererAPI() = default;
+
+ virtual auto init() -> void = 0;
+ virtual auto set_viewport(uint32_t x, uint32_t y,
+ uint32_t width, uint32_t height) -> void = 0;
+ virtual auto set_clear_color(const glm::vec4& color) -> void = 0;
+ virtual auto clear() -> void = 0;
+ virtual auto enable_depth_test() -> void = 0;
+ virtual auto disable_depth_test() -> void = 0;
+ virtual auto set_face_culling(bool enabled) -> void = 0;
+ virtual auto enable_blending() -> void = 0;
+ virtual auto disable_blending() -> void = 0;
+
+ virtual auto draw_indexed(const Ref<VertexArray>& vertex_array,
+ uint32_t index_count = 0) -> void = 0;
+
+ virtual auto draw_arrays(uint32_t vertex_count, uint32_t first = 0) -> void = 0;
+ virtual auto draw_lines(const Ref<VertexArray>& vertex_array,
+ uint32_t index_count = 0) -> void = 0;
+ virtual auto bind_texture(uint32_t texture_id, uint32_t slot = 0) -> void = 0;
+ virtual auto bind_image_texture(uint32_t texture_id,
+ uint32_t slot = 0,
+ bool read_only = false) -> void = 0;
+ virtual auto read_pixels(uint32_t x, uint32_t y, uint32_t width, uint32_t height,
+ uint32_t format, uint32_t type, void* pixels) -> void = 0;
+
+ inline static auto get_api() -> API { return s_api; }
+ inline static auto set_api(API api) -> void { s_api = api; }
+ static auto create() -> Scope<RendererAPI>;
+
+ private:
+ static API s_api;
+ };
+
+ class RenderCommand
+ {
+ public:
+ inline static auto init() -> void
+ {
+ s_renderer_api->init();
+ }
+
+ inline static auto set_viewport(uint32_t x, uint32_t y, uint32_t width, uint32_t height) -> void
+ {
+ s_renderer_api->set_viewport(x, y, width, height);
+ }
+
+ inline static auto set_clear_color(const glm::vec4& color) -> void
+ {
+ s_renderer_api->set_clear_color(color);
+ }
+
+ inline static auto clear() -> void
+ {
+ s_renderer_api->clear();
+ }
+
+ inline static auto enable_depth_test() -> void
+ {
+ s_renderer_api->enable_depth_test();
+ }
+
+ inline static auto disable_depth_test() -> void
+ {
+ s_renderer_api->disable_depth_test();
+ }
+
+ inline static auto set_face_culling(bool enabled) -> void
+ {
+ s_renderer_api->set_face_culling(enabled);
+ }
+
+ inline static auto enable_blending() -> void
+ {
+ s_renderer_api->enable_blending();
+ }
+
+ inline static auto disable_blending() -> void
+ {
+ s_renderer_api->disable_blending();
+ }
+
+ inline static auto draw_indexed(const Ref<VertexArray>& vertex_array, uint32_t index_count = 0) -> void
+ {
+ s_renderer_api->draw_indexed(vertex_array, index_count);
+ }
+
+ inline static auto draw_arrays(uint32_t vertex_count, uint32_t first = 0) -> void
+ {
+ s_renderer_api->draw_arrays(vertex_count, first);
+ }
+
+ inline static auto draw_lines(const Ref<VertexArray>& vertex_array, uint32_t index_count = 0) -> void
+ {
+ s_renderer_api->draw_lines(vertex_array, index_count);
+ }
+
+ inline static auto bind_texture(uint32_t texture_id, uint32_t slot = 0) -> void
+ {
+ s_renderer_api->bind_texture(texture_id, slot);
+ }
+
+ inline static auto bind_image_texture(uint32_t texture_id, uint32_t slot = 0, bool read_only = false) -> void
+ {
+ s_renderer_api->bind_image_texture(texture_id, slot, read_only);
+ }
+
+ inline static auto read_pixels(uint32_t x, uint32_t y, uint32_t width, uint32_t height,
+ uint32_t format, uint32_t type, void* pixels) -> void
+ {
+ s_renderer_api->read_pixels(x, y, width, height, format, type, pixels);
+ }
+
+ private:
+ static Scope<RendererAPI> s_renderer_api;
+ };
+
+ class Renderer
+ {
+ public:
+ static auto init() -> void;
+ static auto shutdown() -> void;
+
+ static auto on_window_resize(uint32_t width, uint32_t height) -> void;
+
+ static auto submit(const Ref<Shader>& shader,
+ const Ref<VertexArray>& vertex_array,
+ const glm::mat4& transform,
+ const glm::mat4& view_projection) -> void;
+
+ static auto set_clear_color(const glm::vec4& color) -> void;
+ static auto clear() -> void;
+
+ inline static auto get_api() -> RendererAPI::API { return RendererAPI::get_api(); }
+ };
+};
diff --git a/src/rendering/shader.cpp b/src/rendering/shader.cpp
new file mode 100644
index 0000000..167b855
--- /dev/null
+++ b/src/rendering/shader.cpp
@@ -0,0 +1,84 @@
+#include "shader.h"
+#include "renderer.h"
+
+#include "platform/opengl/opengl_shader.h"
+#include "platform/vulkan/vulkan_shader.h"
+
+namespace Donut
+{
+ auto Shader::create(const std::string& filepath) -> Shader*
+ {
+ switch (Renderer::get_api())
+ {
+ case RendererAPI::API::OpenGL:
+ return new OpenGLShader(filepath);
+ case RendererAPI::API::Vulkan:
+ return new VulkanShader(filepath);
+ default:
+ return nullptr;
+ }
+ }
+
+ auto Shader::create(const std::string& name, const std::string& vertex_src, const std::string& fragment_src) -> Shader*
+ {
+ switch (Renderer::get_api())
+ {
+ case RendererAPI::API::OpenGL:
+ return new OpenGLShader(name, vertex_src, fragment_src);
+ case RendererAPI::API::Vulkan:
+ return new VulkanShader(name, vertex_src, fragment_src);
+ default:
+ return nullptr;
+ }
+ }
+
+ auto Shader::create_compute(const std::string& name, const std::string& compute_src) -> Shader*
+ {
+ switch (Renderer::get_api())
+ {
+ case RendererAPI::API::OpenGL:
+ return new OpenGLShader(name, compute_src);
+ case RendererAPI::API::Vulkan:
+ return new VulkanShader(name, compute_src);
+ default:
+ return nullptr;
+ }
+ }
+
+ auto ShaderLibrary::add(const Ref<Shader>& shader) -> void
+ {
+ auto& name = shader->get_name();
+ add(name, shader);
+ }
+
+ auto ShaderLibrary::add(const std::string& name, const Ref<Shader>& shader) -> void
+ {
+ m_shaders[name] = shader;
+ }
+
+ auto ShaderLibrary::load(const std::string& filepath) -> Ref<Shader>
+ {
+ auto shader = Ref<Shader>(Shader::create(filepath));
+ add(shader);
+ return shader;
+ }
+
+ auto ShaderLibrary::load(const std::string& name, const std::string& filepath) -> Ref<Shader>
+ {
+ auto shader = Ref<Shader>(Shader::create(filepath));
+ add(name, shader);
+ return shader;
+ }
+
+ auto ShaderLibrary::Get(const std::string& name) -> Ref<Shader>
+ {
+ if (exists(name))
+ return m_shaders[name];
+ return nullptr;
+ }
+
+ auto ShaderLibrary::exists(const std::string& name) const -> bool
+ {
+ 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..bc3fd9a
--- /dev/null
+++ b/src/rendering/shader.h
@@ -0,0 +1,58 @@
+#pragma once
+
+#include "core/memory.h"
+
+#include <string>
+#include <unordered_map>
+#include <glm/glm.hpp>
+
+#define SHADER_STORAGE_BARRIER_BIT 0x00002000
+#define UNIFORM_BARRIER_BIT 0x00000004
+#define TEXTURE_FETCH_BARRIER_BIT 0x00000008
+#define IMAGE_ACCESS_BARRIER_BIT 0x00000020
+
+namespace Donut
+{
+ class Shader
+ {
+ public:
+ virtual ~Shader() = default;
+
+ virtual auto bind() const -> void = 0;
+ virtual auto unbind() const -> void = 0;
+
+ virtual auto set_int( const std::string& name, int value) -> void = 0;
+ virtual auto set_int_array(const std::string& name, int* values, uint32_t count) -> void = 0;
+ virtual auto set_float( const std::string& name, float value) -> void = 0;
+ virtual auto set_float2( const std::string& name, const glm::vec2& value) -> void = 0;
+ virtual auto set_float3( const std::string& name, const glm::vec3& value) -> void = 0;
+ virtual auto set_float4( const std::string& name, const glm::vec4& value) -> void = 0;
+ virtual auto set_mat4( const std::string& name, const glm::mat4& value) -> void = 0;
+
+ virtual auto dispatch(uint32_t x, uint32_t y = 1, uint32_t z = 1) -> void = 0;
+ virtual auto dispatch_indirect(uint32_t offset = 0) -> void = 0;
+ virtual auto memory_barrier(uint32_t barriers) -> void = 0;
+
+ virtual auto get_name() const -> const std::string& = 0;
+ virtual auto get_renderer_id() const -> uint32_t = 0;
+
+ static auto create(const std::string& filepath) -> Shader*;
+ static auto create(const std::string& name, const std::string& vertex_src, const std::string& fragment_src) -> Shader*;
+ static auto create_compute(const std::string& name, const std::string& compute_src) -> Shader*;
+ };
+
+ class ShaderLibrary
+ {
+ public:
+ auto add(const Ref<Shader>& shader) -> void;
+ auto add(const std::string& name, const Ref<Shader>& shader) -> void;
+ auto load(const std::string& filepath) -> Ref<Shader>;
+ auto load(const std::string& name, const std::string& filepath) -> Ref<Shader>;
+
+ Ref<Shader> Get(const std::string& name);
+
+ auto exists(const std::string& name) const -> bool;
+ private:
+ std::unordered_map<std::string, Ref<Shader>> m_shaders;
+ };
+};
diff --git a/src/rendering/texture.cpp b/src/rendering/texture.cpp
new file mode 100644
index 0000000..2470e46
--- /dev/null
+++ b/src/rendering/texture.cpp
@@ -0,0 +1,68 @@
+#include "texture.h"
+#include "renderer.h"
+
+#include "platform/opengl/opengl_texture.h"
+#include "platform/vulkan/vulkan_texture.h"
+
+namespace Donut
+{
+ auto Texture2D::create(uint32_t width, uint32_t height) -> Ref<Texture2D>
+ {
+ switch (Renderer::get_api())
+ {
+ case RendererAPI::API::OpenGL:
+ return create_ref<OpenGLTexture2D>(width, height);
+ case RendererAPI::API::Vulkan:
+ return create_ref<VulkanTexture2D>(width, height);
+ case RendererAPI::API::None:
+ return nullptr;
+ default:
+ return nullptr;
+ }
+ }
+
+ auto Texture2D::create(const std::string& path) -> Ref<Texture2D>
+ {
+ switch (Renderer::get_api())
+ {
+ case RendererAPI::API::OpenGL:
+ return create_ref<OpenGLTexture2D>(path);
+ case RendererAPI::API::Vulkan:
+ return create_ref<VulkanTexture2D>(path);
+ case RendererAPI::API::None:
+ return nullptr;
+ default:
+ return nullptr;
+ }
+ }
+
+ auto CubemapTexture::create(uint32_t width, uint32_t height) -> Ref<CubemapTexture>
+ {
+ switch (Renderer::get_api())
+ {
+ case RendererAPI::API::OpenGL:
+ return create_ref<OpenGLCubemapTexture>(width, height);
+ case RendererAPI::API::Vulkan:
+ return create_ref<VulkanCubemapTexture>(width, height);
+ case RendererAPI::API::None:
+ return nullptr;
+ default:
+ return nullptr;
+ }
+ }
+
+ auto CubemapTexture::create_from_hdri(const std::string& path) -> Ref<CubemapTexture>
+ {
+ switch (Renderer::get_api())
+ {
+ case RendererAPI::API::OpenGL:
+ return create_ref<OpenGLCubemapTexture>(path);
+ case RendererAPI::API::Vulkan:
+ return create_ref<VulkanCubemapTexture>(path);
+ case RendererAPI::API::None:
+ return nullptr;
+ default:
+ return nullptr;
+ }
+ }
+}; \ No newline at end of file
diff --git a/src/rendering/texture.h b/src/rendering/texture.h
new file mode 100644
index 0000000..e9b3e0a
--- /dev/null
+++ b/src/rendering/texture.h
@@ -0,0 +1,42 @@
+#pragma once
+
+#include "core/memory.h"
+
+#include <string>
+#include <glm/glm.hpp>
+
+namespace Donut
+{
+ class Texture
+ {
+ public:
+ virtual ~Texture() = default;
+
+ virtual auto get_width() const -> uint32_t = 0;
+ virtual auto get_height() const -> uint32_t = 0;
+ virtual auto get_renderer_id() const -> uint32_t = 0;
+
+ virtual auto set_data(void* data, uint32_t size) -> void = 0;
+ virtual auto bind(uint32_t slot = 0) const -> void = 0;
+ virtual void bind_as_image(uint32_t slot = 0,
+ bool read_only = false) const = 0;
+
+ virtual bool operator==(const Texture& other) const = 0;
+ };
+
+ class Texture2D
+ : public Texture
+ {
+ public:
+ static auto create(uint32_t width, uint32_t height) -> Ref<Texture2D>;
+ static auto create(const std::string& path) -> Ref<Texture2D>;
+ };
+
+ class CubemapTexture
+ : public Texture
+ {
+ public:
+ static auto create(uint32_t width, uint32_t height) -> Ref<CubemapTexture>;
+ static auto create_from_hdri(const std::string& path) -> Ref<CubemapTexture>;
+ };
+}; \ No newline at end of file
diff --git a/src/rendering/texture_manager.cpp b/src/rendering/texture_manager.cpp
new file mode 100644
index 0000000..ad2c68b
--- /dev/null
+++ b/src/rendering/texture_manager.cpp
@@ -0,0 +1,34 @@
+#include "texture_manager.h"
+#include "platform/opengl/opengl_texture.h"
+#include "platform/opengl/opengl_renderer_api.h"
+#include <glad/glad.h>
+
+namespace Donut
+{
+ auto TextureManager::create_texture(uint32_t width, uint32_t height) -> Ref<Texture2D>
+ {
+ return create_ref<OpenGLTexture2D>(width, height);
+ }
+
+ auto TextureManager::bind_texture(uint32_t texture_id, uint32_t slot) -> void
+ {
+ RenderCommand::bind_texture(texture_id, slot);
+ }
+
+ auto TextureManager::bind_image_texture(uint32_t texture_id, uint32_t slot, bool read_only) -> void
+ {
+ RenderCommand::bind_image_texture(texture_id, slot, read_only);
+ }
+
+ auto TextureManager::set_texture_data(uint32_t texture_id, void* data, uint32_t width, uint32_t height) -> void
+ {
+ glBindTexture(GL_TEXTURE_2D, texture_id);
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, data);
+ }
+
+ auto TextureManager::resize_texture(uint32_t texture_id, uint32_t width, uint32_t height) -> void
+ {
+ glBindTexture(GL_TEXTURE_2D, texture_id);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
+ }
+};
diff --git a/src/rendering/texture_manager.h b/src/rendering/texture_manager.h
new file mode 100644
index 0000000..02c32b1
--- /dev/null
+++ b/src/rendering/texture_manager.h
@@ -0,0 +1,19 @@
+#pragma once
+
+#include "core/memory.h"
+#include "rendering/texture.h"
+#include <cstdint>
+
+namespace Donut
+{
+ class TextureManager
+ {
+ public:
+ static auto create_texture(uint32_t width, uint32_t height) -> Ref<Texture2D>;
+
+ static auto bind_texture(uint32_t texture_id, uint32_t slot = 0) -> void;
+ static auto bind_image_texture(uint32_t texture_id, uint32_t slot = 0, bool read_only = false) -> void;
+ static auto set_texture_data(uint32_t texture_id, void* data, uint32_t width, uint32_t height) -> void;
+ static auto resize_texture(uint32_t texture_id, uint32_t width, uint32_t height) -> void;
+ };
+};
diff --git a/src/rendering/uniform_buffer.cpp b/src/rendering/uniform_buffer.cpp
new file mode 100644
index 0000000..c344aec
--- /dev/null
+++ b/src/rendering/uniform_buffer.cpp
@@ -0,0 +1,23 @@
+#include "uniform_buffer.h"
+#include "renderer.h"
+
+#include "platform/opengl/opengl_uniform_buffer.h"
+#include "platform/vulkan/vulkan_uniform_buffer.h"
+
+namespace Donut
+{
+ auto UniformBuffer::create(uint32_t size, uint32_t binding) -> Ref<UniformBuffer>
+ {
+ switch (Renderer::get_api())
+ {
+ case RendererAPI::API::OpenGL:
+ return create_ref<OpenGLUniformBuffer>(size, binding);
+ case RendererAPI::API::Vulkan:
+ return create_ref<VulkanUniformBuffer>(size, binding);
+ case RendererAPI::API::None:
+ return nullptr;
+ default:
+ return nullptr;
+ }
+ }
+};
diff --git a/src/rendering/uniform_buffer.h b/src/rendering/uniform_buffer.h
new file mode 100644
index 0000000..eb28e53
--- /dev/null
+++ b/src/rendering/uniform_buffer.h
@@ -0,0 +1,18 @@
+#pragma once
+
+#include "core/memory.h"
+#include <cstdint>
+
+namespace Donut
+{
+ class UniformBuffer
+ {
+ public:
+ virtual ~UniformBuffer() = default;
+
+ virtual auto set_data(const void* data, uint32_t size, uint32_t offset = 0) -> void = 0;
+ virtual auto bind(uint32_t binding) -> void = 0;
+
+ static auto create(uint32_t size, uint32_t binding) -> Ref<UniformBuffer>;
+ };
+};
diff --git a/src/rendering/vertex_array.cpp b/src/rendering/vertex_array.cpp
new file mode 100644
index 0000000..8045707
--- /dev/null
+++ b/src/rendering/vertex_array.cpp
@@ -0,0 +1,32 @@
+#include "vertex_array.h"
+#include "renderer.h"
+
+#include "platform/opengl/opengl_vertex_array.h"
+#include "platform/vulkan/vulkan_vertex_array.h"
+
+namespace Donut
+{
+ auto VertexBufferElement::get_size_of_type(uint32_t type) -> uint32_t
+ {
+ 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;
+ }
+ }
+
+ auto VertexArray::create() -> VertexArray*
+ {
+ switch (Renderer::get_api())
+ {
+ case RendererAPI::API::OpenGL:
+ return new OpenGLVertexArray();
+ case RendererAPI::API::Vulkan:
+ return new VulkanVertexArray();
+ default:
+ return nullptr;
+ }
+ }
+};
diff --git a/src/rendering/vertex_array.h b/src/rendering/vertex_array.h
new file mode 100644
index 0000000..921df56
--- /dev/null
+++ b/src/rendering/vertex_array.h
@@ -0,0 +1,28 @@
+#pragma once
+
+#include "core/memory.h"
+
+#include "vertex_buffer.h"
+#include "index_buffer.h"
+
+#include <vector>
+
+namespace Donut
+{
+ class VertexArray
+ {
+ public:
+ virtual ~VertexArray() = default;
+
+ virtual auto bind() const -> void = 0;
+ virtual auto unbind() const -> void = 0;
+
+ virtual auto add_vertex_buffer(const Ref<VertexBuffer>& vertex_buffer) -> void = 0;
+ virtual auto set_index_buffer(const Ref<IndexBuffer>& index_buffer) -> void = 0;
+
+ virtual auto get_vertex_buffers() const -> const std::vector<Ref<VertexBuffer>>& = 0;
+ virtual auto get_index_buffer() const -> const Ref<IndexBuffer>& = 0;
+
+ static auto create() -> VertexArray*;
+ };
+};
diff --git a/src/rendering/vertex_buffer.cpp b/src/rendering/vertex_buffer.cpp
new file mode 100644
index 0000000..354d0cd
--- /dev/null
+++ b/src/rendering/vertex_buffer.cpp
@@ -0,0 +1,21 @@
+#include "vertex_buffer.h"
+#include "renderer.h"
+
+#include "platform/opengl/opengl_vertex_buffer.h"
+#include "platform/vulkan/vulkan_vertex_buffer.h"
+
+namespace Donut
+{
+ auto VertexBuffer::create(const void* data, uint32_t size) -> VertexBuffer*
+ {
+ switch (Renderer::get_api())
+ {
+ case RendererAPI::API::OpenGL:
+ return new OpenGLVertexBuffer(data, size);
+ case RendererAPI::API::Vulkan:
+ return new VulkanVertexBuffer((float*)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..6be7e34
--- /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 auto get_size_of_type(uint32_t type) -> uint32_t;
+ };
+
+ class VertexBufferLayout
+ {
+ public:
+ VertexBufferLayout() = default;
+ ~VertexBufferLayout() = default;
+
+ template<typename T>
+ auto push(uint32_t count) -> void
+ {
+ 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::get_size_of_type(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::get_size_of_type(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::get_size_of_type(0x1401);
+ }
+
+ inline auto get_elements() const -> const std::vector<VertexBufferElement>& { return m_elements; }
+ inline auto get_stride() const -> uint32_t { return m_stride; }
+
+ private:
+ std::vector<VertexBufferElement> m_elements;
+ uint32_t m_stride = 0;
+ };
+
+ class VertexBuffer
+ {
+ public:
+ virtual ~VertexBuffer() = default;
+
+ virtual auto bind() const -> void = 0;
+ virtual auto unbind() const -> void = 0;
+ virtual auto set_data(const void* data, uint32_t size) -> void = 0;
+
+ virtual auto get_layout() const -> const VertexBufferLayout& = 0;
+ virtual auto set_layout(const VertexBufferLayout& layout) -> void = 0;
+
+ static auto create(const void* data, uint32_t size) -> VertexBuffer*;
+ };
+};