bettola/client/src/gfx/shape_renderer.cpp
Ritchie Cunningham d37f632344 [Refactor] Implement batched shape rendering.
This mirrors the previous refactor of the TextRenderer. All calls to
draw_rect and draw_triangle now buffer vertex data (position and color).
A begin()/flush() system is introduced to manage batching.
2025-10-05 00:44:23 +01:00

83 lines
2.7 KiB
C++

#include <GL/glew.h>
#include "shape_renderer.h"
#include "debug/debug_stats.h"
#include "math/math.h"
ShapeRenderer::ShapeRenderer(unsigned int screen_width, unsigned int screen_height) {
math::ortho_proj(_projection, 0.0f, (float)screen_width, 0.0f, (float)screen_height, -1.0f, 1.0f);
/* Load shader. */
_shape_shader = new Shader("assets/shaders/shape.vert",
"assets/shaders/shape.frag");
_shape_shader->use();
_shape_shader->set_mat4("projection", _projection);
/* Configure VAO/VBO for batch rendering. */
glGenVertexArrays(1, &_vao);
glGenBuffers(1, &_vbo);
glBindVertexArray(_vao);
glBindBuffer(GL_ARRAY_BUFFER, _vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(ShapeVertex) * MAX_SHAPE_VERTICES, nullptr, GL_DYNAMIC_DRAW);
/* Position attribute. */
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(ShapeVertex), (void*)0);
/* Colour attribute. */
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(ShapeVertex), (void*)offsetof(ShapeVertex, r));
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
_vertices.reserve(MAX_SHAPE_VERTICES);
}
ShapeRenderer::~ShapeRenderer(void) {
delete _shape_shader;
}
void ShapeRenderer::begin(void) {
_vertices.clear();
}
void ShapeRenderer::flush(void) {
if(_vertices.empty()) return;
_shape_shader->use();
glBindVertexArray(_vao);
glBindBuffer(GL_ARRAY_BUFFER, _vbo);
glBufferSubData(GL_ARRAY_BUFFER, 0, _vertices.size() * sizeof(ShapeVertex), _vertices.data());
DebugStats::draw_calls++;
DebugStats::shape_vertices += _vertices.size();
glDrawArrays(GL_TRIANGLES, 0, _vertices.size());
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}
void ShapeRenderer::draw_rect(int x, int y, int width, int height, const Color& color) {
float x_f = (float)x;
float y_f = (float)y;
float w_f = (float)width;
float h_f = (float)height;
_vertices.push_back({x_f, y_f+h_f, color.r, color.g, color.b});
_vertices.push_back({x_f, y_f, color.r, color.g, color.b});
_vertices.push_back({x_f+w_f, y_f, color.r, color.g, color.b});
_vertices.push_back({x_f, y_f+h_f, color.r, color.g, color.b});
_vertices.push_back({x_f+w_f, y_f, color.r, color.g, color.b});
_vertices.push_back({x_f+w_f, y_f+h_f, color.r, color.g, color.b});
}
void ShapeRenderer::draw_triangle(int x1, int y1, int x2, int y2, int x3,
int y3, const Color& color) {
_vertices.push_back({(float)x1, (float)y1, color.r, color.g, color.b});
_vertices.push_back({(float)x2, (float)y2, color.r, color.g, color.b});
_vertices.push_back({(float)x3, (float)y3, color.r, color.g, color.b});
}