Compare commits

..

No commits in common. "3535a185dff92dc37fb2d3279cbbfe17d58e2239" and "f7f27119e10f1e3b163f8d4b4714dbd68de1da26" have entirely different histories.

10 changed files with 116 additions and 309 deletions

View File

@ -104,7 +104,6 @@ set(TWN_NONOPT_SOURCE_FILES
src/rendering/twn_draw.c src/rendering/twn_draw_c.h src/rendering/twn_draw.c src/rendering/twn_draw_c.h
src/rendering/twn_sprites.c src/rendering/twn_sprites.c
src/rendering/twn_rects.c
src/rendering/twn_text.c src/rendering/twn_text.c
src/rendering/twn_triangles.c src/rendering/twn_triangles.c
src/rendering/twn_circles.c src/rendering/twn_circles.c

View File

@ -1,9 +1,6 @@
#ifndef TWN_TEXTURES_MODES_H #ifndef TWN_TEXTURES_MODES_H
#define 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 */ /* alpha channel information */
typedef enum TextureMode { typedef enum TextureMode {
TEXTURE_MODE_OPAQUE, /* all pixels are solid */ TEXTURE_MODE_OPAQUE, /* all pixels are solid */

View File

@ -35,6 +35,22 @@ 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) { 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 bt = (float)border_thickness; /* i know! */
const float bt2 = bt * 2; /* combined size of the two borders in an axis */ const float bt2 = bt * 2; /* combined size of the two borders in an axis */
@ -188,25 +204,19 @@ static void render_2d(void) {
switch (current->type) { switch (current->type) {
case PRIMITIVE_2D_SPRITE: { case PRIMITIVE_2D_SPRITE: {
const struct QuadBatch batch = const struct SpriteBatch batch =
collect_sprite_batch(current, render_queue_len - i); collect_sprite_batch(current, render_queue_len - i);
/* TODO: what's even the point? just use OR_EQUAL comparison */ /* TODO: what's even the point? just use OR_EQUAL comparison */
set_depth_range((double)batch_count / UINT16_MAX, 1.0); set_depth_range((double)batch_count / UINT16_MAX, 1.0);
render_sprite_batch(current, batch); render_sprites(current, batch);
i += batch.size - 1; ++batch_count; i += batch.size - 1; ++batch_count;
break; break;
} }
case PRIMITIVE_2D_RECT: { case PRIMITIVE_2D_RECT:
const struct QuadBatch batch = render_rectangle(&current->rect);
collect_rect_batch(current, render_queue_len - i);
render_rect_batch(current, batch);
i += batch.size - 1; ++batch_count;
break; break;
}
case PRIMITIVE_2D_CIRCLE: case PRIMITIVE_2D_CIRCLE:
render_circle(&current->circle); render_circle(&current->circle);
break; break;

View File

@ -135,18 +135,15 @@ void create_circle_geometry(Vec2 position,
SDL_Vertex vertices[], SDL_Vertex vertices[],
int indices[]); int indices[]);
struct QuadBatch { struct SpriteBatch {
size_t size; /* how many primitives are in current batch */ size_t size; /* how many primitives are in current batch */
TextureMode mode; /* how color should be applied */ TextureMode mode;
bool constant_colored; /* whether colored batch is uniformly colored */ bool constant_colored; /* whether colored batch is uniformly colored */
bool repeat; /* whether repeat is needed */ bool repeat; /* whether repeat is needed */
bool textured; } collect_sprite_batch(const Primitive2D primitives[], size_t len);
} collect_quad_batch(const Primitive2D primitives[], size_t len);
void render_quad_batch(const Primitive2D primitives[], struct QuadBatch batch); void render_sprites(const Primitive2D primitives[],
struct QuadBatch collect_sprite_batch(const Primitive2D primitives[], size_t len); const struct SpriteBatch batch);
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, void draw_uncolored_space_traingle_batch(MeshBatch *batch,
TextureKey texture_key); TextureKey texture_key);
@ -167,14 +164,14 @@ VertexBuffer create_vertex_buffer(void);
void delete_vertex_buffer(VertexBuffer buffer); void delete_vertex_buffer(VertexBuffer buffer);
void specify_vertex_buffer(VertexBuffer buffer, void const *data, size_t bytes); void specify_vertex_buffer(VertexBuffer buffer, void *data, size_t bytes);
/* uses present in 1.5 buffer mapping feature */ /* uses present in 1.5 buffer mapping feature */
VertexBufferBuilder build_vertex_buffer(VertexBuffer buffer, size_t bytes); 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 */ /* 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, bool push_to_vertex_buffer_builder(VertexBufferBuilder *builder,
void const *bytes, void *bytes,
size_t size); size_t size);
/* state */ /* state */
@ -199,13 +196,15 @@ void use_2d_pipeline(void);
void use_texture_mode(TextureMode mode); void use_texture_mode(TextureMode mode);
void finally_render_quads(Primitive2D const primitives[], void upload_quad_vertices(Rect rect);
struct QuadBatch batch,
void finally_render_sprites(Primitive2D const primitives[],
struct SpriteBatch batch,
VertexBuffer buffer); VertexBuffer buffer);
size_t get_quad_payload_size(struct QuadBatch batch); size_t get_sprite_payload_size(struct SpriteBatch batch);
bool push_quad_payload_to_vertex_buffer_builder(struct QuadBatch batch, bool push_sprite_payload_to_vertex_buffer_builder(struct SpriteBatch batch,
VertexBufferBuilder *builder, VertexBufferBuilder *builder,
Vec2 v0, Vec2 v1, Vec2 v2, Vec2 v3, Vec2 v0, Vec2 v1, Vec2 v2, Vec2 v3,
Vec2 uv0, Vec2 uv1, Vec2 uv2, Vec2 uv3, Vec2 uv0, Vec2 uv1, Vec2 uv2, Vec2 uv3,

View File

@ -3,7 +3,6 @@
#include "twn_util_c.h" #include "twn_util_c.h"
#include "twn_engine_context_c.h" #include "twn_engine_context_c.h"
#include "twn_text_c.h" #include "twn_text_c.h"
#include "twn_types.h"
#include <glad/glad.h> #include <glad/glad.h>
#include <stb_ds.h> #include <stb_ds.h>
@ -49,34 +48,6 @@ typedef struct ElementIndexedQuadWithoutColor {
} 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 { typedef enum {
PIPELINE_NO, PIPELINE_NO,
PIPELINE_SPACE, PIPELINE_SPACE,
@ -168,6 +139,33 @@ 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) { void render_circle(const CirclePrimitive *circle) {
static SDL_Vertex vertices[CIRCLE_VERTICES_MAX]; static SDL_Vertex vertices[CIRCLE_VERTICES_MAX];
static int indices[CIRCLE_VERTICES_MAX * 3]; static int indices[CIRCLE_VERTICES_MAX * 3];
@ -260,7 +258,7 @@ VertexBufferBuilder build_vertex_buffer(VertexBuffer buffer, size_t bytes) {
bool push_to_vertex_buffer_builder(VertexBufferBuilder *builder, bool push_to_vertex_buffer_builder(VertexBufferBuilder *builder,
void const *bytes, size_t size) { void *bytes, size_t size) {
if (builder->bytes_left == 0) if (builder->bytes_left == 0)
return false; return false;
@ -279,30 +277,24 @@ bool push_to_vertex_buffer_builder(VertexBufferBuilder *builder,
} }
void finally_render_quads(const Primitive2D primitives[], void finally_render_sprites(const Primitive2D primitives[],
const struct QuadBatch batch, const struct SpriteBatch batch,
const VertexBuffer buffer) const VertexBuffer buffer)
{ {
(void)buffer; (void)buffer;
GLsizei off = 0, voff = 0, uvoff = 0, coff = 0; GLsizei off;
GLsizei voff;
GLsizei uvoff;
if (!batch.constant_colored && batch.textured) { if (!batch.constant_colored) {
off = offsetof(ElementIndexedQuad, v1); off = offsetof(ElementIndexedQuad, v1);
voff = offsetof(ElementIndexedQuad, v0); voff = offsetof(ElementIndexedQuad, v0);
uvoff = offsetof(ElementIndexedQuad, uv0); uvoff = offsetof(ElementIndexedQuad, uv0);
coff = offsetof(ElementIndexedQuad, c0); } else {
} else if (batch.constant_colored && batch.textured) {
off = offsetof(ElementIndexedQuadWithoutColor, v1); off = offsetof(ElementIndexedQuadWithoutColor, v1);
voff = offsetof(ElementIndexedQuadWithoutColor, v0); voff = offsetof(ElementIndexedQuadWithoutColor, v0);
uvoff = offsetof(ElementIndexedQuadWithoutColor, uv0); 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 */ /* vertex specification */
@ -312,82 +304,65 @@ void finally_render_quads(const Primitive2D primitives[],
off, off,
(void *)(size_t)voff); (void *)(size_t)voff);
if (batch.textured) {
glEnableClientState(GL_TEXTURE_COORD_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glClientActiveTexture(GL_TEXTURE0); glClientActiveTexture(GL_TEXTURE0);
glTexCoordPointer(2, glTexCoordPointer(2,
GL_FLOAT, GL_FLOAT,
off, off,
(void *)(size_t)uvoff); (void *)(size_t)uvoff);
}
if (!batch.constant_colored) { if (!batch.constant_colored) {
glEnableClientState(GL_COLOR_ARRAY); glEnableClientState(GL_COLOR_ARRAY);
glColorPointer(4, glColorPointer(4,
GL_UNSIGNED_BYTE, GL_UNSIGNED_BYTE,
off, off,
(void *)(size_t)coff); (void *)offsetof(ElementIndexedQuad, c0));
} else } else
glColor4ub(primitives[0].sprite.color.r, glColor4ub(primitives[0].sprite.color.r,
primitives[0].sprite.color.g, primitives[0].sprite.color.g,
primitives[0].sprite.color.b, primitives[0].sprite.color.b,
primitives[0].sprite.color.a); primitives[0].sprite.color.a);
if (batch.textured) {
if (!batch.repeat) if (!batch.repeat)
textures_bind(&ctx.texture_cache, primitives->sprite.texture_key); textures_bind(&ctx.texture_cache, primitives->sprite.texture_key);
else else
textures_bind_repeating(&ctx.texture_cache, primitives->sprite.texture_key); textures_bind_repeating(&ctx.texture_cache, primitives->sprite.texture_key);
}
bind_quad_element_buffer(); bind_quad_element_buffer();
glDrawElements(GL_TRIANGLES, 6 * (GLsizei)batch.size, GL_UNSIGNED_SHORT, NULL); glDrawElements(GL_TRIANGLES, 6 * (GLsizei)batch.size, GL_UNSIGNED_SHORT, NULL);
/* clear the state */ /* clear the state */
{
glBufferData(GL_ARRAY_BUFFER, 0, NULL, GL_STREAM_DRAW); glBufferData(GL_ARRAY_BUFFER, 0, NULL, GL_STREAM_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ARRAY_BUFFER, 0);
if (batch.textured)
glDisableClientState(GL_TEXTURE_COORD_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_VERTEX_ARRAY);
if (!batch.constant_colored) if (!batch.constant_colored)
glDisableClientState(GL_COLOR_ARRAY); glDisableClientState(GL_COLOR_ARRAY);
if (batch.textured)
glBindTexture(GL_TEXTURE_2D, 0); glBindTexture(GL_TEXTURE_2D, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
} }
}
size_t get_quad_payload_size(struct QuadBatch batch) { size_t get_sprite_payload_size(struct SpriteBatch batch) {
if (batch.constant_colored && batch.textured) if (batch.constant_colored)
return sizeof (ElementIndexedQuadWithoutColor); return sizeof (ElementIndexedQuadWithoutColor);
else if (!batch.constant_colored && batch.textured) else
return sizeof (ElementIndexedQuad); 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_quad_payload_to_vertex_buffer_builder(struct QuadBatch batch, bool push_sprite_payload_to_vertex_buffer_builder(struct SpriteBatch batch,
VertexBufferBuilder *builder, VertexBufferBuilder *builder,
Vec2 v0, Vec2 v1, Vec2 v2, Vec2 v3, Vec2 v0, Vec2 v1, Vec2 v2, Vec2 v3,
Vec2 uv0, Vec2 uv1, Vec2 uv2, Vec2 uv3, Vec2 uv0, Vec2 uv1, Vec2 uv2, Vec2 uv3,
Color color) Color color)
{ {
if (!batch.constant_colored && batch.textured) { if (!batch.constant_colored) {
ElementIndexedQuad const buffer_element = { ElementIndexedQuad buffer_element = {
.v0 = v0, .v0 = v0,
.v1 = v1, .v1 = v1,
.v2 = v2, .v2 = v2,
@ -407,8 +382,8 @@ bool push_quad_payload_to_vertex_buffer_builder(struct QuadBatch batch,
return push_to_vertex_buffer_builder(builder, &buffer_element, sizeof buffer_element); return push_to_vertex_buffer_builder(builder, &buffer_element, sizeof buffer_element);
} else if (batch.constant_colored && batch.textured) { } else {
ElementIndexedQuadWithoutColor const buffer_element = { ElementIndexedQuadWithoutColor buffer_element = {
.v0 = v0, .v0 = v0,
.v1 = v1, .v1 = v1,
.v2 = v2, .v2 = v2,
@ -420,37 +395,8 @@ bool push_quad_payload_to_vertex_buffer_builder(struct QuadBatch batch,
.uv3 = uv3, .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); return push_to_vertex_buffer_builder(builder, &buffer_element, sizeof buffer_element);
} }
SDL_assert(false);
return false;
} }

View File

@ -26,7 +26,7 @@ void delete_vertex_buffer(VertexBuffer buffer) {
} }
void specify_vertex_buffer(VertexBuffer buffer, void const *data, size_t bytes) { void specify_vertex_buffer(VertexBuffer buffer, void *data, size_t bytes) {
glBindBuffer(GL_ARRAY_BUFFER, buffer); glBindBuffer(GL_ARRAY_BUFFER, buffer);
glBufferData(GL_ARRAY_BUFFER, bytes, data, GL_STREAM_DRAW); glBufferData(GL_ARRAY_BUFFER, bytes, data, GL_STREAM_DRAW);
} }
@ -74,9 +74,6 @@ void clear_draw_buffer(void) {
/* TODO: don't clear color when skybox is applied? */ /* TODO: don't clear color when skybox is applied? */
/* for that window should match framebuffer */ /* for that window should match framebuffer */
/* also it is driver dependent, from what i can gather */ /* also it is driver dependent, from what i can gather */
/* INFO: also, based on below, driver might prefer it staying this way */
/* https://gamedev.stackexchange.com/questions/90344/render-with-const-depth-value */
/* we could optionally load ARB_invalidate_subdata extension if it's available instead */
glClear(GL_COLOR_BUFFER_BIT | glClear(GL_COLOR_BUFFER_BIT |
GL_DEPTH_BUFFER_BIT | GL_DEPTH_BUFFER_BIT |
GL_STENCIL_BUFFER_BIT); GL_STENCIL_BUFFER_BIT);

View File

@ -1,30 +0,0 @@
#include "twn_draw_c.h"
#include <stddef.h>
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};
}

View File

@ -1,104 +0,0 @@
#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 *)&current->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);
}

View File

@ -60,18 +60,15 @@ void draw_sprite_args(const DrawSpriteArgs args) {
} }
struct QuadBatch collect_sprite_batch(const Primitive2D primitives[], size_t len) { struct SpriteBatch collect_sprite_batch(const Primitive2D primitives[], size_t len) {
SDL_assert(primitives[0].type == PRIMITIVE_2D_SPRITE); /* assumes that first primitive is already a sprite */
SDL_assert(primitives && len != 0);
const uint16_t texture_key_id = primitives[0].sprite.texture_key.id; 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); const int atlas_id = textures_get_atlas_id(&ctx.texture_cache, primitives[0].sprite.texture_key);
struct QuadBatch batch = { struct SpriteBatch batch = {
.mode = textures_get_mode(&ctx.texture_cache, primitives[0].sprite.texture_key), .mode = textures_get_mode(&ctx.texture_cache, primitives[0].sprite.texture_key),
.constant_colored = true, .constant_colored = true,
.repeat = primitives[0].sprite.repeat, .repeat = primitives[0].sprite.repeat,
.textured = true,
}; };
const uint32_t uniform_color = *(const uint32_t *)&primitives[0].sprite.color; const uint32_t uniform_color = *(const uint32_t *)&primitives[0].sprite.color;
@ -119,12 +116,9 @@ struct QuadBatch collect_sprite_batch(const Primitive2D primitives[], size_t len
/* assumes that orthogonal matrix setup is done already */ /* assumes that orthogonal matrix setup is done already */
void render_sprite_batch(const Primitive2D primitives[], void render_sprites(const Primitive2D primitives[],
const struct QuadBatch batch) const struct SpriteBatch 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 */ /* single vertex array is used for every batch with NULL glBufferData() trick at the end */
static VertexBuffer vertex_array = 0; static VertexBuffer vertex_array = 0;
if (vertex_array == 0) if (vertex_array == 0)
@ -137,10 +131,10 @@ void render_sprite_batch(const Primitive2D primitives[],
/* vertex population over a vertex buffer builder interface */ /* vertex population over a vertex buffer builder interface */
{ {
VertexBufferBuilder payload = build_vertex_buffer(vertex_array, get_quad_payload_size(batch) * batch.size); VertexBufferBuilder payload = build_vertex_buffer(vertex_array, get_sprite_payload_size(batch) * batch.size);
for (size_t i = 0; i < batch.size; ++i) { for (size_t i = 0; i < batch.size; ++i) {
/* render opaques front to back, to gain benefit of an early z rejection */ /* render opaques front to back */
const size_t cur = batch.mode == TEXTURE_MODE_GHOSTLY ? i : batch.size - i - 1; const size_t cur = batch.mode == TEXTURE_MODE_GHOSTLY ? i : batch.size - i - 1;
const SpritePrimitive sprite = primitives[cur].sprite; const SpritePrimitive sprite = primitives[cur].sprite;
@ -239,9 +233,9 @@ void render_sprite_batch(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 }; v3 = (Vec2){ c.x + t.x * +h.x - t.y * -h.y, c.y + t.y * +h.x + t.x * -h.y };
} }
push_quad_payload_to_vertex_buffer_builder(batch, &payload, v0, v1, v2, v3, uv0, uv1, uv2, uv3, sprite.color); push_sprite_payload_to_vertex_buffer_builder(batch, &payload, v0, v1, v2, v3, uv0, uv1, uv2, uv3, sprite.color);
} }
} }
finally_render_quads(primitives, batch, vertex_array); finally_render_sprites(primitives, batch, vertex_array);
} }

View File

@ -15,6 +15,5 @@
#include "rendering/twn_fog.c" #include "rendering/twn_fog.c"
#include "rendering/twn_skybox.c" #include "rendering/twn_skybox.c"
#include "rendering/twn_sprites.c" #include "rendering/twn_sprites.c"
#include "rendering/twn_rects.c"
#include "rendering/twn_text.c" #include "rendering/twn_text.c"
#include "rendering/twn_triangles.c" #include "rendering/twn_triangles.c"