rendering: use sprite batching techniques for rect primitives, unite their render path
This commit is contained in:
104
src/rendering/twn_rects.c
Normal file
104
src/rendering/twn_rects.c
Normal file
@ -0,0 +1,104 @@
|
||||
#include "twn_draw.h"
|
||||
#include "twn_draw_c.h"
|
||||
#include "twn_engine_context_c.h"
|
||||
#include "twn_util.h"
|
||||
#include "twn_util_c.h"
|
||||
#include "twn_textures_c.h"
|
||||
#include "twn_option.h"
|
||||
|
||||
#include <stb_ds.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
|
||||
void draw_rectangle(Rect rect, Color color) {
|
||||
RectPrimitive rectangle = {
|
||||
.rect = rect,
|
||||
.color = color,
|
||||
};
|
||||
|
||||
Primitive2D primitive = {
|
||||
.type = PRIMITIVE_2D_RECT,
|
||||
.rect = rectangle,
|
||||
};
|
||||
|
||||
arrput(ctx.render_queue_2d, primitive);
|
||||
}
|
||||
|
||||
|
||||
struct QuadBatch collect_rect_batch(const Primitive2D primitives[], size_t len) {
|
||||
SDL_assert(primitives[0].type == PRIMITIVE_2D_RECT);
|
||||
SDL_assert(primitives && len != 0);
|
||||
|
||||
struct QuadBatch batch = {
|
||||
.mode = primitives[0].rect.color.a == 255 ? TEXTURE_MODE_OPAQUE : TEXTURE_MODE_GHOSTLY,
|
||||
.constant_colored = true,
|
||||
};
|
||||
|
||||
const uint32_t uniform_color = *(const uint32_t *)&primitives[0].rect.color;
|
||||
|
||||
/* batch size is clamped so that reallocated short indices could be used */
|
||||
if (len >= QUAD_ELEMENT_BUFFER_LENGTH)
|
||||
len = QUAD_ELEMENT_BUFFER_LENGTH;
|
||||
|
||||
for (size_t i = 0; i < len; ++i) {
|
||||
const Primitive2D *const current = &primitives[i];
|
||||
|
||||
/* don't touch things other than rectangles */
|
||||
if (current->type != PRIMITIVE_2D_RECT)
|
||||
break;
|
||||
|
||||
/* only collect the same blend modes */
|
||||
if ((current->rect.color.a == 255 ? TEXTURE_MODE_OPAQUE : TEXTURE_MODE_GHOSTLY) != batch.mode)
|
||||
break;
|
||||
|
||||
/* if all are modulated the same we can skip sending the color data */
|
||||
if (*(const uint32_t *)¤t->rect.color != uniform_color)
|
||||
batch.constant_colored = false;
|
||||
|
||||
++batch.size;
|
||||
}
|
||||
|
||||
return batch;
|
||||
}
|
||||
|
||||
|
||||
/* assumes that orthogonal matrix setup is done already */
|
||||
void render_rect_batch(const Primitive2D primitives[],
|
||||
const struct QuadBatch batch)
|
||||
{
|
||||
SDL_assert(primitives && batch.size != 0);
|
||||
SDL_assert(primitives[0].type == PRIMITIVE_2D_RECT);
|
||||
|
||||
/* single vertex array is used for every batch with NULL glBufferData() trick at the end */
|
||||
static VertexBuffer vertex_array = 0;
|
||||
if (vertex_array == 0)
|
||||
vertex_array = create_vertex_buffer();
|
||||
|
||||
use_texture_mode(batch.mode);
|
||||
|
||||
/* vertex population over a vertex buffer builder interface */
|
||||
{
|
||||
VertexBufferBuilder payload = build_vertex_buffer(vertex_array, get_quad_payload_size(batch) * batch.size);
|
||||
|
||||
for (size_t i = 0; i < batch.size; ++i) {
|
||||
/* render opaques front to back, to gain benefit of an early z rejection */
|
||||
const size_t cur = batch.mode == TEXTURE_MODE_GHOSTLY ? i : batch.size - i - 1;
|
||||
const RectPrimitive rect = primitives[cur].rect;
|
||||
|
||||
Vec2 v0 = { rect.rect.x, rect.rect.y };
|
||||
Vec2 v1 = { rect.rect.x, rect.rect.y + rect.rect.h };
|
||||
Vec2 v2 = { rect.rect.x + rect.rect.w, rect.rect.y + rect.rect.h };
|
||||
Vec2 v3 = { rect.rect.x + rect.rect.w, rect.rect.y };
|
||||
|
||||
push_quad_payload_to_vertex_buffer_builder(
|
||||
batch, &payload,
|
||||
v0, v1, v2, v3,
|
||||
(Vec2){0}, (Vec2){0}, (Vec2){0}, (Vec2){0},
|
||||
rect.color);
|
||||
}
|
||||
}
|
||||
|
||||
finally_render_quads(primitives, batch, vertex_array);
|
||||
}
|
Reference in New Issue
Block a user