rework collider clipping logic
This commit is contained in:
parent
a1b8f752c9
commit
25592d24d3
485
src/collider.c
485
src/collider.c
@ -4,11 +4,9 @@
|
|||||||
#include "scratch.h"
|
#include "scratch.h"
|
||||||
|
|
||||||
/* How close can non-overlapping shapes be before collision is considered */
|
/* How close can non-overlapping shapes be before collision is considered */
|
||||||
//#define COLLISION_TOLERANCE 0.005f
|
#define COLLISION_TOLERANCE 0.005f
|
||||||
#define COLLISION_TOLERANCE 0.0005f
|
|
||||||
|
|
||||||
/* NOTE: Should always be less than tolerance, since colliding = true if origin is within this distance. */
|
/* 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)
|
#define MIN_UNIQUE_PT_DIST_SQ (0.0001f * 0.0001f)
|
||||||
|
|
||||||
/* 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 */
|
||||||
@ -37,7 +35,7 @@ INTERNAL void _dbgbreakable(void)
|
|||||||
#define DBGSTEP
|
#define DBGSTEP
|
||||||
#endif
|
#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;
|
struct v2 *points = a->points;
|
||||||
u32 count = a->count;
|
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_rotated(dir, -xform_get_rotation(xf));
|
||||||
dir = v2_mul_v2(dir, xform_get_scale(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;
|
struct v2 furthest = ZI;
|
||||||
|
u32 furthest_index = 0;
|
||||||
f32 furthest_dot = -F32_INFINITY;
|
f32 furthest_dot = -F32_INFINITY;
|
||||||
for (u32 i = 0; i < count; ++i) {
|
for (u32 i = 0; i < count; ++i) {
|
||||||
|
if ((i32)i == ignore) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
struct v2 p = 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 = p;
|
furthest = p;
|
||||||
furthest_dot = dot;
|
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);
|
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 */
|
return collider_get_support_point_internal(a, xf, dir, -1);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
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;
|
struct collider_menkowski_point res;
|
||||||
res.s0 = collider_support_point(shape0, xf0, dir);
|
res.s0 = collider_get_support_point(shape0, xf0, dir);
|
||||||
res.s1 = collider_support_point(shape1, xf1, v2_neg(dir));
|
res.s1 = collider_get_support_point(shape1, xf1, v2_neg(dir));
|
||||||
res.p = v2_sub(res.s0, res.s1);
|
res.p = v2_sub(res.s0.p, res.s1.p);
|
||||||
return res;
|
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 v2 dir = v2_mul(v2_perp(vab), winding);
|
||||||
struct collider_menkowski_point m = get_menkowski_point(shape0, shape1, xf0, xf1, dir);
|
struct collider_menkowski_point m = get_menkowski_point(shape0, shape1, xf0, xf1, dir);
|
||||||
|
|
||||||
/* TODO: Remove this (debugging) */
|
|
||||||
#if COLLIDER_DEBUG
|
#if COLLIDER_DEBUG
|
||||||
{
|
{
|
||||||
normal = v2_norm(dir);
|
normal = v2_norm(dir);
|
||||||
@ -432,6 +425,68 @@ INTERNAL struct epa_result epa_get_normal_from_gjk(struct collider_shape *shape0
|
|||||||
return res;
|
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
|
* 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 f32 min_unique_pt_dist_sq = MIN_UNIQUE_PT_DIST_SQ;
|
||||||
const u32 max_epa_iterations = MAX_EPA_ITERATIONS;
|
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;
|
struct collider_collision_point points[2] = ZI;
|
||||||
u32 num_points = 0;
|
u32 num_points = 0;
|
||||||
b32 colliding = false;
|
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 */
|
/* Max vertices must be < 16 to fit in 4 bit ids */
|
||||||
CT_ASSERT(ARRAY_COUNT(shape0->points) <= 16);
|
CT_ASSERT(ARRAY_COUNT(shape0->points) <= 16);
|
||||||
|
|
||||||
DBGSTEP;
|
struct collider_menkowski_feature f = epa_res.closest_feature;
|
||||||
|
|
||||||
{
|
{
|
||||||
const f32 wedge_epsilon = 0.001f;
|
b32 collapse0 = false;
|
||||||
//const f32 wedge_epsilon = 0.05f;
|
b32 collapse1 = false;
|
||||||
//const f32 wedge_epsilon = 0.1f;
|
|
||||||
|
|
||||||
/* shape0 a -> b winding = clockwise */
|
struct collider_support_point a0 = f.a.s0;
|
||||||
u32 id_a0;
|
struct collider_support_point a1 = f.a.s1;
|
||||||
u32 id_b0;
|
struct collider_support_point b0 = f.b.s0;
|
||||||
struct v2 a0;
|
struct collider_support_point b1 = f.b.s1;
|
||||||
struct v2 b0;
|
/* FIXME: Manually account for shapes w/ 1 & 2 points */
|
||||||
|
if (f.len == 2) {
|
||||||
/* shape1 a -> b winding = counterclockwise */
|
if (a0.i == b0.i) {
|
||||||
u32 id_a1;
|
if (shape0->count > 1) {
|
||||||
u32 id_b1;
|
b0 = collider_get_support_point_internal(shape0, xf0, normal, b0.i);
|
||||||
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;
|
|
||||||
} else {
|
} else {
|
||||||
|
collapse0 = true;
|
||||||
b0 = a0;
|
b0 = a0;
|
||||||
a0t = 0;
|
|
||||||
b0t = 1;
|
|
||||||
}
|
}
|
||||||
vab0 = V2(0, 0);
|
|
||||||
}
|
}
|
||||||
|
if (a1.i == b1.i) {
|
||||||
if (collapse1) {
|
if (shape1->count > 1) {
|
||||||
if (v2_dot(b1, normal) < v2_dot(a1, normal)) {
|
b1 = collider_get_support_point_internal(shape1, xf1, v2_neg(normal), b1.i);
|
||||||
a1 = b1;
|
|
||||||
a1t = 1;
|
|
||||||
b1t = 0;
|
|
||||||
} else {
|
} else {
|
||||||
|
collapse1 = true;
|
||||||
b1 = a1;
|
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 vab0 = v2_sub(b0.p, a0.p);
|
||||||
struct v2 a1_clipped = v2_add(a1, v2_mul(vab1, a1t));
|
struct v2 vab1 = v2_sub(b1.p, a1.p);
|
||||||
struct v2 b0_clipped = v2_add(b0, v2_mul(vab0, -b0t));
|
struct v2 vab0_norm = v2_norm(vab0);
|
||||||
struct v2 b1_clipped = v2_add(b1, v2_mul(vab1, -b1t));
|
struct v2 vab1_norm = v2_norm(vab1);
|
||||||
|
|
||||||
struct v2 va0a1_clipped = v2_sub(a1_clipped, a0_clipped);
|
/* Swap points based on normal direction for consistent clipping */
|
||||||
struct v2 vb0b1_clipped = v2_sub(b1_clipped, b0_clipped);
|
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);
|
/* Collapse lines that are too far in the direction of the normal to be accurately clipped */
|
||||||
f32 b_sep = v2_dot(vb0b1_clipped, normal);
|
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));
|
/* Collapse lines into deepest point */
|
||||||
struct v2 contact_b = v2_add(b0_clipped, v2_mul(vb0b1_clipped, 0.5f));
|
if (collapse0) {
|
||||||
|
if (v2_dot(normal, vab0) > 0) {
|
||||||
b32 ignore_a = false;
|
a0 = b0;
|
||||||
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;
|
|
||||||
} else {
|
} 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++];
|
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->separation = a_sep;
|
||||||
point->point = contact_a;
|
point->point = a_midpoint;
|
||||||
}
|
}
|
||||||
|
if (!ignore_b && b_sep < tolerance) {
|
||||||
if (b_sep < tolerance && !ignore_b) {
|
|
||||||
struct collider_collision_point *point = &points[num_points++];
|
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->separation = b_sep;
|
||||||
point->point = contact_b;
|
point->point = b_midpoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO: Remove this */
|
res.a0 = a0.p;
|
||||||
res.a0_clipped = a0_clipped;
|
res.a1 = a1.p;
|
||||||
res.a1_clipped = a1_clipped;
|
res.b0 = b0.p;
|
||||||
res.b0_clipped = b0_clipped;
|
res.b1 = b1.p;
|
||||||
res.b1_clipped = b1_clipped;
|
|
||||||
res.a0 = a0;
|
|
||||||
res.a1 = a1;
|
|
||||||
res.b0 = b0;
|
|
||||||
res.b1 = b1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -825,8 +778,8 @@ struct collider_closest_points_result collider_closest_points(struct collider_sh
|
|||||||
colliding = gjk_res.overlapping;
|
colliding = gjk_res.overlapping;
|
||||||
struct collider_menkowski_feature f = epa_res.closest_feature;
|
struct collider_menkowski_feature f = epa_res.closest_feature;
|
||||||
if (f.len == 1) {
|
if (f.len == 1) {
|
||||||
p0 = f.a.s0;
|
p0 = f.a.s0.p;
|
||||||
p1 = f.a.s1;
|
p1 = f.a.s1.p;
|
||||||
colliding = gjk_res.overlapping || v2_len_sq(v2_neg(f.a.p)) <= (tolerance * tolerance);
|
colliding = gjk_res.overlapping || v2_len_sq(v2_neg(f.a.p)) <= (tolerance * tolerance);
|
||||||
} else {
|
} else {
|
||||||
ASSERT(f.len == 2);
|
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);
|
ratio = clamp_f32(v2_dot(vab, vao) / v2_dot(vab, vab), 0, 1);
|
||||||
}
|
}
|
||||||
/* Shape 0 */
|
/* 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_mul(p0, ratio);
|
||||||
p0 = v2_add(p0, f.a.s0);
|
p0 = v2_add(p0, f.a.s0.p);
|
||||||
/* Shape 1 */
|
/* 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_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);
|
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 p0 = collider_get_support_point(c0, xf0_t1, dir).p;
|
||||||
struct v2 p1 = collider_support_point(c1, xf1_t1, dir_neg);
|
struct v2 p1 = collider_get_support_point(c1, xf1_t1, dir_neg).p;
|
||||||
t1_sep = v2_dot(dir, v2_sub(p1, p0));
|
t1_sep = v2_dot(dir, v2_sub(p1, p0));
|
||||||
if (t1_sep > 0) {
|
if (t1_sep > 0) {
|
||||||
/* Shapes are not penetrating at t=1 */
|
/* 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 xf0 = xform_lerp(xf0_t0, xf0_t1, t);
|
||||||
struct xform xf1 = xform_lerp(xf1_t0, xf1_t1, t);
|
struct xform xf1 = xform_lerp(xf1_t0, xf1_t1, t);
|
||||||
|
|
||||||
struct v2 p0 = collider_support_point(c0, xf0, dir);
|
struct v2 p0 = collider_get_support_point(c0, xf0, dir).p;
|
||||||
struct v2 p1 = collider_support_point(c1, xf1, dir_neg);
|
struct v2 p1 = collider_get_support_point(c1, xf1, dir_neg).p;
|
||||||
t_sep = v2_dot(dir, v2_sub(p1, p0));
|
t_sep = v2_dot(dir, v2_sub(p1, p0));
|
||||||
|
|
||||||
/* Update bracket */
|
/* Update bracket */
|
||||||
|
|||||||
@ -5,10 +5,15 @@
|
|||||||
extern u32 collider_debug_steps;
|
extern u32 collider_debug_steps;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
struct collider_support_point {
|
||||||
|
struct v2 p;
|
||||||
|
u32 i; /* Index of original point in shape */
|
||||||
|
};
|
||||||
|
|
||||||
struct collider_menkowski_point {
|
struct collider_menkowski_point {
|
||||||
struct v2 p; /* Menkowski difference point */
|
struct v2 p; /* Menkowski difference point */
|
||||||
struct v2 s0; /* Support point of first shape in dir */
|
struct collider_support_point s0; /* Support point of first shape in dir */
|
||||||
struct v2 s1; /* Support point of second shape in -dir */
|
struct collider_support_point s1; /* Support point of second shape in -dir */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct collider_menkowski_simplex {
|
struct collider_menkowski_simplex {
|
||||||
@ -53,7 +58,7 @@ struct collider_closest_points_result {
|
|||||||
struct collider_prototype prototype;
|
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);
|
struct collider_collision_points_result collider_collision_points(struct collider_shape *shape0, struct collider_shape *shape1, struct xform xf0, struct xform xf1);
|
||||||
|
|
||||||
|
|||||||
@ -37,7 +37,7 @@
|
|||||||
#define GAME_PHYSICS_ENABLE_RELAXATION 1
|
#define GAME_PHYSICS_ENABLE_RELAXATION 1
|
||||||
#define GAME_PHYSICS_ENABLE_TOI 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_SPAWN_TESTENT 0
|
||||||
#define GAME_PLAYER_AIM 1
|
#define GAME_PLAYER_AIM 1
|
||||||
|
|
||||||
@ -54,7 +54,7 @@
|
|||||||
#define USER_INTERP_ENABLED 1
|
#define USER_INTERP_ENABLED 1
|
||||||
|
|
||||||
#define COLLIDER_DEBUG RTC
|
#define COLLIDER_DEBUG RTC
|
||||||
#define COLLIDER_DEBUG_DETAILED 1
|
#define COLLIDER_DEBUG_DETAILED 0
|
||||||
#define COLLIDER_DEBUG_DETAILED_DRAW_MENKOWSKI 1
|
#define COLLIDER_DEBUG_DETAILED_DRAW_MENKOWSKI 1
|
||||||
|
|
||||||
/* ========================== *
|
/* ========================== *
|
||||||
|
|||||||
@ -285,7 +285,7 @@ void draw_solid_collider_line(struct renderer_canvas *canvas, struct xform draw_
|
|||||||
for (u32 i = 0; i < detail; ++i) {
|
for (u32 i = 0; i < detail; ++i) {
|
||||||
f32 angle = ((f32)i / (f32)detail) * (2 * PI);
|
f32 angle = ((f32)i / (f32)detail) * (2 * PI);
|
||||||
struct v2 dir = V2(math_cos(angle), math_sin(angle));
|
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);
|
p = xform_mul_v2(draw_xf, p);
|
||||||
points[i] = p;
|
points[i] = p;
|
||||||
}
|
}
|
||||||
|
|||||||
71
src/game.c
71
src/game.c
@ -244,10 +244,9 @@ INTERNAL void spawn_test_entities(void)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/* Box */
|
/* Big box */
|
||||||
#if 1
|
|
||||||
{
|
|
||||||
#if 0
|
#if 0
|
||||||
|
{
|
||||||
struct entity *e = entity_alloc(root);
|
struct entity *e = entity_alloc(root);
|
||||||
|
|
||||||
struct v2 pos = V2(1, -0.5);
|
struct v2 pos = V2(1, -0.5);
|
||||||
@ -260,11 +259,16 @@ INTERNAL void spawn_test_entities(void)
|
|||||||
e->sprite_collider_slice = STR("shape");
|
e->sprite_collider_slice = STR("shape");
|
||||||
|
|
||||||
entity_enable_prop(e, ENTITY_PROP_PHYSICAL_DYNAMIC);
|
entity_enable_prop(e, ENTITY_PROP_PHYSICAL_DYNAMIC);
|
||||||
e->mass_unscaled = 10;
|
e->mass_unscaled = 100;
|
||||||
e->inertia_unscaled = 10;
|
e->inertia_unscaled = 10;
|
||||||
e->linear_ground_friction = 250;
|
e->linear_ground_friction = 100;
|
||||||
e->angular_ground_friction = 5;
|
e->angular_ground_friction = 5;
|
||||||
#else
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Tiny box */
|
||||||
|
#if 0
|
||||||
|
{
|
||||||
struct entity *e = entity_alloc(root);
|
struct entity *e = entity_alloc(root);
|
||||||
|
|
||||||
struct v2 pos = V2(1, -0.5);
|
struct v2 pos = V2(1, -0.5);
|
||||||
@ -280,7 +284,6 @@ INTERNAL void spawn_test_entities(void)
|
|||||||
e->mass_unscaled = 0.5;
|
e->mass_unscaled = 0.5;
|
||||||
e->inertia_unscaled = 1000;
|
e->inertia_unscaled = 1000;
|
||||||
e->linear_ground_friction = 0.001;
|
e->linear_ground_friction = 0.001;
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -629,50 +632,44 @@ INTERNAL void game_update(struct game_cmd_array game_cmds)
|
|||||||
if (ent->sprite_collider_slice.len > 0) {
|
if (ent->sprite_collider_slice.len > 0) {
|
||||||
struct xform cxf = ent->sprite_local_xform;
|
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);
|
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)));
|
ent->local_collider = collider_from_quad(xform_mul_quad(cxf, quad_from_rect(slice.rect)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Test collider */
|
||||||
#if 0
|
#if 0
|
||||||
if (entity_has_prop(ent, ENTITY_PROP_TEST)) {
|
if (entity_has_prop(ent, ENTITY_PROP_TEST)) {
|
||||||
//if ((true)) {
|
//if ((true)) {
|
||||||
#if 0
|
#if 0
|
||||||
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_with_len(V2(0.08f, 0.17f), 0.15f);
|
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.points[1] = v2_with_len(V2(-0.07f, -0.2f), 0.15f);
|
||||||
ent->local_collider.count = 2;
|
ent->local_collider.count = 2;
|
||||||
ent->local_collider.radius = 0.075f;
|
ent->local_collider.radius = 0.075f;
|
||||||
#elif 1
|
#elif 1
|
||||||
#if 0
|
#if 0
|
||||||
/* "Bad" winding order */
|
/* "Bad" winding order */
|
||||||
ent->local_collider.points[0] = V2(-0.15, 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[1] = V2(0.15, 0.15);
|
||||||
ent->local_collider.points[2] = V2(0, -0.15);
|
ent->local_collider.points[2] = V2(0, -0.15);
|
||||||
#else
|
#else
|
||||||
ent->local_collider.points[0] = V2(0, -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[1] = V2(0.15, 0.15);
|
||||||
ent->local_collider.points[2] = V2(-0.15, 0.15);
|
ent->local_collider.points[2] = V2(-0.15, 0.15);
|
||||||
#endif
|
#endif
|
||||||
ent->local_collider.count = 3;
|
ent->local_collider.count = 3;
|
||||||
ent->local_collider.radius = 0.25;
|
ent->local_collider.radius = 0.25;
|
||||||
//ent->local_collider.radius = math_fabs(math_sin(G.tick.time) / 3);
|
//ent->local_collider.radius = math_fabs(math_sin(G.tick.time) / 3);
|
||||||
#else
|
#else
|
||||||
//ent->local_collider.radius = 0.5;
|
//ent->local_collider.radius = 0.5;
|
||||||
ent->local_collider.radius = 0.25;
|
ent->local_collider.radius = 0.25;
|
||||||
//ent->local_collider.radius = 0.;
|
//ent->local_collider.radius = 0.;
|
||||||
#endif
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ========================== *
|
/* ========================== *
|
||||||
@ -863,7 +860,7 @@ INTERNAL void game_update(struct game_cmd_array game_cmds)
|
|||||||
bullet->mass_unscaled = 0.04f;
|
bullet->mass_unscaled = 0.04f;
|
||||||
bullet->inertia_unscaled = 0.00001f;
|
bullet->inertia_unscaled = 0.00001f;
|
||||||
|
|
||||||
#if 0
|
#if 1
|
||||||
/* Point collider */
|
/* Point collider */
|
||||||
bullet->local_collider.points[0] = V2(0, 0);
|
bullet->local_collider.points[0] = V2(0, 0);
|
||||||
bullet->local_collider.count = 1;
|
bullet->local_collider.count = 1;
|
||||||
|
|||||||
@ -1119,7 +1119,7 @@ void phys_step(struct phys_ctx *ctx, f32 timestep)
|
|||||||
{
|
{
|
||||||
#if GAME_PHYSICS_ENABLE_TOI
|
#if GAME_PHYSICS_ENABLE_TOI
|
||||||
const f32 min_toi = 0.000001f;
|
const f32 min_toi = 0.000001f;
|
||||||
const f32 tolerance = 0.00001f;
|
const f32 tolerance = 0.0001f;
|
||||||
const u32 max_iterations = 16;
|
const u32 max_iterations = 16;
|
||||||
f32 earliest_toi = max_f32(phys_determine_earliest_toi_for_bullets(ctx, step_dt, tolerance, max_iterations), min_toi);
|
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;
|
step_dt = remaining_dt * earliest_toi;
|
||||||
|
|||||||
@ -1025,7 +1025,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, 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);
|
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);
|
||||||
@ -1128,6 +1128,7 @@ INTERNAL void user_update(void)
|
|||||||
(UNUSED)e1_collider;
|
(UNUSED)e1_collider;
|
||||||
|
|
||||||
/* Draw closest points */
|
/* Draw closest points */
|
||||||
|
#if 0
|
||||||
{
|
{
|
||||||
f32 radius = 4;
|
f32 radius = 4;
|
||||||
u32 color = RGBA_32_F(1, 1, 0, 0.5);
|
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, a, radius, color, 10);
|
||||||
draw_solid_circle(G.viewport_canvas, b, radius, color, 10);
|
draw_solid_circle(G.viewport_canvas, b, radius, color, 10);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Draw clipping */
|
/* Draw clipping */
|
||||||
{
|
{
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user