From 25592d24d3c9fefd353b1ccddc1c04d1e3f406e3 Mon Sep 17 00:00:00 2001 From: jacob Date: Mon, 13 Jan 2025 15:58:30 -0600 Subject: [PATCH] rework collider clipping logic --- src/collider.c | 485 ++++++++++++++++++++++--------------------------- src/collider.h | 13 +- src/config.h | 4 +- src/draw.c | 2 +- src/game.c | 71 ++++---- src/phys.c | 2 +- src/user.c | 4 +- 7 files changed, 269 insertions(+), 312 deletions(-) diff --git a/src/collider.c b/src/collider.c index f48c1294..a76204b8 100644 --- a/src/collider.c +++ b/src/collider.c @@ -4,11 +4,9 @@ #include "scratch.h" /* How close can non-overlapping shapes be before collision is considered */ -//#define COLLISION_TOLERANCE 0.005f -#define COLLISION_TOLERANCE 0.0005f +#define COLLISION_TOLERANCE 0.005f /* NOTE: Should always be less than tolerance, since colliding = true if origin is within this distance. */ -//#define MIN_UNIQUE_PT_DIST_SQ (0.001f * 0.001f) #define MIN_UNIQUE_PT_DIST_SQ (0.0001f * 0.0001f) /* To prevent extremely large prototypes when origin is in exact center of rounded feature */ @@ -37,7 +35,7 @@ INTERNAL void _dbgbreakable(void) #define DBGSTEP #endif -struct v2 collider_support_point(struct collider_shape *a, struct xform xf, struct v2 dir) +INTERNAL struct collider_support_point collider_get_support_point_internal(struct collider_shape *a, struct xform xf, struct v2 dir, i32 ignore) { struct v2 *points = a->points; u32 count = a->count; @@ -46,14 +44,24 @@ struct v2 collider_support_point(struct collider_shape *a, struct xform xf, stru dir = v2_rotated(dir, -xform_get_rotation(xf)); dir = v2_mul_v2(dir, xform_get_scale(xf)); + if (count == 1) { + /* Skip 'ignore' on single point colliders */ + ignore = -1; + } + struct v2 furthest = ZI; + u32 furthest_index = 0; f32 furthest_dot = -F32_INFINITY; for (u32 i = 0; i < count; ++i) { + if ((i32)i == ignore) { + continue; + } struct v2 p = points[i]; f32 dot = v2_dot(dir, p); if (dot > furthest_dot) { furthest = p; furthest_dot = dot; + furthest_index = i; } } @@ -64,37 +72,23 @@ struct v2 collider_support_point(struct collider_shape *a, struct xform xf, stru furthest = xform_mul_v2(xf, furthest); - return furthest; + struct collider_support_point res; + res.p = furthest; + res.i = furthest_index; + return res; } -INTERNAL u32 collider_support_point_index(struct collider_shape *a, struct xform xf, struct v2 dir) +struct collider_support_point collider_get_support_point(struct collider_shape *a, struct xform xf, struct v2 dir) { - /* 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 = -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; - furthest_dot = dot; - } - } - return furthest; + return collider_get_support_point_internal(a, xf, dir, -1); } INTERNAL struct collider_menkowski_point get_menkowski_point(struct collider_shape *shape0, struct collider_shape *shape1, struct xform xf0, struct xform xf1, struct v2 dir) { struct collider_menkowski_point res; - res.s0 = collider_support_point(shape0, xf0, dir); - res.s1 = collider_support_point(shape1, xf1, v2_neg(dir)); - res.p = v2_sub(res.s0, res.s1); + res.s0 = collider_get_support_point(shape0, xf0, dir); + res.s1 = collider_get_support_point(shape1, xf1, v2_neg(dir)); + res.p = v2_sub(res.s0.p, res.s1.p); return res; } @@ -350,7 +344,6 @@ INTERNAL struct epa_result epa_get_normal_from_gjk(struct collider_shape *shape0 struct v2 dir = v2_mul(v2_perp(vab), winding); struct collider_menkowski_point m = get_menkowski_point(shape0, shape1, xf0, xf1, dir); - /* TODO: Remove this (debugging) */ #if COLLIDER_DEBUG { normal = v2_norm(dir); @@ -432,6 +425,68 @@ INTERNAL struct epa_result epa_get_normal_from_gjk(struct collider_shape *shape0 return res; } +/* ========================== * + * Clipping + * ========================== */ + +struct clip_line_to_line_result { + struct v2 a0_clipped, b0_clipped; + struct v2 a1_clipped, b1_clipped; +}; + +INTERNAL struct clip_line_to_line_result clip_line_to_line(struct v2 a0, struct v2 b0, struct v2 a1, struct v2 b1, struct v2 normal) +{ + struct v2 vab0 = v2_sub(b0, a0); + struct v2 vab1 = v2_sub(b1, a1); + struct v2 va0a1 = v2_sub(a1, a0); + struct v2 vb0b1 = v2_sub(b1, b0); + f32 vab0_w = v2_wedge(vab0, normal); + f32 vab1_w = v2_wedge(vab1, normal); + f32 va0a1_w = v2_wedge(va0a1, normal); + f32 vb0b1_w = v2_wedge(vb0b1, normal); + + /* FIXME: Handle 0 denominator */ + f32 a0t; + f32 b0t; + { + f32 w = 1 / vab0_w; + a0t = clamp_f32(va0a1_w * w, 0, 1); + b0t = clamp_f32(vb0b1_w * -w, 0, 1); + } + f32 a1t; + f32 b1t; + { + f32 w = 1 / vab1_w; + a1t = clamp_f32(-va0a1_w * w, 0, 1); + b1t = clamp_f32(-vb0b1_w * -w, 0, 1); + } + + struct clip_line_to_line_result res; + res.a0_clipped = v2_add(a0, v2_mul(vab0, a0t)); + res.a1_clipped = v2_add(a1, v2_mul(vab1, a1t)); + res.b0_clipped = v2_add(b0, v2_mul(vab0, -b0t)); + res.b1_clipped = v2_add(b1, v2_mul(vab1, -b1t)); + return res; +} + +INTERNAL struct v2 clip_point_to_line(struct v2 a, struct v2 b, struct v2 p, struct v2 normal) +{ + struct v2 vab = v2_sub(b, a); + struct v2 vap = v2_sub(p, a); + + f32 vab_w = v2_wedge(vab, normal); + f32 vap_w = v2_wedge(vap, normal); + + f32 t; + { + f32 w = 1 / vab_w; + t = clamp_f32(vap_w * w, 0, 1); + } + + struct v2 res = v2_add(a, v2_mul(vab, t)); + return res; +} + /* ========================== * * Collision points * ========================== */ @@ -444,13 +499,6 @@ struct collider_collision_points_result collider_collision_points(struct collide const f32 min_unique_pt_dist_sq = MIN_UNIQUE_PT_DIST_SQ; const u32 max_epa_iterations = MAX_EPA_ITERATIONS; - struct v2 *points0 = shape0->points; - struct v2 *points1 = shape1->points; - u32 count0 = shape0->count; - u32 count1 = shape1->count; - f32 radius0 = shape0->radius; - f32 radius1 = shape1->radius; - struct collider_collision_point points[2] = ZI; u32 num_points = 0; b32 colliding = false; @@ -511,253 +559,158 @@ struct collider_collision_points_result collider_collision_points(struct collide /* Max vertices must be < 16 to fit in 4 bit ids */ CT_ASSERT(ARRAY_COUNT(shape0->points) <= 16); - DBGSTEP; + struct collider_menkowski_feature f = epa_res.closest_feature; + { - const f32 wedge_epsilon = 0.001f; - //const f32 wedge_epsilon = 0.05f; - //const f32 wedge_epsilon = 0.1f; + b32 collapse0 = false; + b32 collapse1 = false; - /* shape0 a -> b winding = clockwise */ - u32 id_a0; - u32 id_b0; - struct v2 a0; - struct v2 b0; - - /* shape1 a -> b winding = counterclockwise */ - u32 id_a1; - u32 id_b1; - struct v2 a1; - struct v2 b1; - { - u32 p_i = collider_support_point_index(shape0, xf0, normal); - u32 a_i = (p_i > 0) ? (p_i - 1) : (count0 - 1); - u32 b_i = ((p_i + 1) < count0) ? (p_i + 1) : 0; - - struct v2 p = xform_mul_v2(xf0, points0[p_i]); - struct v2 a = xform_mul_v2(xf0, points0[a_i]); - struct v2 b = xform_mul_v2(xf0, points0[b_i]); - - struct v2 vap = v2_sub(p, a); - struct v2 vpb = v2_sub(b, p); - - f32 vap_wedge = v2_wedge(vap, normal); - f32 vpb_wedge = v2_wedge(vpb, normal); - b32 reversed = count0 > 1 && v2_winding(vap, vpb) < 0; - if (reversed) { - /* Winding is reversed, swap vap & vpb wedge */ - f32 t = vap_wedge; - vap_wedge = vpb_wedge; - vpb_wedge = t; - } - - if (vap_wedge < (vpb_wedge + wedge_epsilon)) { - if (reversed) { - id_a0 = p_i; - id_b0 = a_i; - a0 = p; - b0 = a; - } else { - id_a0 = a_i; - id_b0 = p_i; - a0 = a; - b0 = p; - } - } else { - if (reversed) { - id_a0 = b_i; - id_b0 = p_i; - a0 = b; - b0 = p; - } else { - id_a0 = p_i; - id_b0 = b_i; - a0 = p; - b0 = b; - } - } - } - { - struct v2 neg_normal = v2_neg(normal); - - u32 p_i = collider_support_point_index(shape1, xf1, neg_normal); - u32 a_i = (p_i > 0) ? (p_i - 1) : (count1 - 1); - u32 b_i = ((p_i + 1) < count1) ? (p_i + 1) : 0; - - struct v2 p = xform_mul_v2(xf1, points1[p_i]); - struct v2 a = xform_mul_v2(xf1, points1[a_i]); - struct v2 b = xform_mul_v2(xf1, points1[b_i]); - - struct v2 vap = v2_sub(p, a); - struct v2 vpb = v2_sub(b, p); - - f32 vap_wedge = v2_wedge(vap, normal); - f32 vpb_wedge = v2_wedge(vpb, normal); - b32 reversed = count1 > 1 && v2_winding(vap, vpb) < 0; - if (reversed) { - /* Winding is reversed, swapvap & vpb wedge*/ - f32 t = vap_wedge; - vap_wedge = vpb_wedge; - vpb_wedge = t; - } - - if (vap_wedge > (vpb_wedge + wedge_epsilon)) { - if (reversed) { - id_a1 = a_i; - id_b1 = p_i; - a1 = a; - b1 = p; - } else { - id_a1 = p_i; - id_b1 = a_i; - a1 = p; - b1 = a; - } - } else { - if (reversed) { - id_a1 = p_i; - id_b1 = b_i; - a1 = p; - b1 = b; - } else { - id_a1 = b_i; - id_b1 = p_i; - a1 = b; - b1 = p; - } - } - } - - if (radius0 > 0.0) { - struct v2 radius_dir = v2_rotated(normal, -xform_get_rotation(xf0)); - radius_dir = v2_mul_v2(radius_dir, xform_get_scale(xf0)); - radius_dir = v2_with_len(radius_dir, radius0); - radius_dir = xform_basis_mul_v2(xf0, radius_dir); - a0 = v2_add(a0, radius_dir); - b0 = v2_add(b0, radius_dir); - } - - if (radius1 > 0.0) { - struct v2 radius_dir = v2_rotated(normal, -xform_get_rotation(xf1)); - radius_dir = v2_mul_v2(radius_dir, xform_get_scale(xf1)); - radius_dir = v2_with_len(radius_dir, radius1); - radius_dir = xform_basis_mul_v2(xf1, radius_dir); - a1 = v2_sub(a1, radius_dir); - b1 = v2_sub(b1, radius_dir); - } - - f32 a0t = 0; - f32 a1t = 0; - f32 b0t = 0; - f32 b1t = 0; - - struct v2 vab0 = v2_sub(b0, a0); - struct v2 vab1 = v2_sub(b1, a1); - - { - - f32 vab0_wedge_normal = v2_wedge(vab0, normal); - f32 vab1_wedge_normal = v2_wedge(vab1, normal); - -#if 0 - b32 collapse0 = math_fabs(vab0_wedge_normal) < wedge_epsilon; - b32 collapse1 = math_fabs(vab1_wedge_normal) < wedge_epsilon; -#else - b32 collapse0 = false; - b32 collapse1 = false; -#endif - - if (collapse0) { - if (v2_dot(b0, normal) >= v2_dot(a0, normal)) { - a0 = b0; - a0t = 1; - b0t = 0; + struct collider_support_point a0 = f.a.s0; + struct collider_support_point a1 = f.a.s1; + struct collider_support_point b0 = f.b.s0; + struct collider_support_point b1 = f.b.s1; + /* FIXME: Manually account for shapes w/ 1 & 2 points */ + if (f.len == 2) { + if (a0.i == b0.i) { + if (shape0->count > 1) { + b0 = collider_get_support_point_internal(shape0, xf0, normal, b0.i); } else { + collapse0 = true; b0 = a0; - a0t = 0; - b0t = 1; } - vab0 = V2(0, 0); } - - if (collapse1) { - if (v2_dot(b1, normal) < v2_dot(a1, normal)) { - a1 = b1; - a1t = 1; - b1t = 0; + if (a1.i == b1.i) { + if (shape1->count > 1) { + b1 = collider_get_support_point_internal(shape1, xf1, v2_neg(normal), b1.i); } else { + collapse1 = true; b1 = a1; - a1t = 0; - b1t = 1; } - vab1 = V2(0, 0); - } - - struct v2 va0a1 = v2_sub(a1, a0); - struct v2 vb0b1 = v2_sub(b1, b0); - f32 va0a1_wedge_normal = v2_wedge(va0a1, normal); - f32 vb0b1_wedge_normal = v2_wedge(vb0b1, normal); - - if (!collapse0) { - f32 w = 1 / vab0_wedge_normal; - a0t = clamp_f32(va0a1_wedge_normal * w, 0, 1); - b0t = clamp_f32(vb0b1_wedge_normal * -w, 0, 1); - } - - if (!collapse1) { - 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 { + collapse0 = true; + collapse1 = true; + b0 = a0; + b1 = a1; } - struct v2 a0_clipped = v2_add(a0, v2_mul(vab0, a0t)); - struct v2 a1_clipped = v2_add(a1, v2_mul(vab1, a1t)); - struct v2 b0_clipped = v2_add(b0, v2_mul(vab0, -b0t)); - struct v2 b1_clipped = v2_add(b1, v2_mul(vab1, -b1t)); + struct v2 vab0 = v2_sub(b0.p, a0.p); + struct v2 vab1 = v2_sub(b1.p, a1.p); + struct v2 vab0_norm = v2_norm(vab0); + struct v2 vab1_norm = v2_norm(vab1); - struct v2 va0a1_clipped = v2_sub(a1_clipped, a0_clipped); - struct v2 vb0b1_clipped = v2_sub(b1_clipped, b0_clipped); + /* Swap points based on normal direction for consistent clipping */ + if (v2_wedge(normal, vab0) < 0) { + struct collider_support_point tmp = a0; + a0 = b0; + b0 = tmp; + vab0 = v2_neg(vab0); + } + if (v2_wedge(normal, vab1) < 0) { + struct collider_support_point tmp = a1; + a1 = b1; + b1 = tmp; + vab1 = v2_neg(vab1); + } - f32 a_sep = v2_dot(va0a1_clipped, normal); - f32 b_sep = v2_dot(vb0b1_clipped, normal); + /* Collapse lines that are too far in the direction of the normal to be accurately clipped */ + f32 collapse_epsilon = 0.05f; + collapse0 = collapse0 || math_fabs(v2_wedge(normal, vab0_norm)) < collapse_epsilon; + collapse1 = collapse1 || math_fabs(v2_wedge(normal, vab1_norm)) < collapse_epsilon; - struct v2 contact_a = v2_add(a0_clipped, v2_mul(va0a1_clipped, 0.5f)); - struct v2 contact_b = v2_add(b0_clipped, v2_mul(vb0b1_clipped, 0.5f)); - - b32 ignore_a = false; - b32 ignore_b = false; - if (v2_len_sq(v2_sub(contact_b, contact_a)) < (0.005f * 0.005f)) { - /* Merge contacts */ - if (a_sep > b_sep) { - ignore_a = true; + /* Collapse lines into deepest point */ + if (collapse0) { + if (v2_dot(normal, vab0) > 0) { + a0 = b0; } else { - ignore_b = true; + /* TODO: Remove this (debugging) */ + b0 = a0; + } + } + if (collapse1) { + if (v2_dot(normal, vab1) < 0) { + a1 = b1; + } else { + /* TODO: Remove this (debugging) */ + b1 = a1; } } - if (a_sep < tolerance && !ignore_a) { + f32 a_sep = F32_INFINITY; + f32 b_sep = F32_INFINITY; + struct v2 a_midpoint = ZI; + struct v2 b_midpoint = ZI; + b32 ignore_a = true; + b32 ignore_b = true; + if (!collapse0 && !collapse1) { + /* Clip line to line */ + struct clip_line_to_line_result clip_res = clip_line_to_line(a0.p, b0.p, a1.p, b1.p, normal); + struct v2 a0_clipped = clip_res.a0_clipped; + struct v2 a1_clipped = clip_res.a1_clipped; + struct v2 b0_clipped = clip_res.b0_clipped; + struct v2 b1_clipped = clip_res.b1_clipped; + /* Calc midpoint between clipped a & b */ + struct v2 va0a1_clipped = v2_sub(a1_clipped, a0_clipped); + struct v2 vb0b1_clipped = v2_sub(b1_clipped, b0_clipped); + a_sep = v2_dot(va0a1_clipped, normal); + b_sep = v2_dot(vb0b1_clipped, normal); + a_midpoint = v2_add(a0_clipped, v2_mul(va0a1_clipped, 0.5f)); + b_midpoint = v2_add(b0_clipped, v2_mul(vb0b1_clipped, 0.5f)); + ignore_a = false; + ignore_b = false; + struct v2 vfin = v2_sub(b_midpoint, a_midpoint); + if (v2_len_sq(vfin) < (0.005 * 0.005)) { + if (a_sep > b_sep) { + ignore_a = true; + } else { + ignore_b = true; + } + } + res.a0_clipped = a0_clipped; + res.a1_clipped = a1_clipped; + res.b0_clipped = b0_clipped; + res.b1_clipped = b1_clipped; + } else { + struct v2 p0 = a0.p; + struct v2 p1 = a1.p; + /* TODO: Choose ID based on closest clipped point */ + if (collapse1 && !collapse0) { + /* Project a1 onto vab0 */ + p0 = clip_point_to_line(a0.p, b0.p, a1.p, normal); + } + if (collapse0 && !collapse1) { + /* Project a0 onto vab1 */ + p1 = clip_point_to_line(a1.p, b1.p, a0.p, normal); + } + /* Calc midpoint */ + struct v2 vsep = v2_sub(p1, p0); + a_midpoint = v2_add(p0, v2_mul(vsep, 0.5f)); + a_sep = v2_dot(normal, p1) - v2_dot(normal, p0); + ignore_a = false; + res.a0_clipped = p0; + res.a1_clipped = p1; + res.b0_clipped = p0; + res.b1_clipped = p1; + } + + /* Insert points */ + if (!ignore_a && a_sep < tolerance) { struct collider_collision_point *point = &points[num_points++]; - point->id = id_a0 | (id_a1 << 4); + point->id = a0.i | (a1.i << 4); point->separation = a_sep; - point->point = contact_a; + point->point = a_midpoint; } - - if (b_sep < tolerance && !ignore_b) { + if (!ignore_b && b_sep < tolerance) { struct collider_collision_point *point = &points[num_points++]; - point->id = id_b0 | (id_b1 << 4); + point->id = b0.i | (b1.i << 4); point->separation = b_sep; - point->point = contact_b; + point->point = b_midpoint; } - /* TODO: Remove this */ - res.a0_clipped = a0_clipped; - res.a1_clipped = a1_clipped; - res.b0_clipped = b0_clipped; - res.b1_clipped = b1_clipped; - res.a0 = a0; - res.a1 = a1; - res.b0 = b0; - res.b1 = b1; + res.a0 = a0.p; + res.a1 = a1.p; + res.b0 = b0.p; + res.b1 = b1.p; } } @@ -825,8 +778,8 @@ struct collider_closest_points_result collider_closest_points(struct collider_sh colliding = gjk_res.overlapping; struct collider_menkowski_feature f = epa_res.closest_feature; if (f.len == 1) { - p0 = f.a.s0; - p1 = f.a.s1; + p0 = f.a.s0.p; + p1 = f.a.s1.p; colliding = gjk_res.overlapping || v2_len_sq(v2_neg(f.a.p)) <= (tolerance * tolerance); } else { ASSERT(f.len == 2); @@ -839,13 +792,13 @@ struct collider_closest_points_result collider_closest_points(struct collider_sh ratio = clamp_f32(v2_dot(vab, vao) / v2_dot(vab, vab), 0, 1); } /* Shape 0 */ - p0 = v2_sub(f.b.s0, f.a.s0); + p0 = v2_sub(f.b.s0.p, f.a.s0.p); p0 = v2_mul(p0, ratio); - p0 = v2_add(p0, f.a.s0); + p0 = v2_add(p0, f.a.s0.p); /* Shape 1 */ - p1 = v2_sub(f.b.s1, f.a.s1); + p1 = v2_sub(f.b.s1.p, f.a.s1.p); p1 = v2_mul(p1, ratio); - p1 = v2_add(p1, f.a.s1); + p1 = v2_add(p1, f.a.s1.p); colliding = gjk_res.overlapping || v2_len_sq(v2_sub(p1, p0)) <= (tolerance * tolerance); } @@ -897,8 +850,8 @@ f32 collider_time_of_impact(struct collider_shape *c0, struct collider_shape *c1 } { - struct v2 p0 = collider_support_point(c0, xf0_t1, dir); - struct v2 p1 = collider_support_point(c1, xf1_t1, dir_neg); + struct v2 p0 = collider_get_support_point(c0, xf0_t1, dir).p; + struct v2 p1 = collider_get_support_point(c1, xf1_t1, dir_neg).p; t1_sep = v2_dot(dir, v2_sub(p1, p0)); if (t1_sep > 0) { /* Shapes are not penetrating at t=1 */ @@ -926,8 +879,8 @@ f32 collider_time_of_impact(struct collider_shape *c0, struct collider_shape *c1 struct xform xf0 = xform_lerp(xf0_t0, xf0_t1, t); struct xform xf1 = xform_lerp(xf1_t0, xf1_t1, t); - struct v2 p0 = collider_support_point(c0, xf0, dir); - struct v2 p1 = collider_support_point(c1, xf1, dir_neg); + struct v2 p0 = collider_get_support_point(c0, xf0, dir).p; + struct v2 p1 = collider_get_support_point(c1, xf1, dir_neg).p; t_sep = v2_dot(dir, v2_sub(p1, p0)); /* Update bracket */ diff --git a/src/collider.h b/src/collider.h index e8e172cc..5290a6e4 100644 --- a/src/collider.h +++ b/src/collider.h @@ -5,10 +5,15 @@ extern u32 collider_debug_steps; #endif +struct collider_support_point { + struct v2 p; + u32 i; /* Index of original point in shape */ +}; + struct collider_menkowski_point { - struct v2 p; /* Menkowski difference point */ - struct v2 s0; /* Support point of first shape in dir */ - struct v2 s1; /* Support point of second shape in -dir */ + struct v2 p; /* Menkowski difference point */ + struct collider_support_point s0; /* Support point of first shape in dir */ + struct collider_support_point s1; /* Support point of second shape in -dir */ }; struct collider_menkowski_simplex { @@ -53,7 +58,7 @@ struct collider_closest_points_result { struct collider_prototype prototype; }; -struct v2 collider_support_point(struct collider_shape *a, struct xform xf, struct v2 dir); +struct collider_support_point collider_get_support_point(struct collider_shape *a, struct xform xf, struct v2 dir); struct collider_collision_points_result collider_collision_points(struct collider_shape *shape0, struct collider_shape *shape1, struct xform xf0, struct xform xf1); diff --git a/src/config.h b/src/config.h index 6e3342bd..628ae832 100644 --- a/src/config.h +++ b/src/config.h @@ -37,7 +37,7 @@ #define GAME_PHYSICS_ENABLE_RELAXATION 1 #define GAME_PHYSICS_ENABLE_TOI 1 -#define GAME_PHYSICS_ENABLE_COLLISION 0 +#define GAME_PHYSICS_ENABLE_COLLISION 1 #define GAME_SPAWN_TESTENT 0 #define GAME_PLAYER_AIM 1 @@ -54,7 +54,7 @@ #define USER_INTERP_ENABLED 1 #define COLLIDER_DEBUG RTC -#define COLLIDER_DEBUG_DETAILED 1 +#define COLLIDER_DEBUG_DETAILED 0 #define COLLIDER_DEBUG_DETAILED_DRAW_MENKOWSKI 1 /* ========================== * diff --git a/src/draw.c b/src/draw.c index 0634cb4e..72b842de 100644 --- a/src/draw.c +++ b/src/draw.c @@ -285,7 +285,7 @@ void draw_solid_collider_line(struct renderer_canvas *canvas, struct xform draw_ for (u32 i = 0; i < detail; ++i) { f32 angle = ((f32)i / (f32)detail) * (2 * PI); struct v2 dir = V2(math_cos(angle), math_sin(angle)); - struct v2 p = collider_support_point(&shape, shape_xf, dir); + struct v2 p = collider_get_support_point(&shape, shape_xf, dir).p; p = xform_mul_v2(draw_xf, p); points[i] = p; } diff --git a/src/game.c b/src/game.c index 5be21bea..865caa59 100644 --- a/src/game.c +++ b/src/game.c @@ -244,10 +244,9 @@ INTERNAL void spawn_test_entities(void) #endif - /* Box */ -#if 1 - { + /* Big box */ #if 0 + { struct entity *e = entity_alloc(root); struct v2 pos = V2(1, -0.5); @@ -260,11 +259,16 @@ INTERNAL void spawn_test_entities(void) e->sprite_collider_slice = STR("shape"); entity_enable_prop(e, ENTITY_PROP_PHYSICAL_DYNAMIC); - e->mass_unscaled = 10; + e->mass_unscaled = 100; e->inertia_unscaled = 10; - e->linear_ground_friction = 250; + e->linear_ground_friction = 100; e->angular_ground_friction = 5; -#else + } +#endif + + /* Tiny box */ +#if 0 + { struct entity *e = entity_alloc(root); struct v2 pos = V2(1, -0.5); @@ -280,7 +284,6 @@ INTERNAL void spawn_test_entities(void) e->mass_unscaled = 0.5; e->inertia_unscaled = 1000; e->linear_ground_friction = 0.001; -#endif } #endif @@ -629,50 +632,44 @@ INTERNAL void game_update(struct game_cmd_array game_cmds) if (ent->sprite_collider_slice.len > 0) { struct xform cxf = ent->sprite_local_xform; -#if 0 - if (entity_has_prop(ent, ENTITY_PROP_TEST)) { - f32 scale = 0.5; - cxf = xform_scaled(cxf, V2(scale, scale)); - } -#endif - struct sprite_sheet_slice slice = sprite_sheet_get_slice(sheet, ent->sprite_collider_slice, ent->animation_frame); ent->local_collider = collider_from_quad(xform_mul_quad(cxf, quad_from_rect(slice.rect))); + } + /* Test collider */ #if 0 - if (entity_has_prop(ent, ENTITY_PROP_TEST)) { + if (entity_has_prop(ent, ENTITY_PROP_TEST)) { //if ((true)) { #if 0 - ent->local_collider.points[0] = V2(0, 0); - ent->local_collider.count = 1; - ent->local_collider.radius = 0.5; -#elif 1 - ent->local_collider.points[0] = v2_with_len(V2(0.08f, 0.17f), 0.15f); - ent->local_collider.points[1] = v2_with_len(V2(-0.07f, -0.2f), 0.15f); - ent->local_collider.count = 2; - ent->local_collider.radius = 0.075f; + ent->local_collider.points[0] = V2(0, 0); + ent->local_collider.count = 1; + ent->local_collider.radius = 0.5; +#elif 0 + ent->local_collider.points[0] = v2_with_len(V2(0.08f, 0.17f), 0.15f); + ent->local_collider.points[1] = v2_with_len(V2(-0.07f, -0.2f), 0.15f); + ent->local_collider.count = 2; + ent->local_collider.radius = 0.075f; #elif 1 #if 0 /* "Bad" winding order */ - ent->local_collider.points[0] = V2(-0.15, 0.15); - ent->local_collider.points[1] = V2(0.15, 0.15); - ent->local_collider.points[2] = V2(0, -0.15); + ent->local_collider.points[0] = V2(-0.15, 0.15); + ent->local_collider.points[1] = V2(0.15, 0.15); + ent->local_collider.points[2] = V2(0, -0.15); #else - ent->local_collider.points[0] = V2(0, -0.15); - ent->local_collider.points[1] = V2(0.15, 0.15); - ent->local_collider.points[2] = V2(-0.15, 0.15); + ent->local_collider.points[0] = V2(0, -0.15); + ent->local_collider.points[1] = V2(0.15, 0.15); + ent->local_collider.points[2] = V2(-0.15, 0.15); #endif - ent->local_collider.count = 3; - ent->local_collider.radius = 0.25; - //ent->local_collider.radius = math_fabs(math_sin(G.tick.time) / 3); + ent->local_collider.count = 3; + ent->local_collider.radius = 0.25; + //ent->local_collider.radius = math_fabs(math_sin(G.tick.time) / 3); #else //ent->local_collider.radius = 0.5; - ent->local_collider.radius = 0.25; - //ent->local_collider.radius = 0.; -#endif - } + ent->local_collider.radius = 0.25; + //ent->local_collider.radius = 0.; #endif } +#endif } /* ========================== * @@ -863,7 +860,7 @@ INTERNAL void game_update(struct game_cmd_array game_cmds) bullet->mass_unscaled = 0.04f; bullet->inertia_unscaled = 0.00001f; -#if 0 +#if 1 /* Point collider */ bullet->local_collider.points[0] = V2(0, 0); bullet->local_collider.count = 1; diff --git a/src/phys.c b/src/phys.c index 0331f0bd..25a8d10b 100644 --- a/src/phys.c +++ b/src/phys.c @@ -1119,7 +1119,7 @@ void phys_step(struct phys_ctx *ctx, f32 timestep) { #if GAME_PHYSICS_ENABLE_TOI const f32 min_toi = 0.000001f; - const f32 tolerance = 0.00001f; + const f32 tolerance = 0.0001f; const u32 max_iterations = 16; f32 earliest_toi = max_f32(phys_determine_earliest_toi_for_bullets(ctx, step_dt, tolerance, max_iterations), min_toi); step_dt = remaining_dt * earliest_toi; diff --git a/src/user.c b/src/user.c index d82273fc..7ae10fbd 100644 --- a/src/user.c +++ b/src/user.c @@ -1025,7 +1025,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, v2_neg(xf.by)); + struct v2 end = collider_get_support_point(&collider, xf, v2_neg(xf.by)).p; 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); @@ -1128,6 +1128,7 @@ INTERNAL void user_update(void) (UNUSED)e1_collider; /* Draw closest points */ +#if 0 { f32 radius = 4; u32 color = RGBA_32_F(1, 1, 0, 0.5); @@ -1136,6 +1137,7 @@ INTERNAL void user_update(void) draw_solid_circle(G.viewport_canvas, a, radius, color, 10); draw_solid_circle(G.viewport_canvas, b, radius, color, 10); } +#endif /* Draw clipping */ {