rendering: use sprite batching techniques for rect primitives, unite their render path
This commit is contained in:
@ -3,6 +3,7 @@
|
||||
#include "twn_util_c.h"
|
||||
#include "twn_engine_context_c.h"
|
||||
#include "twn_text_c.h"
|
||||
#include "twn_types.h"
|
||||
|
||||
#include <glad/glad.h>
|
||||
#include <stb_ds.h>
|
||||
@ -48,6 +49,34 @@ typedef struct ElementIndexedQuadWithoutColor {
|
||||
} ElementIndexedQuadWithoutColor;
|
||||
|
||||
|
||||
typedef struct ElementIndexedQuadWithoutTexture {
|
||||
/* upper-left */
|
||||
Vec2 v0;
|
||||
Color c0;
|
||||
/* bottom-left */
|
||||
Vec2 v1;
|
||||
Color c1;
|
||||
/* bottom-right */
|
||||
Vec2 v2;
|
||||
Color c2;
|
||||
/* upper-right */
|
||||
Vec2 v3;
|
||||
Color c3;
|
||||
} ElementIndexedQuadWithoutTexture;
|
||||
|
||||
|
||||
typedef struct ElementIndexedQuadWithoutColorWithoutTexture {
|
||||
/* upper-left */
|
||||
Vec2 v0;
|
||||
/* bottom-left */
|
||||
Vec2 v1;
|
||||
/* bottom-right */
|
||||
Vec2 v2;
|
||||
/* upper-right */
|
||||
Vec2 v3;
|
||||
} ElementIndexedQuadWithoutColorWithoutTexture;
|
||||
|
||||
|
||||
typedef enum {
|
||||
PIPELINE_NO,
|
||||
PIPELINE_SPACE,
|
||||
@ -136,33 +165,6 @@ void use_2d_pipeline(void) {
|
||||
}
|
||||
|
||||
|
||||
void upload_quad_vertices(Rect rect) {
|
||||
/* client memory needs to be reachable on glDraw*, so */
|
||||
static float vertices[6 * 2];
|
||||
|
||||
vertices[0] = rect.x; vertices[1] = rect.y;
|
||||
vertices[2] = rect.x; vertices[3] = rect.y + rect.h;
|
||||
vertices[4] = rect.x + rect.w; vertices[5] = rect.y + rect.h;
|
||||
vertices[6] = rect.x + rect.w; vertices[7] = rect.y + rect.h;
|
||||
vertices[8] = rect.x + rect.w; vertices[9] = rect.y;
|
||||
vertices[10] = rect.x; vertices[11] = rect.y;
|
||||
|
||||
glVertexPointer(2, GL_FLOAT, 0, (void *)&vertices);
|
||||
}
|
||||
|
||||
|
||||
void render_rectangle(const RectPrimitive *rectangle) {
|
||||
glColor4ub(rectangle->color.r, rectangle->color.g,
|
||||
rectangle->color.b, rectangle->color.a);
|
||||
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
upload_quad_vertices(rectangle->rect);
|
||||
|
||||
glDrawArrays(GL_TRIANGLES, 0, 6);
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
}
|
||||
|
||||
|
||||
void render_circle(const CirclePrimitive *circle) {
|
||||
SDL_Vertex *vertices = NULL;
|
||||
int *indices = NULL;
|
||||
@ -258,7 +260,7 @@ VertexBufferBuilder build_vertex_buffer(VertexBuffer buffer, size_t bytes) {
|
||||
|
||||
|
||||
bool push_to_vertex_buffer_builder(VertexBufferBuilder *builder,
|
||||
void *bytes, size_t size) {
|
||||
void const *bytes, size_t size) {
|
||||
if (builder->bytes_left == 0)
|
||||
return false;
|
||||
|
||||
@ -277,24 +279,30 @@ bool push_to_vertex_buffer_builder(VertexBufferBuilder *builder,
|
||||
}
|
||||
|
||||
|
||||
void finally_render_sprites(const Primitive2D primitives[],
|
||||
const struct SpriteBatch batch,
|
||||
const VertexBuffer buffer)
|
||||
void finally_render_quads(const Primitive2D primitives[],
|
||||
const struct QuadBatch batch,
|
||||
const VertexBuffer buffer)
|
||||
{
|
||||
(void)buffer;
|
||||
|
||||
GLsizei off;
|
||||
GLsizei voff;
|
||||
GLsizei uvoff;
|
||||
GLsizei off = 0, voff = 0, uvoff = 0, coff = 0;
|
||||
|
||||
if (!batch.constant_colored) {
|
||||
if (!batch.constant_colored && batch.textured) {
|
||||
off = offsetof(ElementIndexedQuad, v1);
|
||||
voff = offsetof(ElementIndexedQuad, v0);
|
||||
uvoff = offsetof(ElementIndexedQuad, uv0);
|
||||
} else {
|
||||
coff = offsetof(ElementIndexedQuad, c0);
|
||||
} else if (batch.constant_colored && batch.textured) {
|
||||
off = offsetof(ElementIndexedQuadWithoutColor, v1);
|
||||
voff = offsetof(ElementIndexedQuadWithoutColor, v0);
|
||||
uvoff = offsetof(ElementIndexedQuadWithoutColor, uv0);
|
||||
} else if (!batch.constant_colored && !batch.textured) {
|
||||
off = offsetof(ElementIndexedQuadWithoutTexture, v1);
|
||||
voff = offsetof(ElementIndexedQuadWithoutTexture, v0);
|
||||
coff = offsetof(ElementIndexedQuad, c0);
|
||||
} else if (batch.constant_colored && !batch.textured) {
|
||||
off = offsetof(ElementIndexedQuadWithoutColorWithoutTexture, v1);
|
||||
voff = offsetof(ElementIndexedQuadWithoutColorWithoutTexture, v0);
|
||||
}
|
||||
|
||||
/* vertex specification */
|
||||
@ -304,65 +312,82 @@ void finally_render_sprites(const Primitive2D primitives[],
|
||||
off,
|
||||
(void *)(size_t)voff);
|
||||
|
||||
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
glClientActiveTexture(GL_TEXTURE0);
|
||||
glTexCoordPointer(2,
|
||||
GL_FLOAT,
|
||||
off,
|
||||
(void *)(size_t)uvoff);
|
||||
if (batch.textured) {
|
||||
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
glClientActiveTexture(GL_TEXTURE0);
|
||||
glTexCoordPointer(2,
|
||||
GL_FLOAT,
|
||||
off,
|
||||
(void *)(size_t)uvoff);
|
||||
}
|
||||
|
||||
if (!batch.constant_colored) {
|
||||
glEnableClientState(GL_COLOR_ARRAY);
|
||||
glColorPointer(4,
|
||||
GL_UNSIGNED_BYTE,
|
||||
off,
|
||||
(void *)offsetof(ElementIndexedQuad, c0));
|
||||
(void *)(size_t)coff);
|
||||
} else
|
||||
glColor4ub(primitives[0].sprite.color.r,
|
||||
primitives[0].sprite.color.g,
|
||||
primitives[0].sprite.color.b,
|
||||
primitives[0].sprite.color.a);
|
||||
|
||||
if (!batch.repeat)
|
||||
textures_bind(&ctx.texture_cache, primitives->sprite.texture_key);
|
||||
else
|
||||
textures_bind_repeating(&ctx.texture_cache, primitives->sprite.texture_key);
|
||||
if (batch.textured) {
|
||||
if (!batch.repeat)
|
||||
textures_bind(&ctx.texture_cache, primitives->sprite.texture_key);
|
||||
else
|
||||
textures_bind_repeating(&ctx.texture_cache, primitives->sprite.texture_key);
|
||||
}
|
||||
|
||||
bind_quad_element_buffer();
|
||||
|
||||
glDrawElements(GL_TRIANGLES, 6 * (GLsizei)batch.size, GL_UNSIGNED_SHORT, NULL);
|
||||
|
||||
/* clear the state */
|
||||
glBufferData(GL_ARRAY_BUFFER, 0, NULL, GL_STREAM_DRAW);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
{
|
||||
glBufferData(GL_ARRAY_BUFFER, 0, NULL, GL_STREAM_DRAW);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
|
||||
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
if (batch.textured)
|
||||
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
|
||||
if (!batch.constant_colored)
|
||||
glDisableClientState(GL_COLOR_ARRAY);
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||
if (!batch.constant_colored)
|
||||
glDisableClientState(GL_COLOR_ARRAY);
|
||||
|
||||
if (batch.textured)
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
size_t get_sprite_payload_size(struct SpriteBatch batch) {
|
||||
if (batch.constant_colored)
|
||||
size_t get_quad_payload_size(struct QuadBatch batch) {
|
||||
if (batch.constant_colored && batch.textured)
|
||||
return sizeof (ElementIndexedQuadWithoutColor);
|
||||
else
|
||||
else if (!batch.constant_colored && batch.textured)
|
||||
return sizeof (ElementIndexedQuad);
|
||||
else if (batch.constant_colored && !batch.textured)
|
||||
return sizeof (ElementIndexedQuadWithoutTexture);
|
||||
else if (!batch.constant_colored && !batch.textured)
|
||||
return sizeof (ElementIndexedQuadWithoutColorWithoutTexture);
|
||||
|
||||
SDL_assert(false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
bool push_sprite_payload_to_vertex_buffer_builder(struct SpriteBatch batch,
|
||||
VertexBufferBuilder *builder,
|
||||
Vec2 v0, Vec2 v1, Vec2 v2, Vec2 v3,
|
||||
Vec2 uv0, Vec2 uv1, Vec2 uv2, Vec2 uv3,
|
||||
Color color)
|
||||
bool push_quad_payload_to_vertex_buffer_builder(struct QuadBatch batch,
|
||||
VertexBufferBuilder *builder,
|
||||
Vec2 v0, Vec2 v1, Vec2 v2, Vec2 v3,
|
||||
Vec2 uv0, Vec2 uv1, Vec2 uv2, Vec2 uv3,
|
||||
Color color)
|
||||
{
|
||||
if (!batch.constant_colored) {
|
||||
ElementIndexedQuad buffer_element = {
|
||||
if (!batch.constant_colored && batch.textured) {
|
||||
ElementIndexedQuad const buffer_element = {
|
||||
.v0 = v0,
|
||||
.v1 = v1,
|
||||
.v2 = v2,
|
||||
@ -382,8 +407,8 @@ bool push_sprite_payload_to_vertex_buffer_builder(struct SpriteBatch batch,
|
||||
|
||||
return push_to_vertex_buffer_builder(builder, &buffer_element, sizeof buffer_element);
|
||||
|
||||
} else {
|
||||
ElementIndexedQuadWithoutColor buffer_element = {
|
||||
} else if (batch.constant_colored && batch.textured) {
|
||||
ElementIndexedQuadWithoutColor const buffer_element = {
|
||||
.v0 = v0,
|
||||
.v1 = v1,
|
||||
.v2 = v2,
|
||||
@ -395,8 +420,37 @@ bool push_sprite_payload_to_vertex_buffer_builder(struct SpriteBatch batch,
|
||||
.uv3 = uv3,
|
||||
};
|
||||
|
||||
return push_to_vertex_buffer_builder(builder, &buffer_element, sizeof buffer_element);
|
||||
|
||||
} else if (!batch.constant_colored && !batch.textured) {
|
||||
ElementIndexedQuadWithoutTexture const buffer_element = {
|
||||
.v0 = v0,
|
||||
.v1 = v1,
|
||||
.v2 = v2,
|
||||
.v3 = v3,
|
||||
|
||||
/* equal for all (flat shaded) */
|
||||
.c0 = color,
|
||||
.c1 = color,
|
||||
.c2 = color,
|
||||
.c3 = color,
|
||||
};
|
||||
|
||||
return push_to_vertex_buffer_builder(builder, &buffer_element, sizeof buffer_element);
|
||||
|
||||
} else if (batch.constant_colored && !batch.textured) {
|
||||
ElementIndexedQuadWithoutColorWithoutTexture const buffer_element = {
|
||||
.v0 = v0,
|
||||
.v1 = v1,
|
||||
.v2 = v2,
|
||||
.v3 = v3,
|
||||
};
|
||||
|
||||
return push_to_vertex_buffer_builder(builder, &buffer_element, sizeof buffer_element);
|
||||
}
|
||||
|
||||
SDL_assert(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user