replace categorized, sorted render queues with a single ordered 2d queue
This commit is contained in:
parent
5ae59b51d3
commit
bdf2a54107
@ -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;
|
||||
|
@ -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();
|
||||
|
@ -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 */
|
||||
|
139
src/rendering.c
139
src/rendering.c
@ -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);
|
||||
}
|
||||
|
||||
|
||||
@ -56,12 +57,16 @@ void push_sprite_ex(t_frect rect, t_push_sprite_args args) {
|
||||
.rotation = args.rotation,
|
||||
.blend_mode = args.blend_mode,
|
||||
.texture_key = textures_get_key(&ctx.texture_cache, args.path),
|
||||
.layer = args.layer,
|
||||
.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]);
|
||||
switch (current->type) {
|
||||
case PRIMITIVE_2D_SPRITE:
|
||||
render_sprite(¤t->sprite);
|
||||
break;
|
||||
case PRIMITIVE_2D_RECT:
|
||||
render_rectangle(¤t->rect);
|
||||
break;
|
||||
case PRIMITIVE_2D_CIRCLE:
|
||||
render_circle(¤t->circle);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -526,9 +467,7 @@ void render(void) {
|
||||
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
|
||||
render_sprites();
|
||||
render_rectangles();
|
||||
render_circles();
|
||||
render_2d();
|
||||
}
|
||||
|
||||
{
|
||||
|
@ -9,7 +9,6 @@
|
||||
|
||||
typedef struct push_sprite_args {
|
||||
char *path;
|
||||
int layer;
|
||||
t_color color;
|
||||
double rotation;
|
||||
SDL_BlendMode blend_mode;
|
||||
|
Loading…
Reference in New Issue
Block a user