From 6951fa62e3eb97ad63671f07320b4c75990cfac5 Mon Sep 17 00:00:00 2001 From: jacob Date: Fri, 11 Oct 2024 14:32:01 -0500 Subject: [PATCH] popping probably fixed --- src/collider.c | 75 +++++++++++------ src/config.h | 10 ++- src/entity.h | 6 +- src/game.c | 84 ++++++++++++-------- src/math.h | 7 ++ src/user.c | 212 ++++++++++++++++++++++++++++++------------------- 6 files changed, 255 insertions(+), 139 deletions(-) diff --git a/src/collider.c b/src/collider.c index 69df138d..ade8d335 100644 --- a/src/collider.c +++ b/src/collider.c @@ -110,10 +110,14 @@ INTERNAL u32 collider_support_point_index(struct collider_shape *a, struct xform /* TODO: Could probably binary search for largest dot since shape is convex */ struct v2 *points = a->points; u32 count = a->count; + + dir = v2_rotated(dir, -xform_get_rotation(xf)); + dir = v2_mul_v2(dir, xform_get_scale(xf)); + u32 furthest = 0; - f32 furthest_dot = v2_dot(dir, xform_mul_v2(xf, points[0])); - for (u32 i = 1; i < count; ++i) { - struct v2 p = xform_mul_v2(xf, points[i]); + f32 furthest_dot = -F32_INFINITY; + for (u32 i = 0; i < count; ++i) { + struct v2 p = points[i]; f32 dot = v2_dot(dir, p); if (dot > furthest_dot) { furthest = i; @@ -143,11 +147,16 @@ struct collider_collision_points_result collider_collision_points(struct collide (UNUSED)radius1; /* TODO: Parameterize */ - //const f32 tolerance = 0.f; /* How close can shapes be before collision is considered */ - const f32 tolerance = 0.005f; /* How close can shapes be before collision is considered */ - //const f32 tolerance = 0.05f; /* How close can shapes be before collision is considered */ + /* How close can non-overlapping shapes be before collision is considered */ + //const f32 tolerance = 0.f; + const f32 tolerance = 0.05f; + //const f32 tolerance = 0.05f; + + /* NOTE: Should always be less than tolerance, since colliding=true if origin is within this distance. */ const f32 min_unique_pt_dist_sq = 0.0001f * 0.0001f; - const u32 max_epa_iterations = 64; /* To prevent extremely large prototypes when origin is in exact center of rounded feature */ + + /* To prevent extremely large prototypes when origin is in exact center of rounded feature */ + const u32 max_epa_iterations = 64; b32 colliding = false; b32 simplex_is_closest_edge = false; @@ -199,8 +208,14 @@ struct collider_collision_points_result collider_collision_points(struct collide s.a = m; s.len = 2; - /* Third point is support point in direction of line normal towards origin */ - dir = v2_perp_towards_dir(v2_sub(s.b, s.a), v2_neg(s.a)); + if (math_fabs(v2_wedge(v2_sub(s.b, s.a), v2_neg(s.a))) <= min_unique_pt_dist_sq) { + /* Third point is support point in direction of line normal towards origin */ + dir = v2_perp(v2_sub(s.b, s.a)); + } else { + /* Third point is support point in direction of line normal towards origin */ + dir = v2_perp_towards_dir(v2_sub(s.b, s.a), v2_neg(s.a)); + } + } { @@ -224,13 +239,15 @@ struct collider_collision_points_result collider_collision_points(struct collide s.a = m; s.len = 3; - if (math_fabs(v2_wedge(v2_sub(s.b, s.a), v2_neg(s.a))) <= min_unique_pt_dist_sq || +#if 1 + if (colliding || math_fabs(v2_wedge(v2_sub(s.c, s.a), v2_neg(s.a))) <= min_unique_pt_dist_sq || math_fabs(v2_wedge(v2_sub(s.c, s.b), v2_neg(s.b))) <= min_unique_pt_dist_sq) { /* Simplex lies on origin */ colliding = true; break; } +#endif } /* Determine region of the simplex in which the origin lies */ @@ -305,10 +322,10 @@ struct collider_collision_points_result collider_collision_points(struct collide * Epa (to find collision normal from inside shape) * ========================== */ - //const f32 epa_epsilon_sq = 0; - //const f32 epa_epsilon_sq = 0.01f * 0.01f; - //const f32 epa_epsilon_sq = 0.001f * 0.001f; - const f32 epa_epsilon_sq = F32_INFINITY; + //const f32 epa_normal_epsilon_sq = 0; + //const f32 epa_normal_epsilon_sq = 0.01f * 0.01f; + //const f32 epa_normal_epsilon_sq = 0.001f * 0.001f; + const f32 epa_normal_epsilon_sq = F32_INFINITY; proto = arena_dry_push(scratch.arena, struct v2); proto_count = 0; @@ -321,6 +338,8 @@ struct collider_collision_points_result collider_collision_points(struct collide proto_count = 3; } + i32 winding = v2_winding(v2_sub(s.c, s.a), v2_sub(s.b, s.a)); + u32 epa_iterations = 0; while (colliding) { ++epa_iterations; @@ -340,11 +359,12 @@ struct collider_collision_points_result collider_collision_points(struct collide struct v2 vse = v2_sub(pe, ps); struct v2 vso = v2_neg(ps); - struct v2 vsd = v2_mul(vse, (v2_dot(vso, vse) / v2_len_sq(vse))); + struct v2 vsd = v2_mul(vse, clamp_f32(v2_dot(vso, vse) / v2_len_sq(vse), 0, 1)); + //struct v2 vsd = v2_mul(vse, v2_dot(vso, vse) / v2_len_sq(vse)); struct v2 pd = v2_add(ps, vsd); f32 pd_len_sq = v2_len_sq(pd); - if (pd_len_sq < pen_len_sq) { + if (pd_len_sq < pen_len_sq - min_unique_pt_dist_sq) { pen_ps_index = ps_index; pen_pe_index = pe_index; pen_len_sq = pd_len_sq; @@ -364,14 +384,17 @@ struct collider_collision_points_result collider_collision_points(struct collide struct v2 a = proto[pen_ps_index]; struct v2 b = proto[pen_pe_index]; struct v2 vab = v2_sub(b, a); - if (pen_len_sq < epa_epsilon_sq) { +#if 0 + if (pen_len_sq < epa_normal_epsilon_sq) { /* Next point is in direction of line normal pointing outwards from simplex */ struct v2 n = proto[(pen_pe_index < proto_count - 1) ? (pen_pe_index + 1) : 0]; /* Next point along prototype after edge */ dir = v2_perp_towards_dir(vab, v2_sub(a, n)); } else { dir = v2_perp_towards_dir(vab, a); } - +#else + dir = v2_mul(v2_perp(vab), winding); +#endif } m = menkowski_point(shape0, shape1, xf0, xf1, dir); @@ -391,7 +414,7 @@ struct collider_collision_points_result collider_collision_points(struct collide } if (!unique || epa_iterations >= max_epa_iterations) { res.path = 1; - if (pen_len_sq < epa_epsilon_sq) { + if (pen_len_sq < epa_normal_epsilon_sq) { normal = v2_norm(dir); } else { normal = v2_norm(pen); @@ -599,12 +622,16 @@ struct collider_collision_points_result collider_collision_points(struct collide f32 w = 1 / vab0_wedge_normal; a0t = clamp_f32(va0a1_wedge_normal * w, 0, 1); b0t = clamp_f32(vb0b1_wedge_normal * -w, 0, 1); + } else { + DEBUGBREAKABLE; } if (math_fabs(vab1_wedge_normal) > 0.01f) { f32 w = 1 / vab1_wedge_normal; a1t = clamp_f32(-va0a1_wedge_normal * w, 0, 1); b1t = clamp_f32(-vb0b1_wedge_normal * -w, 0, 1); + } else { + DEBUGBREAKABLE; } } @@ -624,13 +651,15 @@ struct collider_collision_points_result collider_collision_points(struct collide b32 ignore_a = false; b32 ignore_b = false; - if (v2_len_sq(v2_sub(contact_b, contact_a)) < 0.001f) { +#if 1 + if (v2_len_sq(v2_sub(contact_b, contact_a)) < (0.005f * 0.005f)) { if (a_sep > b_sep) { ignore_a = true; } else { ignore_b = true; } } +#endif if (a_sep < tolerance && !ignore_a) { struct collider_collision_point *point = &points[num_points++]; @@ -985,7 +1014,7 @@ struct collider_collision_points_result collider_collision_points(struct collide * Epa (to find collision normal from inside shape) * ========================== */ - const f32 epa_epsilon_sq = 0.001f * 0.001f; + const f32 epa_normal_epsilon_sq = 0.001f * 0.001f; proto = arena_dry_push(scratch.arena, struct v2); proto_count = 0; @@ -1041,7 +1070,7 @@ struct collider_collision_points_result collider_collision_points(struct collide struct v2 a = proto[pen_ps_index]; struct v2 b = proto[pen_pe_index]; struct v2 vab = v2_sub(b, a); - if (pen_len_sq < epa_epsilon_sq) { + if (pen_len_sq < epa_normal_epsilon_sq) { /* Next point is in direction of line normal pointing outwards from simplex */ struct v2 n = proto[(pen_pe_index < proto_count - 1) ? (pen_pe_index + 1) : 0]; /* Next point along prototype after edge */ dir = v2_perp_towards_dir(vab, v2_sub(a, n)); @@ -1068,7 +1097,7 @@ struct collider_collision_points_result collider_collision_points(struct collide } if (!unique || epa_iterations >= max_epa_iterations) { res.path = 1; - if (pen_len_sq < epa_epsilon_sq) { + if (pen_len_sq < epa_normal_epsilon_sq) { normal = v2_norm(dir); } else { normal = v2_norm(pen); diff --git a/src/config.h b/src/config.h index 9cad9d77..fda38bcc 100644 --- a/src/config.h +++ b/src/config.h @@ -32,13 +32,17 @@ #define GAME_FPS 50.0 #define GAME_TIMESCALE 1.0 -#define GAME_PHYSICS_SUBSTEPS 8 -#define GAME_PHYSICS_ENABLE_COLLISION 1 +#define GAME_PHYSICS_SUBSTEPS 4 #define GAME_PHYSICS_ENABLE_WARM_STARTING 1 #define GAME_PHYSICS_ENABLE_RELAXATION 1 -#define GAME_PHYSICS_ENABLE_GROUND_FRICTION 0 +#define USER_DRAW_MENKOWSKI 0 +#define GAME_PHYSICS_ENABLE_GROUND_FRICTION 0 +#define GAME_PHYSICS_ENABLE_COLLISION 1 #define GAME_SPAWN_LOTS 1 +#define GAME_SPAWN_TESTENT 0 +#define GAME_SPAWN_BOX 1 +#define GAME_PLAYER_AIM 0 #define GAME_MAX_LINEAR_VELOCITY 100 #define GAME_MAX_ANGULAR_VELOCITY ((2 * PI) * 20) diff --git a/src/entity.h b/src/entity.h index 33111e0a..5f163e46 100644 --- a/src/entity.h +++ b/src/entity.h @@ -119,7 +119,6 @@ struct entity { /* TODO: Remove this (testing) */ i32 colliding; - struct collider_collision_points_result res; b32 test_torque_applied; @@ -140,6 +139,11 @@ struct entity { struct contact contacts[2]; u32 num_contacts; + /* TODO: Remove this (debugging) */ + struct collider_collision_points_result res; + struct xform dbg_xf0; + struct xform dbg_xf1; + diff --git a/src/game.c b/src/game.c index 75a147b4..725be8e0 100644 --- a/src/game.c +++ b/src/game.c @@ -126,18 +126,22 @@ INTERNAL void spawn_test_entities(f32 offset) //const f32 offset_all = -20000; //const f32 offset_all = -5000; const f32 offset_all = 0; + (UNUSED)offset; + (UNUSED)offset_all; /* Player */ struct entity *player_ent = entity_nil(); //if (!G.extra_spawn) { { + + struct entity *e = entity_alloc(root); + +#if 1 //struct v2 pos = V2(0.25, -10); //struct v2 pos = V2(0.25, -7); //struct v2 pos = V2(0.25, -5.27); struct v2 pos = V2(0.5, -1); - //struct v2 pos = V2(1.1230469346046448864129274625156, -1); /* Touching right side of box */ - //struct v2 pos = V2(1.1230469346046448864129274625156 - 0.0001, -1); /* Touching right side of box */ - //struct v2 pos = V2(0.374142020941, -0.246118023992); /* Touching glitch spot */ + //struct v2 pos = V2(1.0295, -1); pos = v2_add(pos, V2(0, offset)); pos = v2_add(pos, V2(0, offset_all)); @@ -146,19 +150,21 @@ INTERNAL void spawn_test_entities(f32 offset) //struct v2 size = V2(0.5, 0.5); struct v2 size = V2(1.0, 0.5); //f32 r = PI; - f32 r = PI / 4; + //f32 r = PI / 4; //f32 r = PI / 3; //f32 r = 0.05; //f32 r = PI / 2; - //f32 r = 0; + //f32 r = PI; + f32 r = 0; //f32 skew = PI / 4; //f32 skew = 0.9f; f32 skew = 0; - struct entity *e = entity_alloc(root); - struct xform xf = XFORM_TRS(.t = pos, .r = r, .s = size); xf = xform_skewed_to(xf, skew); +#else + struct xform xf = { .bx = {0.282509595, -0.412540406}, .by = {0.412528992, 0.282521814}, .og = {3.34883189, -1.35877287} }; +#endif entity_set_xform(e, xf); //e->sprite = sprite_tag_from_path(STR("res/graphics/tim.ase")); @@ -172,6 +178,7 @@ INTERNAL void spawn_test_entities(f32 offset) //e->control_force = 4500; e->control_force = 1200; #else + //e->control_force = 5000; e->control_force = 250; #endif e->control_torque = 10; @@ -184,29 +191,29 @@ INTERNAL void spawn_test_entities(f32 offset) e->linear_ground_friction = 1000; e->angular_ground_friction = 100; - //entity_enable_prop(e, ENTITY_PROP_TEST); + entity_enable_prop(e, ENTITY_PROP_TEST); player_ent = e; } -#if 0 +#if GAME_SPAWN_TESTENT { + struct entity *e = entity_alloc(root); + +#if 1 //struct v2 pos = V2(0.25, -10); //struct v2 pos = V2(0.25, -7); //struct v2 pos = V2(0.25, -5.27); struct v2 pos = V2(0.5, -1); - //struct v2 pos = V2(1.1230469346046448864129274625156, -1); /* Touching right side of box */ - //struct v2 pos = V2(1.1230469346046448864129274625156 - 0.0001, -1); /* Touching right side of box */ - //struct v2 pos = V2(0.374142020941, -0.246118023992); /* Touching glitch spot */ pos = v2_add(pos, V2(0, offset)); pos = v2_add(pos, V2(0, offset_all)); //struct v2 size = V2(1, 1); - //struct v2 size = V2(0.5, 0.5); - struct v2 size = V2(1.0, 0.5); + struct v2 size = V2(0.5, 0.5); + //struct v2 size = V2(1.0, 0.5); //f32 r = PI; - f32 r = PI / 4; + //f32 r = PI / 4; //f32 r = PI / 3; //f32 r = 0.05; //f32 r = PI / 2; @@ -214,10 +221,13 @@ INTERNAL void spawn_test_entities(f32 offset) //f32 skew = PI / 4; f32 skew = 0; - struct entity *e = entity_alloc(root); - struct xform xf = XFORM_TRS(.t = pos, .r = r, .s = size); xf = xform_skewed_to(xf, skew); +#else + struct xform xf = { .bx = {0.256749988, 0.429049402}, .by = {-0.429063231, 0.256720454}, .og = {2.91935277, -0.965838134} }; +#endif + + entity_set_xform(e, xf); //e->sprite = sprite_tag_from_path(STR("res/graphics/tim.ase")); @@ -240,7 +250,7 @@ INTERNAL void spawn_test_entities(f32 offset) e->linear_ground_friction = 1000; e->angular_ground_friction = 100; - //entity_enable_prop(e, ENTITY_PROP_TEST); + entity_enable_prop(e, ENTITY_PROP_TEST); } #endif @@ -267,16 +277,17 @@ INTERNAL void spawn_test_entities(f32 offset) } /* Box */ -#if 1 +#if GAME_SPAWN_BOX if (!G.extra_spawn) { struct v2 pos = V2(0.5, 0); //struct v2 pos = V2(0.5, 29); //struct v2 pos = V2(0.5, 24); //struct v2 pos = V2(1, -1); -#if !GAME_SPAWN_LOTS +#if 0 struct v2 size = V2(1, 1); #else - struct v2 size = V2(500, 1); + //struct v2 size = V2(5000, 1); + struct v2 size = V2(50, 1); #endif //f32 rot = PI / 4; f32 rot = 0; @@ -302,7 +313,7 @@ INTERNAL void spawn_test_entities(f32 offset) #endif /* Camera */ - if (!G.extra_spawn) { + if (!G.extra_spawn && player_ent->valid) { struct entity *e = entity_alloc(root); entity_set_xform(e, XFORM_IDENT); @@ -413,7 +424,6 @@ INTERNAL void create_contact_manifolds(void) CT_ASSERT(ARRAY_COUNT(manifold->contacts) == 2); CT_ASSERT(ARRAY_COUNT(res.points) == 2); - /* TODO: Move this down */ if (res.num_points > 0 || COLLIDER_DEBUG) { if (!manifold) { @@ -438,6 +448,8 @@ INTERNAL void create_contact_manifolds(void) #if COLLIDER_DEBUG { manifold->res = res; + manifold->dbg_xf0 = e0_xf; + manifold->dbg_xf1 = e1_xf; if (manifold->num_contacts == 0) { if (res.num_points > 0) { ++e0->colliding; @@ -771,8 +783,8 @@ INTERNAL void solve_collisions(f32 dt, b32 apply_bias) f32 vt = v2_dot(vrel, tangent); f32 j = vt * k; - //f32 friction = 0.6f; - f32 friction = 1.0f; + f32 friction = 0.6f; + //f32 friction = 1.0f; //f32 friction = F32_INFINITY; f32 max_friction = friction * contact->normal_impulse; f32 old_impulse = contact->tangent_impulse; @@ -852,7 +864,13 @@ INTERNAL void integrate_positions_from_velocities(f32 dt) struct v2 tick_linear_velocity = v2_mul(ent->linear_velocity, dt); f32 tick_angular_velocity = ent->angular_velocity * dt; xf.og = v2_add(xf.og, tick_linear_velocity); - xf = xform_rotated_to(xf, xform_get_rotation(xf) + tick_angular_velocity); + + //xf = xform_rotated_to(xf, xform_get_rotation(xf) + tick_angular_velocity); + + f32 old_angle = xform_get_rotation(xf); + f32 new_angle = old_angle + tick_angular_velocity; + xf = xform_rotated_to(xf, new_angle); + entity_set_xform(ent, xf); #endif } @@ -960,6 +978,7 @@ INTERNAL void game_update(struct game_cmd_array game_cmds) { logf_info("Spawning (test)"); #if GAME_SPAWN_LOTS +//#if 0 for (u32 i = 0; i < 50; ++i) { spawn_test_entities(-(f32)i); } @@ -1062,18 +1081,17 @@ INTERNAL void game_update(struct game_cmd_array game_cmds) ent->local_collider = collider_from_quad(xform_mul_quad(ent->sprite_local_xform, quad_from_rect(slice.rect))); #if 1 - if (entity_has_prop(ent, ENTITY_PROP_PLAYER_CONTROLLED)) { - //if ((true)) { -#if 1 + if (entity_has_prop(ent, ENTITY_PROP_TEST)) { +#if 0 ent->local_collider.points[0] = V2(0, 0); ent->local_collider.count = 1; ent->local_collider.radius = 0.5; -#elif 1 +#elif 0 ent->local_collider.points[0] = V2(0, 0.5); ent->local_collider.points[1] = V2(0, -0.5); ent->local_collider.count = 2; ent->local_collider.radius = 0.25; -#elif 0 +#elif 1 #if 1 /* "Bad" winding order */ ent->local_collider.points[0] = V2(-0.5, 0.5); @@ -1185,6 +1203,7 @@ INTERNAL void game_update(struct game_cmd_array game_cmds) * Test * ========================== */ +#if 0 for (u64 entity_index = 0; entity_index < store->reserved; ++entity_index) { struct entity *ent = &store->entities[entity_index]; if (!entity_is_valid_and_active(ent)) continue; @@ -1235,6 +1254,7 @@ INTERNAL void game_update(struct game_cmd_array game_cmds) entity_set_local_xform(ent, xf); #endif } +#endif /* ========================== * * Trigger equipped @@ -1328,7 +1348,7 @@ INTERNAL void game_update(struct game_cmd_array game_cmds) * Create forces from control focus (aim) * ========================== */ -#if 0 +#if GAME_PLAYER_AIM for (u64 entity_index = 0; entity_index < store->reserved; ++entity_index) { struct entity *ent = &store->entities[entity_index]; if (!entity_is_valid_and_active(ent)) continue; diff --git a/src/math.h b/src/math.h index 626b9a6a..9c2a8a85 100644 --- a/src/math.h +++ b/src/math.h @@ -680,6 +680,13 @@ INLINE struct v2 v2_perp_towards_dir(struct v2 v, struct v2 dir) return v2_perp_mul(v, (wedge >= 0) - (wedge < 0)); } +/* Returns 1 if winding between vectors a & b is clockwise or straight, -1 if counter-clockwise */ +INLINE i32 v2_winding(struct v2 a, struct v2 b) +{ + f32 w = v2_wedge(a, b); + return (w >= 0) - (w < 0); +} + INLINE struct v2 v2_with_len(struct v2 a, f32 len) { f32 l_sq = a.x * a.x + a.y * a.y; diff --git a/src/user.c b/src/user.c index 50c397dd..c013420f 100644 --- a/src/user.c +++ b/src/user.c @@ -1000,6 +1000,7 @@ INTERNAL void user_update(void) f32 thickness = 2; { /* Draw collider using support points */ + //u32 detail = 64; u32 detail = 512; draw_solid_collider_line(G.viewport_canvas, G.world_view, collider, xf, thickness, color, detail); } @@ -1013,7 +1014,7 @@ INTERNAL void user_update(void) if (collider.count == 1 && collider.radius > 0) { /* Draw upwards line for circle */ struct v2 start = xf.og; - struct v2 end = collider_support_point(&collider, xf, xf.by); + struct v2 end = collider_support_point(&collider, xf, v2_neg(xf.by)); start = xform_mul_v2(G.world_view, start); end = xform_mul_v2(G.world_view, end); draw_solid_line(G.viewport_canvas, start, end, thickness, color); @@ -1033,99 +1034,137 @@ INTERNAL void user_update(void) if (entity_has_prop(ent, ENTITY_PROP_MANIFOLD)) { struct entity *e0 = entity_from_handle(store, ent->manifold_e0); struct entity *e1 = entity_from_handle(store, ent->manifold_e1); - (UNUSED)e1; - - struct xform e0_xf = entity_get_xform(e0); - struct xform e1_xf = entity_get_xform(e1); - (UNUSED)e0_xf; - (UNUSED)e1_xf; - struct collider_shape e0_collider = e0->local_collider; struct collider_shape e1_collider = e1->local_collider; (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 = ent->dbg_xf0; + struct xform e1_xf = ent->dbg_xf1; + (UNUSED)e0_xf; + (UNUSED)e1_xf; + +#if USER_DRAW_MENKOWSKI #if 0 - /* Draw menkowski */ - { - - u32 color = ent->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); - //draw_solid_poly(G.viewport_canvas, m, color); - } - - /* Draw cloud */ - { - u32 color = RGBA_32_F(1, 1, 1, 1); - f32 radius = 2; - - struct v2_array m = cloud(temp.arena, &e0_collider, &e1_collider, e0_xf, e1_xf); - - for (u64 i = 0; i < m.count; ++i) { - struct v2 p = xform_mul_v2(G.world_view, m.points[i]);; - draw_solid_circle(G.viewport_canvas, p, radius, color, 10); + b32 should_draw = false; + for (u32 i = 0; i < ent->num_contacts; ++i) { + if (ent->contacts[i].starting_separation < -0.5) { + should_draw = true; + break; } } +#else + b32 should_draw = true; +#endif - /* Draw normal */ - { - u32 color = COLOR_WHITE; - f32 len = 0.1f; - 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(ent->manifold_normal), len)); - draw_solid_arrow_line(G.viewport_canvas, start, end, arrow_thickness, arrow_height, color); - } + if (should_draw) { +#if 0 + /* Test info */ + { + struct font *disp_font = font_load_async(STR("res/fonts/fixedsys.ttf"), 12.0f); + if (disp_font) { + f32 offset_px = 10; + struct string fmt = STR( + "e0 pos: (%F, %F)\n" + "e0 rot: %F\n" + "e1 pos: (%F, %F)\n" + "e1 rot: %F\n" + ); + struct string text = string_format(temp.arena, fmt, + FMT_FLOAT_P(e0_xf.og.x, 24), FMT_FLOAT_P(e0_xf.og.y, 24), + FMT_FLOAT_P(xform_get_rotation(e0_xf), 24), + FMT_FLOAT_P(e1_xf.og.x, 24), FMT_FLOAT_P(e1_xf.og.y, 24), + FMT_FLOAT_P(xform_get_rotation(e1_xf), 24)); - /* Draw prototype */ - { - f32 thickness = 2; - u32 color = RGBA_32_F(1, 1, 1, 0.25); - struct v2_array m = { - .points = ent->res.prototype.points, - .count = ent->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); - } - - /* Draw simplex */ - { - f32 thickness = 2; - u32 line_color = COLOR_YELLOW; - u32 color_first = RGBA_32_F(1, 0, 0, 0.75); - 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 = ent->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 }; - - if (simplex.len >= 1) { - u32 color = simplex.len == 1 ? color_first : (simplex.len == 2 ? color_second : color_third); - draw_solid_circle(G.viewport_canvas, simplex_array.points[0], thickness * 3, color, 10); + draw_text(G.viewport_canvas, disp_font, v2_add(v2_round(xform_mul_v2(G.world_view, V2(0, 0))), V2(0, offset_px)), text); + } } - if (simplex.len >= 2) { - u32 color = simplex.len == 2 ? color_first : color_second; - draw_solid_circle(G.viewport_canvas, simplex_array.points[1], thickness * 3, color, 10); +#endif + + /* Draw menkowski */ + { + + u32 color = ent->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); + //draw_solid_poly(G.viewport_canvas, m, color); } - if (simplex.len >= 3) { - u32 color = color_first; - draw_solid_circle(G.viewport_canvas, simplex_array.points[2], thickness * 3, color, 10); + + /* Draw cloud */ + { + u32 color = RGBA_32_F(1, 1, 1, 1); + f32 radius = 2; + + struct v2_array m = cloud(temp.arena, &e0_collider, &e1_collider, e0_xf, e1_xf); + + for (u64 i = 0; i < m.count; ++i) { + struct v2 p = xform_mul_v2(G.world_view, m.points[i]); + draw_solid_circle(G.viewport_canvas, p, radius, color, 10); + } } - if (simplex.len >= 2) { - draw_solid_poly_line(G.viewport_canvas, simplex_array, simplex.len > 2, thickness, line_color); + + /* Draw normal */ + { + u32 color = COLOR_WHITE; + f32 len = 0.1f; + 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(ent->manifold_normal), len)); + draw_solid_arrow_line(G.viewport_canvas, start, end, arrow_thickness, arrow_height, color); + } + + /* Draw prototype */ + { + f32 thickness = 2; + u32 color = RGBA_32_F(1, 1, 1, 0.25); + + struct v2_array m = { + .points = ent->res.prototype.points, + .count = ent->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); + } + + /* Draw simplex */ + { + f32 thickness = 2; + u32 line_color = COLOR_YELLOW; + u32 color_first = RGBA_32_F(1, 0, 0, 0.75); + 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 = ent->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 }; + + if (simplex.len >= 1) { + u32 color = simplex.len == 1 ? color_first : (simplex.len == 2 ? color_second : color_third); + draw_solid_circle(G.viewport_canvas, simplex_array.points[0], thickness * 3, color, 10); + } + if (simplex.len >= 2) { + u32 color = simplex.len == 2 ? color_first : color_second; + draw_solid_circle(G.viewport_canvas, simplex_array.points[1], thickness * 3, color, 10); + } + if (simplex.len >= 3) { + u32 color = color_first; + draw_solid_circle(G.viewport_canvas, simplex_array.points[2], thickness * 3, color, 10); + } + if (simplex.len >= 2) { + draw_solid_poly_line(G.viewport_canvas, simplex_array, simplex.len > 2, thickness, line_color); + } } } #endif @@ -1168,6 +1207,7 @@ INTERNAL void user_update(void) if (disp_font) { f32 offset_px = 10; +#if 1 struct string fmt = STR( "path: %F\n" "e0 index: %F\n" @@ -1192,6 +1232,18 @@ INTERNAL void user_update(void) draw_text(G.viewport_canvas, disp_font, v2_add(v2_round(xform_mul_v2(G.world_view, point)), V2(0, offset_px)), text); +#else + struct string fmt = STR( + "e0 index: %F\n" + "e1 index: %F\n" + ); + struct string text = string_format(temp.arena, fmt, + FMT_UINT(e0->handle.idx), + FMT_UINT(e1->handle.idx)); + + + draw_text(G.viewport_canvas, disp_font, v2_add(v2_round(xform_mul_v2(G.world_view, point)), V2(0, offset_px)), text); +#endif } } #endif