diff --git a/src/sim_step.c b/src/sim_step.c index 48d7877c..9971bd4f 100644 --- a/src/sim_step.c +++ b/src/sim_step.c @@ -406,34 +406,43 @@ INTERNAL void test_generate_walls(struct sim_snapshot *world) struct temp_arena scratch = scratch_begin_no_conflict(); struct sim_ent *root = sim_ent_from_id(world, SIM_ENT_ROOT_ID); - /* Release existing walls */ - for (u64 ent_index = 0; ent_index < world->num_ents_reserved; ++ent_index) { - struct sim_ent *ent = &world->ents[ent_index]; - if (!ent->valid) continue; - if (sim_ent_has_prop(ent, SEPROP_WALL)) { - sim_ent_enable_prop(ent, SEPROP_RELEASE); - } - } - - /* Sort tile chunks */ - /* 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 - * know the left & top chunks have already been processed) */ - struct sim_ent **x_sorted_tile_chunks = arena_dry_push(scratch.arena, struct sim_ent *); + /* Gather tile chunks and release existing walls. + * NOTE: We sort tile chunks before iterating so that chunk-edge tiles only + * need to check for adjacent walls to merge with in one direction */ + struct sim_ent **x_sorted_tile_chunks = NULL; + struct sim_ent **y_sorted_tile_chunks = NULL; u64 sorted_tile_chunks_count = 0; - for (u64 ent_index = 0; ent_index < world->num_ents_reserved; ++ent_index) { - struct sim_ent *ent = &world->ents[ent_index]; - if (!ent->valid) continue; - if (sim_ent_has_prop(ent, SEPROP_TILE_CHUNK)) { - *arena_push_no_zero(scratch.arena, struct sim_ent *) = ent; - ++sorted_tile_chunks_count; + { + /* NOTE: We sort x & y separately because of the possibility for diagonal + * tile chunks to depend on each other. + * + * For example: In a horizontal iteration, if 2 chunks exist diagonally + * with one to the bottom-left and one to the top-right and the top-right + * chunk has no chunk below it, then the processing of the top-right chunk + * will have to iterate an extra row at the bottom to create bottom walls (since + * walls are created at the tops of tiles). When creating a wall at the bottom-left + * tile of the top-right chunk, it needs to know whether any walls exist at + * the left of that tile that it may need to merge with. If it was iterating + * an array sorted with top-bottom priority, then the bottom-left chunk will not + * have been processed yet, meaning no walls will have been generated to merge with. */ + x_sorted_tile_chunks = arena_dry_push(scratch.arena, struct sim_ent *); + for (u64 ent_index = 0; ent_index < world->num_ents_reserved; ++ent_index) { + struct sim_ent *ent = &world->ents[ent_index]; + if (!ent->valid) continue; + if (sim_ent_has_prop(ent, SEPROP_TILE_CHUNK)) { + /* Append chunk to array */ + *arena_push_no_zero(scratch.arena, struct sim_ent *) = ent; + ++sorted_tile_chunks_count; + } else if (sim_ent_has_prop(ent, SEPROP_WALL)) { + sim_ent_enable_prop(ent, SEPROP_RELEASE); + } } - } - 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); + 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); + 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 v2i32 start; @@ -443,7 +452,7 @@ INTERNAL void test_generate_walls(struct sim_snapshot *world) }; /* Dicts containing walls that end on edge of tile chunk, keyed by tile end index. - * Used to expand walls accross tile chunks. */ + * Used to merge walls accross tile chunks. */ struct dict horizontal_ends_dict = dict_init(scratch.arena, 1024); struct dict vertical_ends_dict = dict_init(scratch.arena, 1024);