diff --git a/src/collider.c b/src/collider.c index a9c2cdc2..10897dc4 100644 --- a/src/collider.c +++ b/src/collider.c @@ -10,7 +10,9 @@ u32 collider_debug_steps = U32_MAX; INTERNAL void _dbgbreakable(void) { +#if RTC DEBUGBREAKABLE; +#endif } #define DBGSTEP \ diff --git a/src/config.h b/src/config.h index 533a1f3c..7200689f 100644 --- a/src/config.h +++ b/src/config.h @@ -36,7 +36,7 @@ #define GAME_PHYSICS_ENABLE_WARM_STARTING 1 #define GAME_PHYSICS_ENABLE_RELAXATION 1 -#define USER_DRAW_MENKOWSKI 1 +#define USER_DRAW_MENKOWSKI 0 #define GAME_PHYSICS_ENABLE_COLLISION 1 #define GAME_SPAWN_TESTENT 0 #define GAME_PLAYER_AIM 1 @@ -53,8 +53,7 @@ #define USER_INTERP_OFFSET_TICK_RATIO 1.1 #define USER_INTERP_ENABLED 1 -//#define COLLIDER_DEBUG RTC -#define COLLIDER_DEBUG 1 +#define COLLIDER_DEBUG RTC /* ========================== * * Settings diff --git a/src/game.c b/src/game.c index f325044c..9d2f9c96 100644 --- a/src/game.c +++ b/src/game.c @@ -291,7 +291,9 @@ INTERNAL void reset_world(void) /* Release world */ world_release(&G.tick); /* Release bookkeeping */ +#if COLLIDER_DEBUG arena_release(&G.collision_debug_lookup.arena); +#endif contact_lookup_release(&G.contact_lookup); } @@ -1462,12 +1464,9 @@ INTERNAL void integrate_positions_from_velocities(f32 dt) * TESTING TOI * ========================== */ - - -#if 0 /* Takes 2 shapes and their xforms at t=0 and t=1. * Returns time of impact in range [0, 1]. */ -INTERNAL f32 toi(struct collider_shape c0, struct collider_shape c1, +INTERNAL f32 toi(struct collider_shape *c0, struct collider_shape *c1, struct xform xf0_t0, struct xform xf1_t0, struct xform xf0_t1, struct xform xf1_t1, f32 tolerance) @@ -1476,7 +1475,7 @@ INTERNAL f32 toi(struct collider_shape c0, struct collider_shape c1, struct v2 dir; struct v2 dir_neg; { - struct collider_closest_points_result closest_points_res = collider_closest_points(&c0, &c1, xf0_t0, xf1_t0); + struct collider_closest_points_result closest_points_res = collider_closest_points(c0, c1, xf0_t0, xf1_t0); if (closest_points_res.colliding) { /* Shapes are penetrating at t=0 */ return 0; @@ -1488,8 +1487,8 @@ INTERNAL f32 toi(struct collider_shape c0, struct collider_shape c1, /* Safety check that shapes penetrate at t=1 */ f32 sep; { - struct v2 p0 = collider_support_point(&c0, xf0_t1, dir); - struct v2 p1 = collider_support_point(&c1, xf1_t1, dir_neg); + struct v2 p0 = collider_support_point(c0, xf0_t1, dir); + struct v2 p1 = collider_support_point(c1, xf1_t1, dir_neg); sep = v2_dot(dir, v2_sub(p1, p0)); if (sep > tolerance) { /* Shapes are not penetrating at t=1 */ @@ -1505,8 +1504,8 @@ INTERNAL f32 toi(struct collider_shape c0, struct collider_shape c1, struct xform xf0 = xform_lerp(xf0_t0, xf0_t1, t); struct xform xf1 = xform_lerp(xf1_t0, xf1_t1, t); - struct v2 p0 = collider_support_point(&c0, xf0, dir); - struct v2 p1 = collider_support_point(&c1, xf1, dir_neg); + struct v2 p0 = collider_support_point(c0, xf0, dir); + struct v2 p1 = collider_support_point(c1, xf1, dir_neg); sep = v2_dot(dir, v2_sub(p1, p0)); @@ -1516,12 +1515,90 @@ INTERNAL f32 toi(struct collider_shape c0, struct collider_shape c1, } else { t1 = t; } - t = (t1 - t0) / 2.0; + t = (t1 + t0) / 2.0; } return t; } -#endif + +INTERNAL f32 determine_earliest_toi(f32 dt, f32 tolerance) +{ + __prof; + f32 smallest_t = 1; + + struct entity_store *store = G.tick.entity_store; + //struct entity *root = G.root; + + + for (u64 e0_index = 0; e0_index < store->reserved; ++e0_index) { + struct entity *e0 = &store->entities[e0_index]; + if (!entity_is_valid_and_active(e0)) continue; + if (!(entity_has_prop(e0, ENTITY_PROP_PHYSICAL_DYNAMIC) || entity_has_prop(e0, ENTITY_PROP_PHYSICAL_KINEMATIC))) continue; + if (e0->local_collider.count <= 0) continue; + + struct collider_shape e0_collider = e0->local_collider; + struct xform e0_xf_t0 = entity_get_xform(e0); + struct xform e0_xf_t1 = e0_xf_t0; + { + /* Calculate xform at t=1 */ + struct v2 linear_velocity = v2_clamp_len(e0->linear_velocity, GAME_MAX_LINEAR_VELOCITY); + f32 angular_velocity = clamp_f32(e0->angular_velocity, -GAME_MAX_ANGULAR_VELOCITY, GAME_MAX_ANGULAR_VELOCITY); + struct v2 tick_linear_velocity = v2_mul(linear_velocity, dt); + f32 tick_angular_velocity = angular_velocity * dt; + e0_xf_t1.og = v2_add(e0_xf_t1.og, tick_linear_velocity); + e0_xf_t1 = xform_basis_rotated_world(e0_xf_t1, tick_angular_velocity); + } + + + /* Start e1 index at e0 index + 1 to prevent redundant checks */ + for (u64 e1_index = e0_index + 1; e1_index < store->reserved; ++e1_index) { + struct entity *e1 = &store->entities[e1_index]; + if (e1 == e0) continue; + if (!entity_is_valid_and_active(e1)) continue; + if (!(entity_has_prop(e1, ENTITY_PROP_PHYSICAL_DYNAMIC) || entity_has_prop(e1, ENTITY_PROP_PHYSICAL_KINEMATIC))) continue; + if (e1->local_collider.count <= 0) continue; + + struct collider_shape e1_collider = e1->local_collider; + struct xform e1_xf_t0 = entity_get_xform(e1); + struct xform e1_xf_t1 = e1_xf_t0; + { + /* Calculate xform at t=1 */ + struct v2 linear_velocity = v2_clamp_len(e1->linear_velocity, GAME_MAX_LINEAR_VELOCITY); + f32 angular_velocity = clamp_f32(e1->angular_velocity, -GAME_MAX_ANGULAR_VELOCITY, GAME_MAX_ANGULAR_VELOCITY); + struct v2 tick_linear_velocity = v2_mul(linear_velocity, dt); + f32 tick_angular_velocity = angular_velocity * dt; + e1_xf_t1.og = v2_add(e1_xf_t1.og, tick_linear_velocity); + e1_xf_t1 = xform_basis_rotated_world(e1_xf_t1, tick_angular_velocity); + } + + f32 t = toi(&e0_collider, &e1_collider, e0_xf_t0, e1_xf_t0, e0_xf_t1, e1_xf_t1, tolerance); + if (t != 0 && t < smallest_t) { + smallest_t = t; + } + + } + } + + return smallest_t; +} + + + + + + + + + + + + + + + + + + @@ -1672,7 +1749,7 @@ INTERNAL void game_update(struct game_cmd_array game_cmds) { struct sprite_sheet_span span = sprite_sheet_get_span(sheet, ent->sprite_span_name); - f64 time_in_frame = ent->animation_time_in_frame + G.tick.dt; + f64 time_in_frame = ent->animation_time_in_frame + dt; u64 frame_index = ent->animation_frame; if (frame_index < span.start || frame_index > span.end) { frame_index = span.start; @@ -2140,33 +2217,42 @@ INTERNAL void game_update(struct game_cmd_array game_cmds) (UNUSED)integrate_positions_from_velocities; #if 1 { - integrate_velocities_from_forces(dt); - create_contacts(); - create_mouse_joints(game_cmds); + f32 remaining_dt = dt; + while (remaining_dt > 0) { + f32 min_toi = 0.00001f; + f32 tolerance = 0.0001f; + f32 earliest_toi = max_f32(determine_earliest_toi(remaining_dt, tolerance), min_toi); + f32 step_dt = remaining_dt * earliest_toi; - prepare_contacts(); - prepare_motor_joints(); - prepare_mouse_joints(); + integrate_velocities_from_forces(step_dt); + create_contacts(); + create_mouse_joints(game_cmds); - f32 substep_dt = dt / GAME_PHYSICS_SUBSTEPS; - for (u32 i = 0; i < GAME_PHYSICS_SUBSTEPS; ++i) { -#if GAME_PHYSICS_ENABLE_WARM_STARTING - warm_start_contacts(); - warm_start_motor_joints(); - warm_start_mouse_joints(); -#endif + prepare_contacts(); + prepare_motor_joints(); + prepare_mouse_joints(); -#if GAME_PHYSICS_ENABLE_COLLISION - solve_contacts(substep_dt, true); -#endif - solve_motor_joints(substep_dt); - solve_mouse_joints(substep_dt); + f32 substep_dt = step_dt / GAME_PHYSICS_SUBSTEPS; + for (u32 i = 0; i < GAME_PHYSICS_SUBSTEPS; ++i) { + #if GAME_PHYSICS_ENABLE_WARM_STARTING + warm_start_contacts(); + warm_start_motor_joints(); + warm_start_mouse_joints(); + #endif - integrate_positions_from_velocities(substep_dt); + #if GAME_PHYSICS_ENABLE_COLLISION + solve_contacts(substep_dt, true); + #endif + solve_motor_joints(substep_dt); + solve_mouse_joints(substep_dt); -#if GAME_PHYSICS_ENABLE_COLLISION && GAME_PHYSICS_ENABLE_RELAXATION - solve_contacts(substep_dt, false); /* Relaxation */ -#endif + integrate_positions_from_velocities(substep_dt); + + #if GAME_PHYSICS_ENABLE_COLLISION && GAME_PHYSICS_ENABLE_RELAXATION + solve_contacts(substep_dt, false); /* Relaxation */ + #endif + } + remaining_dt -= step_dt; } } #endif