its ot'
[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
9 static void rb_tangent_basis( v3f n, v3f tx, v3f ty );
10 static bh_system bh_system_rigidbodies;
11
12 #ifndef RIGIDBODY_H
13 #define RIGIDBODY_H
14
15 #define RB_DEPR
16 #define k_rb_rate 60.0f
17 #define k_rb_delta (1.0f/k_rb_rate)
18
19 typedef struct rigidbody rigidbody;
20 struct rigidbody
21 {
22 v3f co, v, w;
23 v4f q;
24
25 enum rb_shape
26 {
27 k_rb_shape_box,
28 k_rb_shape_sphere,
29 k_rb_shape_capsule
30 }
31 type;
32
33 union
34 {
35 struct rb_sphere
36 {
37 float radius;
38 }
39 sphere;
40
41 struct rb_capsule
42 {
43 float height, radius;
44 }
45 capsule;
46 }
47 inf;
48
49 v3f right, up, forward;
50
51 boxf bbx, bbx_world;
52 float inv_mass;
53
54 v3f delta; /* where is the origin of this in relation to a parent body */
55 m4x3f to_world, to_local;
56 };
57
58 static void rb_debug( rigidbody *rb, u32 colour );
59
60 static struct contact
61 {
62 rigidbody *rba;
63 v3f co, n, delta;
64 v3f t[2];
65 float bias, norm_impulse, tangent_impulse[2];
66 }
67 rb_contact_buffer[256];
68 static int rb_contact_count = 0;
69
70 static void rb_update_transform( rigidbody *rb )
71 {
72 q_normalize( rb->q );
73 q_m3x3( rb->q, rb->to_world );
74 v3_copy( rb->co, rb->to_world[3] );
75
76 m4x3_invert_affine( rb->to_world, rb->to_local );
77
78 box_copy( rb->bbx, rb->bbx_world );
79 m4x3_transform_aabb( rb->to_world, rb->bbx_world );
80
81 m3x3_mulv( rb->to_world, (v3f){1.0f,0.0f, 0.0f}, rb->right );
82 m3x3_mulv( rb->to_world, (v3f){0.0f,1.0f, 0.0f}, rb->up );
83 m3x3_mulv( rb->to_world, (v3f){0.0f,0.0f,-1.0f}, rb->forward );
84 }
85
86 static float sphere_volume( float radius )
87 {
88 float r3 = radius*radius*radius;
89 return (4.0f/3.0f) * VG_PIf * r3;
90 }
91
92 static void rb_init( rigidbody *rb )
93 {
94 float volume = 1.0f;
95
96 if( rb->type == k_rb_shape_box )
97 {
98 v3f dims;
99 v3_sub( rb->bbx[1], rb->bbx[0], dims );
100 volume = dims[0]*dims[1]*dims[2];
101 }
102 else if( rb->type == k_rb_shape_sphere )
103 {
104 volume = sphere_volume( rb->inf.sphere.radius );
105 v3_fill( rb->bbx[0], -rb->inf.sphere.radius );
106 v3_fill( rb->bbx[1], rb->inf.sphere.radius );
107 }
108 else if( rb->type == k_rb_shape_capsule )
109 {
110 float r = rb->inf.capsule.radius,
111 h = rb->inf.capsule.height;
112 volume = sphere_volume( r ) + VG_PIf * r*r * (h - r*2.0f);
113
114 v3_fill( rb->bbx[0], -rb->inf.sphere.radius );
115 v3_fill( rb->bbx[1], rb->inf.sphere.radius );
116 rb->bbx[0][1] = -h;
117 rb->bbx[1][1] = h;
118 }
119
120 rb->inv_mass = 1.0f/(8.0f*volume);
121
122 v3_zero( rb->v );
123 v3_zero( rb->w );
124
125 rb_update_transform( rb );
126 }
127
128 static void rb_iter( rigidbody *rb )
129 {
130 v3f gravity = { 0.0f, -9.6f, 0.0f };
131 v3_muladds( rb->v, gravity, k_rb_delta, rb->v );
132
133 /* intergrate velocity */
134 v3_muladds( rb->co, rb->v, k_rb_delta, rb->co );
135 v3_lerp( rb->w, (v3f){0.0f,0.0f,0.0f}, 0.0025f, rb->w );
136
137 /* inegrate inertia */
138 if( v3_length2( rb->w ) > 0.0f )
139 {
140 v4f rotation;
141 v3f axis;
142 v3_copy( rb->w, axis );
143
144 float mag = v3_length( axis );
145 v3_divs( axis, mag, axis );
146 q_axis_angle( rotation, axis, mag*k_rb_delta );
147 q_mul( rotation, rb->q, rb->q );
148 }
149 }
150
151 static void rb_torque( rigidbody *rb, v3f axis, float mag )
152 {
153 v3_muladds( rb->w, axis, mag*k_rb_delta, rb->w );
154 }
155
156 static void rb_tangent_basis( v3f n, v3f tx, v3f ty )
157 {
158 /* Compute tangent basis (box2d) */
159 if( fabsf( n[0] ) >= 0.57735027f )
160 {
161 tx[0] = n[1];
162 tx[1] = -n[0];
163 tx[2] = 0.0f;
164 }
165 else
166 {
167 tx[0] = 0.0f;
168 tx[1] = n[2];
169 tx[2] = -n[1];
170 }
171
172 v3_normalize( tx );
173 v3_cross( n, tx, ty );
174 }
175
176 static void rb_solver_reset(void);
177 static void rb_build_manifold_terrain( rigidbody *rb );
178 static void rb_build_manifold_terrain_sphere( rigidbody *rb );
179 static void rb_solve_contacts(void);
180
181 static float closest_segment_segment( v3f p1, v3f q1, v3f p2, v3f q2,
182 float *s, float *t, v3f c1, v3f c2)
183 {
184 v3f d1,d2,r;
185 v3_sub( q1, p1, d1 );
186 v3_sub( q2, p2, d2 );
187 v3_sub( p1, p2, r );
188
189 float a = v3_length2( d1 ),
190 e = v3_length2( d2 ),
191 f = v3_dot( d2, r );
192
193 const float kEpsilon = 0.0001f;
194
195 if( a <= kEpsilon && e <= kEpsilon )
196 {
197 *s = 0.0f;
198 *t = 0.0f;
199 v3_copy( p1, c1 );
200 v3_copy( p2, c2 );
201
202 v3f v0;
203 v3_sub( c1, c2, v0 );
204
205 return v3_length2( v0 );
206 }
207
208 if( a<= kEpsilon )
209 {
210 *s = 0.0f;
211 *t = vg_clampf( f / e, 0.0f, 1.0f );
212 }
213 else
214 {
215 float c = v3_dot( d1, r );
216 if( e <= kEpsilon )
217 {
218 *t = 0.0f;
219 *s = vg_clampf( -c / a, 0.0f, 1.0f );
220 }
221 else
222 {
223 float b = v3_dot(d1,d2),
224 d = a*e-b*b;
225
226 if( d != 0.0f )
227 {
228 *s = vg_clampf((b*f - c*e)/d, 0.0f, 1.0f);
229 }
230 else
231 {
232 *s = 0.0f;
233 }
234
235 *t = (b*(*s)+f) / e;
236
237 if( *t < 0.0f )
238 {
239 *t = 0.0f;
240 *s = vg_clampf( -c / a, 0.0f, 1.0f );
241 }
242 else if( *t > 1.0f )
243 {
244 *t = 1.0f;
245 *s = vg_clampf((b-c)/a,0.0f,1.0f);
246 }
247 }
248 }
249
250 v3_muladds( p1, d1, *s, c1 );
251 v3_muladds( p2, d2, *t, c2 );
252
253 v3f v0;
254 v3_sub( c1, c2, v0 );
255 return v3_length2( v0 );
256 }
257
258 static void closest_point_segment( v3f a, v3f b, v3f point, v3f dest )
259 {
260 v3f v0, v1;
261 v3_sub( b, a, v0 );
262 v3_sub( point, a, v1 );
263
264 float t = v3_dot( v1, v0 ) / v3_length2(v0);
265 v3_muladds( a, v0, vg_clampf(t,0.0f,1.0f), dest );
266 }
267
268 /* Real-Time Collision Detection */
269 static void closest_on_triangle( v3f p, v3f tri[3], v3f dest )
270 {
271 v3f ab, ac, ap;
272 float d1, d2;
273
274 /* Region outside A */
275 v3_sub( tri[1], tri[0], ab );
276 v3_sub( tri[2], tri[0], ac );
277 v3_sub( p, tri[0], ap );
278
279 d1 = v3_dot(ab,ap);
280 d2 = v3_dot(ac,ap);
281 if( d1 <= 0.0f && d2 <= 0.0f )
282 {
283 v3_copy( tri[0], dest );
284 v3_copy( (v3f){INFINITY,INFINITY,INFINITY}, dest );
285 return;
286 }
287
288 /* Region outside B */
289 v3f bp;
290 float d3, d4;
291
292 v3_sub( p, tri[1], bp );
293 d3 = v3_dot( ab, bp );
294 d4 = v3_dot( ac, bp );
295
296 if( d3 >= 0.0f && d4 <= d3 )
297 {
298 v3_copy( tri[1], dest );
299 v3_copy( (v3f){INFINITY,INFINITY,INFINITY}, dest );
300 return;
301 }
302
303 /* Edge region of AB */
304 float vc = d1*d4 - d3*d2;
305 if( vc <= 0.0f && d1 >= 0.0f && d3 <= 0.0f )
306 {
307 float v = d1 / (d1-d3);
308 v3_muladds( tri[0], ab, v, dest );
309 v3_copy( (v3f){INFINITY,INFINITY,INFINITY}, dest );
310 return;
311 }
312
313 /* Region outside C */
314 v3f cp;
315 float d5, d6;
316 v3_sub( p, tri[2], cp );
317 d5 = v3_dot(ab, cp);
318 d6 = v3_dot(ac, cp);
319
320 if( d6 >= 0.0f && d5 <= d6 )
321 {
322 v3_copy( tri[2], dest );
323 v3_copy( (v3f){INFINITY,INFINITY,INFINITY}, dest );
324 return;
325 }
326
327 /* Region of AC */
328 float vb = d5*d2 - d1*d6;
329 if( vb <= 0.0f && d2 >= 0.0f && d6 <= 0.0f )
330 {
331 float w = d2 / (d2-d6);
332 v3_muladds( tri[0], ac, w, dest );
333 v3_copy( (v3f){INFINITY,INFINITY,INFINITY}, dest );
334 return;
335 }
336
337 /* Region of BC */
338 float va = d3*d6 - d5*d4;
339 if( va <= 0.0f && (d4-d3) >= 0.0f && (d5-d6) >= 0.0f )
340 {
341 float w = (d4-d3) / ((d4-d3) + (d5-d6));
342 v3f bc;
343 v3_sub( tri[2], tri[1], bc );
344 v3_muladds( tri[1], bc, w, dest );
345 v3_copy( (v3f){INFINITY,INFINITY,INFINITY}, dest );
346 return;
347 }
348
349 /* P inside region, Q via barycentric coordinates uvw */
350 float d = 1.0f/(va+vb+vc),
351 v = vb*d,
352 w = vc*d;
353
354 v3_muladds( tri[0], ab, v, dest );
355 v3_muladds( dest, ac, w, dest );
356 }
357
358 static int sphere_vs_triangle( v3f c, float r, v3f tri[3],
359 v3f co, v3f norm, float *p )
360 {
361 v3f delta;
362 closest_on_triangle( c, tri, co );
363
364 v3_sub( c, co, delta );
365
366
367 float d = v3_length2( delta );
368 if( d < r*r )
369 {
370 v3f ab, ac, tn;
371 v3_sub( tri[1], tri[0], ab );
372 v3_sub( tri[2], tri[0], ac );
373 v3_cross( ac, ab, tn );
374
375 if( v3_dot( delta, tn ) > 0.0f )
376 v3_muls( delta, -1.0f, delta );
377
378 vg_line_pt3( co, 0.05f, 0xff00ff00 );
379
380 d = sqrtf(d);
381 v3_muls( delta, 1.0f/d, norm );
382
383 *p = r-d;
384 return 1;
385 }
386
387 return 0;
388 }
389
390 #include "world.h"
391
392 static void rb_solver_reset(void)
393 {
394 rb_contact_count = 0;
395 }
396
397 static struct contact *rb_start_contact(void)
398 {
399 if( rb_contact_count == vg_list_size(rb_contact_buffer) )
400 {
401 vg_error( "rigidbody: too many contacts generated (%u)\n",
402 rb_contact_count );
403 return NULL;
404 }
405
406 return &rb_contact_buffer[ rb_contact_count ];
407 }
408
409 static void rb_commit_contact( struct contact *ct, float p )
410 {
411 ct->bias = -0.2f*k_rb_rate*vg_minf(0.0f,-p+0.04f);
412 rb_tangent_basis( ct->n, ct->t[0], ct->t[1] );
413
414 ct->norm_impulse = 0.0f;
415 ct->tangent_impulse[0] = 0.0f;
416 ct->tangent_impulse[1] = 0.0f;
417
418 rb_contact_count ++;
419 }
420
421 static void rb_build_manifold_terrain_sphere( rigidbody *rb )
422 {
423 u32 geo[256];
424 v3f tri[3];
425 int len = bh_select( &world.geo.bhtris, rb->bbx_world, geo, 256 );
426
427 for( int i=0; i<len; i++ )
428 {
429 u32 *ptri = &world.geo.indices[ geo[i]*3 ];
430
431 for( int j=0; j<3; j++ )
432 v3_copy( world.geo.verts[ptri[j]].co, tri[j] );
433
434 vg_line(tri[0],tri[1],0xff00ff00 );
435 vg_line(tri[1],tri[2],0xff00ff00 );
436 vg_line(tri[2],tri[0],0xff00ff00 );
437
438 v3f co, norm;
439 float p;
440
441 for( int j=0; j<2; j++ )
442 {
443 if( sphere_vs_triangle( rb->co, rb->inf.sphere.radius, tri,co,norm,&p))
444 {
445 struct contact *ct = rb_start_contact();
446
447 if( !ct )
448 return;
449
450 v3f p1;
451 v3_muladds( rb->co, norm, p, p1 );
452 vg_line( rb->co, p1, 0xffffffff );
453
454 ct->rba = rb;
455 v3_copy( co, ct->co );
456 v3_copy( norm, ct->n );
457
458 v3_sub( co, rb->co, ct->delta );
459 rb_commit_contact( ct, p );
460 }
461 }
462 }
463
464 }
465
466 RB_DEPR
467 static void rb_build_manifold_terrain( rigidbody *rb )
468 {
469 v3f *box = rb->bbx;
470 v3f pts[8];
471 float *p000 = pts[0], *p001 = pts[1], *p010 = pts[2], *p011 = pts[3],
472 *p100 = pts[4], *p101 = pts[5], *p110 = pts[6], *p111 = pts[7];
473
474 p000[0]=box[0][0];p000[1]=box[0][1];p000[2]=box[0][2];
475 p001[0]=box[0][0];p001[1]=box[0][1];p001[2]=box[1][2];
476 p010[0]=box[0][0];p010[1]=box[1][1];p010[2]=box[0][2];
477 p011[0]=box[0][0];p011[1]=box[1][1];p011[2]=box[1][2];
478
479 p100[0]=box[1][0];p100[1]=box[0][1];p100[2]=box[0][2];
480 p101[0]=box[1][0];p101[1]=box[0][1];p101[2]=box[1][2];
481 p110[0]=box[1][0];p110[1]=box[1][1];p110[2]=box[0][2];
482 p111[0]=box[1][0];p111[1]=box[1][1];p111[2]=box[1][2];
483
484 m4x3_mulv( rb->to_world, p000, p000 );
485 m4x3_mulv( rb->to_world, p001, p001 );
486 m4x3_mulv( rb->to_world, p010, p010 );
487 m4x3_mulv( rb->to_world, p011, p011 );
488 m4x3_mulv( rb->to_world, p100, p100 );
489 m4x3_mulv( rb->to_world, p101, p101 );
490 m4x3_mulv( rb->to_world, p110, p110 );
491 m4x3_mulv( rb->to_world, p111, p111 );
492
493 int count = 0;
494
495 for( int i=0; i<8; i++ )
496 {
497 float *point = pts[i];
498 struct contact *ct = rb_start_contact();
499
500 if( !ct )
501 return;
502
503 ct->rba = rb;
504
505 v3f surface;
506 v3_copy( point, surface );
507 surface[1] += 4.0f;
508
509 ray_hit hit;
510 hit.dist = INFINITY;
511 if( !ray_world( surface, (v3f){0.0f,-1.0f,0.0f}, &hit ))
512 continue;
513
514 v3_copy( hit.pos, surface );
515
516 float p = vg_minf( surface[1] - point[1], 1.0f );
517
518 if( p > 0.0f )
519 {
520 v3_copy( hit.normal, ct->n );
521 v3_add( point, surface, ct->co );
522 v3_muls( ct->co, 0.5f, ct->co );
523 v3_sub( ct->co, rb->co, ct->delta );
524
525 rb_commit_contact( ct, p );
526 count ++;
527 if( count == 4 )
528 break;
529 }
530 }
531 }
532
533 static void rb_solve_contacts(void)
534 {
535 float k_friction = 0.1f;
536
537 /* Friction Impulse */
538 for( int i=0; i<rb_contact_count; i++ )
539 {
540 struct contact *ct = &rb_contact_buffer[i];
541 rigidbody *rb = ct->rba;
542
543 v3f dv;
544 v3_cross( rb->w, ct->delta, dv );
545 v3_add( rb->v, dv, dv );
546
547 for( int j=0; j<2; j++ )
548 {
549 float vt = vg_clampf( -v3_dot( dv, ct->t[j] ),
550 -k_friction, k_friction );
551
552 vt = -v3_dot( dv, ct->t[j] );
553
554 float temp = ct->tangent_impulse[j];
555 ct->tangent_impulse[j] = vg_clampf( temp+vt, -k_friction, k_friction );
556 vt = ct->tangent_impulse[j] - temp;
557
558 v3f impulse;
559
560 v3_muls( ct->t[j], vt, impulse );
561 v3_add( impulse, rb->v, rb->v );
562 v3_cross( ct->delta, impulse, impulse );
563 v3_add( impulse, rb->w, rb->w );
564 }
565 }
566
567 /* Normal Impulse */
568 for( int i=0; i<rb_contact_count; i++ )
569 {
570 struct contact *ct = &rb_contact_buffer[i];
571 rigidbody *rb = ct->rba;
572
573 v3f dv;
574 v3_cross( rb->w, ct->delta, dv );
575 v3_add( rb->v, dv, dv );
576
577 float vn = -v3_dot( dv, ct->n );
578 vn += ct->bias;
579
580 float temp = ct->norm_impulse;
581 ct->norm_impulse = vg_maxf( temp + vn, 0.0f );
582 vn = ct->norm_impulse - temp;
583
584 v3f impulse;
585
586 v3_muls( ct->n, vn, impulse );
587 v3_add( impulse, rb->v, rb->v );
588 v3_cross( ct->delta, impulse, impulse );
589 v3_add( impulse, rb->w, rb->w );
590 }
591 }
592
593 struct rb_angle_limit
594 {
595 rigidbody *rba, *rbb;
596 v3f axis;
597 float impulse, bias;
598 };
599
600 static int rb_angle_limit_force( rigidbody *rba, v3f va,
601 rigidbody *rbb, v3f vb,
602 float max )
603 {
604 v3f wva, wvb;
605 m3x3_mulv( rba->to_world, va, wva );
606 m3x3_mulv( rbb->to_world, vb, wvb );
607
608 float dt = v3_dot(wva,wvb)*0.999f,
609 ang = fabsf(dt);
610 ang = acosf( dt );
611 if( ang > max )
612 {
613 float correction = max-ang;
614
615 v3f axis;
616 v3_cross( wva, wvb, axis );
617
618 v4f rotation;
619 q_axis_angle( rotation, axis, -correction*0.25f );
620 q_mul( rotation, rba->q, rba->q );
621
622 q_axis_angle( rotation, axis, correction*0.25f );
623 q_mul( rotation, rbb->q, rbb->q );
624
625 return 1;
626 }
627
628 return 0;
629 }
630
631 static void rb_constraint_angle_limit( struct rb_angle_limit *limit )
632 {
633
634 }
635
636 RB_DEPR
637 static void rb_constraint_angle( rigidbody *rba, v3f va,
638 rigidbody *rbb, v3f vb,
639 float max, float spring )
640 {
641 v3f wva, wvb;
642 m3x3_mulv( rba->to_world, va, wva );
643 m3x3_mulv( rbb->to_world, vb, wvb );
644
645 float dt = v3_dot(wva,wvb)*0.999f,
646 ang = fabsf(dt);
647
648 v3f axis;
649 v3_cross( wva, wvb, axis );
650 v3_muladds( rba->w, axis, ang*spring*0.5f, rba->w );
651 v3_muladds( rbb->w, axis, -ang*spring*0.5f, rbb->w );
652
653 return;
654
655 /* TODO: convert max into the dot product value so we dont have to always
656 * evaluate acosf, only if its greater than the angle specified */
657 ang = acosf( dt );
658 if( ang > max )
659 {
660 float correction = max-ang;
661
662 v4f rotation;
663 q_axis_angle( rotation, axis, -correction*0.125f );
664 q_mul( rotation, rba->q, rba->q );
665
666 q_axis_angle( rotation, axis, correction*0.125f );
667 q_mul( rotation, rbb->q, rbb->q );
668 }
669 }
670
671 static void rb_relative_velocity( rigidbody *ra, v3f lca,
672 rigidbody *rb, v3f lcb, v3f rcv )
673 {
674 v3f wca, wcb;
675 m3x3_mulv( ra->to_world, lca, wca );
676 m3x3_mulv( rb->to_world, lcb, wcb );
677
678 v3_sub( ra->v, rb->v, rcv );
679
680 v3f rcv_Ra, rcv_Rb;
681 v3_cross( ra->w, wca, rcv_Ra );
682 v3_cross( rb->w, wcb, rcv_Rb );
683 v3_add( rcv_Ra, rcv, rcv );
684 v3_sub( rcv, rcv_Rb, rcv );
685 }
686
687 static void rb_constraint_position( rigidbody *ra, v3f lca,
688 rigidbody *rb, v3f lcb )
689 {
690 /* C = (COa + Ra*LCa) - (COb + Rb*LCb) = 0 */
691 v3f wca, wcb;
692 m3x3_mulv( ra->to_world, lca, wca );
693 m3x3_mulv( rb->to_world, lcb, wcb );
694
695 v3f delta;
696 v3_add( wcb, rb->co, delta );
697 v3_sub( delta, wca, delta );
698 v3_sub( delta, ra->co, delta );
699
700 v3_muladds( ra->co, delta, 0.5f, ra->co );
701 v3_muladds( rb->co, delta, -0.5f, rb->co );
702
703 v3f rcv;
704 v3_sub( ra->v, rb->v, rcv );
705
706 v3f rcv_Ra, rcv_Rb;
707 v3_cross( ra->w, wca, rcv_Ra );
708 v3_cross( rb->w, wcb, rcv_Rb );
709 v3_add( rcv_Ra, rcv, rcv );
710 v3_sub( rcv, rcv_Rb, rcv );
711
712 float nm = 0.5f/(rb->inv_mass + ra->inv_mass);
713
714 float mass_a = 1.0f/ra->inv_mass,
715 mass_b = 1.0f/rb->inv_mass,
716 total_mass = mass_a+mass_b;
717
718 v3f impulse;
719 v3_muls( rcv, 1.0f, impulse );
720 v3_muladds( rb->v, impulse, mass_b/total_mass, rb->v );
721 v3_cross( wcb, impulse, impulse );
722 v3_add( impulse, rb->w, rb->w );
723
724 v3_muls( rcv, -1.0f, impulse );
725 v3_muladds( ra->v, impulse, mass_a/total_mass, ra->v );
726 v3_cross( wca, impulse, impulse );
727 v3_add( impulse, ra->w, ra->w );
728
729 #if 0
730 /*
731 * this could be used for spring joints
732 * its not good for position constraint
733 */
734 v3f impulse;
735 v3_muls( delta, 0.5f*spring, impulse );
736
737 v3_add( impulse, ra->v, ra->v );
738 v3_cross( wca, impulse, impulse );
739 v3_add( impulse, ra->w, ra->w );
740
741 v3_muls( delta, -0.5f*spring, impulse );
742
743 v3_add( impulse, rb->v, rb->v );
744 v3_cross( wcb, impulse, impulse );
745 v3_add( impulse, rb->w, rb->w );
746 #endif
747 }
748
749 static void debug_sphere( m4x3f m, float radius, u32 colour )
750 {
751 v3f ly = { 0.0f, 0.0f, radius },
752 lx = { 0.0f, radius, 0.0f },
753 lz = { 0.0f, 0.0f, radius };
754
755 for( int i=0; i<16; i++ )
756 {
757 float t = ((float)(i+1) * (1.0f/16.0f)) * VG_PIf * 2.0f,
758 s = sinf(t),
759 c = cosf(t);
760
761 v3f py = { s*radius, 0.0f, c*radius },
762 px = { s*radius, c*radius, 0.0f },
763 pz = { 0.0f, s*radius, c*radius };
764
765 v3f p0, p1, p2, p3, p4, p5;
766 m4x3_mulv( m, py, p0 );
767 m4x3_mulv( m, ly, p1 );
768 m4x3_mulv( m, px, p2 );
769 m4x3_mulv( m, lx, p3 );
770 m4x3_mulv( m, pz, p4 );
771 m4x3_mulv( m, lz, p5 );
772
773 vg_line( p0, p1, colour == 0x00? 0xff00ff00: colour );
774 vg_line( p2, p3, colour == 0x00? 0xff0000ff: colour );
775 vg_line( p4, p5, colour == 0x00? 0xffff0000: colour );
776
777 v3_copy( py, ly );
778 v3_copy( px, lx );
779 v3_copy( pz, lz );
780 }
781 }
782
783 static void rb_debug( rigidbody *rb, u32 colour )
784 {
785 if( rb->type == k_rb_shape_box )
786 {
787 v3f *box = rb->bbx;
788 vg_line_boxf_transformed( rb->to_world, rb->bbx, colour );
789 }
790 else if( rb->type == k_rb_shape_sphere )
791 {
792 debug_sphere( rb->to_world, rb->inf.sphere.radius, colour );
793 }
794 }
795
796 /*
797 * out penetration distance, normal
798 */
799 static int rb_point_in_body( rigidbody *rb, v3f pos, float *pen, v3f normal )
800 {
801 v3f local;
802 m4x3_mulv( rb->to_local, pos, local );
803
804 if( local[0] > rb->bbx[0][0] && local[0] < rb->bbx[1][0] &&
805 local[1] > rb->bbx[0][1] && local[1] < rb->bbx[1][1] &&
806 local[2] > rb->bbx[0][2] && local[2] < rb->bbx[1][2] )
807 {
808 v3f area, com, comrel;
809 v3_add( rb->bbx[0], rb->bbx[1], com );
810 v3_muls( com, 0.5f, com );
811
812 v3_sub( rb->bbx[1], rb->bbx[0], area );
813 v3_sub( local, com, comrel );
814 v3_div( comrel, area, comrel );
815
816 int axis = 0;
817 float max_mag = fabsf(comrel[0]);
818
819 if( fabsf(comrel[1]) > max_mag )
820 {
821 axis = 1;
822 max_mag = fabsf(comrel[1]);
823 }
824 if( fabsf(comrel[2]) > max_mag )
825 {
826 axis = 2;
827 max_mag = fabsf(comrel[2]);
828 }
829
830 v3_zero( normal );
831 normal[axis] = vg_signf(comrel[axis]);
832
833 if( normal[axis] < 0.0f )
834 *pen = local[axis] - rb->bbx[0][axis];
835 else
836 *pen = rb->bbx[1][axis] - local[axis];
837
838 m3x3_mulv( rb->to_world, normal, normal );
839 return 1;
840 }
841
842 return 0;
843 }
844
845 #if 0
846 static void rb_build_manifold_rb_static( rigidbody *ra, rigidbody *rb_static )
847 {
848 v3f verts[8];
849
850 v3f a, b;
851 v3_copy( ra->bbx[0], a );
852 v3_copy( ra->bbx[1], b );
853
854 m4x3_mulv( ra->to_world, (v3f){ a[0], a[1], a[2] }, verts[0] );
855 m4x3_mulv( ra->to_world, (v3f){ a[0], b[1], a[2] }, verts[1] );
856 m4x3_mulv( ra->to_world, (v3f){ b[0], b[1], a[2] }, verts[2] );
857 m4x3_mulv( ra->to_world, (v3f){ b[0], a[1], a[2] }, verts[3] );
858 m4x3_mulv( ra->to_world, (v3f){ a[0], a[1], b[2] }, verts[4] );
859 m4x3_mulv( ra->to_world, (v3f){ a[0], b[1], b[2] }, verts[5] );
860 m4x3_mulv( ra->to_world, (v3f){ b[0], b[1], b[2] }, verts[6] );
861 m4x3_mulv( ra->to_world, (v3f){ b[0], a[1], b[2] }, verts[7] );
862
863 vg_line_boxf_transformed( rb_static->to_world, rb_static->bbx, 0xff0000ff );
864
865 int count = 0;
866
867 for( int i=0; i<8; i++ )
868 {
869 if( ra->manifold_count == vg_list_size(ra->manifold) )
870 return;
871
872 struct contact *ct = &ra->manifold[ ra->manifold_count ];
873
874 float p;
875 v3f normal;
876
877 if( rb_point_in_body( rb_static, verts[i], &p, normal ))
878 {
879 v3_copy( normal, ct->n );
880 v3_muladds( verts[i], ct->n, p*0.5f, ct->co );
881 v3_sub( ct->co, ra->co, ct->delta );
882
883 vg_line_pt3( ct->co, 0.0125f, 0xffff00ff );
884
885 ct->bias = -0.2f * (1.0f/k_rb_delta) * vg_minf( 0.0f, -p+0.04f );
886 rb_tangent_basis( ct->n, ct->t[0], ct->t[1] );
887
888 ct->norm_impulse = 0.0f;
889 ct->tangent_impulse[0] = 0.0f;
890 ct->tangent_impulse[1] = 0.0f;
891
892 ra->manifold_count ++;
893 count ++;
894 if( count == 4 )
895 return;
896 }
897 }
898 }
899 #endif
900
901 /*
902 * Capsule phyics
903 */
904
905 static void debug_capsule( m4x3f m, float height, float radius, u32 colour )
906 {
907 v3f last = { 0.0f, 0.0f, radius };
908 m4x3f lower, upper;
909 m3x3_copy( m, lower );
910 m3x3_copy( m, upper );
911 m4x3_mulv( m, (v3f){0.0f,-height*0.5f+radius,0.0f}, lower[3] );
912 m4x3_mulv( m, (v3f){0.0f, height*0.5f-radius,0.0f}, upper[3] );
913
914 for( int i=0; i<16; i++ )
915 {
916 float t = ((float)(i+1) * (1.0f/16.0f)) * VG_PIf * 2.0f,
917 s = sinf(t),
918 c = cosf(t);
919
920 v3f p = { s*radius, 0.0f, c*radius };
921
922 v3f p0, p1;
923 m4x3_mulv( lower, p, p0 );
924 m4x3_mulv( lower, last, p1 );
925 vg_line( p0, p1, colour );
926
927 m4x3_mulv( upper, p, p0 );
928 m4x3_mulv( upper, last, p1 );
929 vg_line( p0, p1, colour );
930
931 v3_copy( p, last );
932 }
933
934 for( int i=0; i<4; i++ )
935 {
936 float t = ((float)(i) * (1.0f/4.0f)) * VG_PIf * 2.0f,
937 s = sinf(t),
938 c = cosf(t);
939
940 v3f p = { s*radius, 0.0f, c*radius };
941
942 v3f p0, p1;
943 m4x3_mulv( lower, p, p0 );
944 m4x3_mulv( upper, p, p1 );
945 vg_line( p0, p1, colour );
946
947 m4x3_mulv( lower, (v3f){0.0f,-radius,0.0f}, p0 );
948 m4x3_mulv( upper, (v3f){0.0f, radius,0.0f}, p1 );
949 vg_line( p0, p1, colour );
950 }
951 }
952
953 /*
954 * BVH implementation, this is ONLY for static rigidbodies, its to slow for
955 * realtime use.
956 */
957
958 static void rb_bh_expand_bound( void *user, boxf bound, u32 item_index )
959 {
960 rigidbody *rb = &((rigidbody *)user)[ item_index ];
961 box_concat( bound, rb->bbx_world );
962 }
963
964 static float rb_bh_centroid( void *user, u32 item_index, int axis )
965 {
966 rigidbody *rb = &((rigidbody *)user)[ item_index ];
967 return (rb->bbx_world[axis][0] + rb->bbx_world[1][axis]) * 0.5f;
968 }
969
970 static void rb_bh_swap( void *user, u32 ia, u32 ib )
971 {
972 rigidbody temp, *rba, *rbb;
973 rba = &((rigidbody *)user)[ ia ];
974 rbb = &((rigidbody *)user)[ ib ];
975
976 temp = *rba;
977 *rba = *rbb;
978 *rbb = temp;
979 }
980
981 static void rb_bh_debug( void *user, u32 item_index )
982 {
983 rigidbody *rb = &((rigidbody *)user)[ item_index ];
984 rb_debug( rb, 0xff00ffff );
985 }
986
987 static bh_system bh_system_rigidbodies =
988 {
989 .expand_bound = rb_bh_expand_bound,
990 .item_centroid = rb_bh_centroid,
991 .item_swap = rb_bh_swap,
992 .item_debug = rb_bh_debug,
993 .cast_ray = NULL
994 };
995
996 #endif /* RIGIDBODY_H */