diff options
Diffstat (limited to 'src/renderer')
| -rw-r--r-- | src/renderer/RenderGroup.cpp | 94 | ||||
| -rw-r--r-- | src/renderer/RenderGroup.hpp | 83 | ||||
| -rw-r--r-- | src/renderer/Renderer.cpp | 18 | ||||
| -rw-r--r-- | src/renderer/Renderer.hpp | 26 | ||||
| -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 | 
12 files changed, 718 insertions, 0 deletions
diff --git a/src/renderer/RenderGroup.cpp b/src/renderer/RenderGroup.cpp new file mode 100644 index 0000000..56e7ec5 --- /dev/null +++ b/src/renderer/RenderGroup.cpp @@ -0,0 +1,94 @@ +#include <renderer/RenderGroup.hpp> +#include <algorithm> + +RSortEntry::RSortEntry(float z, size_t entity_index) +        : z(z), entity_index(entity_index) { +} + +RenderGroup::RenderGroup() { +    m_REntities.reserve(1024); +    m_RSortEntries.reserve(1024); +} + +void RenderGroup::Reset() { +    m_CameraWidth = 0; +    m_CameraHeight = 0; +    m_REntities.clear(); +    m_RSortEntries.clear(); +    m_REntities.reserve(1024); +    m_RSortEntries.reserve(1024); +} + +void RenderGroup::SetCameraSize(float width, float height) { +    m_CameraWidth = width; +    m_CameraHeight = height; +} + +float RenderGroup::GetScale() { +    float screen_width = static_cast<float>(m_ScreenWidth); +    float screen_height = static_cast<float>(m_ScreenHeight); +    float xunits = screen_width / m_CameraWidth; +    float yunits = screen_height / m_CameraHeight; +    float scale = std::min(xunits, yunits); +    return scale; +} + +V2F32 RenderGroup::ViewPosToScreenPos(V2F32 view_pos) { +    float scale = GetScale(); +    float screen_width = static_cast<float>(m_ScreenWidth); +    float screen_height = static_cast<float>(m_ScreenHeight); +    float viewport_width = m_CameraWidth * scale; +    float viewport_height = m_CameraHeight * scale; +    float viewport_x0 = (screen_width - viewport_width) / 2; +    float viewport_y0 = (screen_height - viewport_height) / 2; + +    V2F32 result; +    result.x = viewport_x0 + view_pos.x * scale; +    result.y = screen_height - (viewport_y0 + view_pos.y * scale); + +    return result; +} + +V2F32 RenderGroup::ViewSizeToScreenSize(V2F32 view_size) { +    float scale = GetScale(); + +    V2F32 result; +    result.x = view_size.x * scale; +    result.y = view_size.y * scale; + +    return result; +} + +ImVec2 RenderGroup::ViewPosToScreenPosImGui(V2F32 view_pos) { +    V2F32 screen_pos = ViewPosToScreenPos(view_pos); +    ImVec2 result = {screen_pos.x, screen_pos.y}; +    return result; +} + +ImVec2 RenderGroup::ViewSizeToScreenSizeImGui(V2F32 view_size) { +    V2F32 screen_size = ViewSizeToScreenSize(view_size); +    ImVec2 result = {screen_size.x, screen_size.y}; +    return result; +} + +void RenderGroup::Clear(V3F32 color) { +    m_ClearColor = color; +} + +void RenderGroup::PushRectangle(V3F32 pos, V2F32 dim, V3F32 color) { +    m_REntities.emplace_back(REntity{.rect{REntityType_Rectangle, pos, dim, color}}); +    m_RSortEntries.emplace_back(pos.z, m_REntities.size()-1); +} + +void RenderGroup::PushBitmap(V3F32 pos, int w, int h, void *data) { +    m_REntities.emplace_back(REntity{.bitmap{REntityType_Bitmap, pos, w, h, data}}); +    m_RSortEntries.emplace_back(pos.z, m_REntities.size()-1); +} + +void RenderGroup::Sort() { +    std::sort(m_RSortEntries.begin(), m_RSortEntries.end(), +              [](const RSortEntry& e1, const RSortEntry& e2) { +                  return e1.z < e2.z; +              }); +} + diff --git a/src/renderer/RenderGroup.hpp b/src/renderer/RenderGroup.hpp new file mode 100644 index 0000000..4904220 --- /dev/null +++ b/src/renderer/RenderGroup.hpp @@ -0,0 +1,83 @@ +#pragma once + +#include <basic/defs.hpp> +#include <basic/math.hpp> +#include <vector> +#include <imgui.h> + +enum REntityType : int32_t { +    REntityType_Rectangle, +    REntityType_Bitmap, +}; + +struct REntity_Rectangle { +    REntityType type; +    V3F32 pos; +    V2F32 dim; +    V3F32 color; +}; + +struct REntity_Bitmap { +    REntityType type; +    V3F32 pos; +    int32_t width; +    int32_t height; +    void *data; +}; + +union REntity { +    REntityType type; +    REntity_Rectangle rect; +    REntity_Bitmap bitmap; +}; + +struct RSortEntry { +    RSortEntry(float z, size_t entity_index); +    float z; +    size_t entity_index; +}; + + +class RenderGroup { +public: +    RenderGroup(); +    void Clear(V3F32 color); +    void Reset(); + +    void SetCameraSize(float width, float height); +    V2F32 ViewPosToScreenPos(V2F32 view_pos); +    V2F32 ViewSizeToScreenSize(V2F32 view_size); +    ImVec2 ViewPosToScreenPosImGui(V2F32 view_pos); +    ImVec2 ViewSizeToScreenSizeImGui(V2F32 view_size); +    float GetScale(); + + +public: +    void PushRectangle(V3F32 pos, V2F32 dim, V3F32 color); +    void PushBitmap(V3F32 pos, int width, int height, void *bitmap); + + +private: +    void Sort(); + + +public: +    int32_t m_ScreenWidth; +    int32_t m_ScreenHeight; + + +private: +    friend class GlRenderer; + + +    float m_CameraWidth; +    float m_CameraHeight; + + +    V3F32 m_ClearColor; + +    std::vector<REntity> m_REntities; +    std::vector<RSortEntry> m_RSortEntries; +}; + + diff --git a/src/renderer/Renderer.cpp b/src/renderer/Renderer.cpp new file mode 100644 index 0000000..13f5feb --- /dev/null +++ b/src/renderer/Renderer.cpp @@ -0,0 +1,18 @@ +#include <renderer/Renderer.hpp> +#include <renderer/opengl/GlRenderer.hpp> + + +std::unique_ptr<Renderer> +Renderer::Select(Api api, SDL_Window *window) { +    switch (api) { +        case API_OPENGL: { +            return std::make_unique<GlRenderer>(window); +        } +        InvalidDefaultCase; +    } + +    return nullptr; +} + + +Renderer::~Renderer() {} diff --git a/src/renderer/Renderer.hpp b/src/renderer/Renderer.hpp new file mode 100644 index 0000000..a3e0f98 --- /dev/null +++ b/src/renderer/Renderer.hpp @@ -0,0 +1,26 @@ +#pragma once + +#include <basic/math.hpp> +#include <renderer/RenderGroup.hpp> +#include <SDL3/SDL.h> +#include <SDL3/SDL_video.h> + +#include <memory> + +class Renderer { +public: +    enum Api { +        API_OPENGL +    }; + +    Renderer() = default; +    static std::unique_ptr<Renderer> Select(Api api, SDL_Window *window); + + +public: +    virtual ~Renderer() = 0; +    virtual bool Init() = 0; +    virtual void Draw(RenderGroup &render_group) = 0; +    virtual void Present() = 0; +}; + 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; +}; +  | 
