diff --git a/src/user.c b/src/user.c index 254a9e4a..349b23ff 100644 --- a/src/user.c +++ b/src/user.c @@ -429,6 +429,22 @@ INTERNAL void debug_draw_movement(struct entity *ent) draw_solid_arrow_ray(G.viewport_canvas, pos, vel_ray, thickness, arrow_len, color_vel); } +/* ========================== * + * Sort entities + * ========================== */ + +INTERNAL SORT_COMPARE_FUNC_DEF(sort_entities, arg_a, arg_b, udata) +{ + (UNUSED)udata; + struct entity *a = *(struct entity **)arg_a; + struct entity *b = *(struct entity **)arg_b; + + u64 a_index = a->handle.idx; + u64 b_index = b->handle.idx; + + return (a_index < b_index) - (a_index > b_index); +} + /* ========================== * * Update * ========================== */ @@ -872,13 +888,32 @@ INTERNAL void user_update(void) /* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */ + /* ========================== * + * Sort entities + * ========================== */ + + struct entity **sorted = arena_dry_push(scratch.arena, struct entity *); + u64 sorted_count = 0; + { + /* Copy valid entities */ + for (u64 entity_index = 0; entity_index < store->reserved; ++entity_index) { + struct entity *ent = &store->entities[entity_index]; + if (entity_is_valid_and_active(ent)) { + *arena_push(scratch.arena, struct entity *) = ent; + ++sorted_count; + } + } + /* Sort */ + merge_sort(sorted, sorted_count, sizeof(*sorted), sort_entities, NULL); + } + /* ========================== * * Draw entities * ========================== */ - for (u64 entity_index = 0; entity_index < store->reserved; ++entity_index) { + for (u64 sorted_index = 0; sorted_index < sorted_count; ++sorted_index) { __profscope(user_entity_iter); - struct entity *ent = &store->entities[entity_index]; + struct entity *ent = sorted[sorted_index]; if (!entity_is_valid_and_active(ent)) continue; //if (sprite_tag_is_nil(ent->sprite)) continue; diff --git a/src/util.h b/src/util.h index 3547b1c3..6e4b0485 100644 --- a/src/util.h +++ b/src/util.h @@ -7,6 +7,7 @@ #include "arena.h" #include "atomic.h" #include "math.h" +#include "scratch.h" /* Utility functions and stuff that don't have a home :( */ @@ -42,6 +43,77 @@ INLINE u128 hash_fnv128(u128 seed, struct buffer buff) return hash; } +/* ========================== * + * Merge sort + * ========================== */ + +/* Compare functions should + * return an int < 0 if a < b + * return an int = 0 if a == b + * return an int > 0 if a > b + */ +#define SORT_COMPARE_FUNC_DEF(name, arg_a, arg_b, arg_udata) i32 name(void *arg_a, void *arg_b, void *arg_udata) +typedef SORT_COMPARE_FUNC_DEF(sort_compare_func, a, b, udata); + +INLINE void merge_sort_internal(void *left, void *right, void *items, u64 left_count, u64 right_count, u64 item_size, sort_compare_func *callback, void *udata) +{ + u64 i = 0; + u64 l = 0; + u64 r = 0; + while (l < left_count && r < right_count) { + u8 *dst = ((u8 *)items) + (i * item_size); + u8 *left_item = ((u8 *)left) + (l * item_size); + u8 *right_item = ((u8 *)right) + (r * item_size); + ++i; + if (callback(left_item, right_item, udata) > 0) { + MEMCPY(dst, left_item, item_size); + ++l; + } else { + MEMCPY(dst, right_item, item_size); + ++r; + } + } + /* Copy remaining */ + u64 left_remaining_bytes = (left_count - l) * item_size; + u64 right_remaining_bytes = (right_count - r) * item_size; + if (left_remaining_bytes > 0) { + u8 *dst = ((u8 *)items) + (i * item_size); + u8 *src = ((u8 *)left) + (l * item_size); + MEMCPY(dst, src, left_remaining_bytes); + i += left_count - l; + l = left_remaining_bytes; + } + if (right_remaining_bytes > 0) { + u8 *dst = ((u8 *)items) + (i * item_size); + u8 *src = ((u8 *)right) + (r * item_size); + MEMCPY(dst, src, right_remaining_bytes); + i += right_count - r; + l = right_remaining_bytes; + } +} + +INLINE void merge_sort(void *items, u64 item_count, u64 item_size, sort_compare_func *callback, void *udata) +{ + if (item_count > 1) { + struct temp_arena scratch = scratch_begin_no_conflict(); + u64 left_count = item_count / 2; + u64 right_count = item_count - left_count; + + u64 left_size = left_count * item_size; + u64 right_size = right_count * item_size; + + u8 *left = arena_push_array(scratch.arena, u8, left_size); + u8 *right = arena_push_array(scratch.arena, u8, right_size); + MEMCPY(left, items, left_size); + MEMCPY(right, (u8 *)items + left_size, right_size); + + merge_sort(left, left_count, item_size, callback, udata); + merge_sort(right, right_count, item_size, callback, udata); + merge_sort_internal(left, right, items, left_count, right_count, item_size, callback, udata); + scratch_end(scratch); + } +} + /* ========================== * * Fixed Dict *