diff --git a/CMakeLists.txt b/CMakeLists.txt index e10c38b..9ec54d6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -104,6 +104,7 @@ set(TWN_NONOPT_SOURCE_FILES src/rendering/twn_draw.c src/rendering/twn_draw_c.h src/rendering/twn_sprites.c + src/rendering/twn_rects.c src/rendering/twn_text.c src/rendering/twn_triangles.c src/rendering/twn_circles.c diff --git a/include/twn_texture_modes.h b/include/twn_texture_modes.h index 30bcb17..5b2936b 100644 --- a/include/twn_texture_modes.h +++ b/include/twn_texture_modes.h @@ -1,6 +1,9 @@ #ifndef TWN_TEXTURES_MODES_H #define TWN_TEXTURES_MODES_H +/* TODO: rename, as it doesn't have to be about textures only, but blending */ +/* TODO: move from public /include/ tree */ + /* alpha channel information */ typedef enum TextureMode { TEXTURE_MODE_OPAQUE, /* all pixels are solid */ diff --git a/src/rendering/twn_draw.c b/src/rendering/twn_draw.c index 1dec485..57c9fff 100644 --- a/src/rendering/twn_draw.c +++ b/src/rendering/twn_draw.c @@ -35,22 +35,6 @@ void render_queue_clear(void) { } -/* rectangle */ -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); -} - - void draw_9slice(const char *texture_path, int texture_w, int texture_h, int border_thickness, Rect rect, Color color) { const float bt = (float)border_thickness; /* i know! */ const float bt2 = bt * 2; /* combined size of the two borders in an axis */ @@ -204,19 +188,27 @@ static void render_2d(void) { switch (current->type) { case PRIMITIVE_2D_SPRITE: { - const struct SpriteBatch batch = + const struct QuadBatch batch = collect_sprite_batch(current, render_queue_len - i); /* TODO: what's even the point? just use OR_EQUAL comparison */ set_depth_range((double)batch_count / UINT16_MAX, 1.0); - render_sprites(current, batch); + render_sprite_batch(current, batch); i += batch.size - 1; ++batch_count; break; } - case PRIMITIVE_2D_RECT: - render_rectangle(¤t->rect); + case PRIMITIVE_2D_RECT: { + const struct QuadBatch batch = + collect_rect_batch(current, render_queue_len - i); + + /* TODO: what's even the point? just use OR_EQUAL comparison */ + set_depth_range((double)batch_count / UINT16_MAX, 1.0); + render_rect_batch(current, batch); + + i += batch.size - 1; ++batch_count; break; + } case PRIMITIVE_2D_CIRCLE: render_circle(¤t->circle); break; diff --git a/src/rendering/twn_draw_c.h b/src/rendering/twn_draw_c.h index 51a20da..f2a6566 100644 --- a/src/rendering/twn_draw_c.h +++ b/src/rendering/twn_draw_c.h @@ -133,15 +133,18 @@ void create_circle_geometry(Vec2 position, SDL_Vertex **vertices_out, int **indices_out); -struct SpriteBatch { +struct QuadBatch { size_t size; /* how many primitives are in current batch */ - TextureMode mode; + TextureMode mode; /* how color should be applied */ bool constant_colored; /* whether colored batch is uniformly colored */ bool repeat; /* whether repeat is needed */ -} collect_sprite_batch(const Primitive2D primitives[], size_t len); - -void render_sprites(const Primitive2D primitives[], - const struct SpriteBatch batch); + bool textured; +} collect_quad_batch(const Primitive2D primitives[], size_t len); +void render_quad_batch(const Primitive2D primitives[], struct QuadBatch batch); +struct QuadBatch collect_sprite_batch(const Primitive2D primitives[], size_t len); +struct QuadBatch collect_rect_batch(const Primitive2D primitives[], size_t len); +void render_sprite_batch(const Primitive2D primitives[], struct QuadBatch batch); +void render_rect_batch(const Primitive2D primitives[], struct QuadBatch batch); void draw_uncolored_space_traingle_batch(MeshBatch *batch, TextureKey texture_key); @@ -162,14 +165,14 @@ VertexBuffer create_vertex_buffer(void); void delete_vertex_buffer(VertexBuffer buffer); -void specify_vertex_buffer(VertexBuffer buffer, void *data, size_t bytes); +void specify_vertex_buffer(VertexBuffer buffer, void const *data, size_t bytes); /* uses present in 1.5 buffer mapping feature */ VertexBufferBuilder build_vertex_buffer(VertexBuffer buffer, size_t bytes); /* collects bytes for sending to the gpu until all is pushed, which is when false is returned */ bool push_to_vertex_buffer_builder(VertexBufferBuilder *builder, - void *bytes, + void const *bytes, size_t size); /* state */ @@ -194,19 +197,17 @@ void use_2d_pipeline(void); void use_texture_mode(TextureMode mode); -void upload_quad_vertices(Rect rect); +void finally_render_quads(Primitive2D const primitives[], + struct QuadBatch batch, + VertexBuffer buffer); -void finally_render_sprites(Primitive2D const primitives[], - struct SpriteBatch batch, - VertexBuffer buffer); +size_t get_quad_payload_size(struct QuadBatch batch); -size_t get_sprite_payload_size(struct SpriteBatch batch); - -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); void finally_draw_uncolored_space_traingle_batch(MeshBatch const *batch, TextureKey texture_key, diff --git a/src/rendering/twn_gl_15_rendering.c b/src/rendering/twn_gl_15_rendering.c index 82ebc2d..9ca147e 100644 --- a/src/rendering/twn_gl_15_rendering.c +++ b/src/rendering/twn_gl_15_rendering.c @@ -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 #include @@ -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; } diff --git a/src/rendering/twn_gl_any_rendering.c b/src/rendering/twn_gl_any_rendering.c index a710583..8790ef3 100644 --- a/src/rendering/twn_gl_any_rendering.c +++ b/src/rendering/twn_gl_any_rendering.c @@ -26,7 +26,7 @@ void delete_vertex_buffer(VertexBuffer buffer) { } -void specify_vertex_buffer(VertexBuffer buffer, void *data, size_t bytes) { +void specify_vertex_buffer(VertexBuffer buffer, void const *data, size_t bytes) { glBindBuffer(GL_ARRAY_BUFFER, buffer); glBufferData(GL_ARRAY_BUFFER, bytes, data, GL_STREAM_DRAW); } diff --git a/src/rendering/twn_quads.c b/src/rendering/twn_quads.c new file mode 100644 index 0000000..732eee0 --- /dev/null +++ b/src/rendering/twn_quads.c @@ -0,0 +1,30 @@ +#include "twn_draw_c.h" + +#include + + +struct QuadBatch collect_quad_batch(const Primitive2D primitives[], size_t len) { + if (primitives[0].type == PRIMITIVE_2D_SPRITE) + return collect_sprite_batch(primitives, len); + else if (primitives[0].type == PRIMITIVE_2D_RECT) + return collect_rect_batch(primitives, len); + else + SDL_assert(false); + + return (struct QuadBatch){0}; +} + + +/* assumes that orthogonal matrix setup is done already */ +void render_quad_batch(const Primitive2D primitives[], + const struct QuadBatch batch) +{ + if (primitives[0].type == PRIMITIVE_2D_SPRITE) + render_sprite_batch(primitives, batch); + else if (primitives[0].type == PRIMITIVE_2D_RECT) + render_rect_batch(primitives, batch); + else + SDL_assert(false); + + return (struct QuadBatch){0}; +} diff --git a/src/rendering/twn_rects.c b/src/rendering/twn_rects.c new file mode 100644 index 0000000..feacee8 --- /dev/null +++ b/src/rendering/twn_rects.c @@ -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 + +#include +#include + + +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); +} diff --git a/src/rendering/twn_sprites.c b/src/rendering/twn_sprites.c index a29a5fc..20cc7fd 100644 --- a/src/rendering/twn_sprites.c +++ b/src/rendering/twn_sprites.c @@ -60,15 +60,18 @@ void draw_sprite_args(const DrawSpriteArgs args) { } -struct SpriteBatch collect_sprite_batch(const Primitive2D primitives[], size_t len) { - /* assumes that first primitive is already a sprite */ +struct QuadBatch collect_sprite_batch(const Primitive2D primitives[], size_t len) { + SDL_assert(primitives[0].type == PRIMITIVE_2D_SPRITE); + SDL_assert(primitives && len != 0); + const uint16_t texture_key_id = primitives[0].sprite.texture_key.id; const int atlas_id = textures_get_atlas_id(&ctx.texture_cache, primitives[0].sprite.texture_key); - struct SpriteBatch batch = { + struct QuadBatch batch = { .mode = textures_get_mode(&ctx.texture_cache, primitives[0].sprite.texture_key), .constant_colored = true, .repeat = primitives[0].sprite.repeat, + .textured = true, }; const uint32_t uniform_color = *(const uint32_t *)&primitives[0].sprite.color; @@ -116,9 +119,12 @@ struct SpriteBatch collect_sprite_batch(const Primitive2D primitives[], size_t l /* assumes that orthogonal matrix setup is done already */ -void render_sprites(const Primitive2D primitives[], - const struct SpriteBatch batch) +void render_sprite_batch(const Primitive2D primitives[], + const struct QuadBatch batch) { + SDL_assert(primitives && batch.size != 0); + SDL_assert(primitives[0].type == PRIMITIVE_2D_SPRITE); + /* single vertex array is used for every batch with NULL glBufferData() trick at the end */ static VertexBuffer vertex_array = 0; if (vertex_array == 0) @@ -131,10 +137,10 @@ void render_sprites(const Primitive2D primitives[], /* vertex population over a vertex buffer builder interface */ { - VertexBufferBuilder payload = build_vertex_buffer(vertex_array, get_sprite_payload_size(batch) * batch.size); + 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 */ + /* 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 SpritePrimitive sprite = primitives[cur].sprite; @@ -233,9 +239,9 @@ void render_sprites(const Primitive2D primitives[], v3 = (Vec2){ c.x + t.x * +h.x - t.y * -h.y, c.y + t.y * +h.x + t.x * -h.y }; } - push_sprite_payload_to_vertex_buffer_builder(batch, &payload, v0, v1, v2, v3, uv0, uv1, uv2, uv3, sprite.color); + push_quad_payload_to_vertex_buffer_builder(batch, &payload, v0, v1, v2, v3, uv0, uv1, uv2, uv3, sprite.color); } } - finally_render_sprites(primitives, batch, vertex_array); + finally_render_quads(primitives, batch, vertex_array); } diff --git a/src/twn_amalgam.c b/src/twn_amalgam.c index b240d93..cb4741e 100644 --- a/src/twn_amalgam.c +++ b/src/twn_amalgam.c @@ -15,5 +15,6 @@ #include "rendering/twn_fog.c" #include "rendering/twn_skybox.c" #include "rendering/twn_sprites.c" +#include "rendering/twn_rects.c" #include "rendering/twn_text.c" #include "rendering/twn_triangles.c"