diff --git a/res/graphics/box.ase b/res/graphics/box.ase index ed282491..f11bbe39 100644 --- a/res/graphics/box.ase +++ b/res/graphics/box.ase @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e13a0c8f006ad4f77ee6b668c4332145ee165f321f42334c2d27bafce70b43e5 -size 7139 +oid sha256:1818fa9630b3221692c334df3a2b4054efaddd841f231a0f620820461ab65594 +size 10002 diff --git a/src/entity.h b/src/entity.h index a99f6859..575ca314 100644 --- a/src/entity.h +++ b/src/entity.h @@ -50,6 +50,29 @@ struct entity_store { struct entity *entities; }; + + + + + + +/* TODO: Remove this (testing) */ +struct simplex { + struct v2 a, b, c; +}; + + + + + + + + + + + + + struct entity { /* ====================================================================== */ /* Metadata */ diff --git a/src/game.c b/src/game.c index e6237cda..2633ba1a 100644 --- a/src/game.c +++ b/src/game.c @@ -170,7 +170,7 @@ INTERNAL void spawn_test_entities(void) /* Box */ { - struct v2 pos = V2(1, -1); + struct v2 pos = V2(0.5, -0.5); struct v2 size = V2(1, 1); f32 rot = 0; struct entity *e = entity_alloc(root); @@ -223,91 +223,92 @@ INTERNAL struct v2 quad_support_point(struct quad q0, struct quad q1, struct v2 return v2_sub(quad_furthest_point(q0, dir), quad_furthest_point(q1, v2_neg(dir))); } -#if 0 -INTERNAL struct v2 normal_towards_origin(struct v2 p0, struct v2 p1) -{ - struct v2 dir = v2_norm(v2_perp_cw(v2_sub(p1, p0))); -#if 1 - if (v2_dot(dir, p0) > 0) { - dir = v2_neg(dir); - } -#else - dir = v2_mul(dir, 1 - ((v2_dot(dir, p0) > 0) << 1)); -#endif - return dir; -} -#else INTERNAL struct v2 normal_towards_point(struct v2 start, struct v2 end, struct v2 p) { struct v2 dir = v2_norm(v2_perp_cw(v2_sub(end, start))); -#if 1 - if (v2_dot(dir, v2_sub(p, start)) < 0) { - dir = v2_neg(dir); - } -#else - dir = v2_mul(dir, 1 - ((v2_dot(dir, v2_sub(p, start)) > 0) << 1)); -#endif - return dir; -} -#endif + i32 sign = 1 - ((v2_dot(dir, v2_sub(p, start)) < 0) << 1); + return v2_mul(dir, sign); -INTERNAL b32 quad_collision_test(struct quad q0, struct quad q1) +} + +struct gjk_result { + b32 colliding; + struct simplex final_simplex; +}; + +INTERNAL struct gjk_result gjk(struct quad q0, struct quad q1) { struct v2 q0_center = v2_div(v2_add(q0.p4, v2_add(q0.p3, v2_add(q0.p2, q0.p1))), 4); struct v2 q1_center = v2_div(v2_add(q1.p4, v2_add(q1.p3, v2_add(q1.p2, q1.p1))), 4); /* Simplex */ - struct v2 s[3] = { 0 }; + struct simplex s = { 0 }; u32 s_len = 0; /* Append first point to simplex */ struct v2 dir = v2_norm(v2_sub(q1_center, q0_center)); - s[0] = quad_support_point(q0, q1, dir); + s.c = quad_support_point(q0, q1, dir); s_len = 1; - dir = v2_norm(v2_neg(s[0])); /* Next point is towards origin */ + dir = v2_norm(v2_neg(s.c)); /* Next point is towards origin */ + + b32 colliding = false; while (true) { /* Determine support point */ struct v2 p = quad_support_point(q0, q1, dir); if (v2_dot(dir, p) < 0) { /* Point did not cross origin */ - return false; + colliding = false; + break; } - if (s_len == 1) { - s[1] = p; - ++s_len; - } else if (s_len == 2) { + if (s_len < 3) { /* Line case */ /* Next dir is line normal towards origin */ - s[2] = p; + if (s_len == 1) { + s.b = p; + } else if (s_len == 2) { + s.a = p; + } ++s_len; - dir = normal_towards_point(s[0], s[1], V2(0, 0)); + dir = normal_towards_point(s.a, s.b, V2(0, 0)); } else { - s[0] = s[1]; - s[1] = s[2]; - s[2] = p; - /* Triangle case */ - struct v2 a = s[2]; - struct v2 b = s[1]; - struct v2 c = s[0]; + s.c = s.b; + s.b = s.a; + s.a = p; - dir = v2_neg(normal_towards_point(a, b, c)); /* Normal dir of ab pointing away from c */ - if (v2_dot(dir, v2_neg(a)) >= 0) { + /* Ensure point is unique */ + if (v2_eq(s.a, s.b) + || v2_eq(s.b, s.c) + || v2_eq(s.a, s.c)) { + colliding = false; + break; + } + + struct v2 a_to_origin_rel = v2_neg(s.a); + + dir = v2_neg(normal_towards_point(s.a, s.b, s.c)); /* Normal dir of ab pointing away from c */ + if (v2_dot(dir, a_to_origin_rel) >= 0) { /* Point is in region ab, remove c from simplex */ } else { - dir = v2_neg(normal_towards_point(a, c, b)); /* Normal dir of ac pointing away from b */ - if (v2_dot(dir, v2_neg(a)) >= 0) { + dir = v2_neg(normal_towards_point(s.a, s.c, s.b)); /* Normal dir of ac pointing away from b */ + if (v2_dot(dir, a_to_origin_rel) >= 0) { /* Point is in region ac, remove b from simplex */ - s[1] = s[0]; + s.b = s.c; } else { /* Point must be in simplex */ - return true; + colliding = true; + break; } } } } + + return (struct gjk_result) { + .colliding = colliding, + .final_simplex = s + }; } /* ========================== * @@ -747,7 +748,8 @@ INTERNAL void game_update(struct game_cmd_array game_cmds) { struct sprite_sheet *sheet = sprite_sheet_from_tag_await(sprite_frame_scope, e0->sprite); struct sprite_sheet_slice slice = sprite_sheet_get_slice(sheet, STR("shape"), e0->animation_frame); - e0_quad = xform_mul_quad(e0_xf, quad_from_rect(slice.rect)); + e0_quad = xform_mul_quad(e0->sprite_local_xform, quad_from_rect(slice.rect)); + e0_quad = xform_mul_quad(e0_xf, e0_quad); } b32 colliding = false; @@ -762,10 +764,12 @@ INTERNAL void game_update(struct game_cmd_array game_cmds) { struct sprite_sheet *sheet = sprite_sheet_from_tag_await(sprite_frame_scope, e1->sprite); struct sprite_sheet_slice slice = sprite_sheet_get_slice(sheet, STR("shape"), e1->animation_frame); - e1_quad = xform_mul_quad(e1_xf, quad_from_rect(slice.rect)); + e1_quad = xform_mul_quad(e1->sprite_local_xform, quad_from_rect(slice.rect)); + e1_quad = xform_mul_quad(e1_xf, e1_quad); } - if (quad_collision_test(e0_quad, e1_quad)) { + struct gjk_result res = gjk(e0_quad, e1_quad); + if (res.colliding) { colliding = true; break; }