popping probably fixed

This commit is contained in:
jacob 2024-10-11 14:32:01 -05:00
parent 687e9b8c99
commit 6951fa62e3
6 changed files with 255 additions and 139 deletions

View File

@ -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 */ /* TODO: Could probably binary search for largest dot since shape is convex */
struct v2 *points = a->points; struct v2 *points = a->points;
u32 count = a->count; u32 count = a->count;
dir = v2_rotated(dir, -xform_get_rotation(xf));
dir = v2_mul_v2(dir, xform_get_scale(xf));
u32 furthest = 0; u32 furthest = 0;
f32 furthest_dot = v2_dot(dir, xform_mul_v2(xf, points[0])); f32 furthest_dot = -F32_INFINITY;
for (u32 i = 1; i < count; ++i) { for (u32 i = 0; i < count; ++i) {
struct v2 p = xform_mul_v2(xf, points[i]); struct v2 p = points[i];
f32 dot = v2_dot(dir, p); f32 dot = v2_dot(dir, p);
if (dot > furthest_dot) { if (dot > furthest_dot) {
furthest = i; furthest = i;
@ -143,11 +147,16 @@ struct collider_collision_points_result collider_collision_points(struct collide
(UNUSED)radius1; (UNUSED)radius1;
/* TODO: Parameterize */ /* TODO: Parameterize */
//const f32 tolerance = 0.f; /* How close can shapes be before collision is considered */ /* How close can non-overlapping shapes be before collision is considered */
const f32 tolerance = 0.005f; /* How close can shapes be before collision is considered */ //const f32 tolerance = 0.f;
//const f32 tolerance = 0.05f; /* How close can shapes be before collision is considered */ 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 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 colliding = false;
b32 simplex_is_closest_edge = 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.a = m;
s.len = 2; s.len = 2;
/* Third point is support point in direction of line normal towards origin */ if (math_fabs(v2_wedge(v2_sub(s.b, s.a), v2_neg(s.a))) <= min_unique_pt_dist_sq) {
dir = v2_perp_towards_dir(v2_sub(s.b, s.a), v2_neg(s.a)); /* 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.a = m;
s.len = 3; 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.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) { math_fabs(v2_wedge(v2_sub(s.c, s.b), v2_neg(s.b))) <= min_unique_pt_dist_sq) {
/* Simplex lies on origin */ /* Simplex lies on origin */
colliding = true; colliding = true;
break; break;
} }
#endif
} }
/* Determine region of the simplex in which the origin lies */ /* 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) * Epa (to find collision normal from inside shape)
* ========================== */ * ========================== */
//const f32 epa_epsilon_sq = 0; //const f32 epa_normal_epsilon_sq = 0;
//const f32 epa_epsilon_sq = 0.01f * 0.01f; //const f32 epa_normal_epsilon_sq = 0.01f * 0.01f;
//const f32 epa_epsilon_sq = 0.001f * 0.001f; //const f32 epa_normal_epsilon_sq = 0.001f * 0.001f;
const f32 epa_epsilon_sq = F32_INFINITY; const f32 epa_normal_epsilon_sq = F32_INFINITY;
proto = arena_dry_push(scratch.arena, struct v2); proto = arena_dry_push(scratch.arena, struct v2);
proto_count = 0; proto_count = 0;
@ -321,6 +338,8 @@ struct collider_collision_points_result collider_collision_points(struct collide
proto_count = 3; proto_count = 3;
} }
i32 winding = v2_winding(v2_sub(s.c, s.a), v2_sub(s.b, s.a));
u32 epa_iterations = 0; u32 epa_iterations = 0;
while (colliding) { while (colliding) {
++epa_iterations; ++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 vse = v2_sub(pe, ps);
struct v2 vso = v2_neg(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); struct v2 pd = v2_add(ps, vsd);
f32 pd_len_sq = v2_len_sq(pd); 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_ps_index = ps_index;
pen_pe_index = pe_index; pen_pe_index = pe_index;
pen_len_sq = pd_len_sq; 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 a = proto[pen_ps_index];
struct v2 b = proto[pen_pe_index]; struct v2 b = proto[pen_pe_index];
struct v2 vab = v2_sub(b, a); 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 */ /* 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 */ 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)); dir = v2_perp_towards_dir(vab, v2_sub(a, n));
} else { } else {
dir = v2_perp_towards_dir(vab, a); dir = v2_perp_towards_dir(vab, a);
} }
#else
dir = v2_mul(v2_perp(vab), winding);
#endif
} }
m = menkowski_point(shape0, shape1, xf0, xf1, dir); 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) { if (!unique || epa_iterations >= max_epa_iterations) {
res.path = 1; res.path = 1;
if (pen_len_sq < epa_epsilon_sq) { if (pen_len_sq < epa_normal_epsilon_sq) {
normal = v2_norm(dir); normal = v2_norm(dir);
} else { } else {
normal = v2_norm(pen); normal = v2_norm(pen);
@ -599,12 +622,16 @@ struct collider_collision_points_result collider_collision_points(struct collide
f32 w = 1 / vab0_wedge_normal; f32 w = 1 / vab0_wedge_normal;
a0t = clamp_f32(va0a1_wedge_normal * w, 0, 1); a0t = clamp_f32(va0a1_wedge_normal * w, 0, 1);
b0t = clamp_f32(vb0b1_wedge_normal * -w, 0, 1); b0t = clamp_f32(vb0b1_wedge_normal * -w, 0, 1);
} else {
DEBUGBREAKABLE;
} }
if (math_fabs(vab1_wedge_normal) > 0.01f) { if (math_fabs(vab1_wedge_normal) > 0.01f) {
f32 w = 1 / vab1_wedge_normal; f32 w = 1 / vab1_wedge_normal;
a1t = clamp_f32(-va0a1_wedge_normal * w, 0, 1); a1t = clamp_f32(-va0a1_wedge_normal * w, 0, 1);
b1t = clamp_f32(-vb0b1_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_a = false;
b32 ignore_b = 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) { if (a_sep > b_sep) {
ignore_a = true; ignore_a = true;
} else { } else {
ignore_b = true; ignore_b = true;
} }
} }
#endif
if (a_sep < tolerance && !ignore_a) { if (a_sep < tolerance && !ignore_a) {
struct collider_collision_point *point = &points[num_points++]; 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) * 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 = arena_dry_push(scratch.arena, struct v2);
proto_count = 0; 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 a = proto[pen_ps_index];
struct v2 b = proto[pen_pe_index]; struct v2 b = proto[pen_pe_index];
struct v2 vab = v2_sub(b, a); 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 */ /* 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 */ 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)); 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) { if (!unique || epa_iterations >= max_epa_iterations) {
res.path = 1; res.path = 1;
if (pen_len_sq < epa_epsilon_sq) { if (pen_len_sq < epa_normal_epsilon_sq) {
normal = v2_norm(dir); normal = v2_norm(dir);
} else { } else {
normal = v2_norm(pen); normal = v2_norm(pen);

View File

@ -32,13 +32,17 @@
#define GAME_FPS 50.0 #define GAME_FPS 50.0
#define GAME_TIMESCALE 1.0 #define GAME_TIMESCALE 1.0
#define GAME_PHYSICS_SUBSTEPS 8 #define GAME_PHYSICS_SUBSTEPS 4
#define GAME_PHYSICS_ENABLE_COLLISION 1
#define GAME_PHYSICS_ENABLE_WARM_STARTING 1 #define GAME_PHYSICS_ENABLE_WARM_STARTING 1
#define GAME_PHYSICS_ENABLE_RELAXATION 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_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_LINEAR_VELOCITY 100
#define GAME_MAX_ANGULAR_VELOCITY ((2 * PI) * 20) #define GAME_MAX_ANGULAR_VELOCITY ((2 * PI) * 20)

View File

@ -119,7 +119,6 @@ struct entity {
/* TODO: Remove this (testing) */ /* TODO: Remove this (testing) */
i32 colliding; i32 colliding;
struct collider_collision_points_result res;
b32 test_torque_applied; b32 test_torque_applied;
@ -140,6 +139,11 @@ struct entity {
struct contact contacts[2]; struct contact contacts[2];
u32 num_contacts; u32 num_contacts;
/* TODO: Remove this (debugging) */
struct collider_collision_points_result res;
struct xform dbg_xf0;
struct xform dbg_xf1;

View File

@ -126,18 +126,22 @@ INTERNAL void spawn_test_entities(f32 offset)
//const f32 offset_all = -20000; //const f32 offset_all = -20000;
//const f32 offset_all = -5000; //const f32 offset_all = -5000;
const f32 offset_all = 0; const f32 offset_all = 0;
(UNUSED)offset;
(UNUSED)offset_all;
/* Player */ /* Player */
struct entity *player_ent = entity_nil(); struct entity *player_ent = entity_nil();
//if (!G.extra_spawn) { //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, -10);
//struct v2 pos = V2(0.25, -7); //struct v2 pos = V2(0.25, -7);
//struct v2 pos = V2(0.25, -5.27); //struct v2 pos = V2(0.25, -5.27);
struct v2 pos = V2(0.5, -1); struct v2 pos = V2(0.5, -1);
//struct v2 pos = V2(1.1230469346046448864129274625156, -1); /* Touching right side of box */ //struct v2 pos = V2(1.0295, -1);
//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));
pos = v2_add(pos, V2(0, offset_all)); 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(0.5, 0.5);
struct v2 size = V2(1.0, 0.5); struct v2 size = V2(1.0, 0.5);
//f32 r = PI; //f32 r = PI;
f32 r = PI / 4; //f32 r = PI / 4;
//f32 r = PI / 3; //f32 r = PI / 3;
//f32 r = 0.05; //f32 r = 0.05;
//f32 r = PI / 2; //f32 r = PI / 2;
//f32 r = 0; //f32 r = PI;
f32 r = 0;
//f32 skew = PI / 4; //f32 skew = PI / 4;
//f32 skew = 0.9f; //f32 skew = 0.9f;
f32 skew = 0; f32 skew = 0;
struct entity *e = entity_alloc(root);
struct xform xf = XFORM_TRS(.t = pos, .r = r, .s = size); struct xform xf = XFORM_TRS(.t = pos, .r = r, .s = size);
xf = xform_skewed_to(xf, skew); 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); entity_set_xform(e, xf);
//e->sprite = sprite_tag_from_path(STR("res/graphics/tim.ase")); //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 = 4500;
e->control_force = 1200; e->control_force = 1200;
#else #else
//e->control_force = 5000;
e->control_force = 250; e->control_force = 250;
#endif #endif
e->control_torque = 10; e->control_torque = 10;
@ -184,29 +191,29 @@ INTERNAL void spawn_test_entities(f32 offset)
e->linear_ground_friction = 1000; e->linear_ground_friction = 1000;
e->angular_ground_friction = 100; e->angular_ground_friction = 100;
//entity_enable_prop(e, ENTITY_PROP_TEST); entity_enable_prop(e, ENTITY_PROP_TEST);
player_ent = e; 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, -10);
//struct v2 pos = V2(0.25, -7); //struct v2 pos = V2(0.25, -7);
//struct v2 pos = V2(0.25, -5.27); //struct v2 pos = V2(0.25, -5.27);
struct v2 pos = V2(0.5, -1); 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));
pos = v2_add(pos, V2(0, offset_all)); pos = v2_add(pos, V2(0, offset_all));
//struct v2 size = V2(1, 1); //struct v2 size = V2(1, 1);
//struct v2 size = V2(0.5, 0.5); struct v2 size = V2(0.5, 0.5);
struct v2 size = V2(1.0, 0.5); //struct v2 size = V2(1.0, 0.5);
//f32 r = PI; //f32 r = PI;
f32 r = PI / 4; //f32 r = PI / 4;
//f32 r = PI / 3; //f32 r = PI / 3;
//f32 r = 0.05; //f32 r = 0.05;
//f32 r = PI / 2; //f32 r = PI / 2;
@ -214,10 +221,13 @@ INTERNAL void spawn_test_entities(f32 offset)
//f32 skew = PI / 4; //f32 skew = PI / 4;
f32 skew = 0; f32 skew = 0;
struct entity *e = entity_alloc(root);
struct xform xf = XFORM_TRS(.t = pos, .r = r, .s = size); struct xform xf = XFORM_TRS(.t = pos, .r = r, .s = size);
xf = xform_skewed_to(xf, skew); 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); entity_set_xform(e, xf);
//e->sprite = sprite_tag_from_path(STR("res/graphics/tim.ase")); //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->linear_ground_friction = 1000;
e->angular_ground_friction = 100; e->angular_ground_friction = 100;
//entity_enable_prop(e, ENTITY_PROP_TEST); entity_enable_prop(e, ENTITY_PROP_TEST);
} }
#endif #endif
@ -267,16 +277,17 @@ INTERNAL void spawn_test_entities(f32 offset)
} }
/* Box */ /* Box */
#if 1 #if GAME_SPAWN_BOX
if (!G.extra_spawn) { if (!G.extra_spawn) {
struct v2 pos = V2(0.5, 0); struct v2 pos = V2(0.5, 0);
//struct v2 pos = V2(0.5, 29); //struct v2 pos = V2(0.5, 29);
//struct v2 pos = V2(0.5, 24); //struct v2 pos = V2(0.5, 24);
//struct v2 pos = V2(1, -1); //struct v2 pos = V2(1, -1);
#if !GAME_SPAWN_LOTS #if 0
struct v2 size = V2(1, 1); struct v2 size = V2(1, 1);
#else #else
struct v2 size = V2(500, 1); //struct v2 size = V2(5000, 1);
struct v2 size = V2(50, 1);
#endif #endif
//f32 rot = PI / 4; //f32 rot = PI / 4;
f32 rot = 0; f32 rot = 0;
@ -302,7 +313,7 @@ INTERNAL void spawn_test_entities(f32 offset)
#endif #endif
/* Camera */ /* Camera */
if (!G.extra_spawn) { if (!G.extra_spawn && player_ent->valid) {
struct entity *e = entity_alloc(root); struct entity *e = entity_alloc(root);
entity_set_xform(e, XFORM_IDENT); 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(manifold->contacts) == 2);
CT_ASSERT(ARRAY_COUNT(res.points) == 2); CT_ASSERT(ARRAY_COUNT(res.points) == 2);
/* TODO: Move this down */ /* TODO: Move this down */
if (res.num_points > 0 || COLLIDER_DEBUG) { if (res.num_points > 0 || COLLIDER_DEBUG) {
if (!manifold) { if (!manifold) {
@ -438,6 +448,8 @@ INTERNAL void create_contact_manifolds(void)
#if COLLIDER_DEBUG #if COLLIDER_DEBUG
{ {
manifold->res = res; manifold->res = res;
manifold->dbg_xf0 = e0_xf;
manifold->dbg_xf1 = e1_xf;
if (manifold->num_contacts == 0) { if (manifold->num_contacts == 0) {
if (res.num_points > 0) { if (res.num_points > 0) {
++e0->colliding; ++e0->colliding;
@ -771,8 +783,8 @@ INTERNAL void solve_collisions(f32 dt, b32 apply_bias)
f32 vt = v2_dot(vrel, tangent); f32 vt = v2_dot(vrel, tangent);
f32 j = vt * k; f32 j = vt * k;
//f32 friction = 0.6f; f32 friction = 0.6f;
f32 friction = 1.0f; //f32 friction = 1.0f;
//f32 friction = F32_INFINITY; //f32 friction = F32_INFINITY;
f32 max_friction = friction * contact->normal_impulse; f32 max_friction = friction * contact->normal_impulse;
f32 old_impulse = contact->tangent_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); struct v2 tick_linear_velocity = v2_mul(ent->linear_velocity, dt);
f32 tick_angular_velocity = ent->angular_velocity * dt; f32 tick_angular_velocity = ent->angular_velocity * dt;
xf.og = v2_add(xf.og, tick_linear_velocity); 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); entity_set_xform(ent, xf);
#endif #endif
} }
@ -960,6 +978,7 @@ INTERNAL void game_update(struct game_cmd_array game_cmds)
{ {
logf_info("Spawning (test)"); logf_info("Spawning (test)");
#if GAME_SPAWN_LOTS #if GAME_SPAWN_LOTS
//#if 0
for (u32 i = 0; i < 50; ++i) { for (u32 i = 0; i < 50; ++i) {
spawn_test_entities(-(f32)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))); ent->local_collider = collider_from_quad(xform_mul_quad(ent->sprite_local_xform, quad_from_rect(slice.rect)));
#if 1 #if 1
if (entity_has_prop(ent, ENTITY_PROP_PLAYER_CONTROLLED)) { if (entity_has_prop(ent, ENTITY_PROP_TEST)) {
//if ((true)) { #if 0
#if 1
ent->local_collider.points[0] = V2(0, 0); ent->local_collider.points[0] = V2(0, 0);
ent->local_collider.count = 1; ent->local_collider.count = 1;
ent->local_collider.radius = 0.5; ent->local_collider.radius = 0.5;
#elif 1 #elif 0
ent->local_collider.points[0] = V2(0, 0.5); ent->local_collider.points[0] = V2(0, 0.5);
ent->local_collider.points[1] = V2(0, -0.5); ent->local_collider.points[1] = V2(0, -0.5);
ent->local_collider.count = 2; ent->local_collider.count = 2;
ent->local_collider.radius = 0.25; ent->local_collider.radius = 0.25;
#elif 0 #elif 1
#if 1 #if 1
/* "Bad" winding order */ /* "Bad" winding order */
ent->local_collider.points[0] = V2(-0.5, 0.5); 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 * Test
* ========================== */ * ========================== */
#if 0
for (u64 entity_index = 0; entity_index < store->reserved; ++entity_index) { for (u64 entity_index = 0; entity_index < store->reserved; ++entity_index) {
struct entity *ent = &store->entities[entity_index]; struct entity *ent = &store->entities[entity_index];
if (!entity_is_valid_and_active(ent)) continue; 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); entity_set_local_xform(ent, xf);
#endif #endif
} }
#endif
/* ========================== * /* ========================== *
* Trigger equipped * Trigger equipped
@ -1328,7 +1348,7 @@ INTERNAL void game_update(struct game_cmd_array game_cmds)
* Create forces from control focus (aim) * Create forces from control focus (aim)
* ========================== */ * ========================== */
#if 0 #if GAME_PLAYER_AIM
for (u64 entity_index = 0; entity_index < store->reserved; ++entity_index) { for (u64 entity_index = 0; entity_index < store->reserved; ++entity_index) {
struct entity *ent = &store->entities[entity_index]; struct entity *ent = &store->entities[entity_index];
if (!entity_is_valid_and_active(ent)) continue; if (!entity_is_valid_and_active(ent)) continue;

View File

@ -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)); 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) INLINE struct v2 v2_with_len(struct v2 a, f32 len)
{ {
f32 l_sq = a.x * a.x + a.y * a.y; f32 l_sq = a.x * a.x + a.y * a.y;

View File

@ -1000,6 +1000,7 @@ INTERNAL void user_update(void)
f32 thickness = 2; f32 thickness = 2;
{ {
/* Draw collider using support points */ /* Draw collider using support points */
//u32 detail = 64;
u32 detail = 512; u32 detail = 512;
draw_solid_collider_line(G.viewport_canvas, G.world_view, collider, xf, thickness, color, detail); 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) { if (collider.count == 1 && collider.radius > 0) {
/* Draw upwards line for circle */ /* Draw upwards line for circle */
struct v2 start = xf.og; 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); start = xform_mul_v2(G.world_view, start);
end = xform_mul_v2(G.world_view, end); end = xform_mul_v2(G.world_view, end);
draw_solid_line(G.viewport_canvas, start, end, thickness, color); 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)) { if (entity_has_prop(ent, ENTITY_PROP_MANIFOLD)) {
struct entity *e0 = entity_from_handle(store, ent->manifold_e0); struct entity *e0 = entity_from_handle(store, ent->manifold_e0);
struct entity *e1 = entity_from_handle(store, ent->manifold_e1); 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 e0_collider = e0->local_collider;
struct collider_shape e1_collider = e1->local_collider; struct collider_shape e1_collider = e1->local_collider;
(UNUSED)e0_collider; (UNUSED)e0_collider;
(UNUSED)e1_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 #if 0
/* Draw menkowski */ b32 should_draw = false;
{ for (u32 i = 0; i < ent->num_contacts; ++i) {
if (ent->contacts[i].starting_separation < -0.5) {
u32 color = ent->res.solved ? RGBA_32_F(0, 0, 0.25, 1) : RGBA_32_F(0, 0.25, 0.25, 1); should_draw = true;
f32 thickness = 2; break;
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);
} }
} }
#else
b32 should_draw = true;
#endif
/* Draw normal */ if (should_draw) {
{ #if 0
u32 color = COLOR_WHITE; /* Test info */
f32 len = 0.1f; {
f32 arrow_thickness = 2; struct font *disp_font = font_load_async(STR("res/fonts/fixedsys.ttf"), 12.0f);
f32 arrow_height = 5; if (disp_font) {
struct v2 start = xform_mul_v2(G.world_view, V2(0, 0)); f32 offset_px = 10;
struct v2 end = xform_mul_v2(G.world_view, v2_mul(v2_norm(ent->manifold_normal), len)); struct string fmt = STR(
draw_solid_arrow_line(G.viewport_canvas, start, end, arrow_thickness, arrow_height, color); "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 = { 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);
.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) { #endif
u32 color = simplex.len == 2 ? color_first : color_second;
draw_solid_circle(G.viewport_canvas, simplex_array.points[1], thickness * 3, color, 10); /* 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 cloud */
draw_solid_circle(G.viewport_canvas, simplex_array.points[2], thickness * 3, color, 10); {
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 #endif
@ -1168,6 +1207,7 @@ INTERNAL void user_update(void)
if (disp_font) { if (disp_font) {
f32 offset_px = 10; f32 offset_px = 10;
#if 1
struct string fmt = STR( struct string fmt = STR(
"path: %F\n" "path: %F\n"
"e0 index: %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); 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 #endif