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 texture_cache texture_cache;
|
||||||
struct input_state input;
|
struct input_state input;
|
||||||
|
|
||||||
struct sprite_primitive *render_queue_sprites;
|
struct primitive_2d *render_queue_2d;
|
||||||
struct rect_primitive *render_queue_rectangles;
|
|
||||||
struct circle_primitive *render_queue_circles;
|
|
||||||
struct mesh_batch_item *uncolored_mesh_batches;
|
struct mesh_batch_item *uncolored_mesh_batches;
|
||||||
|
|
||||||
struct audio_channel_item *audio_channels;
|
struct audio_channel_item *audio_channels;
|
||||||
|
@ -287,9 +287,7 @@ static bool initialize(void) {
|
|||||||
|
|
||||||
/* rendering */
|
/* rendering */
|
||||||
/* these are dynamic arrays and will be allocated lazily by stb_ds */
|
/* these are dynamic arrays and will be allocated lazily by stb_ds */
|
||||||
ctx.render_queue_sprites = NULL;
|
ctx.render_queue_2d = NULL;
|
||||||
ctx.render_queue_rectangles = NULL;
|
|
||||||
ctx.render_queue_circles = NULL;
|
|
||||||
ctx.circle_radius_hash = NULL;
|
ctx.circle_radius_hash = NULL;
|
||||||
|
|
||||||
textures_cache_init(&ctx.texture_cache, ctx.window);
|
textures_cache_init(&ctx.texture_cache, ctx.window);
|
||||||
@ -324,8 +322,7 @@ static void clean_up(void) {
|
|||||||
|
|
||||||
input_state_deinit(&ctx.input);
|
input_state_deinit(&ctx.input);
|
||||||
|
|
||||||
arrfree(ctx.render_queue_sprites);
|
arrfree(ctx.render_queue_2d);
|
||||||
arrfree(ctx.render_queue_rectangles);
|
|
||||||
textures_cache_deinit(&ctx.texture_cache);
|
textures_cache_deinit(&ctx.texture_cache);
|
||||||
|
|
||||||
PHYSFS_deinit();
|
PHYSFS_deinit();
|
||||||
|
@ -16,7 +16,6 @@ struct sprite_primitive {
|
|||||||
double rotation;
|
double rotation;
|
||||||
SDL_BlendMode blend_mode;
|
SDL_BlendMode blend_mode;
|
||||||
t_texture_key texture_key;
|
t_texture_key texture_key;
|
||||||
int layer;
|
|
||||||
bool flip_x;
|
bool flip_x;
|
||||||
bool flip_y;
|
bool flip_y;
|
||||||
};
|
};
|
||||||
@ -32,6 +31,22 @@ struct circle_primitive {
|
|||||||
t_fvec2 position;
|
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 for in-place recalculation of texture coordinates */
|
||||||
union uncolored_space_triangle {
|
union uncolored_space_triangle {
|
||||||
/* pending for sending, uvs are not final as texture atlases could update */
|
/* pending for sending, uvs are not final as texture atlases could update */
|
||||||
|
143
src/rendering.c
143
src/rendering.c
@ -16,9 +16,7 @@ void render_queue_clear(void) {
|
|||||||
/* since i don't intend to free the queues, */
|
/* since i don't intend to free the queues, */
|
||||||
/* it's faster and simpler to just "start over" */
|
/* it's faster and simpler to just "start over" */
|
||||||
/* and start overwriting the existing data */
|
/* and start overwriting the existing data */
|
||||||
arrsetlen(ctx.render_queue_sprites, 0);
|
arrsetlen(ctx.render_queue_2d, 0);
|
||||||
arrsetlen(ctx.render_queue_rectangles, 0);
|
|
||||||
arrsetlen(ctx.render_queue_circles, 0);
|
|
||||||
|
|
||||||
for (size_t i = 0; i < hmlenu(ctx.uncolored_mesh_batches); ++i)
|
for (size_t i = 0; i < hmlenu(ctx.uncolored_mesh_batches); ++i)
|
||||||
arrsetlen(ctx.uncolored_mesh_batches[i].value.primitives, 0);
|
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
|
* because they will be called multiple times in the main loop
|
||||||
* before anything is really rendered
|
* before anything is really rendered
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* sprite */
|
/* sprite */
|
||||||
void push_sprite(char *path, t_frect rect) {
|
void push_sprite(char *path, t_frect rect) {
|
||||||
struct sprite_primitive sprite = {
|
struct sprite_primitive sprite = {
|
||||||
@ -40,12 +37,16 @@ void push_sprite(char *path, t_frect rect) {
|
|||||||
.rotation = 0.0,
|
.rotation = 0.0,
|
||||||
.blend_mode = SDL_BLENDMODE_BLEND,
|
.blend_mode = SDL_BLENDMODE_BLEND,
|
||||||
.texture_key = textures_get_key(&ctx.texture_cache, path),
|
.texture_key = textures_get_key(&ctx.texture_cache, path),
|
||||||
.layer = 0,
|
|
||||||
.flip_x = false,
|
.flip_x = false,
|
||||||
.flip_y = 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,
|
.color = args.color,
|
||||||
.rotation = args.rotation,
|
.rotation = args.rotation,
|
||||||
.blend_mode = args.blend_mode,
|
.blend_mode = args.blend_mode,
|
||||||
.texture_key = textures_get_key(&ctx.texture_cache, args.path),
|
.texture_key = textures_get_key(&ctx.texture_cache, args.path),
|
||||||
.layer = args.layer,
|
|
||||||
.flip_x = args.flip_x,
|
.flip_x = args.flip_x,
|
||||||
.flip_y = args.flip_y,
|
.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,
|
.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,
|
.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) {
|
static void upload_quad_vertices(t_frect rect) {
|
||||||
/* client memory needs to be reachable on glDraw*, so */
|
/* client memory needs to be reachable on glDraw*, so */
|
||||||
static float vertices[6 * 2];
|
static float vertices[6 * 2];
|
||||||
@ -366,25 +311,21 @@ static void render_circle(struct circle_primitive *circle) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void render_sprites(void) {
|
static void render_2d(void) {
|
||||||
sort_sprites(ctx.render_queue_sprites);
|
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) {
|
switch (current->type) {
|
||||||
render_sprite(&ctx.render_queue_sprites[i]);
|
case PRIMITIVE_2D_SPRITE:
|
||||||
}
|
render_sprite(¤t->sprite);
|
||||||
}
|
break;
|
||||||
|
case PRIMITIVE_2D_RECT:
|
||||||
|
render_rectangle(¤t->rect);
|
||||||
static void render_rectangles(void) {
|
break;
|
||||||
for (size_t i = 0; i < arrlenu(ctx.render_queue_rectangles); ++i) {
|
case PRIMITIVE_2D_CIRCLE:
|
||||||
render_rectangle(&ctx.render_queue_rectangles[i]);
|
render_circle(¤t->circle);
|
||||||
}
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
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);
|
glEnable(GL_TEXTURE_2D);
|
||||||
|
|
||||||
render_sprites();
|
render_2d();
|
||||||
render_rectangles();
|
|
||||||
render_circles();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -9,7 +9,6 @@
|
|||||||
|
|
||||||
typedef struct push_sprite_args {
|
typedef struct push_sprite_args {
|
||||||
char *path;
|
char *path;
|
||||||
int layer;
|
|
||||||
t_color color;
|
t_color color;
|
||||||
double rotation;
|
double rotation;
|
||||||
SDL_BlendMode blend_mode;
|
SDL_BlendMode blend_mode;
|
||||||
|
Loading…
Reference in New Issue
Block a user