diff --git a/src/entity.h b/src/entity.h index 27278b17..c1788473 100644 --- a/src/entity.h +++ b/src/entity.h @@ -60,6 +60,9 @@ struct entity_store { + + + struct entity { /* ====================================================================== */ /* Metadata */ @@ -98,9 +101,7 @@ struct entity { struct v2 pendir; b32 solved; - struct v2 point0; - struct v2 point1; - b32 has_2nd_point; + struct v2 point; b32 test_torque_applied; b32 test_collided; @@ -112,6 +113,25 @@ struct entity { +#if 0 + /* ====================================================================== */ + /* Contact */ + + struct entity *contact_e0; + struct entity *contact_e1; + struct gjk_contact_pair contact_pairs[4]; + u32 num_contact_pairs; +#endif + + + + + + + + + + /* ====================================================================== */ diff --git a/src/game.c b/src/game.c index 6b4645d0..f3276a56 100644 --- a/src/game.c +++ b/src/game.c @@ -910,11 +910,8 @@ INTERNAL void game_update(struct game_cmd_array game_cmds) } b32 colliding = false; - struct v2 pair0p0 = V2(0, 0); - struct v2 pair0p1 = V2(0, 0); - struct v2 pair1p0 = V2(0, 0); - struct v2 pair1p1 = V2(0, 0); - b32 has_2nd_pair = false; + struct v2 p0 = V2(0, 0); + struct v2 p1 = V2(0, 0); struct entity *colliding_with = entity_nil(); struct gjk_simplex simplex = { 0 }; struct gjk_prototype prototype = { 0 }; @@ -944,11 +941,8 @@ INTERNAL void game_update(struct game_cmd_array game_cmds) struct gjk_contact_points_result res = gjk_contact_points(e0_poly, e1_poly); colliding = res.colliding; - pair0p0 = res.pair0p0; - pair0p1 = res.pair0p1; - pair1p0 = res.pair1p0; - pair1p1 = res.pair1p1; - has_2nd_pair = res.has_2nd_pair; + p0 = res.p0; + p1 = res.p1; colliding_with = e1; simplex = res.simplex; prototype = res.prototype; @@ -957,9 +951,7 @@ INTERNAL void game_update(struct game_cmd_array game_cmds) e0->colliding = colliding; e0->colliding_with = colliding_with->handle; - e0->point0 = pair0p0; - e0->point1 = pair1p0; - e0->has_2nd_point = has_2nd_pair; + e0->point = p0; e0->simplex = simplex; e0->prototype = prototype; e0->pendir = velocity; @@ -968,13 +960,11 @@ INTERNAL void game_update(struct game_cmd_array game_cmds) if (colliding_with->valid) { colliding_with->colliding = colliding; colliding_with->colliding_with = e0->handle; - colliding_with->point0 = pair0p1; - colliding_with->point1 = pair1p1; - colliding_with->has_2nd_point = has_2nd_pair; + colliding_with->point = p1; } { -#if 0 +#if 1 if (colliding) { struct entity *e1 = colliding_with; struct xform e1_xf = entity_get_xform(e1); @@ -999,7 +989,7 @@ INTERNAL void game_update(struct game_cmd_array game_cmds) #if 1 f32 bias_factor = 0.2; - f32 bias_slop = 0.005; + f32 bias_slop = 0.001; f32 bias = (bias_factor / dt) * max((v2_len(pen) - bias_slop), 0); #else diff --git a/src/gjk.c b/src/gjk.c index e184ec19..d8867fde 100644 --- a/src/gjk.c +++ b/src/gjk.c @@ -146,6 +146,9 @@ struct v2_array cloud(struct arena *arena, struct v2_array poly0, struct v2_arra + +/* TODO: Update this function to only calculate contact pairs if colliding. Will allow for shortcut-style GJK. + * `colliding` & `has_2nd_pair` become "num_pairs", where 0 = no collision. */ struct gjk_contact_points_result gjk_contact_points(struct v2_array shape0, struct v2_array shape1) { struct temp_arena scratch = scratch_begin_no_conflict(); @@ -158,11 +161,8 @@ struct gjk_contact_points_result gjk_contact_points(struct v2_array shape0, stru struct gjk_menkowski_point *proto = NULL; u32 proto_count = 0; - struct v2 pair0p0 = { 0 }; - struct v2 pair0p1 = { 0 }; - struct v2 pair1p0 = { 0 }; - struct v2 pair1p1 = { 0 }; - b32 has_2nd_pair = false; + struct v2 p0 = { 0 }; + struct v2 p1 = { 0 }; #if GJK_DEBUG u32 dbg_step = 0; @@ -370,36 +370,14 @@ struct gjk_contact_points_result gjk_contact_points(struct v2_array shape0, stru /* Resolve points */ if (s.len == 1) { - pair0p0 = s.a.p0; - pair0p1 = s.a.p1; - } else if (s.len == 2) { - - /* TODO: Epsilon */ - if (v2_eq(s.a.p0, s.b.p0) || v2_eq(s.a.p1, s.b.p1)) { - /* FIXME: Winding order dependent? */ - ASSERT(s.len == 2); - f32 ratio; - { - /* Determine ratio between edge a & b that projected origin lies */ - struct v2 vab = v2_sub(s.b.p, s.a.p); - struct v2 vao = v2_neg(s.a.p); - ratio = clamp_f32(v2_dot(vab, vao) / v2_dot(vab, vab), 0, 1); - } - /* Shape 0 */ - pair0p0 = v2_sub(s.b.p0, s.a.p0); - pair0p0 = v2_mul(pair0p0, ratio); - pair0p0 = v2_add(pair0p0, s.a.p0); - /* Shape 1 */ - pair0p1 = v2_sub(s.b.p1, s.a.p1); - pair0p1 = v2_mul(pair0p1, ratio); - pair0p1 = v2_add(pair0p1, s.a.p1); - } else { - /* Face -> face, need 2nd pair */ - - has_2nd_pair = true; - - /* TODO: Rename abcd variables */ - + p0 = s.a.p0; + p1 = s.a.p1; + } else { + ASSERT(s.len == 2); + b32 p0_is_on_edge = !v2_eq(s.a.p0, s.b.p0); + b32 p1_is_on_edge = !v2_eq(s.a.p1, s.b.p1); + if (p0_is_on_edge && p1_is_on_edge) { + /* Closest features are both faces, use midpoint of clipped faces to represent contact points */ struct v2 a = s.a.p0; struct v2 b = s.b.p0; struct v2 c = s.a.p1; @@ -416,10 +394,23 @@ struct gjk_contact_points_result gjk_contact_points(struct v2_array shape0, stru f32 inv_vab_len_sq = 1.f / v2_len_sq(vab); f32 inv_vcd_len_sq = 1.f / v2_len_sq(vcd); - pair0p0 = v2_add(a, v2_mul(vab, clamp_f32(v2_dot(vab, vac) * inv_vab_len_sq, 0, 1))); - pair1p0 = v2_add(a, v2_mul(vab, clamp_f32(v2_dot(vab, vad) * inv_vab_len_sq, 0, 1))); - pair0p1 = v2_add(c, v2_mul(vcd, clamp_f32(v2_dot(vcd, vca) * inv_vcd_len_sq, 0, 1))); - pair1p1 = v2_add(c, v2_mul(vcd, clamp_f32(v2_dot(vcd, vcb) * inv_vcd_len_sq, 0, 1))); + f32 ab_clip_c = clamp_f32(v2_dot(vab, vac) * inv_vab_len_sq, 0, 1); + f32 ab_clip_d = clamp_f32(v2_dot(vab, vad) * inv_vab_len_sq, 0, 1); + f32 cd_clip_a = clamp_f32(v2_dot(vcd, vca) * inv_vcd_len_sq, 0, 1); + f32 cd_clip_b = clamp_f32(v2_dot(vcd, vcb) * inv_vcd_len_sq, 0, 1); + + p0 = v2_add(a, v2_mul(vab, (ab_clip_c + ab_clip_d) * 0.5f)); + p1 = v2_add(c, v2_mul(vcd, (cd_clip_a + cd_clip_b) * 0.5f)); + } else { + /* Determine ratio between edge a & b that projected origin lies */ + f32 ratio; + { + struct v2 vab = v2_sub(s.b.p, s.a.p); + struct v2 vao = v2_neg(s.a.p); + ratio = clamp_f32(v2_dot(vab, vao) / v2_dot(vab, vab), 0, 1); + } + p0 = v2_add(s.a.p0, v2_mul(v2_sub(s.b.p0, s.a.p0), ratio)); + p1 = v2_add(s.a.p1, v2_mul(v2_sub(s.b.p1, s.a.p1), ratio)); } } @@ -443,11 +434,8 @@ abort: res.prototype.len = s.len; } res.colliding = colliding; - res.pair0p0 = pair0p0; - res.pair0p1 = pair0p1; - res.pair1p0 = pair1p0; - res.pair1p1 = pair1p1; - res.has_2nd_pair = has_2nd_pair; + res.p0 = p0; + res.p1 = p1; res.simplex = s; scratch_end(scratch); return res; diff --git a/src/gjk.h b/src/gjk.h index 16d8228c..6fa0b07e 100644 --- a/src/gjk.h +++ b/src/gjk.h @@ -24,11 +24,8 @@ b32 gjk_boolean(struct v2_array shape0, struct v2_array shape1); struct gjk_prototype { struct v2 points[64]; u32 len; }; struct gjk_contact_points_result { b32 colliding; - - - struct v2 pair0p0, pair0p1; - struct v2 pair1p0, pair1p1; - b32 has_2nd_pair; + struct v2 p0; + struct v2 p1; /* For debugging */ b32 solved; diff --git a/src/user.c b/src/user.c index 5816e507..d9f8789f 100644 --- a/src/user.c +++ b/src/user.c @@ -1118,14 +1118,16 @@ INTERNAL void user_update(void) f32 radius = 5; { u32 color = entity_has_prop(ent, ENTITY_PROP_PLAYER_CONTROLLED) ? RGBA_32_F(1, 0, 0, 0.75) : RGBA_32_F(0, 1, 1, 0.75); - struct v2 point = xform_mul_v2(G.world_view, ent->point0); + struct v2 point = xform_mul_v2(G.world_view, ent->point); draw_solid_circle(G.viewport_canvas, point, radius, color, 10); } +#if 0 if (ent->has_2nd_point) { u32 color = entity_has_prop(ent, ENTITY_PROP_PLAYER_CONTROLLED) ? RGBA_32_F(1, 1, 0, 0.75) : RGBA_32_F(1, 0, 1, 0.75); struct v2 point = xform_mul_v2(G.world_view, ent->point1); draw_solid_circle(G.viewport_canvas, point, radius, color, 10); } +#endif } }