hachem.wtf
aboutsummaryrefslogtreecommitdiff
path: root/src/platform/opengl
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/platform/opengl
parentdbe642e5e26cf2bd99218f727157b58c7fed286e (diff)
feat: start of a basic rendering backend
Diffstat (limited to 'src/platform/opengl')
-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
10 files changed, 528 insertions, 0 deletions
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;
+ };
+};