diff --git a/src/phys.c b/src/phys.c index f2597a27..8d784533 100644 --- a/src/phys.c +++ b/src/phys.c @@ -98,8 +98,8 @@ void phys_create_and_update_contacts(struct phys_step_ctx *ctx, f32 elapsed_dt, b32 create_constraint = collider_res.num_points > 0; if (create_constraint) { struct v2 normal = collider_res.normal; - struct v2 dir0 = e0->test_dir; - struct v2 dir1 = e1->test_dir; + struct v2 dir0 = e0->collision_dir; + struct v2 dir1 = e1->collision_dir; f32 threshold = 0.5; if (create_constraint && !v2_is_zero(dir0)) { create_constraint = v2_dot(dir0, normal) > threshold; diff --git a/src/rand.c b/src/rand.c index 510d2418..5c4f2c50 100644 --- a/src/rand.c +++ b/src/rand.c @@ -41,6 +41,11 @@ u64 rand_u64_from_seed(u64 seed) return seed; } +u64 rand_u64_from_seeds(u64 seed_a, u64 seed_b) +{ + return rand_u64_from_seed((seed_a * 3) + seed_b); +} + f64 rand_f64_from_seed(u64 seed, f64 range_start, f64 range_end) { return range_start + (range_end - range_start) * ((f64)(rand_u64_from_seed(seed) % F64_RAND_MAX) / (f64)F64_RAND_MAX); diff --git a/src/rand.h b/src/rand.h index 1229884b..5d09d624 100644 --- a/src/rand.h +++ b/src/rand.h @@ -11,6 +11,7 @@ u64 rand_u64_from_state(struct rand_state *state); f64 rand_f64_from_state(struct rand_state *state, f64 range_start, f64 range_end); u64 rand_u64_from_seed(u64 seed); +u64 rand_u64_from_seeds(u64 seed_a, u64 seed_b); f64 rand_f64_from_seed(u64 seed, f64 range_start, f64 range_end); #endif diff --git a/src/sim_ent.h b/src/sim_ent.h index fb979bb9..6fe3f1d9 100644 --- a/src/sim_ent.h +++ b/src/sim_ent.h @@ -73,28 +73,6 @@ enum sim_ent_prop { struct sim_ent { struct sim_snapshot *ss; - - - - - - - - - - - - - struct v2 test_dir; - - - - - - - - - /* ====================================================================== */ /* Metadata */ @@ -191,7 +169,6 @@ struct sim_ent { u8 tile_chunk_tiles[SIM_TILES_PER_CHUNK_SQRT * SIM_TILES_PER_CHUNK_SQRT]; struct v2i32 tile_chunk_index; - /* ====================================================================== */ /* Client */ @@ -219,6 +196,7 @@ struct sim_ent { /* ====================================================================== */ /* Collider */ + struct v2 collision_dir; /* If set, then only collisions coming from this direction will generate contacts (used for walls to prevent ghost collisions) */ struct collider_shape local_collider; #if COLLIDER_DEBUG diff --git a/src/sim_step.c b/src/sim_step.c index 62326b4b..c02f3442 100644 --- a/src/sim_step.c +++ b/src/sim_step.c @@ -461,14 +461,13 @@ INTERNAL void test_generate_walls(struct sim_snapshot *world) for (i32 tile_y = 0; tile_y < y_iterations; ++tile_y) { i32 wall_start = -1; i32 wall_end = -1; - i32 last_wall_dir = -1; + i32 wall_dir = -1; for (i32 tile_x = 0; tile_x < x_iterations; ++tile_x) { - i32 wall_dir = -1; + i32 desired_wall_dir = -1; 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_top_wall = false; if (tile_x < SIM_TILES_PER_CHUNK_SQRT) { enum sim_tile_kind top_tile = SIM_TILE_KIND_NONE; if (tile_y == 0) { @@ -481,29 +480,25 @@ INTERNAL void test_generate_walls(struct sim_snapshot *world) } if (tile == SIM_TILE_KIND_WALL) { /* Process wall tile */ - should_have_top_wall = top_tile != SIM_TILE_KIND_WALL; - wall_dir = 0; + if (top_tile != SIM_TILE_KIND_WALL) { + desired_wall_dir = 0; + } } else { /* Process non-wall tile */ - should_have_top_wall = top_tile == SIM_TILE_KIND_WALL; - wall_dir = 2; + if (top_tile == SIM_TILE_KIND_WALL) { + desired_wall_dir = 2; + } } } - if (should_have_top_wall) { - if (wall_start < 0) { - /* Start wall */ - wall_start = tile_x; - } - /* Extend wall */ - wall_end = tile_x + 1; - last_wall_dir = wall_dir; - } else if (wall_end >= 0) { - /* Stop wall */ + + /* Stop wall */ + if (wall_dir >= 0 && desired_wall_dir != wall_dir) { 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); + start_hash = rand_u64_from_seeds(start_hash, wall_dir); struct dict_entry *entry = dict_get_entry(&horizontal_ends_dict, start_hash); if (entry) { /* Existing wall exists accross chunk boundary */ @@ -515,17 +510,29 @@ INTERNAL void test_generate_walls(struct sim_snapshot *world) node = arena_push(scratch.arena, struct wall_node); node->start = start; node->next = first_wall; - node->wall_dir = last_wall_dir; + node->wall_dir = wall_dir; first_wall = node; } node->end = end; if (wall_end == SIM_TILES_PER_CHUNK_SQRT) { u64 end_hash = rand_u64_from_seed(*(u64 *)&end); + end_hash = rand_u64_from_seeds(end_hash, wall_dir); dict_set(scratch.arena, &horizontal_ends_dict, end_hash, node); } wall_start = -1; wall_end = -1; - last_wall_dir = -1; + wall_dir = -1; + } + + /* Start / extend wall */ + if (desired_wall_dir >= 0) { + if (wall_dir != desired_wall_dir) { + /* Start wall */ + wall_start = tile_x; + } + /* Extend wall */ + wall_end = tile_x + 1; + wall_dir = desired_wall_dir; } } } @@ -543,15 +550,14 @@ INTERNAL void test_generate_walls(struct sim_snapshot *world) for (i32 tile_x = 0; tile_x < x_iterations; ++tile_x) { i32 wall_start = -1; i32 wall_end = -1; - i32 last_wall_dir = -1; + i32 wall_dir = -1; for (i32 tile_y = 0; tile_y < y_iterations; ++tile_y) { - i32 wall_dir = -1; + i32 desired_wall_dir = -1; 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) { @@ -564,29 +570,25 @@ INTERNAL void test_generate_walls(struct sim_snapshot *world) } if (tile == SIM_TILE_KIND_WALL) { /* Process wall tile */ - should_have_left_wall = left_tile != SIM_TILE_KIND_WALL; - wall_dir = 3; + if (left_tile != SIM_TILE_KIND_WALL) { + desired_wall_dir = 3; + } } else { /* Process non-wall tile */ - should_have_left_wall = left_tile == SIM_TILE_KIND_WALL; - wall_dir = 1; + if (left_tile == SIM_TILE_KIND_WALL) { + desired_wall_dir = 1; + } } } - if (should_have_left_wall) { - if (wall_start < 0) { - /* Start wall */ - wall_start = tile_y; - } - /* Extend wall */ - wall_end = tile_y + 1; - last_wall_dir = wall_dir; - } else if (wall_end >= 0) { - /* Stop wall */ + + /* Stop wall */ + if (wall_dir >= 0 && desired_wall_dir != wall_dir) { 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); + start_hash = rand_u64_from_seeds(start_hash, wall_dir); struct dict_entry *entry = dict_get_entry(&vertical_ends_dict, start_hash); if (entry) { /* Existing wall exists accross chunk boundary */ @@ -598,17 +600,29 @@ INTERNAL void test_generate_walls(struct sim_snapshot *world) node = arena_push(scratch.arena, struct wall_node); node->start = start; node->next = first_wall; - node->wall_dir = last_wall_dir; + node->wall_dir = wall_dir; first_wall = node; } node->end = end; if (wall_end == SIM_TILES_PER_CHUNK_SQRT) { u64 end_hash = rand_u64_from_seed(*(u64 *)&end); + end_hash = rand_u64_from_seeds(end_hash, wall_dir); dict_set(scratch.arena, &vertical_ends_dict, end_hash, node); } wall_start = -1; wall_end = -1; - last_wall_dir = -1; + wall_dir = -1; + } + + /* Start / extend wall */ + if (desired_wall_dir >= 0) { + if (wall_dir != desired_wall_dir) { + /* Start wall */ + wall_start = tile_y; + } + /* Extend wall */ + wall_end = tile_y + 1; + wall_dir = desired_wall_dir; } } } @@ -629,24 +643,9 @@ INTERNAL void test_generate_walls(struct sim_snapshot *world) wall_ent->local_collider.count = 2; wall_ent->local_collider.points[1] = v2_sub(end, start); - switch (node->wall_dir) { - case 0: - { - wall_ent->test_dir = V2(0, -1); - } break; - case 1: - { - wall_ent->test_dir = V2(1, 0); - } break; - case 2: - { - wall_ent->test_dir = V2(0, 1); - } break; - case 3: - { - wall_ent->test_dir = V2(-1, 0); - } break; - } + LOCAL_PERSIST struct v2 dirs[4] = { V2(0, -1), V2(1, 0), V2(0, 1), V2(-1, 0) }; + ASSERT(node->wall_dir >= 0 && (u32)node->wall_dir < ARRAY_COUNT(dirs)); + wall_ent->collision_dir = dirs[node->wall_dir]; sim_ent_activate(wall_ent, world->tick); } diff --git a/src/user.c b/src/user.c index 216367b7..8b43bf7b 100644 --- a/src/user.c +++ b/src/user.c @@ -410,10 +410,10 @@ INTERNAL struct string get_ent_debug_text(struct arena *arena, struct sim_ent *e f32 angular_velocity = ent->angular_velocity; res.len += string_format(arena, LIT("pos: (%F, %F)\n"), FMT_FLOAT(xf.og.x), FMT_FLOAT(xf.og.y)).len; res.len += string_format(arena, LIT("linear velocity: (%F, %F)\n"), FMT_FLOAT(linear_velocity.x), FMT_FLOAT(linear_velocity.y)).len; - res.len += string_format(arena, LIT("angular velocity: %F\n"), FMT_FLOAT(angular_velocity)).len; + res.len += string_format(arena, LIT("angular velocity: %F\n"), FMT_FLOAT(angular_velocity)).len; /* Test */ - res.len += string_format(arena, LIT("test_dir: (%F, %F)\n"), FMT_FLOAT(ent->test_dir.x), FMT_FLOAT(ent->test_dir.y)).len; + res.len += string_format(arena, LIT("collision dir: (%F, %F)\n"), FMT_FLOAT(ent->collision_dir.x), FMT_FLOAT(ent->collision_dir.y)).len; /* Children */ if (!sim_ent_id_is_nil(ent->first) || !sim_ent_id_is_nil(ent->last)) {