working gjk test

This commit is contained in:
jacob 2024-08-24 13:45:12 -05:00
parent 86f1f1f6e0
commit 8bcc0bd356
3 changed files with 81 additions and 54 deletions

BIN
res/graphics/box.ase (Stored with Git LFS)

Binary file not shown.

View File

@ -50,6 +50,29 @@ struct entity_store {
struct entity *entities;
};
/* TODO: Remove this (testing) */
struct simplex {
struct v2 a, b, c;
};
struct entity {
/* ====================================================================== */
/* Metadata */

View File

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