replace categorized, sorted render queues with a single ordered 2d queue

This commit is contained in:
wanp 2024-07-15 23:31:54 -03:00
parent 5ae59b51d3
commit bdf2a54107
5 changed files with 71 additions and 123 deletions

View File

@ -20,9 +20,7 @@ typedef struct context {
struct texture_cache texture_cache;
struct input_state input;
struct sprite_primitive *render_queue_sprites;
struct rect_primitive *render_queue_rectangles;
struct circle_primitive *render_queue_circles;
struct primitive_2d *render_queue_2d;
struct mesh_batch_item *uncolored_mesh_batches;
struct audio_channel_item *audio_channels;

View File

@ -287,9 +287,7 @@ static bool initialize(void) {
/* rendering */
/* these are dynamic arrays and will be allocated lazily by stb_ds */
ctx.render_queue_sprites = NULL;
ctx.render_queue_rectangles = NULL;
ctx.render_queue_circles = NULL;
ctx.render_queue_2d = NULL;
ctx.circle_radius_hash = NULL;
textures_cache_init(&ctx.texture_cache, ctx.window);
@ -324,8 +322,7 @@ static void clean_up(void) {
input_state_deinit(&ctx.input);
arrfree(ctx.render_queue_sprites);
arrfree(ctx.render_queue_rectangles);
arrfree(ctx.render_queue_2d);
textures_cache_deinit(&ctx.texture_cache);
PHYSFS_deinit();

View File

@ -16,7 +16,6 @@ struct sprite_primitive {
double rotation;
SDL_BlendMode blend_mode;
t_texture_key texture_key;
int layer;
bool flip_x;
bool flip_y;
};
@ -32,6 +31,22 @@ struct circle_primitive {
t_fvec2 position;
};
enum primitive_2d_type {
PRIMITIVE_2D_SPRITE,
PRIMITIVE_2D_RECT,
PRIMITIVE_2D_CIRCLE,
};
struct primitive_2d {
enum primitive_2d_type type;
union {
struct sprite_primitive sprite;
struct rect_primitive rect;
struct circle_primitive circle;
};
};
/* union for in-place recalculation of texture coordinates */
union uncolored_space_triangle {
/* pending for sending, uvs are not final as texture atlases could update */

View File

@ -16,9 +16,7 @@ void render_queue_clear(void) {
/* since i don't intend to free the queues, */
/* it's faster and simpler to just "start over" */
/* and start overwriting the existing data */
arrsetlen(ctx.render_queue_sprites, 0);
arrsetlen(ctx.render_queue_rectangles, 0);
arrsetlen(ctx.render_queue_circles, 0);
arrsetlen(ctx.render_queue_2d, 0);
for (size_t i = 0; i < hmlenu(ctx.uncolored_mesh_batches); ++i)
arrsetlen(ctx.uncolored_mesh_batches[i].value.primitives, 0);
@ -31,7 +29,6 @@ void render_queue_clear(void) {
* because they will be called multiple times in the main loop
* before anything is really rendered
*/
/* sprite */
void push_sprite(char *path, t_frect rect) {
struct sprite_primitive sprite = {
@ -40,12 +37,16 @@ void push_sprite(char *path, t_frect rect) {
.rotation = 0.0,
.blend_mode = SDL_BLENDMODE_BLEND,
.texture_key = textures_get_key(&ctx.texture_cache, path),
.layer = 0,
.flip_x = false,
.flip_y = false,
};
arrput(ctx.render_queue_sprites, sprite);
struct primitive_2d primitive = {
.type = PRIMITIVE_2D_SPRITE,
.sprite = sprite,
};
arrput(ctx.render_queue_2d, primitive);
}
@ -55,13 +56,17 @@ void push_sprite_ex(t_frect rect, t_push_sprite_args args) {
.color = args.color,
.rotation = args.rotation,
.blend_mode = args.blend_mode,
.texture_key = textures_get_key(&ctx.texture_cache, args.path),
.layer = args.layer,
.texture_key = textures_get_key(&ctx.texture_cache, args.path),
.flip_x = args.flip_x,
.flip_y = args.flip_y,
};
arrput(ctx.render_queue_sprites, sprite);
struct primitive_2d primitive = {
.type = PRIMITIVE_2D_SPRITE,
.sprite = sprite,
};
arrput(ctx.render_queue_2d, primitive);
}
@ -72,7 +77,12 @@ void push_rectangle(t_frect rect, t_color color) {
.color = color,
};
arrput(ctx.render_queue_rectangles, rectangle);
struct primitive_2d primitive = {
.type = PRIMITIVE_2D_RECT,
.rect = rectangle,
};
arrput(ctx.render_queue_2d, primitive);
}
@ -84,7 +94,12 @@ void push_circle(t_fvec2 position, float radius, t_color color) {
.position = position,
};
arrput(ctx.render_queue_circles, circle);
struct primitive_2d primitive = {
.type = PRIMITIVE_2D_CIRCLE,
.circle = circle,
};
arrput(ctx.render_queue_2d, primitive);
}
@ -123,76 +138,6 @@ void unfurl_triangle(const char *path,
}
/* compare functions for the sort in render_sprites */
static int cmp_atlases(const void *a, const void *b) {
int index_a = ((const struct sprite_primitive *)a)->texture_key.id;
int index_b = ((const struct sprite_primitive *)b)->texture_key.id;
return (index_a > index_b) - (index_a < index_b);
}
static int cmp_blend_modes(const void *a, const void *b) {
SDL_BlendMode mode_a = ((const struct sprite_primitive *)a)->blend_mode;
SDL_BlendMode mode_b = ((const struct sprite_primitive *)b)->blend_mode;
return (mode_a > mode_b) - (mode_a < mode_b);
}
static int cmp_colors(const void *a, const void *b) {
t_color color_a = ((const struct sprite_primitive *)a)->color;
t_color color_b = ((const struct sprite_primitive *)b)->color;
/* check reds */
if (color_a.r < color_b.r)
return -1;
else if (color_a.r > color_b.r)
return 1;
/* reds were equal, check greens */
else if (color_a.g < color_b.g)
return -1;
else if (color_a.g > color_b.g)
return 1;
/* greens were equal, check blues */
else if (color_a.b < color_b.b)
return -1;
else if (color_a.b > color_b.b)
return 1;
/* blues were equal, check alphas */
else if (color_a.a < color_b.a)
return -1;
else if (color_a.a > color_b.a)
return 1;
/* entirely equal */
else
return 0;
}
static int cmp_layers(const void *a, const void *b) {
int layer_a = ((const struct sprite_primitive *)a)->layer;
int layer_b = ((const struct sprite_primitive *)b)->layer;
return (layer_a > layer_b) - (layer_a < layer_b);
}
/* TODO: not that we're SDL free we need to implement batching ourselves */
/* necessary to allow the renderer to draw in batches in the best case */
static void sort_sprites(struct sprite_primitive *sprites) {
size_t sprites_len = arrlenu(sprites);
qsort(sprites, sprites_len, sizeof *sprites, cmp_atlases);
qsort(sprites, sprites_len, sizeof *sprites, cmp_blend_modes);
qsort(sprites, sprites_len, sizeof *sprites, cmp_colors);
qsort(sprites, sprites_len, sizeof *sprites, cmp_layers);
}
static void upload_quad_vertices(t_frect rect) {
/* client memory needs to be reachable on glDraw*, so */
static float vertices[6 * 2];
@ -366,25 +311,21 @@ static void render_circle(struct circle_primitive *circle) {
}
static void render_sprites(void) {
sort_sprites(ctx.render_queue_sprites);
static void render_2d(void) {
for (size_t i = 0; i < arrlenu(ctx.render_queue_2d); ++i) {
struct primitive_2d *current = &ctx.render_queue_2d[i];
for (size_t i = 0; i < arrlenu(ctx.render_queue_sprites); ++i) {
render_sprite(&ctx.render_queue_sprites[i]);
}
}
static void render_rectangles(void) {
for (size_t i = 0; i < arrlenu(ctx.render_queue_rectangles); ++i) {
render_rectangle(&ctx.render_queue_rectangles[i]);
}
}
static void render_circles(void) {
for (size_t i = 0; i < arrlenu(ctx.render_queue_circles); ++i) {
render_circle(&ctx.render_queue_circles[i]);
switch (current->type) {
case PRIMITIVE_2D_SPRITE:
render_sprite(&current->sprite);
break;
case PRIMITIVE_2D_RECT:
render_rectangle(&current->rect);
break;
case PRIMITIVE_2D_CIRCLE:
render_circle(&current->circle);
break;
}
}
}
@ -526,9 +467,7 @@ void render(void) {
glEnable(GL_TEXTURE_2D);
render_sprites();
render_rectangles();
render_circles();
render_2d();
}
{

View File

@ -9,7 +9,6 @@
typedef struct push_sprite_args {
char *path;
int layer;
t_color color;
double rotation;
SDL_BlendMode blend_mode;