diff options
| author | fschildt <florian.schildt@protonmail.com> | 2025-07-21 16:07:28 +0200 | 
|---|---|---|
| committer | fschildt <florian.schildt@protonmail.com> | 2025-07-21 16:07:28 +0200 | 
| commit | b46a0d9369fbaa1938f0968ab216bc2d564a9c37 (patch) | |
| tree | c28b75187d01be9642af56a54a6101f51b25e4a7 /src/renderer/opengl | |
first commit
Diffstat (limited to 'src/renderer/opengl')
| -rw-r--r-- | src/renderer/opengl/GlIndexBuffer.cpp | 44 | ||||
| -rw-r--r-- | src/renderer/opengl/GlIndexBuffer.hpp | 23 | ||||
| -rw-r--r-- | src/renderer/opengl/GlRenderer.cpp | 220 | ||||
| -rw-r--r-- | src/renderer/opengl/GlRenderer.hpp | 34 | ||||
| -rw-r--r-- | src/renderer/opengl/GlShader.cpp | 80 | ||||
| -rw-r--r-- | src/renderer/opengl/GlShader.hpp | 15 | ||||
| -rw-r--r-- | src/renderer/opengl/GlVertexBuffer.cpp | 54 | ||||
| -rw-r--r-- | src/renderer/opengl/GlVertexBuffer.hpp | 27 | 
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; +}; +  | 
