cross-chunk tile wall merging
This commit is contained in:
parent
4bc6ca6679
commit
a47009f16b
@ -39,7 +39,7 @@
|
||||
#define SPACE_CELL_BINS_SQRT (64)
|
||||
#define SPACE_CELL_SIZE (1)
|
||||
|
||||
#define SIM_TILES_PER_UNIT_SQRT (2)
|
||||
#define SIM_TILES_PER_UNIT_SQRT (4)
|
||||
#define SIM_TILES_PER_CHUNK_SQRT (16)
|
||||
|
||||
#define SIM_TICKS_PER_SECOND 50
|
||||
|
||||
13
src/phys.c
13
src/phys.c
@ -13,6 +13,15 @@
|
||||
* Contact
|
||||
* ========================== */
|
||||
|
||||
INTERNAL b32 can_contact(struct sim_ent *e0, struct sim_ent *e1)
|
||||
{
|
||||
b32 res = false;
|
||||
res = e0 != e1 &&
|
||||
!sim_ent_id_eq(e0->top, e1->top) &&
|
||||
!(sim_ent_has_prop(e0, SEPROP_WALL) && sim_ent_has_prop(e1, SEPROP_WALL));
|
||||
return res;
|
||||
}
|
||||
|
||||
void phys_create_and_update_contacts(struct phys_step_ctx *ctx, f32 elapsed_dt, u64 phys_iteration)
|
||||
{
|
||||
__prof;
|
||||
@ -39,10 +48,10 @@ void phys_create_and_update_contacts(struct phys_step_ctx *ctx, f32 elapsed_dt,
|
||||
struct space_entry *space_entry;
|
||||
while ((space_entry = space_iter_next(&iter))) {
|
||||
struct sim_ent *check1 = sim_ent_from_id(ss, space_entry->ent);
|
||||
if (check1 == check0) continue;
|
||||
if (!sim_ent_is_valid_and_active(check1)) continue;
|
||||
if (!(sim_ent_has_prop(check1, SEPROP_SOLID) || sim_ent_has_prop(check1, SEPROP_SENSOR))) continue;
|
||||
if (check1->local_collider.count <= 0) continue;
|
||||
if (!can_contact(check0, check1)) continue;
|
||||
|
||||
/* Deterministic order based on entity id */
|
||||
struct sim_ent *e0;
|
||||
@ -1171,10 +1180,10 @@ f32 phys_determine_earliest_toi(struct phys_step_ctx *ctx, f32 step_dt, f32 tole
|
||||
struct space_entry *entry;
|
||||
while ((entry = space_iter_next(&iter))) {
|
||||
struct sim_ent *e1 = sim_ent_from_id(ss, entry->ent);
|
||||
if (e1 == e0) continue;
|
||||
if (!sim_ent_should_simulate(e1)) continue;
|
||||
if (!(sim_ent_has_prop(e1, SEPROP_SOLID) || sim_ent_has_prop(e1, SEPROP_SENSOR))) continue;
|
||||
if (e1->local_collider.count <= 0) continue;
|
||||
if (!can_contact(e0, e1)) continue;
|
||||
|
||||
struct collider_shape e1_collider = e1->local_collider;
|
||||
struct xform e1_xf_t0 = sim_ent_get_xform(e1);
|
||||
|
||||
121
src/sim_step.c
121
src/sim_step.c
@ -377,21 +377,21 @@ 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)
|
||||
{
|
||||
(UNUSED)udata;
|
||||
struct sim_ent *a = (struct sim_ent *)arg_a;
|
||||
struct sim_ent *b = (struct sim_ent *)arg_b;
|
||||
struct sim_ent *a = *(struct sim_ent **)arg_a;
|
||||
struct sim_ent *b = *(struct sim_ent **)arg_b;
|
||||
struct v2i32 index_a = a->tile_chunk_index;
|
||||
struct v2i32 index_b = b->tile_chunk_index;
|
||||
|
||||
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 = 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));
|
||||
return res;
|
||||
}
|
||||
|
||||
INTERNAL void test_generate_walls(struct sim_ent *parent)
|
||||
INTERNAL void test_generate_walls(struct sim_snapshot *world)
|
||||
{
|
||||
#if 1
|
||||
__prof;
|
||||
struct temp_arena scratch = scratch_begin_no_conflict();
|
||||
struct sim_snapshot *world = parent->ss;
|
||||
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) {
|
||||
@ -403,17 +403,17 @@ INTERNAL void test_generate_walls(struct sim_ent *parent)
|
||||
}
|
||||
|
||||
/* Sort tile chunks */
|
||||
struct sim_ent **tile_chunks = arena_dry_push(scratch.arena, struct sim_ent *);
|
||||
u64 tile_chunks_count = 0;
|
||||
struct sim_ent **sorted_tile_chunks = arena_dry_push(scratch.arena, struct sim_ent *);
|
||||
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;
|
||||
++tile_chunks_count;
|
||||
++sorted_tile_chunks_count;
|
||||
}
|
||||
}
|
||||
merge_sort(tile_chunks, tile_chunks_count, sizeof(*tile_chunks), tile_chunk_sort, NULL);
|
||||
merge_sort(sorted_tile_chunks, sorted_tile_chunks_count, sizeof(*sorted_tile_chunks), tile_chunk_sort, NULL);
|
||||
|
||||
struct wall_node {
|
||||
struct v2i32 start;
|
||||
@ -421,13 +421,16 @@ INTERNAL void test_generate_walls(struct sim_ent *parent)
|
||||
struct wall_node *next;
|
||||
};
|
||||
|
||||
/* Dicts containing walls that end on edge of tile chunk, keyed by tile end index.
|
||||
* Used to expand walls accross tile chunks. */
|
||||
struct dict horizontal_ends_dict = dict_init(scratch.arena, 1024);
|
||||
struct dict vertical_ends_dict = dict_init(scratch.arena, 1024);
|
||||
|
||||
struct wall_node *first_wall = NULL;
|
||||
|
||||
/* Generate horizontal wall nodes */
|
||||
for (u64 ent_index = 0; ent_index < world->num_ents_reserved; ++ent_index) {
|
||||
struct sim_ent *chunk = &world->ents[ent_index];
|
||||
if (!chunk->valid) continue;
|
||||
if (sim_ent_has_prop(chunk, SEPROP_TILE_CHUNK)) {
|
||||
for (u64 sorted_index = 0; sorted_index < sorted_tile_chunks_count; ++sorted_index) {
|
||||
struct sim_ent *chunk = sorted_tile_chunks[sorted_index];
|
||||
struct v2i32 chunk_index = chunk->tile_chunk_index;
|
||||
/* Generate horizontal wall nodes */
|
||||
{
|
||||
@ -474,11 +477,26 @@ INTERNAL void test_generate_walls(struct sim_ent *parent)
|
||||
/* 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 = arena_push(scratch.arena, struct wall_node);
|
||||
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) {
|
||||
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->end = end;
|
||||
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;
|
||||
}
|
||||
@ -531,11 +549,26 @@ INTERNAL void test_generate_walls(struct sim_ent *parent)
|
||||
/* 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 = arena_push(scratch.arena, struct wall_node);
|
||||
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) {
|
||||
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->end = end;
|
||||
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;
|
||||
}
|
||||
@ -543,21 +576,12 @@ INTERNAL void test_generate_walls(struct sim_ent *parent)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Create wall entities */
|
||||
for (struct wall_node *node = first_wall; node; node = node->next) {
|
||||
struct sim_ent *wall_ent = sim_ent_alloc_sync_src(parent);
|
||||
struct sim_ent *wall_ent = sim_ent_alloc_sync_src(root);
|
||||
sim_ent_enable_prop(wall_ent, SEPROP_WALL);
|
||||
|
||||
#if 0
|
||||
struct v2i32 node_start = node->start;
|
||||
struct v2i32 node_end = node->end;
|
||||
|
||||
struct v2 start = V2(node_start.x / SIM_TILES_PER_UNIT_SQRT, node_start.y / SIM_TILES_PER_UNIT_SQRT);
|
||||
struct v2 end = V2(node_end.x / SIM_TILES_PER_UNIT_SQRT, node_end.y / SIM_TILES_PER_UNIT_SQRT);
|
||||
#endif
|
||||
|
||||
struct v2 start = sim_pos_from_world_tile_index(node->start);
|
||||
struct v2 end = sim_pos_from_world_tile_index(node->end);
|
||||
|
||||
@ -567,12 +591,11 @@ INTERNAL void test_generate_walls(struct sim_ent *parent)
|
||||
sim_ent_enable_prop(wall_ent, SEPROP_SOLID);
|
||||
wall_ent->local_collider.count = 2;
|
||||
wall_ent->local_collider.points[1] = v2_sub(end, start);
|
||||
|
||||
sim_ent_activate(wall_ent, world->tick);
|
||||
}
|
||||
|
||||
scratch_end(scratch);
|
||||
#else
|
||||
(UNUSED)parent;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@ -774,7 +797,7 @@ void sim_step(struct sim_step_ctx *ctx)
|
||||
player->player_client_handle = client->handle;
|
||||
sim_ent_enable_prop(player, SEPROP_PLAYER);
|
||||
player->predictor = player->id;
|
||||
sim_ent_enable_prop(player, SEPROP_ACTIVE);
|
||||
sim_ent_activate(player, world->tick);
|
||||
client->player_id = player->id;
|
||||
if (client == user_input_client) {
|
||||
user_input_client->player_id = player->id;
|
||||
@ -949,7 +972,7 @@ void sim_step(struct sim_step_ctx *ctx)
|
||||
}
|
||||
}
|
||||
if (flags & SIM_CONTROL_FLAG_WALLS_TEST) {
|
||||
test_generate_walls(root);
|
||||
test_generate_walls(world);
|
||||
}
|
||||
if (flags & SIM_CONTROL_FLAG_EXPLODE_TEST) {
|
||||
logf_info("Explosion test");
|
||||
@ -958,37 +981,9 @@ void sim_step(struct sim_step_ctx *ctx)
|
||||
}
|
||||
|
||||
if (flags & SIM_CONTROL_FLAG_TILE_TEST) {
|
||||
#if 0
|
||||
if (is_master) {
|
||||
struct v2 cursor_pos = player->player_cursor_pos;
|
||||
/* FIXME: Negative indices */
|
||||
struct v2i32 tile_pos = V2I32(cursor_pos.x * SIM_TILES_PER_UNIT_SQRT, cursor_pos.y * SIM_TILES_PER_UNIT_SQRT);
|
||||
struct v2i32 chunk_pos = V2I32(tile_pos.x * SIM_TILES_PER_CHUNK_SQRT, tile_pos.y * SIM_TILES_PER_CHUNK_SQRT);
|
||||
struct v2i32 tile_pos_in_chunk = V2I32(tile_pos.x % SIM_TILES_PER_CHUNK_SQRT, tile_pos.y % SIM_TILES_PER_CHUNK_SQRT);
|
||||
|
||||
struct sim_ent_id chunk_id = sim_ent_chunk_id_from_chunk_pos(player->id, chunk_pos);
|
||||
struct sim_ent *chunk_ent = sim_ent_from_id(world, chunk_id);
|
||||
if (!chunk_ent->valid) {
|
||||
chunk_ent = sim_ent_alloc_sync_src_with_id(root, chunk_id);
|
||||
sim_ent_enable_prop(chunk_ent, SEPROP_TILE_CHUNK);
|
||||
}
|
||||
|
||||
struct string old_data = sim_ent_get_tile_chunk_data(chunk_ent);
|
||||
struct string new_data = ZI;
|
||||
new_data.len = SIM_TILES_PER_CHUNK_SQRT * SIM_TILES_PER_CHUNK_SQRT;
|
||||
new_data.text = arena_push_array_no_zero(scratch.arena, u8, new_data.len);
|
||||
if (old_data.len == new_data.len) {
|
||||
MEMCPY(new_data.text, old_data.text, new_data.len);
|
||||
} else {
|
||||
MEMZERO(new_data.text, new_data.len);
|
||||
}
|
||||
u64 tile_index = tile_pos_in_chunk.x + (tile_pos_in_chunk.y * SIM_TILES_PER_CHUNK_SQRT);
|
||||
new_data.text[tile_index] = SIM_TILE_KIND_TEST;
|
||||
sim_ent_set_tile_chunk_data(chunk_ent, new_data);
|
||||
}
|
||||
#else
|
||||
test_spawn_tile(world, player->player_cursor_pos);
|
||||
#endif
|
||||
} else if (old_control.flags & SIM_CONTROL_FLAG_TILE_TEST) {
|
||||
test_generate_walls(world);
|
||||
}
|
||||
}
|
||||
} break;
|
||||
|
||||
@ -162,7 +162,7 @@ struct tar_archive tar_parse(struct arena *arena, struct string data, struct str
|
||||
return archive;
|
||||
}
|
||||
|
||||
struct tar_entry *tar_get(const struct tar_archive *archive, struct string name)
|
||||
struct tar_entry *tar_get(struct tar_archive *archive, struct string name)
|
||||
{
|
||||
u64 hash = hash_fnv64(HASH_FNV64_BASIS, name);
|
||||
return dict_get(&archive->lookup, hash);
|
||||
|
||||
@ -18,6 +18,6 @@ struct tar_archive {
|
||||
};
|
||||
|
||||
struct tar_archive tar_parse(struct arena *arena, struct string data, struct string prefix);
|
||||
struct tar_entry *tar_get(const struct tar_archive *archive, struct string name);
|
||||
struct tar_entry *tar_get(struct tar_archive *archive, struct string name);
|
||||
|
||||
#endif
|
||||
|
||||
90
src/util.h
90
src/util.h
@ -35,9 +35,9 @@ INLINE u64 hash_fnv64(u64 seed, struct string s)
|
||||
* ========================== */
|
||||
|
||||
/* Compare functions should
|
||||
* return an int < 0 if a < b
|
||||
* return an int = 0 if a == b
|
||||
* return an int > 0 if a > b
|
||||
* return a positive value if a should go before b
|
||||
* return a negative value if a should go after b
|
||||
* return 0 otherwise
|
||||
*/
|
||||
#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);
|
||||
@ -108,18 +108,23 @@ INLINE void merge_sort(void *items, u64 item_count, u64 item_size, sort_compare_
|
||||
struct dict_entry {
|
||||
u64 hash;
|
||||
u64 value;
|
||||
struct dict_entry *prev_in_bin;
|
||||
struct dict_entry *next_in_bin;
|
||||
struct dict_entry *prev;
|
||||
struct dict_entry *next;
|
||||
};
|
||||
|
||||
struct dict_bin {
|
||||
struct dict_entry *first;
|
||||
struct dict_entry *last;
|
||||
};
|
||||
|
||||
struct dict {
|
||||
u64 bins_count;
|
||||
struct dict_bin *bins;
|
||||
struct dict_entry *first_free;
|
||||
struct dict_entry *first;
|
||||
struct dict_entry *last;
|
||||
};
|
||||
|
||||
INLINE struct dict dict_init(struct arena *arena, u64 bins_count)
|
||||
@ -131,10 +136,9 @@ INLINE struct dict dict_init(struct arena *arena, u64 bins_count)
|
||||
return dict;
|
||||
}
|
||||
|
||||
INLINE void dict_set(struct arena *arena, struct dict *dict, u64 hash, u64 value)
|
||||
INLINE struct dict_entry *dict_ensure_entry(struct arena *arena, struct dict *dict, u64 hash)
|
||||
{
|
||||
__prof;
|
||||
|
||||
struct dict_bin *bin = &dict->bins[hash % dict->bins_count];
|
||||
|
||||
struct dict_entry *entry = bin->first;
|
||||
@ -148,19 +152,41 @@ INLINE void dict_set(struct arena *arena, struct dict *dict, u64 hash, u64 value
|
||||
|
||||
/* No match found, create new entry */
|
||||
if (!entry) {
|
||||
entry = arena_push(arena, struct dict_entry);
|
||||
entry->value = value;
|
||||
if (dict->first_free) {
|
||||
entry = dict->first_free;
|
||||
dict->first_free = entry->next;
|
||||
} else {
|
||||
entry = arena_push_no_zero(arena, struct dict_entry);
|
||||
}
|
||||
MEMZERO_STRUCT(entry);
|
||||
entry->hash = hash;
|
||||
entry->next_in_bin = bin->first;
|
||||
entry->next = dict->first;
|
||||
dict->first = entry;
|
||||
if (bin->last) {
|
||||
bin->last->next_in_bin = entry;
|
||||
entry->prev_in_bin = bin->last;
|
||||
} else {
|
||||
bin->first = entry;
|
||||
}
|
||||
bin->last = entry;
|
||||
if (dict->last) {
|
||||
dict->last->next = entry;
|
||||
entry->prev = dict->last;
|
||||
} else {
|
||||
dict->first = entry;
|
||||
}
|
||||
dict->last = entry;
|
||||
}
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
INLINE void dict_set(struct arena *arena, struct dict *dict, u64 hash, u64 value)
|
||||
{
|
||||
__prof;
|
||||
struct dict_entry *entry = dict_ensure_entry(arena, dict, hash);
|
||||
entry->value = value;
|
||||
}
|
||||
|
||||
INLINE struct dict_entry *dict_get_entry(const struct dict *dict, u64 hash)
|
||||
INLINE struct dict_entry *dict_get_entry(struct dict *dict, u64 hash)
|
||||
{
|
||||
__prof;
|
||||
struct dict_entry *result = NULL;
|
||||
@ -175,13 +201,53 @@ INLINE struct dict_entry *dict_get_entry(const struct dict *dict, u64 hash)
|
||||
return result;
|
||||
}
|
||||
|
||||
INLINE u64 dict_get(const struct dict *dict, u64 hash)
|
||||
INLINE u64 dict_get(struct dict *dict, u64 hash)
|
||||
{
|
||||
__prof;
|
||||
struct dict_entry *entry = dict_get_entry(dict, hash);
|
||||
return entry ? entry->value : 0;
|
||||
}
|
||||
|
||||
INLINE void dict_remove_entry(struct dict *dict, struct dict_entry *entry)
|
||||
{
|
||||
/* Remove from bin */
|
||||
{
|
||||
struct dict_bin *bin = &dict->bins[entry->hash % dict->bins_count];
|
||||
struct dict_entry *prev_in_bin = entry->prev_in_bin;
|
||||
struct dict_entry *next_in_bin = entry->next_in_bin;
|
||||
if (prev_in_bin) {
|
||||
prev_in_bin->next_in_bin = next_in_bin;
|
||||
} else {
|
||||
bin->first = next_in_bin;
|
||||
}
|
||||
if (next_in_bin) {
|
||||
next_in_bin->prev_in_bin = prev_in_bin;
|
||||
} else {
|
||||
bin->last = prev_in_bin;
|
||||
}
|
||||
}
|
||||
/* Remove from list */
|
||||
{
|
||||
struct dict_entry *prev = entry->prev;
|
||||
struct dict_entry *next = entry->next;
|
||||
if (prev) {
|
||||
prev->next = next;
|
||||
} else {
|
||||
dict->first = next;
|
||||
}
|
||||
if (next) {
|
||||
next->prev = prev;
|
||||
} else {
|
||||
dict->last = prev;
|
||||
}
|
||||
}
|
||||
/* Insert into free list */
|
||||
{
|
||||
entry->next = dict->first_free;
|
||||
dict->first_free = entry;
|
||||
}
|
||||
}
|
||||
|
||||
/* ========================== *
|
||||
* Sync flag
|
||||
* ========================== */
|
||||
|
||||
Loading…
Reference in New Issue
Block a user