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; +}; + |