sort tile chunks by x & y separately to fix bug

This commit is contained in:
jacob 2025-05-21 23:01:40 -05:00
parent d9f841dad6
commit 92bb82cdb4
2 changed files with 155 additions and 141 deletions

View File

@ -374,16 +374,29 @@ INTERNAL void test_spawn_tile(struct sim_snapshot *world, struct v2 world_pos)
INTERNAL SORT_COMPARE_FUNC_DEF(tile_chunk_sort, arg_a, arg_b, udata) INTERNAL SORT_COMPARE_FUNC_DEF(tile_chunk_sort_x, arg_a, arg_b, udata)
{ {
(UNUSED)udata; (UNUSED)udata;
struct sim_ent *a = *(struct sim_ent **)arg_a; struct sim_ent *a = *(struct sim_ent **)arg_a;
struct sim_ent *b = *(struct sim_ent **)arg_b; struct sim_ent *b = *(struct sim_ent **)arg_b;
struct v2i32 index_a = a->tile_chunk_index; i32 a_x = a->tile_chunk_index.x;
struct v2i32 index_b = b->tile_chunk_index; i32 b_x = b->tile_chunk_index.x;
i32 res = 0; i32 res = 0;
res = 2 * ((index_a.y < index_b.y) - (index_a.y > index_b.y)) + ((index_a.x < index_b.x) - (index_a.x > index_b.x)); res = (a_x < b_x) - (a_x > b_x);
return res;
}
INTERNAL SORT_COMPARE_FUNC_DEF(tile_chunk_sort_y, arg_a, arg_b, udata)
{
(UNUSED)udata;
struct sim_ent *a = *(struct sim_ent **)arg_a;
struct sim_ent *b = *(struct sim_ent **)arg_b;
i32 a_y = a->tile_chunk_index.y;
i32 b_y = b->tile_chunk_index.y;
i32 res = 0;
res = (a_y < b_y) - (a_y > b_y);
return res; return res;
} }
@ -403,10 +416,10 @@ INTERNAL void test_generate_walls(struct sim_snapshot *world)
} }
/* Sort tile chunks */ /* Sort tile chunks */
/* NOTE: We sort tile chunks from top-left to bottom-right so that cross /* NOTE: We sort tile chunks from left-right and top-bottom so that cross
* chunk tile checks only have to happen in one direction (because we * chunk tile checks only have to happen in one direction (because we
* know the left & top chunks have already been processed) */ * know the left & top chunks have already been processed) */
struct sim_ent **sorted_tile_chunks = arena_dry_push(scratch.arena, struct sim_ent *); struct sim_ent **x_sorted_tile_chunks = arena_dry_push(scratch.arena, struct sim_ent *);
u64 sorted_tile_chunks_count = 0; u64 sorted_tile_chunks_count = 0;
for (u64 ent_index = 0; ent_index < world->num_ents_reserved; ++ent_index) { for (u64 ent_index = 0; ent_index < world->num_ents_reserved; ++ent_index) {
struct sim_ent *ent = &world->ents[ent_index]; struct sim_ent *ent = &world->ents[ent_index];
@ -416,7 +429,11 @@ INTERNAL void test_generate_walls(struct sim_snapshot *world)
++sorted_tile_chunks_count; ++sorted_tile_chunks_count;
} }
} }
merge_sort(sorted_tile_chunks, sorted_tile_chunks_count, sizeof(*sorted_tile_chunks), tile_chunk_sort, NULL); struct sim_ent **y_sorted_tile_chunks = arena_push_array_no_zero(scratch.arena, struct sim_ent *, sorted_tile_chunks_count);
MEMCPY(y_sorted_tile_chunks, x_sorted_tile_chunks, sizeof(*x_sorted_tile_chunks) * sorted_tile_chunks_count);
merge_sort(x_sorted_tile_chunks, sorted_tile_chunks_count, sizeof(*x_sorted_tile_chunks), tile_chunk_sort_x, NULL);
merge_sort(y_sorted_tile_chunks, sorted_tile_chunks_count, sizeof(*y_sorted_tile_chunks), tile_chunk_sort_y, NULL);
struct wall_node { struct wall_node {
struct v2i32 start; struct v2i32 start;
@ -433,150 +450,150 @@ INTERNAL void test_generate_walls(struct sim_snapshot *world)
/* Generate horizontal wall nodes */ /* Generate horizontal wall nodes */
for (u64 sorted_index = 0; sorted_index < sorted_tile_chunks_count; ++sorted_index) { for (u64 sorted_index = 0; sorted_index < sorted_tile_chunks_count; ++sorted_index) {
struct sim_ent *chunk = sorted_tile_chunks[sorted_index]; struct sim_ent *chunk = x_sorted_tile_chunks[sorted_index];
struct v2i32 chunk_index = chunk->tile_chunk_index; struct v2i32 chunk_index = chunk->tile_chunk_index;
/* Generate horizontal wall nodes */ struct sim_ent *top_chunk = sim_tile_chunk_from_chunk_index(world, V2I32(chunk_index.x, chunk_index.y - 1));
{ struct sim_ent *bottom_chunk = sim_tile_chunk_from_chunk_index(world, V2I32(chunk_index.x, chunk_index.y + 1));
struct sim_ent *top_chunk = sim_tile_chunk_from_chunk_index(world, V2I32(chunk_index.x, chunk_index.y - 1)); /* If there's no chunk below this one, then do an extra iteration (since walls are created at the top of each tile) */
struct sim_ent *bottom_chunk = sim_tile_chunk_from_chunk_index(world, V2I32(chunk_index.x, chunk_index.y + 1)); i32 y_iterations = SIM_TILES_PER_CHUNK_SQRT + !bottom_chunk->valid;
/* If there's no chunk below this one, then do an extra iteration (since walls are created at the top of each tile) */ i32 x_iterations = SIM_TILES_PER_CHUNK_SQRT + 1;
i32 y_iterations = SIM_TILES_PER_CHUNK_SQRT + !bottom_chunk->valid; for (i32 tile_y = 0; tile_y < y_iterations; ++tile_y) {
i32 x_iterations = SIM_TILES_PER_CHUNK_SQRT + 1; i32 wall_start = -1;
for (i32 tile_y = 0; tile_y < y_iterations; ++tile_y) { i32 wall_end = -1;
i32 wall_start = -1; for (i32 tile_x = 0; tile_x < x_iterations; ++tile_x) {
i32 wall_end = -1; enum sim_tile_kind tile = SIM_TILE_KIND_NONE;
for (i32 tile_x = 0; tile_x < x_iterations; ++tile_x) { if (tile_x < SIM_TILES_PER_CHUNK_SQRT && tile_y < SIM_TILES_PER_CHUNK_SQRT) {
enum sim_tile_kind tile = SIM_TILE_KIND_NONE; tile = sim_get_chunk_tile(chunk, V2I32(tile_x, tile_y));
if (tile_x < SIM_TILES_PER_CHUNK_SQRT && tile_y < SIM_TILES_PER_CHUNK_SQRT) { }
tile = sim_get_chunk_tile(chunk, V2I32(tile_x, tile_y)); b32 should_have_top_wall = false;
} if (tile_x < SIM_TILES_PER_CHUNK_SQRT) {
b32 should_have_top_wall = false; enum sim_tile_kind top_tile = SIM_TILE_KIND_NONE;
if (tile_x < SIM_TILES_PER_CHUNK_SQRT) { if (tile_y == 0) {
enum sim_tile_kind top_tile = SIM_TILE_KIND_NONE; if (top_chunk->valid) {
if (tile_y == 0) { struct v2i32 top_tile_local_index = V2I32(tile_x, SIM_TILES_PER_CHUNK_SQRT - 1);
if (top_chunk->valid) { top_tile = sim_get_chunk_tile(top_chunk, top_tile_local_index);
struct v2i32 top_tile_local_index = V2I32(tile_x, SIM_TILES_PER_CHUNK_SQRT - 1);
top_tile = sim_get_chunk_tile(top_chunk, top_tile_local_index);
}
} else {
top_tile = sim_get_chunk_tile(chunk, V2I32(tile_x, tile_y - 1));
} }
if (tile == SIM_TILE_KIND_WALL) { } else {
/* Process wall tile */ top_tile = sim_get_chunk_tile(chunk, V2I32(tile_x, tile_y - 1));
should_have_top_wall = top_tile != SIM_TILE_KIND_WALL; }
} else { if (tile == SIM_TILE_KIND_WALL) {
/* Process non-wall tile */ /* Process wall tile */
should_have_top_wall = top_tile == SIM_TILE_KIND_WALL; should_have_top_wall = top_tile != SIM_TILE_KIND_WALL;
} else {
/* Process non-wall tile */
should_have_top_wall = top_tile == SIM_TILE_KIND_WALL;
}
}
if (should_have_top_wall) {
if (wall_start < 0) {
/* Start wall */
wall_start = tile_x;
}
/* Extend wall */
wall_end = tile_x + 1;
} else if (wall_end >= 0) {
/* Stop wall */
struct v2i32 start = sim_world_tile_index_from_local_tile_index(chunk_index, V2I32(wall_start, tile_y));
struct v2i32 end = sim_world_tile_index_from_local_tile_index(chunk_index, V2I32(wall_end, tile_y));
struct wall_node *node = NULL;
if (wall_start == 0) {
u64 start_hash = rand_u64_from_seed(*(u64 *)&start);
struct dict_entry *entry = dict_get_entry(&horizontal_ends_dict, start_hash);
if (entry) {
/* Existing wall exists accross chunk boundary */
node = (struct wall_node *)entry->value;
dict_remove_entry(&horizontal_ends_dict, entry);
} }
} }
if (should_have_top_wall) { if (!node) {
if (wall_start < 0) { node = arena_push(scratch.arena, struct wall_node);
/* Start wall */ node->start = start;
wall_start = tile_x; node->next = first_wall;
} first_wall = node;
/* Extend wall */
wall_end = tile_x + 1;
} else if (wall_end >= 0) {
/* Stop wall */
struct v2i32 start = sim_world_tile_index_from_local_tile_index(chunk_index, V2I32(wall_start, tile_y));
struct v2i32 end = sim_world_tile_index_from_local_tile_index(chunk_index, V2I32(wall_end, tile_y));
struct wall_node *node = NULL;
if (wall_start == 0) {
u64 start_hash = rand_u64_from_seed(*(u64 *)&start);
struct dict_entry *entry = dict_get_entry(&horizontal_ends_dict, start_hash);
if (entry) {
/* Existing wall exists accross chunk boundary */
node = (struct wall_node *)entry->value;
dict_remove_entry(&horizontal_ends_dict, entry);
}
}
if (!node) {
node = arena_push(scratch.arena, struct wall_node);
node->start = start;
node->next = first_wall;
first_wall = node;
}
node->end = end;
if (wall_end == SIM_TILES_PER_CHUNK_SQRT) {
u64 end_hash = rand_u64_from_seed(*(u64 *)&end);
dict_set(scratch.arena, &horizontal_ends_dict, end_hash, node);
}
wall_start = -1;
wall_end = -1;
} }
node->end = end;
if (wall_end == SIM_TILES_PER_CHUNK_SQRT) {
u64 end_hash = rand_u64_from_seed(*(u64 *)&end);
dict_set(scratch.arena, &horizontal_ends_dict, end_hash, node);
}
wall_start = -1;
wall_end = -1;
} }
} }
} }
/* Generate vertical wall nodes */ }
{
struct sim_ent *left_chunk = sim_tile_chunk_from_chunk_index(world, V2I32(chunk_index.x - 1, chunk_index.y));
struct sim_ent *right_chunk = sim_tile_chunk_from_chunk_index(world, V2I32(chunk_index.x + 1, chunk_index.y));
/* If there's no chunk to the right of this one, then do an extra iteration (since walls are created on the left of each tile) */
i32 y_iterations = SIM_TILES_PER_CHUNK_SQRT + 1;
i32 x_iterations = SIM_TILES_PER_CHUNK_SQRT + !right_chunk->valid;
for (i32 tile_x = 0; tile_x < x_iterations; ++tile_x) {
i32 wall_start = -1;
i32 wall_end = -1;
for (i32 tile_y = 0; tile_y < y_iterations; ++tile_y) {
enum sim_tile_kind tile = SIM_TILE_KIND_NONE;
if (tile_x < SIM_TILES_PER_CHUNK_SQRT && tile_y < SIM_TILES_PER_CHUNK_SQRT) {
tile = sim_get_chunk_tile(chunk, V2I32(tile_x, tile_y));
}
b32 should_have_left_wall = false; /* Generate vertical wall nodes */
if (tile_y < SIM_TILES_PER_CHUNK_SQRT) { for (u64 sorted_index = 0; sorted_index < sorted_tile_chunks_count; ++sorted_index) {
enum sim_tile_kind left_tile = SIM_TILE_KIND_NONE; struct sim_ent *chunk = y_sorted_tile_chunks[sorted_index];
if (tile_x == 0) { struct v2i32 chunk_index = chunk->tile_chunk_index;
if (left_chunk->valid) { struct sim_ent *left_chunk = sim_tile_chunk_from_chunk_index(world, V2I32(chunk_index.x - 1, chunk_index.y));
struct v2i32 left_tile_local_index = V2I32(SIM_TILES_PER_CHUNK_SQRT - 1, tile_y); struct sim_ent *right_chunk = sim_tile_chunk_from_chunk_index(world, V2I32(chunk_index.x + 1, chunk_index.y));
left_tile = sim_get_chunk_tile(left_chunk, left_tile_local_index); /* If there's no chunk to the right of this one, then do an extra iteration (since walls are created on the left of each tile) */
} i32 y_iterations = SIM_TILES_PER_CHUNK_SQRT + 1;
} else { i32 x_iterations = SIM_TILES_PER_CHUNK_SQRT + !right_chunk->valid;
left_tile = sim_get_chunk_tile(chunk, V2I32(tile_x - 1, tile_y)); for (i32 tile_x = 0; tile_x < x_iterations; ++tile_x) {
i32 wall_start = -1;
i32 wall_end = -1;
for (i32 tile_y = 0; tile_y < y_iterations; ++tile_y) {
enum sim_tile_kind tile = SIM_TILE_KIND_NONE;
if (tile_x < SIM_TILES_PER_CHUNK_SQRT && tile_y < SIM_TILES_PER_CHUNK_SQRT) {
tile = sim_get_chunk_tile(chunk, V2I32(tile_x, tile_y));
}
b32 should_have_left_wall = false;
if (tile_y < SIM_TILES_PER_CHUNK_SQRT) {
enum sim_tile_kind left_tile = SIM_TILE_KIND_NONE;
if (tile_x == 0) {
if (left_chunk->valid) {
struct v2i32 left_tile_local_index = V2I32(SIM_TILES_PER_CHUNK_SQRT - 1, tile_y);
left_tile = sim_get_chunk_tile(left_chunk, left_tile_local_index);
} }
if (tile == SIM_TILE_KIND_WALL) { } else {
/* Process wall tile */ left_tile = sim_get_chunk_tile(chunk, V2I32(tile_x - 1, tile_y));
should_have_left_wall = left_tile != SIM_TILE_KIND_WALL; }
} else { if (tile == SIM_TILE_KIND_WALL) {
/* Process non-wall tile */ /* Process wall tile */
should_have_left_wall = left_tile == SIM_TILE_KIND_WALL; should_have_left_wall = left_tile != SIM_TILE_KIND_WALL;
} else {
/* Process non-wall tile */
should_have_left_wall = left_tile == SIM_TILE_KIND_WALL;
}
}
if (should_have_left_wall) {
if (wall_start < 0) {
/* Start wall */
wall_start = tile_y;
}
/* Extend wall */
wall_end = tile_y + 1;
} else if (wall_end >= 0) {
/* Stop wall */
struct v2i32 start = sim_world_tile_index_from_local_tile_index(chunk_index, V2I32(tile_x, wall_start));
struct v2i32 end = sim_world_tile_index_from_local_tile_index(chunk_index, V2I32(tile_x, wall_end));
struct wall_node *node = NULL;
if (wall_start == 0) {
u64 start_hash = rand_u64_from_seed(*(u64 *)&start);
struct dict_entry *entry = dict_get_entry(&vertical_ends_dict, start_hash);
if (entry) {
/* Existing wall exists accross chunk boundary */
node = (struct wall_node *)entry->value;
dict_remove_entry(&vertical_ends_dict, entry);
} }
} }
if (should_have_left_wall) { if (!node) {
if (wall_start < 0) { node = arena_push(scratch.arena, struct wall_node);
/* Start wall */ node->start = start;
wall_start = tile_y; node->next = first_wall;
} first_wall = node;
/* Extend wall */
wall_end = tile_y + 1;
} else if (wall_end >= 0) {
/* Stop wall */
struct v2i32 start = sim_world_tile_index_from_local_tile_index(chunk_index, V2I32(tile_x, wall_start));
struct v2i32 end = sim_world_tile_index_from_local_tile_index(chunk_index, V2I32(tile_x, wall_end));
struct wall_node *node = NULL;
if (wall_start == 0) {
u64 start_hash = rand_u64_from_seed(*(u64 *)&start);
struct dict_entry *entry = dict_get_entry(&vertical_ends_dict, start_hash);
if (entry) {
/* Existing wall exists accross chunk boundary */
node = (struct wall_node *)entry->value;
dict_remove_entry(&vertical_ends_dict, entry);
}
}
if (!node) {
node = arena_push(scratch.arena, struct wall_node);
node->start = start;
node->next = first_wall;
first_wall = node;
}
node->end = end;
if (wall_end == SIM_TILES_PER_CHUNK_SQRT) {
u64 end_hash = rand_u64_from_seed(*(u64 *)&end);
dict_set(scratch.arena, &vertical_ends_dict, end_hash, node);
}
wall_start = -1;
wall_end = -1;
} }
node->end = end;
if (wall_end == SIM_TILES_PER_CHUNK_SQRT) {
u64 end_hash = rand_u64_from_seed(*(u64 *)&end);
dict_set(scratch.arena, &vertical_ends_dict, end_hash, node);
}
wall_start = -1;
wall_end = -1;
} }
} }
} }

View File

@ -1861,9 +1861,6 @@ INTERNAL void user_update(void)
draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, LIT("Video memory usage: %F MiB"), FMT_FLOAT((f64)gstat_get(GSTAT_VRAM_USAGE) / 1024 / 1024))); draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, LIT("Video memory usage: %F MiB"), FMT_FLOAT((f64)gstat_get(GSTAT_VRAM_USAGE) / 1024 / 1024)));
pos.y += spacing; pos.y += spacing;
draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, LIT("Video memory budget: %F GiB"), FMT_FLOAT((f64)gstat_get(GSTAT_VRAM_BUDGET) / 1024 / 1024 / 1024)));
pos.y += spacing;
pos.y += spacing; pos.y += spacing;
#if 0 #if 0