diff --git a/src/config.h b/src/config.h index 617f9ec7..533a1f3c 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 0 +#define USER_DRAW_MENKOWSKI 1 #define GAME_PHYSICS_ENABLE_COLLISION 1 #define GAME_SPAWN_TESTENT 0 #define GAME_PLAYER_AIM 1 diff --git a/src/entity.h b/src/entity.h index 927d417e..a7fed20d 100644 --- a/src/entity.h +++ b/src/entity.h @@ -14,6 +14,7 @@ enum entity_prop { ENTITY_PROP_PHYSICAL_DYNAMIC, ENTITY_PROP_PHYSICAL_KINEMATIC, + ENTITY_PROP_COLLISION_DEBUG, ENTITY_PROP_CONTACT_CONSTRAINT, ENTITY_PROP_MOTOR_JOINT, ENTITY_PROP_MOUSE_JOINT, @@ -102,11 +103,18 @@ struct contact_constraint { struct math_spring_result softness; f32 pushout_velocity; +}; - /* TODO: Remove this (debugging) */ +struct collision_debug { + struct entity_handle e0; + struct entity_handle e1; struct collider_collision_points_result res; - struct xform dbg_xf0; - struct xform dbg_xf1; + + struct contact_point points[2]; + u32 num_points; + + struct xform xf0; + struct xform xf1; }; @@ -226,6 +234,7 @@ struct entity { /* TODO: Remove this (testing) */ i32 colliding; + struct collision_debug collision_debug_data; /* ====================================================================== */ diff --git a/src/game.c b/src/game.c index 9b9d546f..4502bf0f 100644 --- a/src/game.c +++ b/src/game.c @@ -30,6 +30,14 @@ struct contact_lookup { struct contact_lookup_entry *first_free_entry; }; +#if COLLIDER_DEBUG +/* TODO: Remove this (debugging) */ +struct collision_debug_lookup { + struct arena arena; + struct fixed_dict dict; +}; +#endif + GLOBAL struct { struct atomic_i32 game_thread_shutdown; struct sys_thread game_thread; @@ -57,6 +65,9 @@ GLOBAL struct { /* Bookkeeping structures */ struct contact_lookup contact_lookup; +#if COLLIDER_DEBUG + struct collision_debug_lookup collision_debug_lookup; +#endif /* Ticks */ struct sys_mutex prev_tick_mutex; @@ -280,10 +291,17 @@ INTERNAL void reset_world(void) /* Release world */ world_release(&G.tick); /* Release bookkeeping */ + arena_release(&G.collision_debug_lookup.arena); contact_lookup_release(&G.contact_lookup); } + /* Create bookkeeping */ contact_lookup_alloc(&G.contact_lookup); +#if COLLIDER_DEBUG + G.collision_debug_lookup.arena = arena_alloc(GIGABYTE(64)); + G.collision_debug_lookup.dict = fixed_dict_init(&G.collision_debug_lookup.arena, 4096); +#endif + /* Re-create world */ world_alloc(&G.tick); G.tick.continuity_gen = atomic_u64_eval(&G.prev_tick_continuity_gen) + 1; @@ -491,6 +509,7 @@ INTERNAL void create_contacts(void) CT_ASSERT(ARRAY_COUNT(constraint_ent->contact_constraint_data.points) == 2); CT_ASSERT(ARRAY_COUNT(collider_res.points) == 2); + struct contact_constraint *constraint = NULL; if (collider_res.num_points > 0) { if (!entity_is_valid_and_active(constraint_ent)) { /* Create hit event */ @@ -543,29 +562,8 @@ INTERNAL void create_contacts(void) } } } - struct contact_constraint *constraint = &constraint_ent->contact_constraint_data; + constraint = &constraint_ent->contact_constraint_data; constraint->normal = collider_res.normal; - -#if 0 - /* TODO: Remove this (debugging) */ - { - constraint->res = collider_res; - constraint->dbg_xf0 = e0_xf; - constraint->dbg_xf1 = e1_xf; - if (constraint->num_points == 0) { - if (collider_res.num_points > 0) { - ++e0->colliding; - ++e1->colliding; - } - } else { - if (collider_res.num_points == 0) { - --e0->colliding; - --e1->colliding; - } - } - } -#endif - constraint->friction = math_sqrt(e0->friction * e1->friction); /* Delete old contacts that are no longer present */ @@ -622,6 +620,54 @@ INTERNAL void create_contacts(void) } else if (constraint_ent->valid) { constraint_ent->contact_constraint_data.num_points = 0; } + + /* TODO: Remove this (debugging) */ +#if COLLIDER_DEBUG + { + struct string fdkey = STRING_FROM_BUFFER(BUFFER_FROM_STRUCT(&lookup_hash)); + struct entity_handle *dbg_ent_handle = fixed_dict_get(&G.collision_debug_lookup.dict, fdkey); + if (!dbg_ent_handle) { + dbg_ent_handle = arena_push_zero(&G.collision_debug_lookup.arena, struct entity_handle); + } + + struct entity *dbg_ent = entity_from_handle(store, *dbg_ent_handle); + + if (!dbg_ent->valid) { + /* FIXME: Entity never released */ + dbg_ent = entity_alloc(root); + entity_enable_prop(dbg_ent, ENTITY_PROP_COLLISION_DEBUG); + *dbg_ent_handle = dbg_ent->handle; + fixed_dict_set(&G.collision_debug_lookup.arena, &G.collision_debug_lookup.dict, fdkey, dbg_ent_handle); + } + + struct collision_debug *dbg = &dbg_ent->collision_debug_data; + + if (dbg->res.num_points == 0) { + if (collider_res.num_points > 0) { + ++e0->colliding; + ++e1->colliding; + } + } else { + if (collider_res.num_points == 0) { + --e0->colliding; + --e1->colliding; + } + } + dbg->e0 = e0->handle; + dbg->e1 = e1->handle; + dbg->res = collider_res; + + if (constraint) { + MEMCPY(dbg->points, constraint->points, sizeof(dbg->points)); + dbg->num_points = constraint->num_points; + } else { + dbg->num_points = 0; + } + + dbg->xf0 = e0_xf; + dbg->xf1 = e1_xf; + } +#endif } } } diff --git a/src/user.c b/src/user.c index 8d62a4ea..ce6f62fc 100644 --- a/src/user.c +++ b/src/user.c @@ -1069,10 +1069,14 @@ INTERNAL void user_update(void) #endif } - /* Draw collision */ + /* Draw constraint */ #if 1 - if (entity_has_prop(ent, ENTITY_PROP_CONTACT_CONSTRAINT)) { - struct contact_constraint *data = &ent->contact_constraint_data; + if (entity_has_prop(ent, ENTITY_PROP_COLLISION_DEBUG)) { + struct collision_debug *data = &ent->collision_debug_data; + struct collider_collision_points_result collider_res = data->res; + + //struct contact_constraint *data = &entity_from_handle(store, data->contact_constraint_ent)->contact_constraint_data; + //struct contact_constraint *data = &data->contact_constraint_data; struct entity *e0 = entity_from_handle(store, data->e0); struct entity *e1 = entity_from_handle(store, data->e1); struct collider_shape e0_collider = e0->local_collider; @@ -1080,18 +1084,15 @@ INTERNAL void user_update(void) (UNUSED)e0_collider; (UNUSED)e1_collider; - //struct xform e0_xf = entity_get_xform(e0); - //struct xform e1_xf = entity_get_xform(e1); - struct xform e0_xf = data->dbg_xf0; - struct xform e1_xf = data->dbg_xf1; - (UNUSED)e0_xf; - (UNUSED)e1_xf; - #if USER_DRAW_MENKOWSKI + struct xform e0_xf = data->xf0; + struct xform e1_xf = data->xf1; + #if 0 + /* Only draw points with large separation */ b32 should_draw = false; - for (u32 i = 0; i < ent->num_contacts; ++i) { - if (ent->contacts[i].starting_separation < -0.1) { + for (u32 i = 0; i < data->num_points; ++i) { + if (data->points[i].starting_separation < -0.1) { should_draw = true; break; } @@ -1128,13 +1129,12 @@ INTERNAL void user_update(void) /* Draw menkowski */ { - u32 color = data->res.solved ? RGBA_32_F(0, 0, 0.25, 1) : RGBA_32_F(0, 0.25, 0.25, 1); + u32 color = collider_res.solved ? RGBA_32_F(0, 0, 0.25, 1) : RGBA_32_F(0, 0.25, 0.25, 1); f32 thickness = 2; u32 detail = 512; (UNUSED)thickness; struct v2_array m = menkowski(temp.arena, &e0_collider, &e1_collider, e0_xf, e1_xf, detail); - //struct v2_array m = menkowski(temp.arena, e0_collider, e1_collider, v2_sub(ent->xf1.og, ent->xf0.og)); for (u64 i = 0; i < m.count; ++i) m.points[i] = xform_mul_v2(G.world_view, m.points[i]); draw_solid_poly_line(G.viewport_canvas, m, true, thickness, color); @@ -1161,7 +1161,7 @@ INTERNAL void user_update(void) f32 arrow_thickness = 2; f32 arrow_height = 5; struct v2 start = xform_mul_v2(G.world_view, V2(0, 0)); - struct v2 end = xform_mul_v2(G.world_view, v2_mul(v2_norm(data->normal), len)); + struct v2 end = xform_mul_v2(G.world_view, v2_mul(v2_norm(collider_res.normal), len)); draw_solid_arrow_line(G.viewport_canvas, start, end, arrow_thickness, arrow_height, color); } @@ -1171,8 +1171,8 @@ INTERNAL void user_update(void) u32 color = RGBA_32_F(1, 1, 1, 0.25); struct v2_array m = { - .points = data->res.prototype.points, - .count = data->res.prototype.len + .points = collider_res.prototype.points, + .count = collider_res.prototype.len }; for (u64 i = 0; i < m.count; ++i) m.points[i] = xform_mul_v2(G.world_view, m.points[i]); draw_solid_poly_line(G.viewport_canvas, m, true, thickness, color); @@ -1187,7 +1187,7 @@ INTERNAL void user_update(void) u32 color_second = RGBA_32_F(0, 1, 0, 0.75); u32 color_third = RGBA_32_F(0, 0, 1, 0.75); - struct collider_simplex simplex = data->res.simplex; + struct collider_simplex simplex = collider_res.simplex; struct v2 simplex_points[] = { simplex.a, simplex.b, simplex.c }; for (u64 i = 0; i < ARRAY_COUNT(simplex_points); ++i) simplex_points[i] = xform_mul_v2(G.world_view, simplex_points[i]); struct v2_array simplex_array = { .count = simplex.len, .points = simplex_points }; @@ -1212,11 +1212,11 @@ INTERNAL void user_update(void) #endif #if 1 - /* Draw contacts */ + /* Draw contact points */ { f32 radius = 5; - for (u32 i = 0; i < ent->contact_constraint_data.num_points; ++i) { - struct contact_point point = ent->contact_constraint_data.points[i]; + for (u32 i = 0; i < data->num_points; ++i) { + struct contact_point point = data->points[i]; #if 0 struct v2 p0 = xform_mul_v2(e0_xf, contact.point_local_e0); struct v2 p1 = xform_mul_v2(e1_xf, contact.point_local_e1); @@ -1239,7 +1239,7 @@ INTERNAL void user_update(void) f32 arrow_thickness = 2; f32 arrow_height = 5; struct v2 start = xform_mul_v2(G.world_view, dbg_pt); - struct v2 end = xform_mul_v2(G.world_view, v2_add(dbg_pt, v2_mul(v2_norm(ent->contact_constraint_data.normal), len))); + struct v2 end = xform_mul_v2(G.world_view, v2_add(dbg_pt, v2_mul(v2_norm(collider_res.normal), len))); draw_solid_arrow_line(G.viewport_canvas, start, end, arrow_thickness, arrow_height, color); } #if 0 @@ -1262,7 +1262,7 @@ INTERNAL void user_update(void) "num contacts: %F" ); struct string text = string_format(temp.arena, fmt, - FMT_SINT(data->res.path), + FMT_SINT(collider_res.path), FMT_UINT(e0->handle.idx), FMT_UINT(e1->handle.idx), FMT_HEX(point.id), @@ -1292,7 +1292,6 @@ INTERNAL void user_update(void) } } -#if 1 /* Draw clipping */ { f32 thickness = 2; @@ -1300,7 +1299,7 @@ INTERNAL void user_update(void) u32 color_line = RGBA_32_F(1, 0, 1, 0.5); u32 color_a = RGBA_32_F(1, 0, 0, 0.5); u32 color_b = RGBA_32_F(0, 1, 0, 0.5); - struct collider_collision_points_result res = ent->contact_constraint_data.res; + struct collider_collision_points_result res = collider_res; { struct v2 a = xform_mul_v2(G.world_view, res.a0); struct v2 b = xform_mul_v2(G.world_view, res.b0); @@ -1316,7 +1315,6 @@ INTERNAL void user_update(void) draw_solid_circle(G.viewport_canvas, b, radius, color_b, 10); } } -#endif #endif } #endif