create separate entities for visualizing collision debug info

This commit is contained in:
jacob 2025-01-03 17:24:34 -06:00
parent 9981b600a8
commit 33df739cc6
4 changed files with 105 additions and 52 deletions

View File

@ -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

View File

@ -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;
/* ====================================================================== */

View File

@ -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
}
}
}

View File

@ -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