aboutsummaryrefslogtreecommitdiff
path: root/src/renderer/opengl
diff options
context:
space:
mode:
authorfschildt <florian.schildt@protonmail.com>2025-07-21 16:07:28 +0200
committerfschildt <florian.schildt@protonmail.com>2025-07-21 16:07:28 +0200
commitb46a0d9369fbaa1938f0968ab216bc2d564a9c37 (patch)
treec28b75187d01be9642af56a54a6101f51b25e4a7 /src/renderer/opengl
first commitHEADmaster
Diffstat (limited to 'src/renderer/opengl')
-rw-r--r--src/renderer/opengl/GlIndexBuffer.cpp44
-rw-r--r--src/renderer/opengl/GlIndexBuffer.hpp23
-rw-r--r--src/renderer/opengl/GlRenderer.cpp220
-rw-r--r--src/renderer/opengl/GlRenderer.hpp34
-rw-r--r--src/renderer/opengl/GlShader.cpp80
-rw-r--r--src/renderer/opengl/GlShader.hpp15
-rw-r--r--src/renderer/opengl/GlVertexBuffer.cpp54
-rw-r--r--src/renderer/opengl/GlVertexBuffer.hpp27
8 files changed, 497 insertions, 0 deletions
diff --git a/src/renderer/opengl/GlIndexBuffer.cpp b/src/renderer/opengl/GlIndexBuffer.cpp
new file mode 100644
index 0000000..c5bd713
--- /dev/null
+++ b/src/renderer/opengl/GlIndexBuffer.cpp
@@ -0,0 +1,44 @@
+#include <renderer/opengl/GlIndexBuffer.hpp>
+
+#include <GL/glew.h>
+#include <string.h>
+#include <stdio.h>
+#include <assert.h>
+
+void GlIndexBuffer::Init() {
+ m_CurrentIndex = 0;
+ m_Indices.reserve(16384);
+ glGenBuffers(1, &m_Id);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_Id);
+}
+
+uint32_t *GlIndexBuffer::GetData() {
+ return m_Indices.data();
+}
+
+uint32_t GlIndexBuffer::GetCount() {
+ uint32_t count = static_cast<uint32_t>(m_Indices.size());
+ return count;
+}
+
+void GlIndexBuffer::Reset() {
+ m_CurrentIndex = 0;
+ m_Indices.clear();
+}
+
+void GlIndexBuffer::PushRectangle() {
+ uint32_t current_index = m_CurrentIndex;
+ m_Indices.push_back(current_index + 0);
+ m_Indices.push_back(current_index + 1);
+ m_Indices.push_back(current_index + 2);
+ m_Indices.push_back(current_index + 0);
+ m_Indices.push_back(current_index + 2);
+ m_Indices.push_back(current_index + 3);
+ m_CurrentIndex += 4;
+}
+
+void GlIndexBuffer::TransferData() {
+ size_t size = m_Indices.size() * sizeof(uint32_t);
+ glBufferData(GL_ELEMENT_ARRAY_BUFFER, size, m_Indices.data(), GL_STATIC_DRAW);
+}
+
diff --git a/src/renderer/opengl/GlIndexBuffer.hpp b/src/renderer/opengl/GlIndexBuffer.hpp
new file mode 100644
index 0000000..7805460
--- /dev/null
+++ b/src/renderer/opengl/GlIndexBuffer.hpp
@@ -0,0 +1,23 @@
+#pragma once
+
+#include <renderer/Renderer.hpp>
+
+class GlIndexBuffer {
+public:
+ GlIndexBuffer() = default;
+ void Init();
+ void Reset();
+
+public:
+ uint32_t GetCount();
+ uint32_t *GetData();
+
+ void PushRectangle();
+ void TransferData();
+
+private:
+ uint32_t m_Id;
+ uint32_t m_CurrentIndex;
+ std::vector<uint32_t> m_Indices;
+};
+
diff --git a/src/renderer/opengl/GlRenderer.cpp b/src/renderer/opengl/GlRenderer.cpp
new file mode 100644
index 0000000..5d7c985
--- /dev/null
+++ b/src/renderer/opengl/GlRenderer.cpp
@@ -0,0 +1,220 @@
+#include <basic/defs.hpp>
+#include <iterator>
+#include <renderer/RenderGroup.hpp>
+#include <renderer/opengl/GlRenderer.hpp>
+#include <basic/math.hpp>
+#include <renderer/Renderer.hpp>
+#include <renderer/opengl/GlVertexBuffer.hpp>
+
+#include <SDL3/SDL.h>
+#include <SDL3/SDL_video.h>
+#include <GL/glew.h>
+#include <GL/gl.h>
+#include <assert.h>
+#include <cstdio>
+
+void GLAPIENTRY
+MessageCallback(GLenum source,
+ GLenum type,
+ GLuint id,
+ GLenum severity,
+ GLsizei length,
+ const GLchar* message,
+ const void* userParam)
+{
+ fprintf(stderr, "GL CALLBACK: %s, type = 0x%x, severity = 0x%x, message = %s\n",
+ type == GL_DEBUG_TYPE_ERROR ? "** GL ERROR **" : "",
+ type,
+ severity,
+ message
+ );
+}
+
+GlRenderer::~GlRenderer() {
+ SDL_GL_DestroyContext(m_Context);
+}
+
+GlRenderer::GlRenderer(SDL_Window *window)
+ : m_Window(window), m_Context(nullptr) {
+}
+
+bool GlRenderer::Init() {
+ SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
+ SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
+ SDL_GLContext sdl_gl_context = SDL_GL_CreateContext(m_Window);
+ if (!sdl_gl_context) {
+ return false;
+ }
+
+ GLenum err = glewInit();
+ if (GLEW_OK != err)
+ {
+ fprintf(stderr, "Error: %s\n", glewGetErrorString(err));
+ SDL_GL_DestroyContext(sdl_gl_context);
+ return false;
+ }
+
+#if 0
+ glEnable(GL_DEBUG_OUTPUT);
+ glDebugMessageCallback(MessageCallback, 0);
+#endif
+
+ GLuint vertex_array;
+ glGenVertexArrays(1, &vertex_array);
+ glBindVertexArray(vertex_array);
+
+
+ // init rectangle rendering
+ if (!m_RectangleShader.InitProgram()) {
+ return false;
+ }
+ m_RectangleVertexBuffer.Init();
+ m_RectangleIndexBuffer.Init();
+
+
+ // init text rendering
+ if (!m_TextShader.InitProgram()) {
+ return false;
+ }
+ m_TextVertexBuffer.Init();
+ m_TextIndexBuffer.Init();
+
+
+ m_Context = sdl_gl_context;
+ return true;
+}
+
+void GlRenderer::Draw(RenderGroup& render_group) {
+ render_group.Sort();
+
+ float camera_width = render_group.m_CameraWidth;
+ float camera_height = render_group.m_CameraHeight;
+
+
+ glViewport(0, 0, render_group.m_ScreenWidth, render_group.m_ScreenHeight);
+ glClearColor(render_group.m_ClearColor.x,
+ render_group.m_ClearColor.y,
+ render_group.m_ClearColor.z,
+ 1.0f);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+
+ // viewport space
+ float scale = render_group.GetScale();
+ int32_t viewport_width = static_cast<int32_t>(camera_width * scale);
+ int32_t viewport_height = static_cast<int32_t>(camera_height * scale);
+ int32_t viewport_x0 = (render_group.m_ScreenWidth - viewport_width) / 2;
+ int32_t viewport_y0 = (render_group.m_ScreenHeight - viewport_height) / 2;
+ glViewport(viewport_x0, viewport_y0, viewport_width, viewport_height);
+
+
+ // draw batches
+ float last_z = -1;
+ for (auto [z, entity_index] : render_group.m_RSortEntries) {
+ REntity& render_entity = render_group.m_REntities[entity_index];
+ switch (render_entity.type) {
+ case REntityType_Rectangle: {
+ // clip space (from camera space to [-1, 1] for pos and [0, 2] for dim)
+ V3F32 pos = render_entity.rect.pos;
+ V2F32 dim = render_entity.rect.dim;
+ pos.x = 2*(pos.x / camera_width) - 1;
+ pos.y = 2*(pos.y / camera_height) - 1;
+ dim.x = 2*(dim.x / camera_width);
+ dim.y = 2*(dim.y / camera_height);
+
+ if (render_entity.rect.pos.z > last_z) {
+ DrawBatch();
+ last_z = z;
+ }
+
+ m_RectangleVertexBuffer.PushRectangle(pos, dim, render_entity.rect.color);
+ m_RectangleIndexBuffer.PushRectangle();
+ }
+
+ case REntityType_Bitmap: {
+ REntity_Bitmap& bitmap = render_entity.bitmap;
+
+ // clip space (from camera space to [-1, 1] for pos and [0, 2] for dim)
+ V3F32 pos = render_entity.bitmap.pos;
+ pos.x = 2*(pos.x / camera_width) - 1;
+ pos.y = 2*(pos.y / camera_height) - 1;
+
+#if 0
+
+ // create setup texture
+ unsigned int texture_id;
+ glGenTextures(1, &texture_id);
+ glBindTexture(GL_TEXTURE_2D, texture_id);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, bitmap.width, bitmap.height, 0, GL_RGB, GL_UNSIGNED_BYTE, bitmap.data);
+
+ glGenerateMipmap(GL_TEXTURE_2D);
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+
+ // apply texture
+ glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float)));
+ glEnableVertexAttribArray(2);
+
+ // delete texture
+ glDeleteTextures(1, &texture_id);
+
+
+
+ // 1) set vertex buffer
+ // 2) set texture coordinates
+ pos.x = 2*(pos.x / camera_width) - 1;
+ pos.y = 2*(pos.y / camera_height) - 1;
+ dim.x = 2*(dim.x / camera_width);
+ dim.y = 2*(dim.y / camera_height);
+ if (render_entity.rect.pos.z > last_z) {
+ DrawBatch();
+ last_z = z;
+ }
+#endif
+
+
+ } break;
+
+ InvalidDefaultCase;
+ }
+ }
+
+ DrawBatch();
+}
+
+void GlRenderer::Present() {
+ SDL_GL_SwapWindow(m_Window);
+}
+
+void GlRenderer::DrawBatch() {
+ int32_t rectangle_index_count = static_cast<int32_t>(m_RectangleIndexBuffer.GetCount());
+ int32_t text_index_count = static_cast<int32_t>(m_TextIndexBuffer.GetCount());
+
+ if (rectangle_index_count) {
+ m_RectangleVertexBuffer.TransferData();
+ m_RectangleIndexBuffer.TransferData();
+ m_RectangleShader.UseProgram();
+
+ glDrawElements(GL_TRIANGLES, rectangle_index_count, GL_UNSIGNED_INT, 0);
+
+ m_RectangleVertexBuffer.Reset();
+ m_RectangleIndexBuffer.Reset();
+ }
+
+ if (text_index_count) {
+ m_TextVertexBuffer.TransferData();
+ m_TextIndexBuffer.TransferData();
+ m_TextShader.UseProgram();
+
+ glDrawElements(GL_TRIANGLES, text_index_count, GL_UNSIGNED_INT, 0);
+
+ m_TextVertexBuffer.Reset();
+ m_TextIndexBuffer.Reset();
+ }
+}
+
+
diff --git a/src/renderer/opengl/GlRenderer.hpp b/src/renderer/opengl/GlRenderer.hpp
new file mode 100644
index 0000000..d59ba45
--- /dev/null
+++ b/src/renderer/opengl/GlRenderer.hpp
@@ -0,0 +1,34 @@
+#pragma once
+
+#include <renderer/Renderer.hpp>
+#include <renderer/opengl/GlVertexBuffer.hpp>
+#include <renderer/opengl/GlIndexBuffer.hpp>
+#include <renderer/opengl/GlShader.hpp>
+
+class GlRenderer : public Renderer {
+public:
+ GlRenderer(SDL_Window *window);
+ ~GlRenderer() override;
+
+ bool Init() override;
+ void Draw(RenderGroup& render_group) override;
+ void Present() override;
+
+ void InitTexture();
+
+private:
+ void DrawBatch();
+
+private:
+ SDL_Window *m_Window;
+ SDL_GLContext m_Context;
+
+ GlVertexBuffer m_RectangleVertexBuffer;
+ GlIndexBuffer m_RectangleIndexBuffer;
+ GlShader m_RectangleShader;
+
+ GlVertexBuffer m_TextVertexBuffer;
+ GlVertexBuffer m_TextIndexBuffer;
+ GlShader m_TextShader;
+};
+
diff --git a/src/renderer/opengl/GlShader.cpp b/src/renderer/opengl/GlShader.cpp
new file mode 100644
index 0000000..cf7c6c5
--- /dev/null
+++ b/src/renderer/opengl/GlShader.cpp
@@ -0,0 +1,80 @@
+#include <renderer/opengl/GlShader.hpp>
+#include <GL/glew.h>
+#include <stdio.h>
+
+static const char *s_vertex_shader_src =
+"#version 330 core\n"
+"layout (location = 0) in vec3 aPos;\n"
+"layout (location = 1) in vec3 aColor;\n"
+"\n"
+"out vec4 vertexColor;\n"
+"\n"
+"void main()\n"
+"{\n"
+" gl_Position = vec4(aPos.xy, 0.0, 1.0);\n"
+" vertexColor = vec4(aColor, 1.0);\n"
+"}\n"
+;
+
+static const char *s_fragment_shader_src =
+"#version 330 core\n"
+"in vec4 vertexColor;\n"
+"\n"
+"out vec4 FragColor;\n"
+"\n"
+"void main()\n"
+"{\n"
+" FragColor = vertexColor;\n"
+"}\n"
+;
+
+bool GlShader::InitProgram() {
+ GLuint vertex_shader;
+ GLuint fragment_shader;
+ if (!CompileShader(&vertex_shader, s_vertex_shader_src, GL_VERTEX_SHADER) ||
+ !CompileShader(&fragment_shader, s_fragment_shader_src, GL_FRAGMENT_SHADER)) {
+ return false;
+ }
+
+ GLuint program = glCreateProgram();
+ glAttachShader(program, vertex_shader);
+ glAttachShader(program, fragment_shader);
+ glLinkProgram(program);
+
+ glDeleteShader(vertex_shader);
+ glDeleteShader(fragment_shader);
+
+ int success;
+ char info_log[512];
+ glGetProgramiv(program, GL_LINK_STATUS, &success);
+ if (!success) {
+ printf("error linking shader program\n%s\n", info_log);
+ return false;
+ }
+
+ m_ProgramId = program;
+ return true;
+}
+
+void GlShader::UseProgram() {
+ glUseProgram(m_ProgramId);
+}
+
+bool GlShader::CompileShader(GLuint *id, const char *src, GLenum type) {
+ GLuint shader = glCreateShader(type);
+ glShaderSource(shader, 1, &src, 0);
+ glCompileShader(shader);
+
+ int success;
+ char info_log[512];
+ glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
+ if(!success) {
+ glGetShaderInfoLog(shader, 512, 0, info_log);
+ printf("error %s shader compilation failed\n%s\n", type == GL_VERTEX_SHADER ? "vertex" : "fragment", info_log);
+ glDeleteShader(shader);
+ return false;
+ }
+
+ *id = shader;
+ return true;
+}
diff --git a/src/renderer/opengl/GlShader.hpp b/src/renderer/opengl/GlShader.hpp
new file mode 100644
index 0000000..d195a8a
--- /dev/null
+++ b/src/renderer/opengl/GlShader.hpp
@@ -0,0 +1,15 @@
+#pragma once
+
+#include <GL/glew.h>
+
+class GlShader {
+public:
+ GlShader() = default;
+ bool InitProgram();
+ void UseProgram();
+private:
+ bool CompileShader(GLuint *id, const char *src, GLenum type);
+
+private:
+ GLuint m_ProgramId;
+};
diff --git a/src/renderer/opengl/GlVertexBuffer.cpp b/src/renderer/opengl/GlVertexBuffer.cpp
new file mode 100644
index 0000000..f716c50
--- /dev/null
+++ b/src/renderer/opengl/GlVertexBuffer.cpp
@@ -0,0 +1,54 @@
+#include <renderer/opengl/GlVertexBuffer.hpp>
+
+#include <GL/glew.h>
+#include <string.h>
+
+#include <stdio.h>
+
+void GlVertexBuffer::Init() {
+ m_Vertices.reserve(16384);
+ glGenBuffers(1, &m_Id);
+ glBindBuffer(GL_ARRAY_BUFFER, m_Id);
+}
+
+void GlVertexBuffer::Reset() {
+ glDisableVertexAttribArray(0);
+ glDisableVertexAttribArray(1);
+ m_Vertices.clear();
+}
+
+float *GlVertexBuffer::GetData() {
+ return reinterpret_cast<float*>(m_Vertices.data());
+}
+
+uint32_t GlVertexBuffer::GetCount() {
+ return static_cast<uint32_t>(m_Vertices.size());
+}
+
+void GlVertexBuffer::PushRectangle(V3F32 pos, V2F32 dim, V3F32 color) {
+ V3F32 positions[4] = {
+ V3F32(pos.x, pos.y, pos.z),
+ V3F32(pos.x + dim.x, pos.y, pos.z),
+ V3F32(pos.x + dim.x, pos.y + dim.y, pos.z),
+ V3F32(pos.x, pos.y + dim.y, pos.z),
+ };
+
+ for (int i = 0; i < 4; i++) {
+ GlVertex vertex = {};
+ vertex.pos = positions[i];
+ vertex.color = color;
+ m_Vertices.push_back(vertex);
+ }
+}
+
+void GlVertexBuffer::TransferData() {
+ size_t size = m_Vertices.size() * sizeof(GlVertex);
+ GLsizei stride = sizeof(GlVertex);
+ const void *offset_color = (const void*)(3*sizeof(float));
+ glEnableVertexAttribArray(0);
+ glEnableVertexAttribArray(1);
+ glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, stride, 0);
+ glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, stride, offset_color);
+ glBufferData(GL_ARRAY_BUFFER, size, m_Vertices.data(), GL_STATIC_DRAW);
+}
+
diff --git a/src/renderer/opengl/GlVertexBuffer.hpp b/src/renderer/opengl/GlVertexBuffer.hpp
new file mode 100644
index 0000000..4099ca2
--- /dev/null
+++ b/src/renderer/opengl/GlVertexBuffer.hpp
@@ -0,0 +1,27 @@
+#pragma once
+
+#include <renderer/Renderer.hpp>
+
+struct GlVertex {
+ V3F32 pos;
+ V3F32 color;
+};
+
+class GlVertexBuffer {
+public:
+ GlVertexBuffer() = default;
+ void Init();
+ void Reset();
+
+public:
+ float *GetData();
+ uint32_t GetCount();
+
+ void PushRectangle(V3F32 pos, V2F32 dim, V3F32 color);
+ void TransferData();
+
+private:
+ uint32_t m_Id;
+ std::vector<GlVertex> m_Vertices;
+};
+