latest
[carveJwlIkooP6JGAAIwe30JlM.git] / rigidbody.h
1 /*
2 * Resources: Box2D - Erin Catto
3 * qu3e - Randy Gaul
4 */
5
6 #include "common.h"
7 #include "bvh.h"
8 #include "scene.h"
9
10 static void rb_tangent_basis( v3f n, v3f tx, v3f ty );
11 static bh_system bh_system_rigidbodies;
12
13 #ifndef RIGIDBODY_H
14 #define RIGIDBODY_H
15
16 //#define RB_DEPR
17 #define k_rb_rate 60.0f
18 #define k_rb_delta (1.0f/k_rb_rate)
19
20 typedef struct rigidbody rigidbody;
21 typedef struct contact rb_ct;
22
23 struct rigidbody
24 {
25 v3f co, v, w;
26 v4f q;
27
28 enum rb_shape
29 {
30 k_rb_shape_box = 0,
31 k_rb_shape_sphere = 1,
32 k_rb_shape_capsule = 2,
33 k_rb_shape_scene = 3
34 }
35 type;
36
37 union
38 {
39 struct rb_sphere
40 {
41 float radius;
42 }
43 sphere;
44
45 struct rb_capsule
46 {
47 float height, radius;
48 }
49 capsule;
50
51 struct rb_scene
52 {
53 scene *pscene;
54 }
55 scene;
56 }
57 inf;
58
59 v3f right, up, forward;
60
61 int is_world;
62
63 boxf bbx, bbx_world;
64 float inv_mass;
65
66 v3f delta; /* where is the origin of this in relation to a parent body
67 TODO: Move this somewhere other than rigidbody struct
68 it is only used by character.h's ragdoll
69 */
70 m4x3f to_world, to_local;
71 };
72
73 #ifdef RB_DEPR
74 /*
75 * Impulses on static objects get re-routed here
76 */
77 static rigidbody rb_static_null =
78 {
79 .co={0.0f,0.0f,0.0f},
80 .q={0.0f,0.0f,0.0f,1.0f},
81 .v={0.0f,0.0f,0.0f},
82 .w={0.0f,0.0f,0.0f},
83 .is_world = 1,
84 .inv_mass = 0.0f
85 };
86 #endif
87
88 static void rb_debug( rigidbody *rb, u32 colour );
89
90 static struct contact
91 {
92 rigidbody *rba, *rbb;
93 v3f co, n;
94 v3f t[2];
95 float mass_total, p, bias, norm_impulse, tangent_impulse[2];
96 }
97 rb_contact_buffer[256];
98 static int rb_contact_count = 0;
99
100 static void rb_update_bounds( rigidbody *rb )
101 {
102 box_copy( rb->bbx, rb->bbx_world );
103 m4x3_transform_aabb( rb->to_world, rb->bbx_world );
104 }
105
106 static void rb_update_transform( rigidbody *rb )
107 {
108 q_normalize( rb->q );
109 q_m3x3( rb->q, rb->to_world );
110 v3_copy( rb->co, rb->to_world[3] );
111
112 m4x3_invert_affine( rb->to_world, rb->to_local );
113
114 m3x3_mulv( rb->to_world, (v3f){1.0f,0.0f, 0.0f}, rb->right );
115 m3x3_mulv( rb->to_world, (v3f){0.0f,1.0f, 0.0f}, rb->up );
116 m3x3_mulv( rb->to_world, (v3f){0.0f,0.0f,-1.0f}, rb->forward );
117
118 rb_update_bounds( rb );
119 }
120
121 static float sphere_volume( float radius )
122 {
123 float r3 = radius*radius*radius;
124 return (4.0f/3.0f) * VG_PIf * r3;
125 }
126
127 static void rb_init( rigidbody *rb )
128 {
129 float volume = 1.0f;
130
131 if( rb->type == k_rb_shape_box )
132 {
133 v3f dims;
134 v3_sub( rb->bbx[1], rb->bbx[0], dims );
135 volume = dims[0]*dims[1]*dims[2];
136 }
137 else if( rb->type == k_rb_shape_sphere )
138 {
139 volume = sphere_volume( rb->inf.sphere.radius );
140 v3_fill( rb->bbx[0], -rb->inf.sphere.radius );
141 v3_fill( rb->bbx[1], rb->inf.sphere.radius );
142 }
143 else if( rb->type == k_rb_shape_capsule )
144 {
145 float r = rb->inf.capsule.radius,
146 h = rb->inf.capsule.height;
147 volume = sphere_volume( r ) + VG_PIf * r*r * (h - r*2.0f);
148
149 v3_fill( rb->bbx[0], -rb->inf.sphere.radius );
150 v3_fill( rb->bbx[1], rb->inf.sphere.radius );
151 rb->bbx[0][1] = -h;
152 rb->bbx[1][1] = h;
153 }
154 else if( rb->type == k_rb_shape_scene )
155 {
156 rb->is_world = 1;
157 box_copy( rb->inf.scene.pscene->bbx, rb->bbx );
158 }
159
160 if( rb->is_world )
161 {
162 rb->inv_mass = 0.0f;
163 }
164 else
165 {
166 rb->inv_mass = 1.0f/(8.0f*volume);
167 }
168
169 v3_zero( rb->v );
170 v3_zero( rb->w );
171
172 rb_update_transform( rb );
173 }
174
175 static void rb_iter( rigidbody *rb )
176 {
177 v3f gravity = { 0.0f, -9.6f, 0.0f };
178 v3_muladds( rb->v, gravity, k_rb_delta, rb->v );
179
180 /* intergrate velocity */
181 v3_muladds( rb->co, rb->v, k_rb_delta, rb->co );
182 v3_lerp( rb->w, (v3f){0.0f,0.0f,0.0f}, 0.0025f, rb->w );
183
184 /* inegrate inertia */
185 if( v3_length2( rb->w ) > 0.0f )
186 {
187 v4f rotation;
188 v3f axis;
189 v3_copy( rb->w, axis );
190
191 float mag = v3_length( axis );
192 v3_divs( axis, mag, axis );
193 q_axis_angle( rotation, axis, mag*k_rb_delta );
194 q_mul( rotation, rb->q, rb->q );
195 }
196 }
197
198 static void rb_torque( rigidbody *rb, v3f axis, float mag )
199 {
200 v3_muladds( rb->w, axis, mag*k_rb_delta, rb->w );
201 }
202
203 static void rb_tangent_basis( v3f n, v3f tx, v3f ty )
204 {
205 /* Compute tangent basis (box2d) */
206 if( fabsf( n[0] ) >= 0.57735027f )
207 {
208 tx[0] = n[1];
209 tx[1] = -n[0];
210 tx[2] = 0.0f;
211 }
212 else
213 {
214 tx[0] = 0.0f;
215 tx[1] = n[2];
216 tx[2] = -n[1];
217 }
218
219 v3_normalize( tx );
220 v3_cross( n, tx, ty );
221 }
222
223 static void rb_solver_reset(void);
224 #ifdef RB_DEPR
225 static void rb_build_manifold_terrain( rigidbody *rb );
226 static void rb_build_manifold_terrain_sphere( rigidbody *rb );
227 #endif
228 static void rb_solve_contacts( rb_ct *buf, int len );
229 static void rb_presolve_contacts( rb_ct *buffer, int len );
230
231 /*
232 * These closest point tests were learned from Real-Time Collision Detection by
233 * Christer Ericson
234 */
235 static float closest_segment_segment( v3f p1, v3f q1, v3f p2, v3f q2,
236 float *s, float *t, v3f c1, v3f c2)
237 {
238 v3f d1,d2,r;
239 v3_sub( q1, p1, d1 );
240 v3_sub( q2, p2, d2 );
241 v3_sub( p1, p2, r );
242
243 float a = v3_length2( d1 ),
244 e = v3_length2( d2 ),
245 f = v3_dot( d2, r );
246
247 const float kEpsilon = 0.0001f;
248
249 if( a <= kEpsilon && e <= kEpsilon )
250 {
251 *s = 0.0f;
252 *t = 0.0f;
253 v3_copy( p1, c1 );
254 v3_copy( p2, c2 );
255
256 v3f v0;
257 v3_sub( c1, c2, v0 );
258
259 return v3_length2( v0 );
260 }
261
262 if( a<= kEpsilon )
263 {
264 *s = 0.0f;
265 *t = vg_clampf( f / e, 0.0f, 1.0f );
266 }
267 else
268 {
269 float c = v3_dot( d1, r );
270 if( e <= kEpsilon )
271 {
272 *t = 0.0f;
273 *s = vg_clampf( -c / a, 0.0f, 1.0f );
274 }
275 else
276 {
277 float b = v3_dot(d1,d2),
278 d = a*e-b*b;
279
280 if( d != 0.0f )
281 {
282 *s = vg_clampf((b*f - c*e)/d, 0.0f, 1.0f);
283 }
284 else
285 {
286 *s = 0.0f;
287 }
288
289 *t = (b*(*s)+f) / e;
290
291 if( *t < 0.0f )
292 {
293 *t = 0.0f;
294 *s = vg_clampf( -c / a, 0.0f, 1.0f );
295 }
296 else if( *t > 1.0f )
297 {
298 *t = 1.0f;
299 *s = vg_clampf((b-c)/a,0.0f,1.0f);
300 }
301 }
302 }
303
304 v3_muladds( p1, d1, *s, c1 );
305 v3_muladds( p2, d2, *t, c2 );
306
307 v3f v0;
308 v3_sub( c1, c2, v0 );
309 return v3_length2( v0 );
310 }
311
312 static void closest_point_aabb( v3f p, boxf box, v3f dest )
313 {
314 v3_maxv( p, box[0], dest );
315 v3_minv( dest, box[1], dest );
316 }
317
318 static void closest_point_obb( v3f p, rigidbody *rb, v3f dest )
319 {
320 v3f local;
321 m4x3_mulv( rb->to_local, p, local );
322 closest_point_aabb( local, rb->bbx, local );
323 m4x3_mulv( rb->to_world, local, dest );
324 }
325
326 static float closest_point_segment( v3f a, v3f b, v3f point, v3f dest )
327 {
328 v3f v0, v1;
329 v3_sub( b, a, v0 );
330 v3_sub( point, a, v1 );
331
332 float t = v3_dot( v1, v0 ) / v3_length2(v0);
333 t = vg_clampf(t,0.0f,1.0f);
334 v3_muladds( a, v0, t, dest );
335 return t;
336 }
337
338 static void closest_on_triangle( v3f p, v3f tri[3], v3f dest )
339 {
340 v3f ab, ac, ap;
341 float d1, d2;
342
343 /* Region outside A */
344 v3_sub( tri[1], tri[0], ab );
345 v3_sub( tri[2], tri[0], ac );
346 v3_sub( p, tri[0], ap );
347
348 d1 = v3_dot(ab,ap);
349 d2 = v3_dot(ac,ap);
350 if( d1 <= 0.0f && d2 <= 0.0f )
351 {
352 v3_copy( tri[0], dest );
353 v3_copy( (v3f){INFINITY,INFINITY,INFINITY}, dest );
354 return;
355 }
356
357 /* Region outside B */
358 v3f bp;
359 float d3, d4;
360
361 v3_sub( p, tri[1], bp );
362 d3 = v3_dot( ab, bp );
363 d4 = v3_dot( ac, bp );
364
365 if( d3 >= 0.0f && d4 <= d3 )
366 {
367 v3_copy( tri[1], dest );
368 v3_copy( (v3f){INFINITY,INFINITY,INFINITY}, dest );
369 return;
370 }
371
372 /* Edge region of AB */
373 float vc = d1*d4 - d3*d2;
374 if( vc <= 0.0f && d1 >= 0.0f && d3 <= 0.0f )
375 {
376 float v = d1 / (d1-d3);
377 v3_muladds( tri[0], ab, v, dest );
378 v3_copy( (v3f){INFINITY,INFINITY,INFINITY}, dest );
379 return;
380 }
381
382 /* Region outside C */
383 v3f cp;
384 float d5, d6;
385 v3_sub( p, tri[2], cp );
386 d5 = v3_dot(ab, cp);
387 d6 = v3_dot(ac, cp);
388
389 if( d6 >= 0.0f && d5 <= d6 )
390 {
391 v3_copy( tri[2], dest );
392 v3_copy( (v3f){INFINITY,INFINITY,INFINITY}, dest );
393 return;
394 }
395
396 /* Region of AC */
397 float vb = d5*d2 - d1*d6;
398 if( vb <= 0.0f && d2 >= 0.0f && d6 <= 0.0f )
399 {
400 float w = d2 / (d2-d6);
401 v3_muladds( tri[0], ac, w, dest );
402 v3_copy( (v3f){INFINITY,INFINITY,INFINITY}, dest );
403 return;
404 }
405
406 /* Region of BC */
407 float va = d3*d6 - d5*d4;
408 if( va <= 0.0f && (d4-d3) >= 0.0f && (d5-d6) >= 0.0f )
409 {
410 float w = (d4-d3) / ((d4-d3) + (d5-d6));
411 v3f bc;
412 v3_sub( tri[2], tri[1], bc );
413 v3_muladds( tri[1], bc, w, dest );
414 v3_copy( (v3f){INFINITY,INFINITY,INFINITY}, dest );
415 return;
416 }
417
418 /* P inside region, Q via barycentric coordinates uvw */
419 float d = 1.0f/(va+vb+vc),
420 v = vb*d,
421 w = vc*d;
422
423 v3_muladds( tri[0], ab, v, dest );
424 v3_muladds( dest, ac, w, dest );
425 }
426
427 /*
428 * Contact generators
429 *
430 * These do not automatically allocate contacts, an appropriately sized
431 * buffer must be supplied. The function returns the size of the manifold
432 * which was generated.
433 *
434 * The values set on the contacts are: n, co, p, rba, rbb
435 */
436
437 static void rb_debug_contact( rb_ct *ct )
438 {
439 v3f p1;
440 v3_muladds( ct->co, ct->n, 0.2f, p1 );
441 vg_line_pt3( ct->co, 0.1f, 0xff0000ff );
442 vg_line( ct->co, p1, 0xffffffff );
443 }
444
445 /*
446 * By collecting the minimum(time) and maximum(time) pairs of points, we
447 * build a reduced and stable exact manifold.
448 *
449 * tx: time at point
450 * rx: minimum distance of these points
451 * dx: the delta between the two points
452 *
453 * pairs will only ammend these if they are creating a collision
454 */
455 typedef struct capsule_manifold capsule_manifold;
456 struct capsule_manifold
457 {
458 float t0, t1;
459 float r0, r1;
460 v3f d0, d1;
461 };
462
463 /*
464 * Expand a line manifold with a new pair. t value is the time along segment
465 * on the oriented object which created this pair.
466 */
467 static void rb_capsule_manifold( v3f pa, v3f pb, float t, float r,
468 capsule_manifold *manifold )
469 {
470 v3f delta;
471 v3_sub( pa, pb, delta );
472
473 if( v3_length2(delta) < r*r )
474 {
475 if( t < manifold->t0 )
476 {
477 v3_copy( delta, manifold->d0 );
478 manifold->t0 = t;
479 manifold->r0 = r;
480 }
481
482 if( t > manifold->t1 )
483 {
484 v3_copy( delta, manifold->d1 );
485 manifold->t1 = t;
486 manifold->r1 = r;
487 }
488 }
489 }
490
491 static void rb_capsule_manifold_init( capsule_manifold *manifold )
492 {
493 manifold->t0 = INFINITY;
494 manifold->t1 = -INFINITY;
495 }
496
497 static int rb_capsule_manifold_done( rigidbody *rba, rigidbody *rbb,
498 capsule_manifold *manifold, rb_ct *buf )
499 {
500 float h = rba->inf.capsule.height,
501 ra = rba->inf.capsule.radius;
502
503 v3f p0, p1;
504 v3_muladds( rba->co, rba->up, -h*0.5f+ra, p0 );
505 v3_muladds( rba->co, rba->up, h*0.5f-ra, p1 );
506
507 int count = 0;
508 if( manifold->t0 <= 1.0f )
509 {
510 rb_ct *ct = buf;
511
512 v3f pa;
513 v3_muls( p0, 1.0f-manifold->t0, pa );
514 v3_muladds( pa, p1, manifold->t0, pa );
515
516 float d = v3_length( manifold->d0 );
517 v3_muls( manifold->d0, 1.0f/d, ct->n );
518 v3_muladds( pa, ct->n, -ra, ct->co );
519
520 ct->p = manifold->r0 - d;
521 ct->rba = rba;
522 ct->rbb = rbb;
523
524 count ++;
525 }
526
527 if( (manifold->t1 >= 0.0f) && (manifold->t0 != manifold->t1) )
528 {
529 rb_ct *ct = buf+count;
530
531 v3f pa;
532 v3_muls( p0, 1.0f-manifold->t1, pa );
533 v3_muladds( pa, p1, manifold->t1, pa );
534
535 float d = v3_length( manifold->d1 );
536 v3_muls( manifold->d1, 1.0f/d, ct->n );
537 v3_muladds( pa, ct->n, -ra, ct->co );
538
539 ct->p = manifold->r1 - d;
540 ct->rba = rba;
541 ct->rbb = rbb;
542
543 count ++;
544 }
545
546 /*
547 * Debugging
548 */
549
550 if( count == 2 )
551 vg_line( buf[0].co, buf[1].co, 0xff0000ff );
552
553 return count;
554 }
555
556 static int rb_capsule_vs_sphere( rigidbody *rba, rigidbody *rbb, rb_ct *buf )
557 {
558 float h = rba->inf.capsule.height,
559 ra = rba->inf.capsule.radius,
560 rb = rbb->inf.sphere.radius;
561
562 v3f p0, p1;
563 v3_muladds( rba->co, rba->up, -h*0.5f+ra, p0 );
564 v3_muladds( rba->co, rba->up, h*0.5f-ra, p1 );
565
566 v3f c, delta;
567 closest_point_segment( p0, p1, rbb->co, c );
568 v3_sub( c, rbb->co, delta );
569
570 float d2 = v3_length2(delta),
571 r = ra + rb;
572
573 if( d2 < r*r )
574 {
575 float d = sqrtf(d2);
576
577 rb_ct *ct = buf;
578 v3_muls( delta, 1.0f/d, ct->n );
579 ct->p = r-d;
580
581 v3f p0, p1;
582 v3_muladds( c, ct->n, -ra, p0 );
583 v3_muladds( rbb->co, ct->n, rb, p1 );
584 v3_add( p0, p1, ct->co );
585 v3_muls( ct->co, 0.5f, ct->co );
586
587 ct->rba = rba;
588 ct->rbb = rbb;
589
590 return 1;
591 }
592
593 return 0;
594 }
595
596 static int rb_capsule_vs_capsule( rigidbody *rba, rigidbody *rbb, rb_ct *buf )
597 {
598 float ha = rba->inf.capsule.height,
599 hb = rbb->inf.capsule.height,
600 ra = rba->inf.capsule.radius,
601 rb = rbb->inf.capsule.radius,
602 r = ra+rb;
603
604 v3f p0, p1, p2, p3;
605 v3_muladds( rba->co, rba->up, -ha*0.5f+ra, p0 );
606 v3_muladds( rba->co, rba->up, ha*0.5f-ra, p1 );
607 v3_muladds( rbb->co, rbb->up, -hb*0.5f+rb, p2 );
608 v3_muladds( rbb->co, rbb->up, hb*0.5f-rb, p3 );
609
610 capsule_manifold manifold;
611 rb_capsule_manifold_init( &manifold );
612
613 v3f pa, pb;
614 float ta, tb;
615 closest_segment_segment( p0, p1, p2, p3, &ta, &tb, pa, pb );
616 rb_capsule_manifold( pa, pb, ta, r, &manifold );
617
618 ta = closest_point_segment( p0, p1, p2, pa );
619 tb = closest_point_segment( p0, p1, p3, pb );
620 rb_capsule_manifold( pa, p2, ta, r, &manifold );
621 rb_capsule_manifold( pb, p3, tb, r, &manifold );
622
623 closest_point_segment( p2, p3, p0, pa );
624 closest_point_segment( p2, p3, p1, pb );
625 rb_capsule_manifold( p0, pa, 0.0f, r, &manifold );
626 rb_capsule_manifold( p1, pb, 1.0f, r, &manifold );
627
628 return rb_capsule_manifold_done( rba, rbb, &manifold, buf );
629 }
630
631 /*
632 * Generates up to two contacts; optimised for the most stable manifold
633 */
634 static int rb_capsule_vs_box( rigidbody *rba, rigidbody *rbb, rb_ct *buf )
635 {
636 float h = rba->inf.capsule.height,
637 r = rba->inf.capsule.radius;
638
639 /*
640 * Solving this in symetric local space of the cube saves us some time and a
641 * couple branches when it comes to the quad stage.
642 */
643 v3f centroid;
644 v3_add( rbb->bbx[0], rbb->bbx[1], centroid );
645 v3_muls( centroid, 0.5f, centroid );
646
647 boxf bbx;
648 v3_sub( rbb->bbx[0], centroid, bbx[0] );
649 v3_sub( rbb->bbx[1], centroid, bbx[1] );
650
651 v3f pc, p0w, p1w, p0, p1;
652 v3_muladds( rba->co, rba->up, -h*0.5f+r, p0w );
653 v3_muladds( rba->co, rba->up, h*0.5f-r, p1w );
654
655 m4x3_mulv( rbb->to_local, p0w, p0 );
656 m4x3_mulv( rbb->to_local, p1w, p1 );
657 v3_sub( p0, centroid, p0 );
658 v3_sub( p1, centroid, p1 );
659 v3_add( p0, p1, pc );
660 v3_muls( pc, 0.5f, pc );
661
662 /*
663 * Finding an appropriate quad to collide lines with
664 */
665 v3f region;
666 v3_div( pc, bbx[1], region );
667
668 v3f quad[4];
669 if( (fabsf(region[0]) > fabsf(region[1])) &&
670 (fabsf(region[0]) > fabsf(region[2])) )
671 {
672 float px = vg_signf(region[0]) * bbx[1][0];
673 v3_copy( (v3f){ px, bbx[0][1], bbx[0][2] }, quad[0] );
674 v3_copy( (v3f){ px, bbx[1][1], bbx[0][2] }, quad[1] );
675 v3_copy( (v3f){ px, bbx[1][1], bbx[1][2] }, quad[2] );
676 v3_copy( (v3f){ px, bbx[0][1], bbx[1][2] }, quad[3] );
677 }
678 else if( fabsf(region[1]) > fabsf(region[2]) )
679 {
680 float py = vg_signf(region[1]) * bbx[1][1];
681 v3_copy( (v3f){ bbx[0][0], py, bbx[0][2] }, quad[0] );
682 v3_copy( (v3f){ bbx[1][0], py, bbx[0][2] }, quad[1] );
683 v3_copy( (v3f){ bbx[1][0], py, bbx[1][2] }, quad[2] );
684 v3_copy( (v3f){ bbx[0][0], py, bbx[1][2] }, quad[3] );
685 }
686 else
687 {
688 float pz = vg_signf(region[2]) * bbx[1][2];
689 v3_copy( (v3f){ bbx[0][0], bbx[0][1], pz }, quad[0] );
690 v3_copy( (v3f){ bbx[1][0], bbx[0][1], pz }, quad[1] );
691 v3_copy( (v3f){ bbx[1][0], bbx[1][1], pz }, quad[2] );
692 v3_copy( (v3f){ bbx[0][0], bbx[1][1], pz }, quad[3] );
693 }
694
695 capsule_manifold manifold;
696 rb_capsule_manifold_init( &manifold );
697
698 v3f c0, c1;
699 closest_point_aabb( p0, bbx, c0 );
700 closest_point_aabb( p1, bbx, c1 );
701
702 v3f d0, d1, da;
703 v3_sub( c0, p0, d0 );
704 v3_sub( c1, p1, d1 );
705 v3_sub( p1, p0, da );
706
707 /* TODO: ? */
708 v3_normalize(d0);
709 v3_normalize(d1);
710 v3_normalize(da);
711
712 if( v3_dot( da, d0 ) <= 0.01f )
713 rb_capsule_manifold( p0, c0, 0.0f, r, &manifold );
714
715 if( v3_dot( da, d1 ) >= -0.01f )
716 rb_capsule_manifold( p1, c1, 1.0f, r, &manifold );
717
718 for( int i=0; i<4; i++ )
719 {
720 int i0 = i,
721 i1 = (i+1)%4;
722
723 v3f ca, cb;
724 float ta, tb;
725 closest_segment_segment( p0, p1, quad[i0], quad[i1], &ta, &tb, ca, cb );
726 rb_capsule_manifold( ca, cb, ta, r, &manifold );
727 }
728
729 /*
730 * Create final contacts based on line manifold
731 */
732 m3x3_mulv( rbb->to_world, manifold.d0, manifold.d0 );
733 m3x3_mulv( rbb->to_world, manifold.d1, manifold.d1 );
734
735 /*
736 * Debugging
737 */
738
739 #if 0
740 for( int i=0; i<4; i++ )
741 {
742 v3f q0, q1;
743 int i0 = i,
744 i1 = (i+1)%4;
745
746 v3_add( quad[i0], centroid, q0 );
747 v3_add( quad[i1], centroid, q1 );
748
749 m4x3_mulv( rbb->to_world, q0, q0 );
750 m4x3_mulv( rbb->to_world, q1, q1 );
751
752 vg_line( q0, q1, 0xffffffff );
753 }
754 #endif
755
756 return rb_capsule_manifold_done( rba, rbb, &manifold, buf );
757 }
758
759 static int rb_sphere_vs_box( rigidbody *rba, rigidbody *rbb, rb_ct *buf )
760 {
761 v3f co, delta;
762
763 closest_point_obb( rba->co, rbb, co );
764 v3_sub( rba->co, co, delta );
765
766 float d2 = v3_length2(delta),
767 r = rba->inf.sphere.radius;
768
769 if( d2 <= r*r )
770 {
771 float d;
772
773 rb_ct *ct = buf;
774 if( d2 <= 0.0001f )
775 {
776 v3_sub( rba->co, rbb->co, delta );
777
778 /*
779 * some extra testing is required to find the best axis to push the
780 * object back outside the box. Since there isnt a clear seperating
781 * vector already, especially on really high aspect boxes.
782 */
783 float lx = v3_dot( rbb->right, delta ),
784 ly = v3_dot( rbb->up, delta ),
785 lz = v3_dot( rbb->forward, delta ),
786 px = rbb->bbx[1][0] - fabsf(lx),
787 py = rbb->bbx[1][1] - fabsf(ly),
788 pz = rbb->bbx[1][2] - fabsf(lz);
789
790 if( px < py && px < pz )
791 v3_muls( rbb->right, vg_signf(lx), ct->n );
792 else if( py < pz )
793 v3_muls( rbb->up, vg_signf(ly), ct->n );
794 else
795 v3_muls( rbb->forward, vg_signf(lz), ct->n );
796
797 v3_muladds( rba->co, ct->n, -r, ct->co );
798 ct->p = r;
799 }
800 else
801 {
802 d = sqrtf(d2);
803 v3_muls( delta, 1.0f/d, ct->n );
804 ct->p = r-d;
805 v3_copy( co, ct->co );
806 }
807
808 ct->rba = rba;
809 ct->rbb = rbb;
810 return 1;
811 }
812
813 return 0;
814 }
815
816 static int rb_sphere_vs_sphere( rigidbody *rba, rigidbody *rbb, rb_ct *buf )
817 {
818 v3f delta;
819 v3_sub( rba->co, rbb->co, delta );
820
821 float d2 = v3_length2(delta),
822 r = rba->inf.sphere.radius + rbb->inf.sphere.radius;
823
824 if( d2 < r*r )
825 {
826 float d = sqrtf(d2);
827
828 rb_ct *ct = buf;
829 v3_muls( delta, 1.0f/d, ct->n );
830
831 v3f p0, p1;
832 v3_muladds( rba->co, ct->n,-rba->inf.sphere.radius, p0 );
833 v3_muladds( rbb->co, ct->n, rbb->inf.sphere.radius, p1 );
834 v3_add( p0, p1, ct->co );
835 v3_muls( ct->co, 0.5f, ct->co );
836 ct->p = r-d;
837 ct->rba = rba;
838 ct->rbb = rbb;
839 return 1;
840 }
841
842 return 0;
843 }
844
845 /* TODO: these guys */
846
847 static int rb_capsule_vs_scene( rigidbody *rba, rigidbody *rbb, rb_ct *buf )
848 {
849 u32 geo[128];
850 v3f tri[3];
851 int len = bh_select( &rbb->inf.scene.pscene->bhtris,
852 rba->bbx_world, geo, 128 );
853
854 return 0;
855 }
856
857 static int rb_sphere_vs_triangle( rigidbody *rba, rigidbody *rbb,
858 v3f tri[3], rb_ct *buf )
859 {
860 v3f delta, co;
861
862 closest_on_triangle( rba->co, tri, co );
863 v3_sub( rba->co, co, delta );
864
865 vg_line( rba->co, co, 0xffff0000 );
866 vg_line_pt3( rba->co, 0.1f, 0xff00ffff );
867
868 float d2 = v3_length2( delta ),
869 r = rba->inf.sphere.radius;
870
871 if( d2 < r*r )
872 {
873 rb_ct *ct = buf;
874
875 v3f ab, ac, tn;
876 v3_sub( tri[2], tri[0], ab );
877 v3_sub( tri[1], tri[0], ac );
878 v3_cross( ac, ab, tn );
879 v3_copy( tn, ct->n );
880 v3_normalize( ct->n );
881
882 float d = sqrtf(d2);
883
884 v3_copy( co, ct->co );
885 ct->p = r-d;
886 ct->rba = rba;
887 ct->rbb = rbb;
888 return 1;
889 }
890
891 return 0;
892 }
893
894 static int rb_sphere_vs_scene( rigidbody *rba, rigidbody *rbb, rb_ct *buf )
895 {
896 scene *sc = rbb->inf.scene.pscene;
897
898 u32 geo[128];
899 v3f tri[3];
900 int len = bh_select( &sc->bhtris, rba->bbx_world, geo, 128 );
901
902 int count = 0;
903
904 for( int i=0; i<len; i++ )
905 {
906 u32 *ptri = &sc->indices[ geo[i]*3 ];
907
908 for( int j=0; j<3; j++ )
909 v3_copy( sc->verts[ptri[j]].co, tri[j] );
910
911 vg_line(tri[0],tri[1],0xff00ff00 );
912 vg_line(tri[1],tri[2],0xff00ff00 );
913 vg_line(tri[2],tri[0],0xff00ff00 );
914
915 count += rb_sphere_vs_triangle( rba, rbb, tri, buf+count );
916
917 if( count == 12 )
918 {
919 vg_warn( "Exceeding sphere_vs_scene capacity. Geometry too dense!\n" );
920 return count;
921 }
922 }
923
924 return count;
925 }
926
927 static int RB_MATRIX_ERROR( rigidbody *rba, rigidbody *rbb, rb_ct *buf )
928 {
929 vg_error( "Collision type is unimplemented between types %d and %d\n",
930 rba->type, rbb->type );
931
932 return 0;
933 }
934
935 static int rb_sphere_vs_capsule( rigidbody *rba, rigidbody *rbb, rb_ct *buf )
936 {
937 return rb_capsule_vs_sphere( rbb, rba, buf );
938 }
939
940 static int rb_box_vs_capsule( rigidbody *rba, rigidbody *rbb, rb_ct *buf )
941 {
942 return rb_capsule_vs_box( rbb, rba, buf );
943 }
944
945 static int rb_box_vs_sphere( rigidbody *rba, rigidbody *rbb, rb_ct *buf )
946 {
947 return rb_sphere_vs_box( rbb, rba, buf );
948 }
949
950 static int (*rb_jump_table[4][4])( rigidbody *rba, rigidbody *rbb, rb_ct *buf )
951 = {
952 /* box */ /* Sphere */ /* Capsule */
953 /*box */ { RB_MATRIX_ERROR, rb_box_vs_sphere, rb_box_vs_capsule, RB_MATRIX_ERROR },
954 /*sphere */ { rb_sphere_vs_box, rb_sphere_vs_sphere, rb_sphere_vs_capsule, rb_sphere_vs_scene },
955 /*capsule*/ { rb_capsule_vs_box,rb_capsule_vs_sphere,rb_capsule_vs_capsule,RB_MATRIX_ERROR },
956 /*mesh */ { RB_MATRIX_ERROR, RB_MATRIX_ERROR, RB_MATRIX_ERROR, RB_MATRIX_ERROR }
957 };
958
959 static int rb_collide( rigidbody *rba, rigidbody *rbb )
960 {
961 int (*collider_jump)(rigidbody *rba, rigidbody *rbb, rb_ct *buf )
962 = rb_jump_table[rba->type][rbb->type];
963
964 /*
965 * 12 is the maximum manifold size we can generate, so we are forced to abort
966 * potentially checking any more.
967 */
968 if( rb_contact_count + 12 > vg_list_size(rb_contact_buffer) )
969 {
970 vg_warn( "Too many contacts made in global collider buffer (%d of %d\n)",
971 rb_contact_count, vg_list_size(rb_contact_buffer) );
972 return 0;
973 }
974
975 /*
976 * TODO: Replace this with a more dedicated broad phase pass
977 */
978 if( box_overlap( rba->bbx_world, rbb->bbx_world ) )
979 {
980 int count = collider_jump( rba, rbb, rb_contact_buffer+rb_contact_count);
981 rb_contact_count += count;
982 return count;
983 }
984 else
985 return 0;
986 }
987
988 /*
989 * Generic functions
990 */
991
992 #ifdef RB_DEPR
993 /*
994 * This function does not accept triangle as a dynamic object, it is assumed
995 * to always be static.
996 *
997 * The triangle is also assumed to be one sided for better detection
998 */
999 static int rb_sphere_vs_triangle( rigidbody *rba, v3f tri[3], rb_ct *buf )
1000 {
1001 v3f delta, co;
1002
1003 closest_on_triangle( rba->co, tri, co );
1004 v3_sub( rba->co, co, delta );
1005
1006 float d2 = v3_length2( delta ),
1007 r = rba->inf.sphere.radius;
1008
1009 if( d2 < r*r )
1010 {
1011 v3f ab, ac, tn;
1012 v3_sub( tri[1], tri[0], ab );
1013 v3_sub( tri[2], tri[0], ac );
1014 v3_cross( ac, ab, tn );
1015
1016 if( v3_dot( delta, tn ) > 0.0f )
1017 v3_muls( delta, -1.0f, delta );
1018
1019 float d = sqrtf(d2);
1020
1021 rb_ct *ct = buf;
1022 v3_muls( delta, 1.0f/d, ct->n );
1023 v3_copy( co, ct->co );
1024 ct->p = r-d;
1025 ct->rba = rba;
1026 ct->rbb = &rb_static_null;
1027 return 1;
1028 }
1029
1030 return 0;
1031 }
1032
1033 static int sphere_vs_triangle( v3f c, float r, v3f tri[3],
1034 v3f co, v3f norm, float *p )
1035 {
1036 v3f delta;
1037 closest_on_triangle( c, tri, co );
1038
1039 v3_sub( c, co, delta );
1040
1041
1042 float d = v3_length2( delta );
1043 if( d < r*r )
1044 {
1045 v3f ab, ac, tn;
1046 v3_sub( tri[1], tri[0], ab );
1047 v3_sub( tri[2], tri[0], ac );
1048 v3_cross( ac, ab, tn );
1049
1050 if( v3_dot( delta, tn ) > 0.0f )
1051 v3_muls( delta, -1.0f, delta );
1052
1053 vg_line_pt3( co, 0.05f, 0xff00ff00 );
1054
1055 d = sqrtf(d);
1056 v3_muls( delta, 1.0f/d, norm );
1057
1058 *p = r-d;
1059 return 1;
1060 }
1061
1062 return 0;
1063 }
1064
1065 #include "world.h"
1066 #endif
1067
1068 static void rb_solver_reset(void)
1069 {
1070 rb_contact_count = 0;
1071 }
1072
1073 static rb_ct *rb_global_ct(void)
1074 {
1075 return rb_contact_buffer + rb_contact_count;
1076 }
1077
1078 #ifdef RB_DEPR
1079 static struct contact *rb_start_contact(void)
1080 {
1081 if( rb_contact_count == vg_list_size(rb_contact_buffer) )
1082 {
1083 vg_error( "rigidbody: too many contacts generated (%u)\n",
1084 rb_contact_count );
1085 return NULL;
1086 }
1087
1088 return &rb_contact_buffer[ rb_contact_count ];
1089 }
1090
1091 static void rb_commit_contact( struct contact *ct, float p )
1092 {
1093 ct->bias = -0.2f*k_rb_rate*vg_minf(0.0f,-p+0.04f);
1094 rb_tangent_basis( ct->n, ct->t[0], ct->t[1] );
1095
1096 ct->norm_impulse = 0.0f;
1097 ct->tangent_impulse[0] = 0.0f;
1098 ct->tangent_impulse[1] = 0.0f;
1099
1100 rb_contact_count ++;
1101 }
1102
1103 static void rb_build_manifold_terrain_sphere( rigidbody *rb )
1104 {
1105 u32 geo[256];
1106 v3f tri[3];
1107 int len = bh_select( &world.geo.bhtris, rb->bbx_world, geo, 256 );
1108
1109 for( int i=0; i<len; i++ )
1110 {
1111 u32 *ptri = &world.geo.indices[ geo[i]*3 ];
1112
1113 for( int j=0; j<3; j++ )
1114 v3_copy( world.geo.verts[ptri[j]].co, tri[j] );
1115
1116 vg_line(tri[0],tri[1],0xff00ff00 );
1117 vg_line(tri[1],tri[2],0xff00ff00 );
1118 vg_line(tri[2],tri[0],0xff00ff00 );
1119
1120 v3f co, norm;
1121 float p;
1122
1123 for( int j=0; j<2; j++ )
1124 {
1125 if( sphere_vs_triangle( rb->co, rb->inf.sphere.radius, tri,co,norm,&p))
1126 {
1127 struct contact *ct = rb_start_contact();
1128
1129 if( !ct )
1130 return;
1131
1132 v3f p1;
1133 v3_muladds( rb->co, norm, p, p1 );
1134 vg_line( rb->co, p1, 0xffffffff );
1135
1136 ct->rba = rb;
1137 v3_copy( co, ct->co );
1138 v3_copy( norm, ct->n );
1139 rb_commit_contact( ct, p );
1140 }
1141 }
1142 }
1143
1144 }
1145
1146 static void rb_build_manifold_terrain( rigidbody *rb )
1147 {
1148 v3f *box = rb->bbx;
1149 v3f pts[8];
1150 float *p000 = pts[0], *p001 = pts[1], *p010 = pts[2], *p011 = pts[3],
1151 *p100 = pts[4], *p101 = pts[5], *p110 = pts[6], *p111 = pts[7];
1152
1153 p000[0]=box[0][0];p000[1]=box[0][1];p000[2]=box[0][2];
1154 p001[0]=box[0][0];p001[1]=box[0][1];p001[2]=box[1][2];
1155 p010[0]=box[0][0];p010[1]=box[1][1];p010[2]=box[0][2];
1156 p011[0]=box[0][0];p011[1]=box[1][1];p011[2]=box[1][2];
1157
1158 p100[0]=box[1][0];p100[1]=box[0][1];p100[2]=box[0][2];
1159 p101[0]=box[1][0];p101[1]=box[0][1];p101[2]=box[1][2];
1160 p110[0]=box[1][0];p110[1]=box[1][1];p110[2]=box[0][2];
1161 p111[0]=box[1][0];p111[1]=box[1][1];p111[2]=box[1][2];
1162
1163 m4x3_mulv( rb->to_world, p000, p000 );
1164 m4x3_mulv( rb->to_world, p001, p001 );
1165 m4x3_mulv( rb->to_world, p010, p010 );
1166 m4x3_mulv( rb->to_world, p011, p011 );
1167 m4x3_mulv( rb->to_world, p100, p100 );
1168 m4x3_mulv( rb->to_world, p101, p101 );
1169 m4x3_mulv( rb->to_world, p110, p110 );
1170 m4x3_mulv( rb->to_world, p111, p111 );
1171
1172 int count = 0;
1173
1174 for( int i=0; i<8; i++ )
1175 {
1176 float *point = pts[i];
1177 struct contact *ct = rb_start_contact();
1178
1179 if( !ct )
1180 return;
1181
1182 ct->rba = rb;
1183
1184 v3f surface;
1185 v3_copy( point, surface );
1186 surface[1] += 4.0f;
1187
1188 ray_hit hit;
1189 hit.dist = INFINITY;
1190 if( !ray_world( surface, (v3f){0.0f,-1.0f,0.0f}, &hit ))
1191 continue;
1192
1193 v3_copy( hit.pos, surface );
1194
1195 float p = vg_minf( surface[1] - point[1], 1.0f );
1196
1197 if( p > 0.0f )
1198 {
1199 v3_copy( hit.normal, ct->n );
1200 v3_add( point, surface, ct->co );
1201 v3_muls( ct->co, 0.5f, ct->co );
1202
1203 rb_commit_contact( ct, p );
1204 count ++;
1205 if( count == 4 )
1206 break;
1207 }
1208 }
1209 }
1210 #endif
1211
1212 /*
1213 * Initializing things like tangent vectors
1214 */
1215
1216 static void rb_presolve_contacts( rb_ct *buffer, int len )
1217 {
1218 for( int i=0; i<len; i++ )
1219 {
1220 rb_ct *ct = &buffer[i];
1221 ct->bias = -0.2f * k_rb_rate * vg_minf(0.0f,-ct->p+0.04f);
1222 rb_tangent_basis( ct->n, ct->t[0], ct->t[1] );
1223
1224 ct->norm_impulse = 0.0f;
1225 ct->tangent_impulse[0] = 0.0f;
1226 ct->tangent_impulse[1] = 0.0f;
1227 ct->mass_total = 1.0f/(ct->rba->inv_mass + ct->rbb->inv_mass);
1228
1229 rb_debug_contact( ct );
1230 }
1231 }
1232
1233 /*
1234 * Creates relative contact velocity vector, and offsets between each body
1235 */
1236 static void rb_rcv( rb_ct *ct, v3f rv, v3f da, v3f db )
1237 {
1238 rigidbody *rba = ct->rba,
1239 *rbb = ct->rbb;
1240
1241 v3_sub( ct->co, rba->co, da );
1242 v3_sub( ct->co, rbb->co, db );
1243
1244 v3f rva, rvb;
1245 v3_cross( rba->w, da, rva );
1246 v3_add( rba->v, rva, rva );
1247 v3_cross( rbb->w, db, rvb );
1248 v3_add( rbb->v, rvb, rvb );
1249
1250 v3_sub( rva, rvb, rv );
1251 }
1252
1253 /*
1254 * Apply regular and angular velocity impulses to objects involved in contact
1255 */
1256 static void rb_standard_impulse( rb_ct *ct, v3f da, v3f db, v3f impulse )
1257 {
1258 rigidbody *rba = ct->rba,
1259 *rbb = ct->rbb;
1260
1261 v3f ia, ib;
1262 v3_muls( impulse, ct->mass_total*rba->inv_mass, ia );
1263 v3_muls( impulse, -ct->mass_total*rbb->inv_mass, ib );
1264
1265 /* response */
1266 v3_add( rba->v, ia, rba->v );
1267 v3_add( rbb->v, ib, rbb->v );
1268
1269 /* Angular velocity */
1270 v3f wa, wb;
1271 v3_cross( da, ia, wa );
1272 v3_cross( db, ib, wb );
1273 v3_add( rba->w, wa, rba->w );
1274 v3_add( rbb->w, wb, rbb->w );
1275 }
1276
1277 /*
1278 * One iteration to solve the contact constraint
1279 */
1280 static void rb_solve_contacts( rb_ct *buf, int len )
1281 {
1282 float k_friction = 0.1f;
1283
1284 /* Friction Impulse */
1285 for( int i=0; i<len; i++ )
1286 {
1287 struct contact *ct = &buf[i];
1288 rigidbody *rb = ct->rba;
1289
1290 v3f rv, da, db;
1291 rb_rcv( ct, rv, da, db );
1292
1293 for( int j=0; j<2; j++ )
1294 {
1295 float f = k_friction * ct->norm_impulse,
1296 vt = -v3_dot( rv, ct->t[j] );
1297
1298 float temp = ct->tangent_impulse[j];
1299 ct->tangent_impulse[j] = vg_clampf( temp+vt, -f, f );
1300 vt = ct->tangent_impulse[j] - temp;
1301
1302 v3f impulse;
1303 v3_muls( ct->t[j], vt, impulse );
1304 rb_standard_impulse( ct, da, db, impulse );
1305 }
1306 }
1307
1308 /* Normal Impulse */
1309 for( int i=0; i<len; i++ )
1310 {
1311 struct contact *ct = &buf[i];
1312 rigidbody *rba = ct->rba,
1313 *rbb = ct->rbb;
1314
1315 v3f rv, da, db;
1316 rb_rcv( ct, rv, da, db );
1317
1318 float vn = -v3_dot( rv, ct->n ) + ct->bias;
1319
1320 float temp = ct->norm_impulse;
1321 ct->norm_impulse = vg_maxf( temp + vn, 0.0f );
1322 vn = ct->norm_impulse - temp;
1323
1324 v3f impulse;
1325 v3_muls( ct->n, vn, impulse );
1326 rb_standard_impulse( ct, da, db, impulse );
1327 }
1328 }
1329
1330 /*
1331 * The following ventures into not really very sophisticated at all maths
1332 */
1333
1334 struct rb_angle_limit
1335 {
1336 rigidbody *rba, *rbb;
1337 v3f axis;
1338 float impulse, bias;
1339 };
1340
1341 static int rb_angle_limit_force( rigidbody *rba, v3f va,
1342 rigidbody *rbb, v3f vb,
1343 float max )
1344 {
1345 v3f wva, wvb;
1346 m3x3_mulv( rba->to_world, va, wva );
1347 m3x3_mulv( rbb->to_world, vb, wvb );
1348
1349 float dt = v3_dot(wva,wvb)*0.999f,
1350 ang = fabsf(dt);
1351 ang = acosf( dt );
1352 if( ang > max )
1353 {
1354 float correction = max-ang;
1355
1356 v3f axis;
1357 v3_cross( wva, wvb, axis );
1358
1359 v4f rotation;
1360 q_axis_angle( rotation, axis, -correction*0.25f );
1361 q_mul( rotation, rba->q, rba->q );
1362
1363 q_axis_angle( rotation, axis, correction*0.25f );
1364 q_mul( rotation, rbb->q, rbb->q );
1365
1366 return 1;
1367 }
1368
1369 return 0;
1370 }
1371
1372 static void rb_constraint_angle_limit( struct rb_angle_limit *limit )
1373 {
1374
1375 }
1376
1377 static void rb_constraint_angle( rigidbody *rba, v3f va,
1378 rigidbody *rbb, v3f vb,
1379 float max, float spring )
1380 {
1381 v3f wva, wvb;
1382 m3x3_mulv( rba->to_world, va, wva );
1383 m3x3_mulv( rbb->to_world, vb, wvb );
1384
1385 float dt = v3_dot(wva,wvb)*0.999f,
1386 ang = fabsf(dt);
1387
1388 v3f axis;
1389 v3_cross( wva, wvb, axis );
1390 v3_muladds( rba->w, axis, ang*spring*0.5f, rba->w );
1391 v3_muladds( rbb->w, axis, -ang*spring*0.5f, rbb->w );
1392
1393 return;
1394
1395 /* TODO: convert max into the dot product value so we dont have to always
1396 * evaluate acosf, only if its greater than the angle specified */
1397 ang = acosf( dt );
1398 if( ang > max )
1399 {
1400 float correction = max-ang;
1401
1402 v4f rotation;
1403 q_axis_angle( rotation, axis, -correction*0.125f );
1404 q_mul( rotation, rba->q, rba->q );
1405
1406 q_axis_angle( rotation, axis, correction*0.125f );
1407 q_mul( rotation, rbb->q, rbb->q );
1408 }
1409 }
1410
1411 static void rb_relative_velocity( rigidbody *ra, v3f lca,
1412 rigidbody *rb, v3f lcb, v3f rcv )
1413 {
1414 v3f wca, wcb;
1415 m3x3_mulv( ra->to_world, lca, wca );
1416 m3x3_mulv( rb->to_world, lcb, wcb );
1417
1418 v3_sub( ra->v, rb->v, rcv );
1419
1420 v3f rcv_Ra, rcv_Rb;
1421 v3_cross( ra->w, wca, rcv_Ra );
1422 v3_cross( rb->w, wcb, rcv_Rb );
1423 v3_add( rcv_Ra, rcv, rcv );
1424 v3_sub( rcv, rcv_Rb, rcv );
1425 }
1426
1427 static void rb_constraint_position( rigidbody *ra, v3f lca,
1428 rigidbody *rb, v3f lcb )
1429 {
1430 /* C = (COa + Ra*LCa) - (COb + Rb*LCb) = 0 */
1431 v3f wca, wcb;
1432 m3x3_mulv( ra->to_world, lca, wca );
1433 m3x3_mulv( rb->to_world, lcb, wcb );
1434
1435 v3f delta;
1436 v3_add( wcb, rb->co, delta );
1437 v3_sub( delta, wca, delta );
1438 v3_sub( delta, ra->co, delta );
1439
1440 v3_muladds( ra->co, delta, 0.5f, ra->co );
1441 v3_muladds( rb->co, delta, -0.5f, rb->co );
1442
1443 v3f rcv;
1444 v3_sub( ra->v, rb->v, rcv );
1445
1446 v3f rcv_Ra, rcv_Rb;
1447 v3_cross( ra->w, wca, rcv_Ra );
1448 v3_cross( rb->w, wcb, rcv_Rb );
1449 v3_add( rcv_Ra, rcv, rcv );
1450 v3_sub( rcv, rcv_Rb, rcv );
1451
1452 float nm = 0.5f/(rb->inv_mass + ra->inv_mass);
1453
1454 float mass_a = 1.0f/ra->inv_mass,
1455 mass_b = 1.0f/rb->inv_mass,
1456 total_mass = mass_a+mass_b;
1457
1458 v3f impulse;
1459 v3_muls( rcv, 1.0f, impulse );
1460 v3_muladds( rb->v, impulse, mass_b/total_mass, rb->v );
1461 v3_cross( wcb, impulse, impulse );
1462 v3_add( impulse, rb->w, rb->w );
1463
1464 v3_muls( rcv, -1.0f, impulse );
1465 v3_muladds( ra->v, impulse, mass_a/total_mass, ra->v );
1466 v3_cross( wca, impulse, impulse );
1467 v3_add( impulse, ra->w, ra->w );
1468
1469 #if 0
1470 /*
1471 * this could be used for spring joints
1472 * its not good for position constraint
1473 */
1474 v3f impulse;
1475 v3_muls( delta, 0.5f*spring, impulse );
1476
1477 v3_add( impulse, ra->v, ra->v );
1478 v3_cross( wca, impulse, impulse );
1479 v3_add( impulse, ra->w, ra->w );
1480
1481 v3_muls( delta, -0.5f*spring, impulse );
1482
1483 v3_add( impulse, rb->v, rb->v );
1484 v3_cross( wcb, impulse, impulse );
1485 v3_add( impulse, rb->w, rb->w );
1486 #endif
1487 }
1488
1489 static void debug_sphere( m4x3f m, float radius, u32 colour )
1490 {
1491 v3f ly = { 0.0f, 0.0f, radius },
1492 lx = { 0.0f, radius, 0.0f },
1493 lz = { 0.0f, 0.0f, radius };
1494
1495 for( int i=0; i<16; i++ )
1496 {
1497 float t = ((float)(i+1) * (1.0f/16.0f)) * VG_PIf * 2.0f,
1498 s = sinf(t),
1499 c = cosf(t);
1500
1501 v3f py = { s*radius, 0.0f, c*radius },
1502 px = { s*radius, c*radius, 0.0f },
1503 pz = { 0.0f, s*radius, c*radius };
1504
1505 v3f p0, p1, p2, p3, p4, p5;
1506 m4x3_mulv( m, py, p0 );
1507 m4x3_mulv( m, ly, p1 );
1508 m4x3_mulv( m, px, p2 );
1509 m4x3_mulv( m, lx, p3 );
1510 m4x3_mulv( m, pz, p4 );
1511 m4x3_mulv( m, lz, p5 );
1512
1513 vg_line( p0, p1, colour == 0x00? 0xff00ff00: colour );
1514 vg_line( p2, p3, colour == 0x00? 0xff0000ff: colour );
1515 vg_line( p4, p5, colour == 0x00? 0xffff0000: colour );
1516
1517 v3_copy( py, ly );
1518 v3_copy( px, lx );
1519 v3_copy( pz, lz );
1520 }
1521 }
1522
1523 static void debug_capsule( m4x3f m, float radius, float h, u32 colour )
1524 {
1525 v3f ly = { 0.0f, 0.0f, radius },
1526 lx = { 0.0f, radius, 0.0f },
1527 lz = { 0.0f, 0.0f, radius };
1528
1529 float s0 = sinf(0.0f)*radius,
1530 c0 = cosf(0.0f)*radius;
1531
1532 v3f p0, p1, up, right, forward;
1533 m3x3_mulv( m, (v3f){0.0f,1.0f,0.0f}, up );
1534 m3x3_mulv( m, (v3f){1.0f,0.0f,0.0f}, right );
1535 m3x3_mulv( m, (v3f){0.0f,0.0f,-1.0f}, forward );
1536 v3_muladds( m[3], up, -h*0.5f+radius, p0 );
1537 v3_muladds( m[3], up, h*0.5f-radius, p1 );
1538
1539 v3f a0, a1, b0, b1;
1540 v3_muladds( p0, right, radius, a0 );
1541 v3_muladds( p1, right, radius, a1 );
1542 v3_muladds( p0, forward, radius, b0 );
1543 v3_muladds( p1, forward, radius, b1 );
1544 vg_line( a0, a1, colour );
1545 vg_line( b0, b1, colour );
1546
1547 v3_muladds( p0, right, -radius, a0 );
1548 v3_muladds( p1, right, -radius, a1 );
1549 v3_muladds( p0, forward, -radius, b0 );
1550 v3_muladds( p1, forward, -radius, b1 );
1551 vg_line( a0, a1, colour );
1552 vg_line( b0, b1, colour );
1553
1554 for( int i=0; i<16; i++ )
1555 {
1556 float t = ((float)(i+1) * (1.0f/16.0f)) * VG_PIf * 2.0f,
1557 s1 = sinf(t)*radius,
1558 c1 = cosf(t)*radius;
1559
1560 v3f e0 = { s0, 0.0f, c0 },
1561 e1 = { s1, 0.0f, c1 },
1562 e2 = { s0, c0, 0.0f },
1563 e3 = { s1, c1, 0.0f },
1564 e4 = { 0.0f, c0, s0 },
1565 e5 = { 0.0f, c1, s1 };
1566
1567 m3x3_mulv( m, e0, e0 );
1568 m3x3_mulv( m, e1, e1 );
1569 m3x3_mulv( m, e2, e2 );
1570 m3x3_mulv( m, e3, e3 );
1571 m3x3_mulv( m, e4, e4 );
1572 m3x3_mulv( m, e5, e5 );
1573
1574 v3_add( p0, e0, a0 );
1575 v3_add( p0, e1, a1 );
1576 v3_add( p1, e0, b0 );
1577 v3_add( p1, e1, b1 );
1578
1579 vg_line( a0, a1, colour );
1580 vg_line( b0, b1, colour );
1581
1582 if( c0 < 0.0f )
1583 {
1584 v3_add( p0, e2, a0 );
1585 v3_add( p0, e3, a1 );
1586 v3_add( p0, e4, b0 );
1587 v3_add( p0, e5, b1 );
1588 }
1589 else
1590 {
1591 v3_add( p1, e2, a0 );
1592 v3_add( p1, e3, a1 );
1593 v3_add( p1, e4, b0 );
1594 v3_add( p1, e5, b1 );
1595 }
1596
1597 vg_line( a0, a1, colour );
1598 vg_line( b0, b1, colour );
1599
1600 s0 = s1;
1601 c0 = c1;
1602 }
1603 }
1604
1605 static void rb_debug( rigidbody *rb, u32 colour )
1606 {
1607 if( rb->type == k_rb_shape_box )
1608 {
1609 v3f *box = rb->bbx;
1610 vg_line_boxf_transformed( rb->to_world, rb->bbx, colour );
1611 }
1612 else if( rb->type == k_rb_shape_sphere )
1613 {
1614 debug_sphere( rb->to_world, rb->inf.sphere.radius, colour );
1615 }
1616 else if( rb->type == k_rb_shape_capsule )
1617 {
1618 m4x3f m0, m1;
1619 float h = rb->inf.capsule.height,
1620 r = rb->inf.capsule.radius;
1621
1622 debug_capsule( rb->to_world, r, h, colour );
1623 }
1624 else if( rb->type == k_rb_shape_scene )
1625 {
1626 vg_line_boxf( rb->bbx, colour );
1627 }
1628 }
1629
1630 #ifdef RB_DEPR
1631 /*
1632 * out penetration distance, normal
1633 */
1634 static int rb_point_in_body( rigidbody *rb, v3f pos, float *pen, v3f normal )
1635 {
1636 v3f local;
1637 m4x3_mulv( rb->to_local, pos, local );
1638
1639 if( local[0] > rb->bbx[0][0] && local[0] < rb->bbx[1][0] &&
1640 local[1] > rb->bbx[0][1] && local[1] < rb->bbx[1][1] &&
1641 local[2] > rb->bbx[0][2] && local[2] < rb->bbx[1][2] )
1642 {
1643 v3f area, com, comrel;
1644 v3_add( rb->bbx[0], rb->bbx[1], com );
1645 v3_muls( com, 0.5f, com );
1646
1647 v3_sub( rb->bbx[1], rb->bbx[0], area );
1648 v3_sub( local, com, comrel );
1649 v3_div( comrel, area, comrel );
1650
1651 int axis = 0;
1652 float max_mag = fabsf(comrel[0]);
1653
1654 if( fabsf(comrel[1]) > max_mag )
1655 {
1656 axis = 1;
1657 max_mag = fabsf(comrel[1]);
1658 }
1659 if( fabsf(comrel[2]) > max_mag )
1660 {
1661 axis = 2;
1662 max_mag = fabsf(comrel[2]);
1663 }
1664
1665 v3_zero( normal );
1666 normal[axis] = vg_signf(comrel[axis]);
1667
1668 if( normal[axis] < 0.0f )
1669 *pen = local[axis] - rb->bbx[0][axis];
1670 else
1671 *pen = rb->bbx[1][axis] - local[axis];
1672
1673 m3x3_mulv( rb->to_world, normal, normal );
1674 return 1;
1675 }
1676
1677 return 0;
1678 }
1679
1680 /*
1681 * BVH implementation, this is ONLY for static rigidbodies, its to slow for
1682 * realtime use.
1683 */
1684
1685 static void rb_bh_expand_bound( void *user, boxf bound, u32 item_index )
1686 {
1687 rigidbody *rb = &((rigidbody *)user)[ item_index ];
1688 box_concat( bound, rb->bbx_world );
1689 }
1690
1691 static float rb_bh_centroid( void *user, u32 item_index, int axis )
1692 {
1693 rigidbody *rb = &((rigidbody *)user)[ item_index ];
1694 return (rb->bbx_world[axis][0] + rb->bbx_world[1][axis]) * 0.5f;
1695 }
1696
1697 static void rb_bh_swap( void *user, u32 ia, u32 ib )
1698 {
1699 rigidbody temp, *rba, *rbb;
1700 rba = &((rigidbody *)user)[ ia ];
1701 rbb = &((rigidbody *)user)[ ib ];
1702
1703 temp = *rba;
1704 *rba = *rbb;
1705 *rbb = temp;
1706 }
1707
1708 static void rb_bh_debug( void *user, u32 item_index )
1709 {
1710 rigidbody *rb = &((rigidbody *)user)[ item_index ];
1711 rb_debug( rb, 0xff00ffff );
1712 }
1713
1714 static bh_system bh_system_rigidbodies =
1715 {
1716 .expand_bound = rb_bh_expand_bound,
1717 .item_centroid = rb_bh_centroid,
1718 .item_swap = rb_bh_swap,
1719 .item_debug = rb_bh_debug,
1720 .cast_ray = NULL
1721 };
1722
1723 #endif
1724
1725 #endif /* RIGIDBODY_H */