/* poly */ poly poly_alloc(int cnt) { poly p = {0}; p.cnt = cnt; p.verts = REALLOC(p.verts, sizeof(p.verts[0]) * cnt); // array_resize(p.verts, cnt); return p; } void poly_free(poly *p) { REALLOC(p->verts, 0); // array_free(p->verts); poly z = {0}; *p = z; } /* plane */ vec4 plane4(vec3 p, vec3 n) { return vec34(n, -dot3(n,p)); } /* pyramid */ poly pyramid(vec3 from, vec3 to, float size) { /* calculate axis */ vec3 up, right, forward = norm3( sub3(to, from) ); ortho3(&right, &up, forward); /* calculate extend */ vec3 xext = scale3(right, size); vec3 yext = scale3(up, size); vec3 nxext = scale3(right, -size); vec3 nyext = scale3(up, -size); /* calculate base vertices */ poly p = {0}; p.verts = REALLOC(p.verts, sizeof(p.verts[0]) * (5+1)); p.cnt = 5; /*+1 for diamond case*/ // array_resize(p.verts, 5+1); p.cnt = 5; p.verts[0] = add3(add3(from, xext), yext); /*a*/ p.verts[1] = add3(add3(from, xext), nyext); /*b*/ p.verts[2] = add3(add3(from, nxext), nyext); /*c*/ p.verts[3] = add3(add3(from, nxext), yext); /*d*/ p.verts[4] = to; /*r*/ return p; } /* pyramid */ poly diamond(vec3 from, vec3 to, float size) { vec3 mid = add3(from, scale3(sub3(to, from), 0.5f)); poly p = pyramid(mid, to, size); p.verts[5] = from; p.cnt = 6; return p; } // --- static void transform_(vec3 *r, vec3 v, const float *r33, vec3 t3) { for (int i = 0; i < 3; ++i) { i[&r->x] = i[&v.x] * r33[i*3+0]; i[&r->x] += i[&v.x] * r33[i*3+1]; i[&r->x] += i[&v.x] * r33[i*3+2]; i[&r->x] += i[&t3.x]; } } static void transformS(vec3 *v, const float *r33, vec3 t3) { vec3 tmp = *v; transform_(v, tmp, r33, t3); } static void transformT(vec3 *r, vec3 v, const float *r33, vec3 t3) { for (int i = 0; i < 3; ++i) { float p = i[&v.x] - i[&t3.x]; i[&r->x] = p * r33[0*3+i]; i[&r->x] += p * r33[1*3+i]; i[&r->x] += p * r33[2*3+i]; } } static void transformST(vec3 *v, const float *r33, vec3 t3) { vec3 tmp = *v; transformT(v, tmp, r33, t3); } /* ============================================================================ * * COLLISION * * =========================================================================== */ static __thread hit hits[16] = {0}; static __thread int hit_index = -1; #define hit_next() &hits[ (++hit_index) & 15 ] static float line_closest_line_(float *t1, float *t2, vec3 *c1, vec3 *c2, line l, line m) { vec3 r, d1, d2; d1 = sub3(l.b, l.a); /* direction vector segment s1 */ d2 = sub3(m.b, m.a); /* direction vector segment s2 */ r = sub3(l.a, m.a); float i = dot3(d1, d1); float e = dot3(d2, d2); float f = dot3(d2, r); if (i <= C_EPSILON && e <= C_EPSILON) { /* both segments degenerate into points */ vec3 d12; *t1 = *t2 = 0.0f; *c1 = l.a; *c2 = m.a; d12 = sub3(*c1, *c2); return dot3(d12,d12); } if (i > C_EPSILON) { float c = dot3(d1,r); if (e > C_EPSILON) { /* non-degenerate case */ float b = dot3(d1,d2); float denom = i*e - b*b; /* compute closest point on L1/L2 if not parallel else pick any t2 */ if (denom != 0.0f) *t1 = clampf(0.0f, (b*f - c*e) / denom, 1.0f); else *t1 = 0.0f; /* cmpute point on L2 closest to S1(s) */ *t2 = (b*(*t1) + f) / e; if (*t2 < 0.0f) { *t2 = 0.0f; *t1 = clampf(0.0f, -c/i, 1.0f); } else if (*t2 > 1.0f) { *t2 = 1.0f; *t1 = clampf(0.0f, (b-c)/i, 1.0f); } } else { /* second segment degenerates into a point */ *t1 = clampf(0.0f, -c/i, 1.0f); *t2 = 0.0f; } } else { /* first segment degenerates into a point */ *t2 = clampf(0.0f, f/e, 1.0f); *t1 = 0.0f; } /* calculate closest points */ vec3 n, d12; n = scale3(d1, *t1); *c1 = add3(l.a, n); n = scale3(d2, *t2); *c2 = add3(m.a, n); /* calculate squared distance */ d12 = sub3(*c1, *c2); return dot3(d12,d12); } vec3 line_closest_point(line l, vec3 p) { vec3 ab = sub3(l.b,l.a), pa = sub3(p,l.a); float t = dot3(pa,ab) / dot3(ab,ab); return add3(l.a, scale3(ab, t < 0 ? 0 : t > 1 ? 1 : t)); } float line_distance2_point(line l, vec3 p) { vec3 ab = sub3(l.a,l.b), ap = sub3(l.a,p), bp = sub3(l.b,p); /* handle cases p proj outside ab */ float e = dot3(ap,ab); if (e <= 0) return dot3(ap,ap); float f = dot3(ab,ab); if (e >= f) return dot3(bp,bp); return dot3(ap,ap) - (e*e)/f; } float ray_test_plane(ray r, vec4 plane) { /* Ray: P = origin + rd * t * Plane: plane_normal * P + d = 0 * * Substitute: * normal * (origin + rd*t) + d = 0 * * Solve for t: * plane_normal * origin + plane_normal * rd*t + d = 0 * -(plane_normal*rd*t) = plane_normal * origin + d * * plane_normal * origin + d * t = -1 * ------------------------- * plane_normal * rd * * Result: * Behind: t < 0 * Infront: t >= 0 * Parallel: t = 0 * Intersection point: ro + rd * t */ vec3 p = ptr3(&plane.x); float n = -(dot3(p,r.p) + plane.w); if (fabs(n) < 0.0001f) return 0.0f; return n/(dot3(p,r.d)); } float ray_test_triangle(ray r, triangle tr) { float t = 0; vec3 di0, di1, di2; vec3 d21, d02, in; vec3 n, d10, d20; vec3 in0, in1, in2; /* calculate triangle normal */ d10 = sub3(tr.p1,tr.p0); d20 = sub3(tr.p2,tr.p0); d21 = sub3(tr.p2,tr.p1); d02 = sub3(tr.p0,tr.p2); n = cross3(d10,d20); /* check for plane intersection */ vec4 p = plane4(tr.p0, n); t = ray_test_plane(r, p); if (t <= 0.0f) return t; /* intersection point */ in = scale3(r.d,t); in = add3(in,r.p); /* check if point inside triangle in plane */ di0 = sub3(in, tr.p0); di1 = sub3(in, tr.p1); di2 = sub3(in, tr.p2); in0 = cross3(d10, di0); in1 = cross3(d21, di1); in2 = cross3(d02, di2); if (dot3(in0,n) < 0.0f) return -1; if (dot3(in1,n) < 0.0f) return -1; if (dot3(in2,n) < 0.0f) return -1; return t; } int ray_test_sphere(float *t0, float *t1, ray r, sphere s) { vec3 a; float tc,td,d2,r2; a = sub3(s.c,r.p); tc = dot3(r.d,a); if (tc < 0) return 0; r2 = s.r*s.r; d2 = dot3(a,a) - tc*tc; if (d2 > r2) return 0; td = sqrtf(r2 - d2); *t0 = tc - td; *t1 = tc + td; return 1; } int ray_test_aabb(float *t0, float *t1, ray r, aabb a) { float t0x = (a.min.x - r.p.x) / r.d.x; float t0y = (a.min.y - r.p.y) / r.d.y; float t0z = (a.min.z - r.p.z) / r.d.z; float t1x = (a.max.x - r.p.x) / r.d.x; float t1y = (a.max.y - r.p.y) / r.d.y; float t1z = (a.max.z - r.p.z) / r.d.z; float tminx = minf(t0x, t1x); float tminy = minf(t0y, t1y); float tminz = minf(t0z, t1z); float tmaxx = maxf(t0x, t1x); float tmaxy = maxf(t0y, t1y); float tmaxz = maxf(t0z, t1z); if (tminx > tmaxy || tminy > tmaxx) return 0; *t0 = maxf(tminx, tminy); *t1 = minf(tmaxy, tmaxx); if (*t0 > tmaxz || tminz> *t1) return 0; *t0 = maxf(*t0, tminz); *t1 = minf(*t1, tmaxz); return 1; } vec3 sphere_closest_point(sphere s, vec3 p) { vec3 d = norm3(sub3(p, s.c)); return add3(s.c, scale3(d,s.r)); } int sphere_test_sphere(sphere a, sphere b) { vec3 d = sub3(b.c, a.c); float r = a.r + b.r; if (dot3(d,d) > r*r) return 0; return 1; } hit *sphere_hit_sphere(sphere a, sphere b) { vec3 d = sub3(b.c, a.c); float r = a.r + b.r; float d2 = dot3(d,d); if (d2 > r*r) return 0; hit *m = hit_next(); float l = sqrtf(d2); float linv = 1.0f / ((l != 0) ? l: 1.0f); m->normal = scale3(d, linv); m->depth = r - l; d = scale3(m->normal, b.r); m->contact_point = sub3(b.c, d); return m; } int sphere_test_aabb(sphere s, aabb a) { return aabb_test_sphere(a, s); } hit *sphere_hit_aabb(sphere s, aabb a) { /* find closest aabb point to sphere center point */ vec3 ap = aabb_closest_point(a, s.c); vec3 d = sub3(s.c, ap); float d2 = dot3(d, d); if (d2 > s.r*s.r) return 0; hit *m = hit_next(); /* calculate distance vector between sphere and aabb center points */ vec3 ac = add3(a.min, scale3(sub3(a.max, a.min), 0.5f)); d = sub3(ac, s.c); /* normalize distance vector */ float l2 = dot3(d,d); float l = l2 != 0.0f ? sqrtf(l2): 1.0f; float linv = 1.0f/l; d = scale3(d, linv); m->normal = d; m->contact_point = scale3(m->normal, s.r); m->contact_point = add3(s.c, m->contact_point); /* calculate penetration depth */ vec3 sp = sphere_closest_point(s, ap); d = sub3(sp, ap); m->depth = sqrtf(dot3(d,d)) - l; return m; } int sphere_test_capsule(sphere s, capsule c) { return capsule_test_sphere(c, s); } hit *sphere_hit_capsule(sphere s, capsule c) { #if 0 // original code /* find closest capsule point to sphere center point */ hit *m = hit_next(); vec3 cp = capsule_closest_point(c, s.c); m->normal = sub3(cp, s.c); float d2 = dot3(m->normal, m->normal); if (d2 > s.r*s.r) return 0; /* normalize hit normal vector */ m->normal = norm3(m->normal); /* calculate penetration depth */ m->depth = d2 - s.r*s.r; m->depth = m->depth != 0.0f ? sqrtf(m->depth): 0.0f; m->contact_point = add3(s.c, scale3(m->normal, s.r)); return m; #else // aproximation of I would expect this function to return instead vec3 l = sub3(c.a,c.b); float len = len3(l); vec3 d = norm3(l); ray r = ray(add3(c.a,scale3(d,-2*len)), d); s.r += c.r; hit *h = ray_hit_sphere(r, s); if(!h) return 0; s.r -= c.r; h->contact_point = add3(s.c,scale3(norm3(sub3(h->contact_point,s.c)),s.r)); return h; #endif } int sphere_test_poly(sphere s, poly p) { return poly_test_sphere(p, s); } void aabb_rebalance_transform(aabb *b, aabb a, mat33 m, vec3 t) { for (int i = 0; i < 3; ++i) { i[&b->min.x] = i[&b->max.x] = i[&t.x]; for (int j = 0; j < 3; ++j) { float e = m[i*3+j] * j[&a.min.x]; float f = m[i*3+j] * j[&a.max.x]; if (e < f) { i[&b->min.x] += e; i[&b->max.x] += f; } else { i[&b->min.x] += f; i[&b->max.x] += e; } } } } vec3 aabb_closest_point(aabb a, vec3 p) { vec3 res; for (int i = 0; i < 3; ++i) { float v = i[&p.x]; if (v < i[&a.min.x]) v = i[&a.min.x]; if (v > i[&a.max.x]) v = i[&a.max.x]; i[&res.x] = v; } return res; } float aabb_distance2_point(aabb a, vec3 p) { float r = 0; for (int i = 0; i < 3; ++i) { float v = i[&p.x]; if (v < i[&a.min.x]) r += (i[&a.min.x]-v) * (i[&a.min.x]-v); if (v > i[&a.max.x]) r += (v-i[&a.max.x]) * (v-i[&a.max.x]); } return r; } int aabb_contains_point(aabb a, vec3 p) { if (p.x < a.min.x || p.x > a.max.x) return 0; if (p.y < a.min.y || p.y > a.max.y) return 0; if (p.z < a.min.z || p.z > a.max.z) return 0; return 1; } int aabb_test_aabb(aabb a, aabb b) { if (a.max.x < b.min.x || a.min.x > b.max.x) return 0; if (a.max.y < b.min.y || a.min.y > b.max.y) return 0; if (a.max.z < b.min.z || a.min.z > b.max.z) return 0; return 1; } hit *aabb_hit_aabb(aabb a, aabb b) { if (!aabb_test_aabb(a, b)) return 0; hit *m = hit_next(); /* calculate distance vector between both aabb center points */ vec3 ac, bc, d; ac = sub3(a.max, a.min); bc = sub3(b.max, b.min); ac = scale3(ac, 0.5f); bc = scale3(bc, 0.5f); ac = add3(a.min, ac); bc = add3(b.min, bc); d = sub3(bc, ac); /* normalize distance vector */ float l2 = dot3(d,d); float l = l2 != 0.0f ? sqrtf(l2): 1.0f; float linv = 1.0f/l; d = scale3(d, linv); /* calculate contact point */ m->normal = d; m->contact_point = aabb_closest_point(a, bc); d = sub3(m->contact_point, ac); /* calculate penetration depth */ float r2 = dot3(d,d); float r = sqrtf(r2); m->depth = r - l; return m; } int aabb_test_sphere(aabb a, sphere s) { /* compute squared distance between sphere center and aabb */ float d2 = aabb_distance2_point(a, s.c); /* intersection if distance is smaller/equal sphere radius*/ return d2 <= s.r*s.r; } hit *aabb_hit_sphere(aabb a, sphere s) { /* find closest aabb point to sphere center point */ hit *m = hit_next(); m->contact_point = aabb_closest_point(a, s.c); vec3 d = sub3(s.c, m->contact_point); float d2 = dot3(d, d); if (d2 > s.r*s.r) return 0; /* calculate distance vector between aabb and sphere center points */ vec3 ac = add3(a.min, scale3(sub3(a.max, a.min), 0.5f)); d = sub3(s.c, ac); /* normalize distance vector */ float l2 = dot3(d,d); float l = l2 != 0.0f ? sqrtf(l2): 1.0f; float linv = 1.0f/l; d = scale3(d, linv); /* calculate penetration depth */ m->normal = d; d = sub3(m->contact_point, ac); m->depth = sqrtf(dot3(d,d)); return m; } int aabb_test_capsule(aabb a, capsule c) { return capsule_test_aabb(c, a); } hit *aabb_hit_capsule(aabb a, capsule c) { /* calculate aabb center point */ vec3 ac = add3(a.min, scale3(sub3(a.max, a.min), 0.5f)); /* calculate closest point from aabb to point on capsule and check if inside aabb */ vec3 cp = capsule_closest_point(c, ac); if (!aabb_contains_point(a, cp)) return 0; hit *m = hit_next(); /* vector and distance between both capsule closests point and aabb center*/ vec3 d; float d2; d = sub3(cp, ac); d2 = dot3(d,d); /* calculate penetration depth from closest aabb point to capsule */ vec3 ap = aabb_closest_point(a, cp); vec3 dt = sub3(ap, cp); m->depth = sqrtf(dot3(dt,dt)); /* calculate normal */ float l = sqrtf(d2); float linv = 1.0f / ((l != 0.0f) ? l: 1.0f); m->normal = scale3(d, linv); m->contact_point = ap; return m; } int aabb_test_poly(aabb a, poly p) { return poly_test_aabb(p, a); } float capsule_distance2_point(capsule c, vec3 p) { float d2 = line_distance2_point(line(c.a,c.b), p); return d2 - (c.r*c.r); } vec3 capsule_closest_point(capsule c, vec3 p) { /* calculate closest point to internal capsule segment */ vec3 pp = line_closest_point(line(c.a,c.b), p); /* extend point out by radius in normal direction */ vec3 d = norm3(sub3(p,pp)); return add3(pp, scale3(d, c.r)); } int capsule_test_capsule(capsule a, capsule b) { float t1, t2; vec3 c1, c2; float d2 = line_closest_line_(&t1, &t2, &c1, &c2, line(a.a,a.b), line(b.a,b.b)); float r = a.r + b.r; return d2 <= r*r; } hit *capsule_hit_capsule(capsule a, capsule b) { float t1, t2; vec3 c1, c2; float d2 = line_closest_line_(&t1, &t2, &c1, &c2, line(a.a,a.b), line(b.a,b.b)); float r = a.r + b.r; if (d2 > r*r) return 0; hit *m = hit_next(); /* calculate normal from both closest points for each segement */ vec3 cp, d; m->normal = sub3(c2, c1); m->normal = norm3(m->normal); /* calculate contact point from closest point and depth */ m->contact_point = capsule_closest_point(a, c2); cp = capsule_closest_point(b, c1); d = sub3(c1, cp); m->depth = sqrtf(dot3(d,d)); return m; } int capsule_test_sphere(capsule c, sphere s) { /* squared distance bwetween sphere center and capsule line segment */ float d2 = line_distance2_point(line(c.a,c.b), s.c); float r = s.r + c.r; return d2 <= r * r; } hit *capsule_hit_sphere(capsule c, sphere s) { /* find closest capsule point to sphere center point */ hit *m = hit_next(); m->contact_point = capsule_closest_point(c, s.c); m->normal = sub3(s.c, m->contact_point); float d2 = dot3(m->normal, m->normal); if (d2 > s.r*s.r) return 0; /* normalize hit normal vector */ float l = d2 != 0.0f ? sqrtf(d2): 1; float linv = 1.0f/l; m->normal = scale3(m->normal, linv); /* calculate penetration depth */ m->depth = d2 - s.r*s.r; m->depth = m->depth != 0.0f ? sqrtf(m->depth): 0.0f; return m; } int capsule_test_aabb(capsule c, aabb a) { /* calculate aabb center point */ vec3 ac = scale3(sub3(a.max, a.min), 0.5f); /* calculate closest point from aabb to point on capsule and check if inside aabb */ vec3 p = capsule_closest_point(c, ac); return aabb_contains_point(a, p); } hit *capsule_hit_aabb(capsule c, aabb a) { /* calculate aabb center point */ vec3 ac = add3(a.min, scale3(sub3(a.max, a.min), 0.5f)); /* calculate closest point from aabb to point on capsule and check if inside aabb */ vec3 cp = capsule_closest_point(c, ac); if (!aabb_contains_point(a, cp)) return 0; hit *m = hit_next(); /* vector and distance between both capsule closests point and aabb center*/ vec3 d; float d2; d = sub3(ac, cp); d2 = dot3(d,d); /* calculate penetration depth from closest aabb point to capsule */ vec3 ap = aabb_closest_point(a, cp); vec3 dt = sub3(ap, cp); m->depth = sqrtf(dot3(dt,dt)); /* calculate normal */ float l = sqrtf(d2); float linv = 1.0f / ((l != 0.0f) ? l: 1.0f); m->normal = scale3(d, linv); m->contact_point = cp; return m; } int capsule_test_poly(capsule c, poly p) { return poly_test_capsule(p, c); } int line_support(vec3 *support, vec3 d, vec3 a, vec3 b) { int i = 0; float adot = dot3(a, d); float bdot = dot3(b, d); if (adot < bdot) { *support = b; i = 1; } else *support = a; return i; } int poly_support(vec3 *support, vec3 d, poly p) { int imax = 0; float dmax = dot3(*p.verts, d); for (int i = 1; i < p.cnt; ++i) { /* find vertex with max dot product in direction d */ float dot = dot3(p.verts[i], d); if (dot < dmax) continue; imax = i, dmax = dot; } *support = p.verts[imax]; return imax; } int poly_hit_sphere(struct gjk_result *res, poly p, sphere s) { /* initial guess */ vec3 d = {0}; gjk_support gs = {0}; gs.a = *p.verts; gs.b = s.c; d = sub3(gs.b, gs.a); /* run gjk algorithm */ gjk_simplex gsx = {0}; while (gjk(&gsx, &gs, &d)) { vec3 n = scale3(d, -1); gs.aid = poly_support(&gs.a, n, p); d = sub3(gs.b, gs.a); } /* check distance between closest points */ *res = gjk_analyze(&gsx); return res->distance_squared <= s.r*s.r; } int poly_hit_sphere_transform(struct gjk_result *res, poly p, vec3 pos3, mat33 rot33, sphere s) { /* initial guess */ vec3 d = {0}; gjk_support gs = {0}; gs.a = *p.verts; gs.b = s.c; transformS(&gs.a, rot33, pos3); d = sub3(gs.b, gs.a); /* run gjk algorithm */ gjk_simplex gsx = {0}; while (gjk(&gsx, &gs, &d)) { vec3 n = scale3(d, -1); vec3 da; transformT(&da, n, rot33, pos3); gs.aid = poly_support(&gs.a, da, p); transformS(&gs.a, rot33, pos3); d = sub3(gs.b, gs.a); } /* check distance between closest points */ *res = gjk_analyze(&gsx); return res->distance_squared <= s.r*s.r; } int poly_test_sphere(poly p, sphere s) { struct gjk_result res; return poly_hit_sphere(&res, p, s); } int poly_test_sphere_transform(poly p, vec3 pos3, mat33 rot33, sphere s) { struct gjk_result res; return poly_hit_sphere_transform(&res, p, pos3, rot33, s); } int poly_hit_capsule(struct gjk_result *res, poly p, capsule c) { /* initial guess */ vec3 d = {0}; gjk_support s = {0}; s.a = *p.verts; s.b = c.a; d = sub3(s.b, s.a); /* run gjk algorithm */ gjk_simplex gsx = {0}; while (gjk(&gsx, &s, &d)) { vec3 n = scale3(d, -1); s.aid = poly_support(&s.a, n, p); s.bid = line_support(&s.b, d, c.a, c.b); d = sub3(s.b, s.a); } /* check distance between closest points */ assert(gsx.iter < gsx.max_iter); *res = gjk_analyze(&gsx); return res->distance_squared <= c.r*c.r; } int poly_test_capsule(poly p, capsule c) { struct gjk_result res; return poly_hit_capsule(&res, p, c); } int poly_hit_capsule_transform(struct gjk_result *res, poly p, vec3 pos3, mat33 rot33, capsule c) { /* initial guess */ vec3 d = {0}; gjk_support gs = {0}; gs.a = *p.verts; gs.b = c.a; transformS(&gs.a, rot33, pos3); d = sub3(gs.b, gs.a); /* run gjk algorithm */ gjk_simplex gsx = {0}; while (gjk(&gsx, &gs, &d)) { vec3 n = scale3(d, -1); vec3 da; transformT(&da, n, rot33, pos3); gs.aid = poly_support(&gs.a, da, p); gs.bid = line_support(&gs.b, d, c.a, c.b); transformS(&gs.a, rot33, pos3); d = sub3(gs.b, gs.a); } /* check distance between closest points */ *res = gjk_analyze(&gsx); return res->distance_squared <= c.r*c.r; } int poly_test_capsule_transform(poly p, vec3 pos3, mat33 rot33, capsule c) { struct gjk_result res; return poly_hit_capsule_transform(&res, p, pos3, rot33, c); } int poly_hit_poly_transform(struct gjk_result *res, poly a, vec3 at3, mat33 ar33, poly b, vec3 bt3, mat33 br33) { /* initial guess */ vec3 d = {0}; gjk_support gs = {0}; gs.a = *a.verts; gs.b = *b.verts; transformS(&gs.a, ar33, at3); transformS(&gs.b, br33, bt3); d = sub3(gs.b, gs.a); /* run gjk algorithm */ gjk_simplex gsx = {0}; while (gjk(&gsx, &gs, &d)) { /* transform direction */ vec3 n = scale3(d, -1); vec3 da; transformT(&da, n, ar33, at3); vec3 db; transformT(&db, d, br33, bt3); /* run support function on tranformed directions */ gs.aid = poly_support(&gs.a, da, a); gs.bid = poly_support(&gs.b, db, b); /* calculate distance vector on transformed points */ transformS(&gs.a, ar33, at3); transformS(&gs.b, br33, bt3); d = sub3(gs.b, gs.a); } *res = gjk_analyze(&gsx); return gsx.hit; } int poly_hit_poly(struct gjk_result *res, poly a, poly b) { /* initial guess */ vec3 d = {0}; gjk_support gs = {0}; gs.a = *a.verts; gs.b = *b.verts; d = sub3(gs.b, gs.a); /* run gjk algorithm */ gjk_simplex gsx = {0}; while (gjk(&gsx, &gs, &d)) { vec3 n = scale3(d, -1); gs.aid = poly_support(&gs.a, n, a); gs.bid = poly_support(&gs.b, d, b); d = sub3(gs.b, gs.a); } *res = gjk_analyze(&gsx); return gsx.hit; } int poly_test_poly(poly a, poly b) { struct gjk_result res; return poly_hit_poly(&res, a, b); } int poly_test_poly_transform(poly a, vec3 apos3, mat33 arot33, poly b, vec3 bpos3, mat33 brot33) { struct gjk_result res; return poly_hit_poly_transform(&res, a, apos3, arot33, b, bpos3, brot33); } int poly_hit_aabb(struct gjk_result *res, poly p, aabb a) { vec3 box[8]; box[0] = vec3(a.min.x, a.min.y, a.min.z), box[1] = vec3(a.min.x, a.min.y, a.max.z); box[2] = vec3(a.min.x, a.max.y, a.min.z); box[3] = vec3(a.min.x, a.max.y, a.max.z); box[4] = vec3(a.max.x, a.min.y, a.min.z); box[5] = vec3(a.max.x, a.min.y, a.max.z); box[6] = vec3(a.max.x, a.max.y, a.min.z); box[7] = vec3(a.max.x, a.max.y, a.max.z); return poly_hit_poly(res, p, poly(&box[0], 8)); } int poly_hit_aabb_transform(struct gjk_result *res, poly p, vec3 pos3, mat33 rot33, aabb a) { vec3 zero = {0}; vec3 id[3] = {{1,0,0},{0,1,0},{0,0,1}}; vec3 box[8]; box[0] = vec3(a.min.x, a.min.y, a.min.z), box[1] = vec3(a.min.x, a.min.y, a.max.z); box[2] = vec3(a.min.x, a.max.y, a.min.z); box[3] = vec3(a.min.x, a.max.y, a.max.z); box[4] = vec3(a.max.x, a.min.y, a.min.z); box[5] = vec3(a.max.x, a.min.y, a.max.z); box[6] = vec3(a.max.x, a.max.y, a.min.z); box[7] = vec3(a.max.x, a.max.y, a.max.z); return poly_hit_poly_transform(res, p, pos3, rot33, poly(&box[0], 8), zero, id[0].v3); } int poly_test_aabb(poly p, aabb a) { struct gjk_result res; return poly_hit_aabb(&res, p, a); } int poly_test_aabb_transform(poly p, vec3 apos3, mat33 arot33, aabb a) { struct gjk_result res; return poly_hit_aabb_transform(&res, p, apos3, arot33, a); } /* ============================================================================ * * COLLISION VOLUME * * =========================================================================== */ hit *ray_hit_plane(ray r, plane p) { vec4 pf = plane4(p.p, p.n); float t = ray_test_plane(r, pf); if (t <= 0.0f) return 0; hit *o = hit_next(); o->p = add3(r.p, scale3(r.d, t)); o->t0 = o->t1 = t; o->n = scale3(p.n, -1.0f); return o; } hit *ray_hit_triangle(ray r, triangle tr) { float t = ray_test_triangle(r, tr); if (t <= 0) return 0; hit *o = hit_next(); o->t0 = o->t1 = t; o->p = add3(r.p, scale3(r.d, t)); o->n = norm3(cross3(sub3(tr.p1,tr.p0),sub3(tr.p2,tr.p0))); return o; } hit *ray_hit_sphere(ray r, sphere s) { hit *o = hit_next(); if (!ray_test_sphere(&o->t0, &o->t1, r, s)) return 0; o->p = add3(r.p, scale3(r.d, minf(o->t0,o->t1))); o->n = norm3(sub3(o->p, s.c)); return o; } hit *ray_hit_aabb(ray r, aabb a) { hit *o = hit_next(); vec3 pnt, ext, c; float d, min; if (!ray_test_aabb(&o->t0, &o->t1, r, a)) return 0; o->p = add3(r.p, scale3(r.d, minf(o->t0,o->t1))); ext = sub3(a.max, a.min); c = add3(a.min, scale3(ext,0.5f)); pnt = sub3(o->p, c); min = fabs(ext.x - fabs(pnt.x)); o->n = scale3(vec3(1,0,0), signf(pnt.x)); d = fabs(ext.y - fabs(pnt.y)); if (d < min) { min = d; o->n = scale3(vec3(0,1,0), signf(pnt.y)); } d = fabs(ext.z - fabs(pnt.z)); if (d < min) o->n = scale3(vec3(0,0,1), signf(pnt.z)); return o; } frustum frustum_build(mat44 pv) { frustum f; f.l = vec4(pv[ 3]+pv[ 0], pv[ 7]+pv[ 4], pv[11]+pv[ 8], pv[15]+pv[12]); f.r = vec4(pv[ 3]-pv[ 0], pv[ 7]-pv[ 4], pv[11]-pv[ 8], pv[15]-pv[12]); f.t = vec4(pv[ 3]-pv[ 1], pv[ 7]-pv[ 5], pv[11]-pv[ 9], pv[15]-pv[13]); f.b = vec4(pv[ 3]+pv[ 1], pv[ 7]+pv[ 5], pv[11]+pv[ 9], pv[15]+pv[13]); f.n = vec4(pv[ 3]+pv[ 2], pv[ 7]+pv[ 6], pv[11]+pv[10], pv[15]+pv[14]); f.f = vec4(pv[ 3]-pv[ 2], pv[ 7]-pv[ 6], pv[11]-pv[10], pv[15]-pv[14]); for (int i = 0; i < 6; i++) f.pl[i] = scale4(f.pl[i], 1 / len3(f.pl[i].xyz)); return f; } int frustum_test_sphere(frustum f, sphere s) { for(int i = 0; i < 6; i++) { if((dot3(f.pl[i].xyz, s.c) + f.pl[i].w + s.r) < 0) return 0; } return 1; } int frustum_test_aabb(frustum f, aabb a) { for(int i = 0; i < 6; i++) { vec3 v = vec3(f.pl[i].x > 0 ? a.max.x : a.min.x, f.pl[i].y > 0 ? a.max.y : a.min.y, f.pl[i].z > 0 ? a.max.z : a.min.z); if((dot3(f.pl[i].xyz, v) + f.pl[i].w) < 0) return 0; } return 1; } void collide_demo() { // debug draw collisions // @fixme: fix leaks: poly_free() // animation static float dx = 0, dy = 0; float delta = (0.25f / 60.f); dx = dx + delta * 2.0f; dy = dy + delta * 0.8f; #if 0 // 3D glEnable(GL_DEPTH_TEST); // grid ddraw_grid(0); #endif { // Triangle-Ray Intersection*/ vec3 ro, rd; int suc; triangle tri = { vec3(-9,1,28), vec3(-10,0,28), vec3(-11,1,28) }; // ray ro = vec3(-10,-1,20); rd = vec3(-10+0.4f*sin(dx), 2.0f*cos(dy), 29.81023f); rd = sub3(rd, ro); rd = norm3(rd); ray r = ray(ro, rd); hit *hit = ray_hit_triangle(r, tri); if (hit) { // point of intersection ddraw_color(RED); ddraw_box(hit->p, vec3(0.10f, 0.10f, 0.10f)); // intersection normal ddraw_color(BLUE); vec3 v = add3(hit->p, hit->n); ddraw_arrow(hit->p, v); } // line ddraw_color(RED); rd = scale3(rd,10); rd = add3(ro,rd); ddraw_line(ro, rd); // triangle if (hit) ddraw_color(RED); else ddraw_color(WHITE); ddraw_triangle(tri.p0,tri.p1,tri.p2); } { // Plane-Ray Intersection*/ vec3 ro, rd; mat33 rot; // ray static float d = 0; d += delta * 2.0f; ro = vec3(0,-1,20); rd = vec3(0.1f, 0.5f, 9.81023f); rd = sub3(rd, ro); rd = norm3(rd); // rotation rotation33(rot, deg(d), 0,1,0); rd = mulv33(rot, rd); // intersection ray r = ray(ro, rd); plane pl = plane(vec3(0,0,28), vec3(0,0,1)); hit *hit = ray_hit_plane(r, pl); if (hit) { // point of intersection ddraw_color(RED); ddraw_box(hit->p, vec3(0.10f, 0.10f, 0.10f)); // intersection normal ddraw_color(BLUE); vec3 v = add3(hit->p, hit->n); ddraw_arrow(hit->p, v); ddraw_color(RED); } // line ddraw_color(RED); rd = scale3(rd,9); rd = add3(ro,rd); ddraw_line(ro, rd); // plane if (hit) ddraw_color(RED); else ddraw_color(WHITE); ddraw_plane(vec3(0,0,28), vec3(0,0,1), 3.0f); } { // Sphere-Ray Intersection*/ vec3 ro, rd; sphere s; // ray ro = vec3(0,-1,0); rd = vec3(0.4f*sin(dx), 2.0f*cos(dy), 9.81023f); rd = sub3(rd, ro); rd = norm3(rd); ray r = ray(ro, rd); s = sphere(vec3(0,0,8), 1); hit *hit = ray_hit_sphere(r, s); if(hit) { // points of intersection vec3 in = add3(ro,scale3(rd,hit->t0)); ddraw_color(GREEN); ddraw_box(in, vec3(0.05f, 0.05f, 0.05f)); in = add3(ro,scale3(rd,hit->t1)); ddraw_color(YELLOW); ddraw_box(in, vec3(0.05f, 0.05f, 0.05f)); // intersection normal ddraw_color(BLUE); vec3 v = add3(hit->p, hit->n); ddraw_arrow(hit->p, v); ddraw_color(RED); } // line ddraw_color(RED); rd = scale3(rd,10); rd = add3(ro,rd); ddraw_line(ro, rd); // sphere if (hit) ddraw_color(RED); else ddraw_color(WHITE); ddraw_sphere(vec3(0,0,8), 1); } { // ray-aabb aabb bounds = aabb(vec3(10-0.5f,-0.5f,7.5f), vec3(10.5f,0.5f,8.5f)); vec3 ro = vec3(10,-1,0); vec3 rd = vec3(10+0.4f*sin(dx), 2.0f*cos(dy), 9.81023f); rd = norm3(sub3(rd, ro)); ray r = ray(ro, rd); hit *hit = ray_hit_aabb(r, bounds); if(hit) { // points of intersection vec3 in; in = scale3(rd,hit->t0); in = add3(ro,in); ddraw_color(RED); ddraw_box(in, vec3(0.05f, 0.05f, 0.05f)); in = scale3(rd,hit->t1); in = add3(ro,in); ddraw_color(RED); ddraw_box(in, vec3(0.05f, 0.05f, 0.05f)); // intersection normal ddraw_color(BLUE); vec3 v = add3(hit->p, hit->n); ddraw_arrow(hit->p, v); ddraw_color(RED); } else ddraw_color(WHITE); ddraw_box(vec3(10,0,8), vec3(1,1,1)); // line ddraw_color(RED); rd = scale3(rd,10); rd = add3(ro,rd); ddraw_line(ro, rd); } { // Sphere-Sphere intersection*/ sphere a = sphere(vec3(-10,0,8), 1); sphere b = sphere(vec3(-10+0.6f*sin(dx), 3.0f*cos(dy),8), 1); hit *m = sphere_hit_sphere(a, b); if (m) { vec3 v; ddraw_color(BLUE); ddraw_box(m->contact_point, vec3(0.05f, 0.05f, 0.05f)); v = add3(m->contact_point, m->normal); ddraw_arrow(m->contact_point, v); ddraw_color(RED); } else ddraw_color(WHITE); ddraw_sphere(a.c, 1); ddraw_sphere(b.c, 1); } { // AABB-AABB intersection*/ const float x = 10+0.6f*sin(dx); const float y = 3.0f*cos(dy); const float z = 20.0f; aabb a = aabb(vec3(10-0.5f,-0.5f,20-0.5f), vec3(10+0.5f,0.5f,20.5f)); aabb b = aabb(vec3(x-0.5f,y-0.5f,z-0.5f), vec3(x+0.5f,y+0.5f,z+0.5f)); hit *m = aabb_hit_aabb(a, b); if(m) { vec3 v; ddraw_color(BLUE); ddraw_box(m->contact_point, vec3(0.05f, 0.05f, 0.05f)); v = add3(m->contact_point, m->normal); ddraw_arrow(m->contact_point, v); ddraw_color(RED); } else ddraw_color(WHITE); ddraw_box(vec3(10,0,20), vec3(1,1,1)); ddraw_box(vec3(x,y,z), vec3(1,1,1)); } { // Capsule-Capsule intersection*/ const float x = 20+0.4f*sin(dx); const float y = 3.0f*cos(dy); const float z = 28.5f; capsule a = capsule(vec3(20.0f,-1.0f,28.0f), vec3(20.0f,1.0f,28.0f), 0.2f); capsule b = capsule(vec3(x,y-1.0f,z), vec3(x,y+1.0f,z-1.0f), 0.2f); hit *m = capsule_hit_capsule(a, b); if( m ) { vec3 v; ddraw_color(BLUE); ddraw_box(m->contact_point, vec3(0.05f, 0.05f, 0.05f)); v = add3(m->contact_point, m->normal); ddraw_arrow(m->contact_point, v); ddraw_color(RED); } else ddraw_color(WHITE); ddraw_capsule(vec3(x,y-1.0f,z), vec3(x,y+1.0f,z-1.0f), 0.2f); ddraw_capsule(vec3(20.0f,-1.0f,28.0f), vec3(20.0f,1.0f,28.0f), 0.2f); } { // AABB-Sphere intersection*/ aabb a = aabb(vec3(20-0.5f,-0.5f,7.5f), vec3(20.5f,0.5f,8.5f)); sphere s = sphere(vec3(20+0.6f*sin(dx), 3.0f*cos(dy),8), 1); hit *m = aabb_hit_sphere(a, s); if(m) { vec3 v; ddraw_color(BLUE); ddraw_box(m->contact_point, vec3(0.05f, 0.05f, 0.05f)); v = add3(m->contact_point, m->normal); ddraw_arrow(m->contact_point, v); ddraw_color(RED); } else ddraw_color(WHITE); ddraw_box(vec3(20,0,8), vec3(1,1,1)); ddraw_sphere(s.c, 1); } { // Sphere-AABB intersection*/ const float x = 10+0.6f*sin(dx); const float y = 3.0f*cos(dy); const float z = -8.0f; sphere s = sphere(vec3(10,0,-8), 1); aabb a = aabb(vec3(x-0.5f,y-0.5f,z-0.5f), vec3(x+0.5f,y+0.5f,z+0.5f)); hit *m = sphere_hit_aabb(s, a); if(m) { vec3 v; ddraw_color(BLUE); ddraw_box(m->contact_point, vec3(0.05f, 0.05f, 0.05f)); v = add3(m->contact_point, m->normal); ddraw_arrow(m->contact_point, v); ddraw_color(RED); } else ddraw_color(WHITE); ddraw_box(vec3(x,y,z), vec3(1,1,1)); ddraw_sphere(s.c, 1); } { // Capsule-Sphere intersection*/ capsule c = capsule(vec3(-20.5f,-1.0f,7.5f), vec3(-20+0.5f,1.0f,8.5f), 0.2f); sphere b = sphere(vec3(-20+0.6f*sin(dx), 3.0f*cos(dy),8), 1); hit *m = capsule_hit_sphere(c, b); if(m) { vec3 v; ddraw_color(BLUE); ddraw_box(m->contact_point, vec3(0.05f, 0.05f, 0.05f)); v = add3(m->contact_point, m->normal); ddraw_arrow(m->contact_point, v); ddraw_color(RED); } else ddraw_color(WHITE); ddraw_sphere(b.c, 1); ddraw_capsule(vec3(-20.5f,-1.0f,7.5f), vec3(-20+0.5f,1.0f,8.5f), 0.2f); } { // Sphere-Capsule intersection*/ const float x = 20+0.4f*sin(dx); const float y = 3.0f*cos(dy); const float z = -8; sphere s = sphere(vec3(20,0,-8), 1); capsule c = capsule(vec3(x,y-1.0f,z), vec3(x,y+1.0f,z-1.0f), 0.2f); hit *m = sphere_hit_capsule(s, c); if(m) { vec3 v; ddraw_color(BLUE); ddraw_box(m->contact_point, vec3(0.05f, 0.05f, 0.05f)); v = add3(m->contact_point, m->normal); ddraw_arrow(m->contact_point, v); ddraw_color(RED); } else ddraw_color(WHITE); ddraw_capsule(vec3(x,y-1.0f,z), vec3(x,y+1.0f,z-1.0f), 0.2f); ddraw_sphere(s.c, 1); } { // Capsule-AABB intersection*/ const float x = -20+0.6f*sin(dx); const float y = 3.0f*cos(dy); const float z = 28.0f; capsule c = capsule(vec3(-20.5f,-1.0f,27.5f), vec3(-20+0.5f,1.0f,28.5f), 0.2f); aabb b = aabb(vec3(x-0.5f,y-0.5f,z-0.5f), vec3(x+0.5f,y+0.5f,z+0.5f)); hit *m = capsule_hit_aabb(c, b); if(m) { vec3 v; ddraw_color(BLUE); ddraw_box(m->contact_point, vec3(0.05f, 0.05f, 0.05f)); v = add3(m->contact_point, m->normal); ddraw_arrow(m->contact_point, v); ddraw_color(RED); } else ddraw_color(WHITE); ddraw_box(vec3(x,y,z), vec3(1,1,1)); ddraw_capsule(vec3(-20.5f,-1.0f,27.5f), vec3(-20+0.5f,1.0f,28.5f), 0.2f); } { // AABB-Capsule intersection*/ const float x = 0.4f*sin(dx); const float y = 3.0f*cos(dy); const float z = -8; aabb a = aabb(vec3(-0.5f,-0.5f,-8.5f), vec3(0.5f,0.5f,-7.5f)); capsule c = capsule(vec3(x,y-1.0f,z), vec3(x,y+1.0f,z-1.0f), 0.2f); hit *m = aabb_hit_capsule(a, c); if(m) { ddraw_color(RED); ddraw_box(m->contact_point, vec3(0.05f, 0.05f, 0.05f)); ddraw_arrow(m->contact_point, add3(m->contact_point, m->normal)); } else ddraw_color(WHITE); ddraw_capsule(vec3(x,y-1.0f,z), vec3(x,y+1.0f,z-1.0f), 0.2f); ddraw_box(vec3(0,0,-8.0f), vec3(1,1,1)); } { // poly(Pyramid)-Sphere (GJK) intersection*/ sphere s = sphere(vec3(-10+0.6f*sin(dx), 3.0f*cos(dy),-8), 1); poly pyr = pyramid(vec3(-10.5f,-0.5f,-7.5f), vec3(-10.5f,1.0f,-7.5f), 1.0f); gjk_result gjk; if (poly_hit_sphere(&gjk, pyr, s)) ddraw_color(RED); else ddraw_color(WHITE); ddraw_sphere(s.c, 1); ddraw_pyramid(vec3(-10.5f,-0.5f,-7.5f), 0.5f/*vec3(-10.5f,1.0f,-7.5f)*/, 1.0f); poly_free(&pyr); ddraw_box(gjk.p0, vec3(0.05f, 0.05f, 0.05f)); ddraw_box(gjk.p1, vec3(0.05f, 0.05f, 0.05f)); ddraw_line(gjk.p0, gjk.p1); } { // poly(Diamond)-Sphere (GJK) intersection*/ sphere s = sphere(vec3(-20+0.6f*sin(dx), 3.0f*cos(dy),-8), 1); poly dmd = diamond(vec3(-20.5f,-0.5f,-7.5f), vec3(-20.5f,1.0f,-7.5f), 0.5f); gjk_result gjk; if (poly_hit_sphere(&gjk, dmd, s)) ddraw_color(RED); else ddraw_color(WHITE); ddraw_sphere(s.c, 1); ddraw_diamond(vec3(-20.5f,-0.5f,-7.5f), vec3(-20.5f,1.0f,-7.5f), 0.5f); poly_free(&dmd); ddraw_box(gjk.p0, vec3(0.05f, 0.05f, 0.05f)); ddraw_box(gjk.p1, vec3(0.05f, 0.05f, 0.05f)); ddraw_line(gjk.p0, gjk.p1); } { // poly(Pyramid)-Capsule (GJK) intersection*/ const float x = 0.4f*sin(dx); const float y = 3.0f*cos(dy); const float z = -15; capsule c = capsule(vec3(x,y-1.0f,z), vec3(x,y+1.0f,z), 0.2f); poly pyr = pyramid(vec3(-0.5f,-0.5f,-15.5f), vec3(-0.5f,1.0f,-15.5f), 1.0f); gjk_result gjk; if (poly_hit_capsule(&gjk, pyr, c)) ddraw_color(RED); else ddraw_color(WHITE); ddraw_capsule(c.a, c.b, c.r); ddraw_pyramid(vec3(-0.5f,-0.5f,-15.5f), 0.5f/*vec3(-0.5f,1.0f,-15.5f)*/, 1.0f); poly_free(&pyr); ddraw_box(gjk.p0, vec3(0.05f, 0.05f, 0.05f)); ddraw_box(gjk.p1, vec3(0.05f, 0.05f, 0.05f)); ddraw_line(gjk.p0, gjk.p1); } { // poly(Diamond)-Capsule (GJK) intersection*/ const float x = -10 + 0.4f*sin(dx); const float y = 3.0f*cos(dy); const float z = -15; capsule c = capsule(vec3(x,y-1.0f,z), vec3(x,y+1.0f,z), 0.2f); poly dmd = diamond(vec3(-10.5f,-0.5f,-15.5f), vec3(-10.5f,1.0f,-15.5f), 0.5f); gjk_result gjk; if (poly_hit_capsule(&gjk, dmd, c)) ddraw_color(RED); else ddraw_color(WHITE); ddraw_capsule(c.a, c.b, c.r); ddraw_diamond(vec3(-10.5f,-0.5f,-15.5f), vec3(-10.5f,1.0f,-15.5f), 0.5f); poly_free(&dmd); ddraw_box(gjk.p0, vec3(0.05f, 0.05f, 0.05f)); ddraw_box(gjk.p1, vec3(0.05f, 0.05f, 0.05f)); ddraw_line(gjk.p0, gjk.p1); } { // poly(Diamond)-poly(Pyramid) (GJK) intersection*/ const float x = -20 + 0.4f*sin(dx); const float y = 3.0f*cos(dy); const float z = -15; poly pyr = pyramid(vec3(x,y-0.5f,z), vec3(x,y+1,z), 0.8f); poly dmd = diamond(vec3(-20.5f,-0.5f,-15.5f), vec3(-20.5f,1.0f,-15.5f), 0.5f); gjk_result gjk; if (poly_hit_poly(&gjk, dmd, pyr)) ddraw_color(RED); else ddraw_color(WHITE); ddraw_pyramid(vec3(x,y-0.5f,z), 1/*vec3(x,y+1,z)*/, 1/*0.8f*/); ddraw_diamond(vec3(-20.5f,-0.5f,-15.5f), vec3(-20.5f,1.0f,-15.5f), 0.5f); poly_free(&dmd); poly_free(&pyr); ddraw_box(gjk.p0, vec3(0.05f, 0.05f, 0.05f)); ddraw_box(gjk.p1, vec3(0.05f, 0.05f, 0.05f)); ddraw_line(gjk.p0, gjk.p1); } { // poly(Pyramid)-poly(Diamond) (GJK) intersection*/ const float x = 10 + 0.4f*sin(dx); const float y = 3.0f*cos(dy); const float z = -15; poly dmd = diamond(vec3(x,y-0.5f,z), vec3(x,y+1,z), 0.5f); poly pyr = pyramid(vec3(10.5f,-0.5f,-15.5f), vec3(10.5f,1.0f,-15.5f), 1.0f); gjk_result gjk; if (poly_hit_poly(&gjk, dmd, pyr)) ddraw_color(RED); else ddraw_color(WHITE); ddraw_diamond(vec3(x,y-0.5f,z), vec3(x,y+1,z), 0.5f); ddraw_pyramid(vec3(10.5f,-0.5f,-15.5f), 0.5f/*vec3(10.5f,1.0f,-15.5f)*/, 1.0f); poly_free(&dmd); poly_free(&pyr); ddraw_box(gjk.p0, vec3(0.05f, 0.05f, 0.05f)); ddraw_box(gjk.p1, vec3(0.05f, 0.05f, 0.05f)); ddraw_line(gjk.p0, gjk.p1); } { // poly(Diamond)-AABB (GJK) intersection*/ const float x = 20 + 0.4f*sin(dx); const float y = 3.0f*cos(dy); const float z = -15; poly dmd = diamond(vec3(x,y-0.5f,z), vec3(x,y+1,z), 0.5f); aabb a = aabb(vec3(19.5f,-0.5f,-14.5f), vec3(20.5f,0.5f,-15.5f)); gjk_result gjk; if (poly_hit_aabb(&gjk, dmd, a)) ddraw_color(RED); else ddraw_color(WHITE); poly_free(&dmd); ddraw_diamond(vec3(x,y-0.5f,z), vec3(x,y+1,z), 0.5f); ddraw_box(vec3(20,0,-15), vec3(1,1,1)); ddraw_box(gjk.p0, vec3(0.05f, 0.05f, 0.05f)); ddraw_box(gjk.p1, vec3(0.05f, 0.05f, 0.05f)); ddraw_line(gjk.p0, gjk.p1); } }