hachem.wtf
aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/core/application.cpp54
-rw-r--r--src/core/application.h13
-rw-r--r--src/core/window.cpp9
-rw-r--r--src/platform/opengl/opengl_index_buffer.cpp28
-rw-r--r--src/platform/opengl/opengl_index_buffer.h22
-rw-r--r--src/platform/opengl/opengl_renderer_api.cpp34
-rw-r--r--src/platform/opengl/opengl_renderer_api.h19
-rw-r--r--src/platform/opengl/opengl_shader.cpp224
-rw-r--r--src/platform/opengl/opengl_shader.h47
-rw-r--r--src/platform/opengl/opengl_vertex_array.cpp55
-rw-r--r--src/platform/opengl/opengl_vertex_array.h40
-rw-r--r--src/platform/opengl/opengl_vertex_buffer.cpp34
-rw-r--r--src/platform/opengl/opengl_vertex_buffer.h25
-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
23 files changed, 1054 insertions, 2 deletions
diff --git a/src/core/application.cpp b/src/core/application.cpp
index d98ae4f..92bf211 100644
--- a/src/core/application.cpp
+++ b/src/core/application.cpp
@@ -1,5 +1,14 @@
#include "application.h"
+
+#include "rendering/renderer.h"
+#include "rendering/vertex_array.h"
+#include "rendering/vertex_buffer.h"
+#include "rendering/index_buffer.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::on_init() { }
- void Application::on_shutdown() { }
+ void Application::on_init()
+ {
+ 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_vertex_array = std::shared_ptr<VertexArray>(VertexArray::create());
+ m_vertex_buffer = std::shared_ptr<VertexBuffer>(VertexBuffer::create(vertices, sizeof(vertices)));
+
+ VertexBufferLayout layout;
+ layout.push<float>(3);
+ layout.push<float>(4);
+ m_vertex_buffer->set_layout(layout);
+
+ m_vertex_array->add_vertex_buffer(m_vertex_buffer);
+
+ m_index_buffer = std::shared_ptr<IndexBuffer>(IndexBuffer::create(indices, 3));
+ m_vertex_array->set_index_buffer(m_index_buffer);
+
+ m_shader = std::shared_ptr<Shader>(Shader::create("assets/basic.glsl"));
+ }
+
+ void Application::on_shutdown()
+ {
+ Renderer::shutdown();
+ }
void Application::on_update()
{
@@ -82,5 +122,15 @@ namespace Donut
void Application::on_render()
{
+ Renderer::set_clear_color({ 0.1f, 0.1f, 0.1f, 1.0f });
+ Renderer::clear();
+
+ Renderer::begin_scene();
+
+ glm::mat4 view_projection = glm::ortho(-1.0f, 1.0f, -1.0f, 1.0f, -1.0f, 1.0f);
+
+ Renderer::submit(m_shader, m_vertex_array, glm::mat4(1.0f));
+
+ Renderer::end_scene();
}
}
diff --git a/src/core/application.h b/src/core/application.h
index d88eab2..a860e1c 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_vertex_array;
+ std::shared_ptr<VertexBuffer> m_vertex_buffer;
+ std::shared_ptr<IndexBuffer> m_index_buffer;
+ std::shared_ptr<Shader> m_shader;
+
static Application* s_instance;
};
}
diff --git a/src/core/window.cpp b/src/core/window.cpp
index ab5b977..77ef885 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,14 @@ namespace Donut
}
glfwMakeContextCurrent(m_window);
+
+ if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
+ {
+ std::cout << "Failed to initialize GLAD!" << std::endl;
+ glfwTerminate();
+ return;
+ }
+
glfwSetWindowUserPointer(m_window, this);
glfwSetErrorCallback(glfw_error_callback);
diff --git a/src/platform/opengl/opengl_index_buffer.cpp b/src/platform/opengl/opengl_index_buffer.cpp
new file mode 100644
index 0000000..fac0585
--- /dev/null
+++ b/src/platform/opengl/opengl_index_buffer.cpp
@@ -0,0 +1,28 @@
+#include "opengl_index_buffer.h"
+#include <glad/glad.h>
+
+namespace Donut
+{
+ OpenGLIndexBuffer::OpenGLIndexBuffer(const uint32_t* indices, uint32_t count)
+ : m_count(count)
+ {
+ glCreateBuffers(1, &m_renderer_id);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_renderer_id);
+ glBufferData(GL_ELEMENT_ARRAY_BUFFER, count * sizeof(uint32_t), indices, GL_STATIC_DRAW);
+ }
+
+ OpenGLIndexBuffer::~OpenGLIndexBuffer()
+ {
+ glDeleteBuffers(1, &m_renderer_id);
+ }
+
+ void OpenGLIndexBuffer::bind() const
+ {
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_renderer_id);
+ }
+
+ void OpenGLIndexBuffer::unbind() const
+ {
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+ }
+};
diff --git a/src/platform/opengl/opengl_index_buffer.h b/src/platform/opengl/opengl_index_buffer.h
new file mode 100644
index 0000000..b0498b4
--- /dev/null
+++ b/src/platform/opengl/opengl_index_buffer.h
@@ -0,0 +1,22 @@
+#pragma once
+
+#include "rendering/index_buffer.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 get_count() const override { return m_count; }
+
+ private:
+ uint32_t m_renderer_id;
+ uint32_t m_count;
+ };
+};
diff --git a/src/platform/opengl/opengl_renderer_api.cpp b/src/platform/opengl/opengl_renderer_api.cpp
new file mode 100644
index 0000000..9fb911a
--- /dev/null
+++ b/src/platform/opengl/opengl_renderer_api.cpp
@@ -0,0 +1,34 @@
+#include "opengl_renderer_api.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::set_viewport(uint32_t x, uint32_t y, uint32_t width, uint32_t height)
+ {
+ glViewport(x, y, width, height);
+ }
+
+ void OpenGLRendererAPI::set_clear_color(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::draw_indexed(const std::shared_ptr<VertexArray>& vertex_array, uint32_t index_count)
+ {
+ uint32_t count = index_count ? index_count : vertex_array->get_index_buffer()->get_count();
+ glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_INT, nullptr);
+ glBindTexture(GL_TEXTURE_2D, 0);
+ }
+};
diff --git a/src/platform/opengl/opengl_renderer_api.h b/src/platform/opengl/opengl_renderer_api.h
new file mode 100644
index 0000000..26e779a
--- /dev/null
+++ b/src/platform/opengl/opengl_renderer_api.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 set_viewport(uint32_t x, uint32_t y, uint32_t width, uint32_t height) override;
+ virtual void set_clear_color(const glm::vec4& color) override;
+ virtual void clear() override;
+
+ virtual void draw_indexed(const std::shared_ptr<VertexArray>& vertex_array, uint32_t index_count = 0) override;
+ };
+};
diff --git a/src/platform/opengl/opengl_shader.cpp b/src/platform/opengl/opengl_shader.cpp
new file mode 100644
index 0000000..e2e6279
--- /dev/null
+++ b/src/platform/opengl/opengl_shader.cpp
@@ -0,0 +1,224 @@
+#include "opengl_shader.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 = read_file(filepath);
+ auto shader_sources = pre_process(source);
+ compile(shader_sources);
+
+ auto last_slash = filepath.find_last_of("/\\");
+ last_slash = last_slash == std::string::npos ? 0 : last_slash + 1;
+ auto last_dot = filepath.rfind('.');
+ auto count = last_dot == std::string::npos ? filepath.size() - last_slash : last_dot - last_slash;
+ m_name = filepath.substr(last_slash, count);
+ }
+
+ OpenGLShader::OpenGLShader(const std::string& name, const std::string& vertex_src, const std::string& fragment_src)
+ : m_name(name)
+ {
+ std::unordered_map<uint32_t, std::string> sources;
+ sources[GL_VERTEX_SHADER] = vertex_src;
+ sources[GL_FRAGMENT_SHADER] = fragment_src;
+ compile(sources);
+ }
+
+ OpenGLShader::~OpenGLShader()
+ {
+ glDeleteProgram(m_renderer_id);
+ }
+
+ std::string OpenGLShader::read_file(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::pre_process(const std::string& source)
+ {
+ std::unordered_map<uint32_t, std::string> shader_sources;
+
+ const char* type_token = "#type";
+ size_t type_token_length = strlen(type_token);
+ size_t pos = source.find(type_token, 0);
+ while (pos != std::string::npos) {
+ size_t eol = source.find_first_of("\r\n", pos);
+ size_t begin = pos + type_token_length + 1;
+ std::string type = source.substr(begin, eol - begin);
+
+ size_t next_line_pos = source.find_first_not_of("\r\n", eol);
+ pos = source.find(type_token, next_line_pos);
+ shader_sources[ShaderTypeFromString(type)] = (pos == std::string::npos) ? source.substr(next_line_pos) :
+ source.substr(next_line_pos, pos - next_line_pos);
+ }
+
+ return shader_sources;
+ }
+
+ void OpenGLShader::compile(const std::unordered_map<uint32_t, std::string>& shader_sources)
+ {
+ uint32_t program = glCreateProgram();
+ std::vector<uint32_t> glShaderIDs(shader_sources.size());
+ for (auto& kv : shader_sources)
+ {
+ uint32_t type = kv.first;
+ const std::string& source = kv.second;
+
+ uint32_t shader = glCreateShader(type);
+ const char* source_c_str = source.c_str();
+ glShaderSource(shader, 1, &source_c_str, 0);
+ glCompileShader(shader);
+
+ int is_compiled = 0;
+ glGetShaderiv(shader, GL_COMPILE_STATUS, &is_compiled);
+ if (is_compiled == GL_FALSE)
+ {
+ int max_length = 0;
+ glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &max_length);
+ std::vector<char> info_log(max_length);
+ glGetShaderInfoLog(shader, max_length, &max_length, &info_log[0]);
+ glDeleteShader(shader);
+ std::cout << "Shader compilation failure!" << std::endl << info_log.data() << std::endl;
+ return;
+ }
+ glAttachShader(program, shader);
+ glShaderIDs.push_back(shader);
+ }
+
+ m_renderer_id = program;
+ glLinkProgram(m_renderer_id);
+
+ int is_linked = 0;
+ glGetProgramiv(m_renderer_id, GL_LINK_STATUS, (int*)&is_linked);
+ if (is_linked == GL_FALSE)
+ {
+ int max_length = 0;
+ glGetProgramiv(m_renderer_id, GL_INFO_LOG_LENGTH, &max_length);
+ std::vector<char> info_log(max_length);
+ glGetProgramInfoLog(m_renderer_id, max_length, &max_length, &info_log[0]);
+ glDeleteProgram(m_renderer_id);
+ for (auto id : glShaderIDs)
+ glDeleteShader(id);
+ std::cout << "Shader link failure!" << std::endl << info_log.data() << std::endl;
+ return;
+ }
+
+ for (auto id : glShaderIDs)
+ {
+ glDetachShader(m_renderer_id, id);
+ glDeleteShader(id);
+ }
+ }
+
+ void OpenGLShader::bind() const
+ {
+ glUseProgram(m_renderer_id);
+ }
+
+ void OpenGLShader::unbind() const
+ {
+ glUseProgram(0);
+ }
+
+ void OpenGLShader::set_int(const std::string& name, int value)
+ {
+ upload_uniform_int(name, value);
+ }
+
+ void OpenGLShader::set_int_array(const std::string& name, int* values, uint32_t count)
+ {
+ upload_uniform_int_array(name, values, count);
+ }
+
+ void OpenGLShader::set_float(const std::string& name, float value)
+ {
+ upload_uniform_float(name, value);
+ }
+
+ void OpenGLShader::set_float3(const std::string& name, const glm::vec3& value)
+ {
+ upload_uniform_float3(name, value);
+ }
+
+ void OpenGLShader::set_float4(const std::string& name, const glm::vec4& value)
+ {
+ upload_uniform_float4(name, value);
+ }
+
+ void OpenGLShader::set_mat4(const std::string& name, const glm::mat4& value)
+ {
+ upload_uniform_mat4(name, value);
+ }
+
+ void OpenGLShader::upload_uniform_int(const std::string& name, int value)
+ {
+ int location = glGetUniformLocation(m_renderer_id, name.c_str());
+ glUniform1i(location, value);
+ }
+
+ void OpenGLShader::upload_uniform_int_array(const std::string& name, int* values, uint32_t count)
+ {
+ int location = glGetUniformLocation(m_renderer_id, name.c_str());
+ glUniform1iv(location, count, values);
+ }
+
+ void OpenGLShader::upload_uniform_float(const std::string& name, float value)
+ {
+ int location = glGetUniformLocation(m_renderer_id, name.c_str());
+ glUniform1f(location, value);
+ }
+
+ void OpenGLShader::upload_uniform_float2(const std::string& name, const glm::vec2& value)
+ {
+ int location = glGetUniformLocation(m_renderer_id, name.c_str());
+ glUniform2f(location, value.x, value.y);
+ }
+
+ void OpenGLShader::upload_uniform_float3(const std::string& name, const glm::vec3& value)
+ {
+ int location = glGetUniformLocation(m_renderer_id, name.c_str());
+ glUniform3f(location, value.x, value.y, value.z);
+ }
+
+ void OpenGLShader::upload_uniform_float4(const std::string& name, const glm::vec4& value)
+ {
+ int location = glGetUniformLocation(m_renderer_id, name.c_str());
+ glUniform4f(location, value.x, value.y, value.z, value.w);
+ }
+
+ void OpenGLShader::upload_uniform_mat3(const std::string& name, const glm::mat3& matrix)
+ {
+ int location = glGetUniformLocation(m_renderer_id, name.c_str());
+ glUniformMatrix3fv(location, 1, GL_FALSE, glm::value_ptr(matrix));
+ }
+
+ void OpenGLShader::upload_uniform_mat4(const std::string& name, const glm::mat4& matrix)
+ {
+ int location = glGetUniformLocation(m_renderer_id, name.c_str());
+ glUniformMatrix4fv(location, 1, GL_FALSE, glm::value_ptr(matrix));
+ }
+};
diff --git a/src/platform/opengl/opengl_shader.h b/src/platform/opengl/opengl_shader.h
new file mode 100644
index 0000000..e87c839
--- /dev/null
+++ b/src/platform/opengl/opengl_shader.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& vertex_src, const std::string& fragment_src);
+ virtual ~OpenGLShader();
+
+ virtual void bind() const override;
+ virtual void unbind() const override;
+
+ virtual void set_int(const std::string& name, int value) override;
+ virtual void set_int_array(const std::string& name, int* values, uint32_t count) override;
+ virtual void set_float(const std::string& name, float value) override;
+ virtual void set_float3(const std::string& name, const glm::vec3& value) override;
+ virtual void set_float4(const std::string& name, const glm::vec4& value) override;
+ virtual void set_mat4(const std::string& name, const glm::mat4& value) override;
+
+ virtual const std::string& get_name() const override { return m_name; }
+
+ void upload_uniform_int(const std::string& name, int value);
+ void upload_uniform_int_array(const std::string& name, int* values, uint32_t count);
+ void upload_uniform_float(const std::string& name, float value);
+ void upload_uniform_float2(const std::string& name, const glm::vec2& value);
+ void upload_uniform_float3(const std::string& name, const glm::vec3& value);
+ void upload_uniform_float4(const std::string& name, const glm::vec4& value);
+ void upload_uniform_mat3(const std::string& name, const glm::mat3& matrix);
+ void upload_uniform_mat4(const std::string& name, const glm::mat4& matrix);
+
+ private:
+ std::string read_file(const std::string& filepath);
+ std::unordered_map<uint32_t, std::string> pre_process(const std::string& source);
+ void compile(const std::unordered_map<uint32_t, std::string>& shader_sources);
+
+ private:
+ uint32_t m_renderer_id;
+ std::string m_name;
+ };
+};
diff --git a/src/platform/opengl/opengl_vertex_array.cpp b/src/platform/opengl/opengl_vertex_array.cpp
new file mode 100644
index 0000000..14d4e63
--- /dev/null
+++ b/src/platform/opengl/opengl_vertex_array.cpp
@@ -0,0 +1,55 @@
+#include <glad/glad.h>
+#include "opengl_vertex_array.h"
+#include "rendering/vertex_buffer.h"
+#include "rendering/index_buffer.h"
+
+namespace Donut
+{
+ OpenGLVertexArray::OpenGLVertexArray()
+ {
+ glCreateVertexArrays(1, &m_renderer_id);
+ }
+
+ OpenGLVertexArray::~OpenGLVertexArray()
+ {
+ glDeleteVertexArrays(1, &m_renderer_id);
+ }
+
+ void OpenGLVertexArray::bind() const
+ {
+ glBindVertexArray(m_renderer_id);
+ }
+
+ void OpenGLVertexArray::unbind() const
+ {
+ glBindVertexArray(0);
+ }
+
+ void OpenGLVertexArray::add_vertex_buffer(const std::shared_ptr<VertexBuffer>& vertex_buffer)
+ {
+ glBindVertexArray(m_renderer_id);
+ vertex_buffer->bind();
+
+ const auto& layout = vertex_buffer->get_layout();
+ for (const auto& element : layout.get_elements())
+ {
+ glEnableVertexAttribArray(m_vertex_buffer_index);
+ glVertexAttribPointer(m_vertex_buffer_index,
+ element.count,
+ element.type,
+ element.normalized ? GL_TRUE : GL_FALSE,
+ layout.get_stride(),
+ (const void*)element.offset);
+ m_vertex_buffer_index++;
+ }
+
+ m_vertex_buffers.push_back(vertex_buffer);
+ }
+
+ void OpenGLVertexArray::set_index_buffer(const std::shared_ptr<IndexBuffer>& index_buffer)
+ {
+ glBindVertexArray(m_renderer_id);
+ index_buffer->bind();
+ m_index_buffer = index_buffer;
+ }
+};
diff --git a/src/platform/opengl/opengl_vertex_array.h b/src/platform/opengl/opengl_vertex_array.h
new file mode 100644
index 0000000..e1a02f6
--- /dev/null
+++ b/src/platform/opengl/opengl_vertex_array.h
@@ -0,0 +1,40 @@
+#pragma once
+
+#include "rendering/vertex_array.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 add_vertex_buffer(const std::shared_ptr<VertexBuffer>& vertex_buffer) override;
+ virtual void set_index_buffer(const std::shared_ptr<IndexBuffer>& index_buffer) override;
+
+ virtual const std::vector<std::shared_ptr<VertexBuffer>>& get_vertex_buffers() const override
+ {
+ return m_vertex_buffers;
+ }
+
+ virtual const std::shared_ptr<IndexBuffer>& get_index_buffer() const override
+ {
+ return m_index_buffer;
+ }
+ private:
+ uint32_t m_renderer_id;
+ uint32_t m_vertex_buffer_index = 0;
+ std::vector<std::shared_ptr<VertexBuffer>> m_vertex_buffers;
+ std::shared_ptr<IndexBuffer> m_index_buffer;
+ };
+};
diff --git a/src/platform/opengl/opengl_vertex_buffer.cpp b/src/platform/opengl/opengl_vertex_buffer.cpp
new file mode 100644
index 0000000..76b620a
--- /dev/null
+++ b/src/platform/opengl/opengl_vertex_buffer.cpp
@@ -0,0 +1,34 @@
+#include "opengl_vertex_buffer.h"
+#include "rendering/vertex_buffer.h"
+#include <glad/glad.h>
+
+namespace Donut
+{
+ OpenGLVertexBuffer::OpenGLVertexBuffer(const void* data, uint32_t size)
+ {
+ glCreateBuffers(1, &m_renderer_id);
+ glBindBuffer(GL_ARRAY_BUFFER, m_renderer_id);
+ glBufferData(GL_ARRAY_BUFFER, size, data, GL_STATIC_DRAW);
+ }
+
+ OpenGLVertexBuffer::~OpenGLVertexBuffer()
+ {
+ glDeleteBuffers(1, &m_renderer_id);
+ }
+
+ void OpenGLVertexBuffer::bind() const
+ {
+ glBindBuffer(GL_ARRAY_BUFFER, m_renderer_id);
+ }
+
+ void OpenGLVertexBuffer::unbind() const
+ {
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ }
+
+ void OpenGLVertexBuffer::set_data(const void* data, uint32_t size)
+ {
+ glBindBuffer(GL_ARRAY_BUFFER, m_renderer_id);
+ glBufferSubData(GL_ARRAY_BUFFER, 0, size, data);
+ }
+};
diff --git a/src/platform/opengl/opengl_vertex_buffer.h b/src/platform/opengl/opengl_vertex_buffer.h
new file mode 100644
index 0000000..bdc0645
--- /dev/null
+++ b/src/platform/opengl/opengl_vertex_buffer.h
@@ -0,0 +1,25 @@
+#pragma once
+
+#include "rendering/vertex_buffer.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 set_data(const void* data, uint32_t size) override;
+
+ virtual const VertexBufferLayout& get_layout() const override { return m_layout; }
+ virtual void set_layout(const VertexBufferLayout& layout) override { m_layout = layout; }
+
+ private:
+ uint32_t m_renderer_id;
+ VertexBufferLayout m_layout;
+ };
+};
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);
+ };
+};