Richard Boegli's CnC_Generals_Zero_Hour Fork WIP
This is documentation of Richard Boegil's Zero Hour Fork
 
Loading...
Searching...
No Matches
colmathobbobb.cpp
Go to the documentation of this file.
1/*
2** Command & Conquer Generals Zero Hour(tm)
3** Copyright 2025 Electronic Arts Inc.
4**
5** This program is free software: you can redistribute it and/or modify
6** it under the terms of the GNU General Public License as published by
7** the Free Software Foundation, either version 3 of the License, or
8** (at your option) any later version.
9**
10** This program is distributed in the hope that it will be useful,
11** but WITHOUT ANY WARRANTY; without even the implied warranty of
12** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13** GNU General Public License for more details.
14**
15** You should have received a copy of the GNU General Public License
16** along with this program. If not, see <http://www.gnu.org/licenses/>.
17*/
18
19/***********************************************************************************************
20 *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
21 ***********************************************************************************************
22 * *
23 * Project Name : WWMath *
24 * *
25 * $Archive:: /Commando/Code/wwmath/colmathobbobb.cpp $*
26 * *
27 * Author:: Greg Hjelstrom *
28 * *
29 * $Modtime:: 1/04/02 6:29p $*
30 * *
31 * $Revision:: 15 $*
32 * *
33 *---------------------------------------------------------------------------------------------*
34 * Functions: *
35 * obb_intersect_box0_basis -- intersection test for a basis vector from box0 *
36 * obb_intersect_box1_basis -- intersection test for a basis vector from box1 *
37 * obb_intersect_axis -- intersection test for a axis *
38 * intersect_obb_obb -- test two OBBoxes for intersection *
39 * CollisionMath::Intersection_Test -- test two obb's for intersection *
40 * CollisionMath::Intersection_Test -- test an OBB for intersection with an AAB *
41 * CollisionMath::Intersection_Test -- Test an AAB for intersection with an OBB *
42 * obb_separation_test -- test the projections of two obb's for separation *
43 * obb_check_box0_basis -- projects the boxes onto a basis vector from box0 *
44 * obb_check_box1_basis -- projects the two obbs onto a basis vector from box1 *
45 * obb_check_axis -- projects the obbs onto an arbitrary axis *
46 * obb_compute_projections -- computes projections of two boxes onto an arbitrary axis *
47 * compute_contact_normal -- computes the contact normal (after contact is detected) *
48 * eval_side -- returns -1,0,1 depending on ab and side *
49 * compute_contact_point -- computes the contact point (after contact is detected) *
50 * collide_obb_obb -- test two obb's for collision *
51 * CollisionMath::Collide -- collide two OBB's *
52 * CollisionMath::Collide -- collide an OBB with an AAB *
53 * CollisionMath::Collide -- collide an AAB with an OBB *
54 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
55
56#include "colmath.h"
57#include "obbox.h"
58#include "aabox.h"
59#include "wwdebug.h"
60
61
62/*
63** Separating Axes have to be rejected if their length is smaller than some epsilon.
64** Otherwise, erroneous results can be reported.
65*/
66#define AXISLEN_EPSILON2 WWMATH_EPSILON * WWMATH_EPSILON // squared length of a separating axis must be larger than this
67
68
69enum
70{
71 /* Axes used in Box-Box intersection tests */
88};
89
90
91
92/********************************************************************************
93
94 OBBox-OBBox intersection detection
95
96 As with most of the collision detection functions, this code is based on the theorem
97 that given any two non-intersecting convex polyhedra, a separating plane/axis
98 can be found that will be defined by one of the face normals of one of the polyhedra
99 or the cross product of an edge from each polyhedra.
100
101 In the case of two oriented 3D boxes, 15 separating axes must be tested.
102 Each of the basis vectors from box A, each of the basis vectors from box B, and
103 the cross products of any combination of a basis vector from A and a basis vector
104 from B. Some of these separating axis tests can be optimized. For example, if
105 the axis being tested is a basis vector from the first box, then that box's
106 extent does not need to be projected onto the axis...
107
108 The first batch of functions in this module implement a intersection test.
109 A boolean is returned indicating whether the two boxes intersect each other
110 in any way.
111
112 The OBB-ABB and ABB-OBB functions are also implemented in a way that re-uses
113 the OBB-OBB code.
114
115********************************************************************************/
116
117
124{
125 ObbIntersectionStruct(const OBBoxClass &box0,const OBBoxClass & box1) :
126 Box0(box0),
127 Box1(box1)
128 {
129 Vector3::Subtract(box1.Center,box0.Center,&C); // vector from center of box0 to center of box1
130
131 A[0].Set(box0.Basis[0][0],box0.Basis[1][0],box0.Basis[2][0]);
132 A[1].Set(box0.Basis[0][1],box0.Basis[1][1],box0.Basis[2][1]);
133 A[2].Set(box0.Basis[0][2],box0.Basis[1][2],box0.Basis[2][2]);
134
135 B[0].Set(box1.Basis[0][0],box1.Basis[1][0],box1.Basis[2][0]);
136 B[1].Set(box1.Basis[0][1],box1.Basis[1][1],box1.Basis[2][1]);
137 B[2].Set(box1.Basis[0][2],box1.Basis[1][2],box1.Basis[2][2]);
138 }
139
140 Vector3 C; // Vector from the center0 to center1
141 Vector3 A[3]; // basis vectors for box0
142 Vector3 B[3]; // basis vectors for box1
143 float AB[3][3]; // dot products of the basis vectors
144
147
148private:
149 //not implemented
151 ObbIntersectionStruct & operator = (const ObbIntersectionStruct&);
152};
153
154
155
156/***********************************************************************************************
157 * obb_intersect_box0_basis -- intersection test for a basis vector from box0 *
158 * *
159 * The optimization here is that the projection of the first box is known since the axis is *
160 * one of its basis vectors. *
161 * *
162 * INPUT: *
163 * *
164 * OUTPUT: *
165 * *
166 * WARNINGS: *
167 * *
168 * HISTORY: *
169 * 5/4/99 GTH : Created. *
170 *=============================================================================================*/
171static bool obb_intersect_box0_basis
172(
173 ObbIntersectionStruct & context,
174 int axis_index
175)
176{
177 // ra = box0 projection onto the axis
178 // rb = box1 projection onto the axis
179 float ra = context.Box0.Extent[axis_index];
180 float rb = WWMath::Fabs(context.Box1.Extent[0]*context.AB[axis_index][0]) +
181 WWMath::Fabs(context.Box1.Extent[1]*context.AB[axis_index][1]) +
182 WWMath::Fabs(context.Box1.Extent[2]*context.AB[axis_index][2]);
183 float rsum = ra+rb;
184
185 // u = projected distance between the box centers
186 float u = Vector3::Dot_Product(context.C,context.A[axis_index]);
187
188 // (gth) the epsilon here was not scaled to the length of the axis so it
189 // caused problems when the axis being tested became very small
190 return ((u /*+ WWMATH_EPSILON*/ > rsum) || (u /*- WWMATH_EPSILON*/ < -rsum));
191}
192
193
194/***********************************************************************************************
195 * obb_intersect_box1_basis -- intersection test for a basis vector from box1 *
196 * *
197 * The "optimization" here is that the extent for the second box is known since the axis is *
198 * one of its basis vectors. *
199 * *
200 * INPUT: *
201 * *
202 * OUTPUT: *
203 * *
204 * WARNINGS: *
205 * *
206 * HISTORY: *
207 * 5/4/99 GTH : Created. *
208 *=============================================================================================*/
209static bool obb_intersect_box1_basis
210(
211 ObbIntersectionStruct & context,
212 int axis_index
213)
214{
215 // ra = box0 projection onto the axis
216 // rb = box1 projection onto the axis
217 float ra = WWMath::Fabs(context.Box0.Extent[0]*context.AB[0][axis_index]) +
218 WWMath::Fabs(context.Box0.Extent[1]*context.AB[1][axis_index]) +
219 WWMath::Fabs(context.Box0.Extent[2]*context.AB[2][axis_index]);
220 float rb = context.Box1.Extent[axis_index];
221 float rsum = ra+rb;
222
223 // u = projected distance between the box centers
224 float u = Vector3::Dot_Product(context.C,context.B[axis_index]);
225
226 // (gth) the epsilon here was not scaled to the length of the axis so it
227 // caused problems when the axis being tested became very small
228 return ((u /*+ WWMATH_EPSILON*/ > rsum) || (u /*- WWMATH_EPSILON*/ < -rsum));
229}
230
231
232/***********************************************************************************************
233 * obb_intersect_axis -- intersection test for a axis *
234 * *
235 * Checks intersection on an arbitrary axis where you've already computed the projectsions. *
236 * Many of the later tests in the OBB-OBB algorigthm fall into here since there are *
237 * optimizations in computing the projections but they are all specific to the axis being used *
238 * *
239 * INPUT: *
240 * *
241 * OUTPUT: *
242 * *
243 * WARNINGS: *
244 * *
245 * HISTORY: *
246 * 5/4/99 GTH : Created. *
247 *=============================================================================================*/
248static inline bool obb_intersect_axis
249(
250 ObbIntersectionStruct & context,
251 const Vector3 & axis,
252 float ra,
253 float rb
254)
255{
256 float rsum = ra+rb;
257 float u = Vector3::Dot_Product(context.C,axis);
258
259 // (gth) the epsilon here was not scaled to the length of the axis so it
260 // caused problems when the axis being tested became very small
261 return ((u /*+ WWMATH_EPSILON*/ > rsum) || (u /*- WWMATH_EPSILON*/ < -rsum));
262}
263
264
265/***********************************************************************************************
266 * intersect_obb_obb -- test two OBBoxes for intersection *
267 * *
268 * This function works in a very similar (but simplified) way as the Collide function. See *
269 * the comments in that function for more clues regarding the math involved... *
270 * *
271 * Due to the re-usage of intermediate calculations, this function is ~2x faster than the *
272 * equivalent Oriented_Boxes_Intersect. *
273 * *
274 * INPUT: *
275 * *
276 * OUTPUT: *
277 * *
278 * WARNINGS: *
279 * *
280 * HISTORY: *
281 * 5/4/99 GTH : Created. *
282 *=============================================================================================*/
284(
285 ObbIntersectionStruct & context
286)
287{
288 Vector3 axis;
289 float ra,rb;
290
292 // Axis = A0
294 context.AB[0][0] = Vector3::Dot_Product(context.A[0],context.B[0]);
295 context.AB[0][1] = Vector3::Dot_Product(context.A[0],context.B[1]);
296 context.AB[0][2] = Vector3::Dot_Product(context.A[0],context.B[2]);
297 if (context.Box0.Extent[0] > 0.0f) {
298 if (obb_intersect_box0_basis(context,0)) return false;
299 }
300
302 // Axsis A1
304 context.AB[1][0] = Vector3::Dot_Product(context.A[1],context.B[0]);
305 context.AB[1][1] = Vector3::Dot_Product(context.A[1],context.B[1]);
306 context.AB[1][2] = Vector3::Dot_Product(context.A[1],context.B[2]);
307 if (context.Box0.Extent[1] > 0.0f) {
308 if (obb_intersect_box0_basis(context,1)) return false;
309 }
310
311
313 // Axis = A2
315 context.AB[2][0] = Vector3::Dot_Product(context.A[2],context.B[0]);
316 context.AB[2][1] = Vector3::Dot_Product(context.A[2],context.B[1]);
317 context.AB[2][2] = Vector3::Dot_Product(context.A[2],context.B[2]);
318 if (context.Box0.Extent[2] > 0.0f) {
319 if (obb_intersect_box0_basis(context,2)) return false;
320 }
321
322
324 // Axis B0,B1,B2
326 if (context.Box1.Extent[0] > 0.0f) {
327 if (obb_intersect_box1_basis(context,0)) return false;
328 }
329
330 if (context.Box1.Extent[1] > 0.0f) {
331 if (obb_intersect_box1_basis(context,1)) return false;
332 }
333
334 if (context.Box1.Extent[2] > 0.0f) {
335 if (obb_intersect_box1_basis(context,2)) return false;
336 }
337
339 // Axis = A0xB0
341 Vector3::Cross_Product(context.A[0],context.B[0],&axis);
342 if (axis.Length2() > AXISLEN_EPSILON2) {
343 ra = WWMath::Fabs(context.Box0.Extent[1]*context.AB[2][0])+WWMath::Fabs(context.Box0.Extent[2]*context.AB[1][0]);
344 rb = WWMath::Fabs(context.Box1.Extent[1]*context.AB[0][2])+WWMath::Fabs(context.Box1.Extent[2]*context.AB[0][1]);
345 if (obb_intersect_axis(context,axis,ra,rb)) return false;
346 }
347
349 // Axis = A0xB1
351 Vector3::Cross_Product(context.A[0],context.B[1],&axis);
352 if (axis.Length2() > AXISLEN_EPSILON2) {
353 ra = WWMath::Fabs(context.Box0.Extent[1]*context.AB[2][1])+WWMath::Fabs(context.Box0.Extent[2]*context.AB[1][1]);
354 rb = WWMath::Fabs(context.Box1.Extent[0]*context.AB[0][2])+WWMath::Fabs(context.Box1.Extent[2]*context.AB[0][0]);
355 if (obb_intersect_axis(context,axis,ra,rb)) return false;
356 }
357
359 // Axis = A0xB2
361 Vector3::Cross_Product(context.A[0],context.B[2],&axis);
362 if (axis.Length2() > AXISLEN_EPSILON2) {
363 ra = WWMath::Fabs(context.Box0.Extent[1]*context.AB[2][2])+WWMath::Fabs(context.Box0.Extent[2]*context.AB[1][2]);
364 rb = WWMath::Fabs(context.Box1.Extent[0]*context.AB[0][1])+WWMath::Fabs(context.Box1.Extent[1]*context.AB[0][0]);
365 if (obb_intersect_axis(context,axis,ra,rb)) return false;
366 }
367
369 // Axis = A1xB0
371 Vector3::Cross_Product(context.A[1],context.B[0],&axis);
372 if (axis.Length2() > AXISLEN_EPSILON2) {
373 ra = WWMath::Fabs(context.Box0.Extent[0]*context.AB[2][0])+WWMath::Fabs(context.Box0.Extent[2]*context.AB[0][0]);
374 rb = WWMath::Fabs(context.Box1.Extent[1]*context.AB[1][2])+WWMath::Fabs(context.Box1.Extent[2]*context.AB[1][1]);
375 if (obb_intersect_axis(context,axis,ra,rb)) return false;
376 }
377
379 // Axis = A1xB1
381 Vector3::Cross_Product(context.A[1],context.B[1],&axis);
382 if (axis.Length2() > AXISLEN_EPSILON2) {
383 ra = WWMath::Fabs(context.Box0.Extent[0]*context.AB[2][1])+WWMath::Fabs(context.Box0.Extent[2]*context.AB[0][1]);
384 rb = WWMath::Fabs(context.Box1.Extent[0]*context.AB[1][2])+WWMath::Fabs(context.Box1.Extent[2]*context.AB[1][0]);
385 if (obb_intersect_axis(context,axis,ra,rb)) return false;
386 }
387
389 // Axis = A1xB2
391 Vector3::Cross_Product(context.A[1],context.B[2],&axis);
392 if (axis.Length2() > AXISLEN_EPSILON2) {
393 ra = WWMath::Fabs(context.Box0.Extent[0]*context.AB[2][2])+WWMath::Fabs(context.Box0.Extent[2]*context.AB[0][2]);
394 rb = WWMath::Fabs(context.Box1.Extent[0]*context.AB[1][1])+WWMath::Fabs(context.Box1.Extent[1]*context.AB[1][0]);
395 if (obb_intersect_axis(context,axis,ra,rb)) return false;
396 }
397
399 // Axis = A2xB0
401 Vector3::Cross_Product(context.A[2],context.B[0],&axis);
402 if (axis.Length2() > AXISLEN_EPSILON2) {
403 ra = WWMath::Fabs(context.Box0.Extent[0]*context.AB[1][0])+WWMath::Fabs(context.Box0.Extent[1]*context.AB[0][0]);
404 rb = WWMath::Fabs(context.Box1.Extent[1]*context.AB[2][2])+WWMath::Fabs(context.Box1.Extent[2]*context.AB[2][1]);
405 if (obb_intersect_axis(context,axis,ra,rb)) return false;
406 }
407
409 // Axis = A2xB1
411 Vector3::Cross_Product(context.A[2],context.B[1],&axis);
412 if (axis.Length2() > AXISLEN_EPSILON2) {
413 ra = WWMath::Fabs(context.Box0.Extent[0]*context.AB[1][1])+WWMath::Fabs(context.Box0.Extent[1]*context.AB[0][1]);
414 rb = WWMath::Fabs(context.Box1.Extent[0]*context.AB[2][2])+WWMath::Fabs(context.Box1.Extent[2]*context.AB[2][0]);
415 if (obb_intersect_axis(context,axis,ra,rb)) return false;
416 }
417
419 // Axis = A2xB2
421 Vector3::Cross_Product(context.A[2],context.B[2],&axis);
422 if (axis.Length2() > AXISLEN_EPSILON2) {
423 ra = WWMath::Fabs(context.Box0.Extent[0]*context.AB[1][2])+WWMath::Fabs(context.Box0.Extent[1]*context.AB[0][2]);
424 rb = WWMath::Fabs(context.Box1.Extent[0]*context.AB[2][1])+WWMath::Fabs(context.Box1.Extent[1]*context.AB[2][0]);
425 if (obb_intersect_axis(context,axis,ra,rb)) return false;
426 }
427
428 return true;
429}
430
431
432/***********************************************************************************************
433 * CollisionMath::Intersection_Test -- test two obb's for intersection *
434 * *
435 * Simply sets up the context and calls intersect_obb_obb *
436 * *
437 * INPUT: *
438 * *
439 * OUTPUT: *
440 * *
441 * WARNINGS: *
442 * *
443 * HISTORY: *
444 * 5/25/99 GTH : Created. *
445 *=============================================================================================*/
447{
448 ObbIntersectionStruct context(box0,box1);
449 return intersect_obb_obb(context);
450}
451
452
453/***********************************************************************************************
454 * CollisionMath::Intersection_Test -- test an OBB for intersection with an AAB *
455 * *
456 * INPUT: *
457 * *
458 * OUTPUT: *
459 * *
460 * WARNINGS: *
461 * *
462 * HISTORY: *
463 * 5/25/99 GTH : Created. *
464 *=============================================================================================*/
466{
467 OBBoxClass obbox1(box1.Center,box1.Extent);
468 ObbIntersectionStruct context(box0,obbox1);
469 return intersect_obb_obb(context);
470}
471
472
473/***********************************************************************************************
474 * CollisionMath::Intersection_Test -- Test an AAB for intersection with an OBB *
475 * *
476 * INPUT: *
477 * *
478 * OUTPUT: *
479 * *
480 * WARNINGS: *
481 * *
482 * HISTORY: *
483 * 5/25/99 GTH : Created. *
484 *=============================================================================================*/
486{
487 OBBoxClass obbox0(box0.Center,box0.Extent);
488 ObbIntersectionStruct context(obbox0,box1);
489 return intersect_obb_obb(context);
490}
491
492
493/********************************************************************************
494
495 OBBox-OBBox collision detection
496
497 This batch of functions implement collision detection for moving oriented
498 boxes. Assuming that the two arbitrarily oriented boxes are moving at a constant
499 velocity along a path and not rotating, the time of collision can be found.
500 The OBB-ABB and ABB-OBB functions are also implemented in a way that re-uses
501 the OBB-OBB code.
502
503 For the code which computes the point of collision and collision normal, you'll
504 have to refer to the paper by Dave Eberly on oriented bounding boxes. The
505 formulas for the collision point are the only part of this I was unable to
506 derive myself (they are pretty nasty...)
507
508********************************************************************************/
509
510
517{
518 ObbCollisionStruct(const OBBoxClass &box0,const Vector3 &move0,const OBBoxClass & box1,const Vector3 &move1) :
519 StartBad(true), // Startbad is true until one of the axes clears it
520 AxisId(INTERSECTION), // AxisId will be the axis that allowed the longest move
521 MaxFrac(0.0f), // MaxFrac is the longest allowed move so far
522 Box0(box0),
523 Move0(move0),
524 Box1(box1),
525 Move1(move1)
526 {
527 Vector3::Subtract(box1.Center,box0.Center,&C); // vector from center of box0 to center of box1
528 Vector3::Subtract(move1,move0,&M); // move vector relative to stationary box0
529
530 A[0].Set(box0.Basis[0][0],box0.Basis[1][0],box0.Basis[2][0]);
531 A[1].Set(box0.Basis[0][1],box0.Basis[1][1],box0.Basis[2][1]);
532 A[2].Set(box0.Basis[0][2],box0.Basis[1][2],box0.Basis[2][2]);
533
534 B[0].Set(box1.Basis[0][0],box1.Basis[1][0],box1.Basis[2][0]);
535 B[1].Set(box1.Basis[0][1],box1.Basis[1][1],box1.Basis[2][1]);
536 B[2].Set(box1.Basis[0][2],box1.Basis[1][2],box1.Basis[2][2]);
537 }
538
539 bool StartBad; // Inital configuration is intersecting?
540 float MaxFrac; // Longest move allowed so far
541 int AxisId; // Last separating axis
542 int Side; // which side of the interval
543
544 int TestAxisId; // Axis 'id' we're working on
545 Vector3 TestAxis; // Axis that we're working on
546
547 Vector3 C; // Vector from the center0 to center1
548 Vector3 M; // Move vector relative to stationary box0
549
550 Vector3 A[3]; // basis vectors for box0
551 Vector3 B[3]; // basis vectors for box1
552 float AB[3][3]; // dot products of the basis vectors
553
555 const Vector3 & Move0;
557 const Vector3 & Move1;
558
559private:
560 //not implemented
562 ObbCollisionStruct & operator = (const ObbCollisionStruct&);
563};
564
565
566
567/***********************************************************************************************
568 * obb_separation_test -- test the projections of two obb's for separation *
569 * *
570 * INPUT: *
571 * *
572 * OUTPUT: *
573 * *
574 * WARNINGS: *
575 * *
576 * HISTORY: *
577 * 4/8/99 GTH : Created. *
578 *=============================================================================================*/
579static inline bool obb_separation_test
580(
581 ObbCollisionStruct & context,
582 float ra,
583 float rb,
584 float u0,
585 float u1
586)
587{
588 float tmp;
589 float rsum = ra+rb;
590
591 if ( u0 + WWMATH_EPSILON > rsum ) {
592 context.StartBad = false;
593 if ( u1 > rsum ) {
594 context.MaxFrac = 1.0f;
595 return true;
596 } else if (WWMath::Fabs(u1-u0) > 0.0f) {
597 tmp = (rsum-u0)/(u1-u0);
598 if ( tmp > context.MaxFrac ) {
599 context.MaxFrac = tmp;
600 context.AxisId = context.TestAxisId;
601 context.Side = +1;
602 }
603 }
604 } else if ( u0 - WWMATH_EPSILON < -rsum ) {
605 context.StartBad = false;
606 if ( u1 < -rsum ) {
607 context.MaxFrac = 1.0f;
608 return true;
609 } else if (WWMath::Fabs(u1-u0) > 0.0f) {
610 tmp = (-rsum-u0)/(u1-u0);
611 if ( tmp > context.MaxFrac ) {
612 context.MaxFrac = tmp;
613 context.AxisId = context.TestAxisId;
614 context.Side = -1;
615 }
616 }
617 }
618 return false;
619}
620
621
622/***********************************************************************************************
623 * obb_check_box0_basis -- projects the boxes onto a basis vector from box0 *
624 * *
625 * INPUT: *
626 * *
627 * OUTPUT: *
628 * *
629 * WARNINGS: *
630 * *
631 * HISTORY: *
632 * 4/8/99 GTH : Created. *
633 *=============================================================================================*/
634static bool obb_check_box0_basis
635(
636 ObbCollisionStruct & context,
637 int axis_index
638)
639{
640 // ra = box0 projection onto the axis
641 // rb = box1 projection onto the axis
642 float ra = context.Box0.Extent[axis_index];
643 float rb = WWMath::Fabs(context.Box1.Extent[0]*context.AB[axis_index][0]) +
644 WWMath::Fabs(context.Box1.Extent[1]*context.AB[axis_index][1]) +
645 WWMath::Fabs(context.Box1.Extent[2]*context.AB[axis_index][2]);
646
647 // u0 = projected distance between the box centers at t0
648 // u1 = projected distance between the box centers at t1
649 float u0 = Vector3::Dot_Product(context.C,context.A[axis_index]);
650 float u1 = u0 + Vector3::Dot_Product(context.M,context.A[axis_index]);
651
652 return obb_separation_test(context,ra,rb,u0,u1);
653}
654
655
656/***********************************************************************************************
657 * obb_check_box1_basis -- projects the two obbs onto a basis vector from box1 *
658 * *
659 * INPUT: *
660 * *
661 * OUTPUT: *
662 * *
663 * WARNINGS: *
664 * *
665 * HISTORY: *
666 * 4/8/99 GTH : Created. *
667 *=============================================================================================*/
668static bool obb_check_box1_basis
669(
670 ObbCollisionStruct & context,
671 int axis_index
672)
673{
674 // ra = box0 projection onto the axis
675 // rb = box1 projection onto the axis
676 float ra = WWMath::Fabs(context.Box0.Extent[0]*context.AB[0][axis_index]) +
677 WWMath::Fabs(context.Box0.Extent[1]*context.AB[1][axis_index]) +
678 WWMath::Fabs(context.Box0.Extent[2]*context.AB[2][axis_index]);
679 float rb = context.Box1.Extent[axis_index];
680
681 // u0 = projected distance between the box centers at t0
682 // u1 = projected distance between the box centers at t1
683 float u0 = Vector3::Dot_Product(context.C,context.B[axis_index]);
684 float u1 = u0 + Vector3::Dot_Product(context.M,context.B[axis_index]);
685 return obb_separation_test(context,ra,rb,u0,u1);
686}
687
688
689/***********************************************************************************************
690 * obb_check_axis -- projects the obbs onto an arbitrary axis *
691 * *
692 * INPUT: *
693 * *
694 * OUTPUT: *
695 * *
696 * WARNINGS: *
697 * *
698 * HISTORY: *
699 * 4/8/99 GTH : Created. *
700 *=============================================================================================*/
701static inline bool obb_check_axis
702(
703 ObbCollisionStruct & context,
704 float ra,
705 float rb
706)
707{
708 float u0 = Vector3::Dot_Product(context.C,context.TestAxis);
709 float u1 = u0 + Vector3::Dot_Product(context.M,context.TestAxis);
710 return obb_separation_test(context,ra,rb,u0,u1);
711}
712
713
714/***********************************************************************************************
715 * obb_compute_projections -- computes projections of two boxes onto an arbitrary axis *
716 * *
717 * INPUT: *
718 * *
719 * OUTPUT: *
720 * *
721 * WARNINGS: *
722 * *
723 * HISTORY: *
724 * 4/8/99 GTH : Created. *
725 *=============================================================================================*/
726static inline void obb_compute_projections
727(
728 const ObbCollisionStruct & context,
729 float * ra,
730 float * rb
731)
732{
733 *ra = context.Box0.Extent.X * WWMath::Fabs(Vector3::Dot_Product(context.A[0],context.TestAxis)) +
734 context.Box0.Extent.Y * WWMath::Fabs(Vector3::Dot_Product(context.A[1],context.TestAxis)) +
735 context.Box0.Extent.Z * WWMath::Fabs(Vector3::Dot_Product(context.A[2],context.TestAxis));
736
737 *rb = context.Box1.Extent.X * WWMath::Fabs(Vector3::Dot_Product(context.B[0],context.TestAxis)) +
738 context.Box1.Extent.Y * WWMath::Fabs(Vector3::Dot_Product(context.B[1],context.TestAxis)) +
739 context.Box1.Extent.Z * WWMath::Fabs(Vector3::Dot_Product(context.B[2],context.TestAxis));
740}
741
742
743/***********************************************************************************************
744 * compute_contact_normal -- computes the contact normal (after contact is detected) *
745 * *
746 * INPUT: *
747 * *
748 * OUTPUT: *
749 * *
750 * WARNINGS: *
751 * *
752 * HISTORY: *
753 * 4/8/99 GTH : Created. *
754 *=============================================================================================*/
755static inline void compute_contact_normal(ObbCollisionStruct & context,CastResultStruct * result)
756{
757 switch(context.AxisId)
758 {
759 case INTERSECTION:
760#pragma message("Fatal assert disabled for demo, obb-obb collision")
761// WWASSERT(0);
762// break;
763
764 case AXIS_A0:
765 result->Normal = context.A[0];
766 break;
767
768 case AXIS_A1:
769 result->Normal = context.A[1];
770 break;
771
772 case AXIS_A2:
773 result->Normal = context.A[2];
774 break;
775
776 case AXIS_B0:
777 result->Normal = context.B[0];
778 break;
779
780 case AXIS_B1:
781 result->Normal = context.B[1];
782 break;
783
784 case AXIS_B2:
785 result->Normal = context.B[2];
786 break;
787
788 case AXIS_A0B0:
789 Vector3::Cross_Product(context.A[0],context.B[0],&result->Normal);
790 result->Normal.Normalize();
791 break;
792
793 case AXIS_A0B1:
794 Vector3::Cross_Product(context.A[0],context.B[1],&result->Normal);
795 result->Normal.Normalize();
796 break;
797
798 case AXIS_A0B2:
799 Vector3::Cross_Product(context.A[0],context.B[2],&result->Normal);
800 result->Normal.Normalize();
801 break;
802
803 case AXIS_A1B0:
804 Vector3::Cross_Product(context.A[1],context.B[0],&result->Normal);
805 result->Normal.Normalize();
806 break;
807
808 case AXIS_A1B1:
809 Vector3::Cross_Product(context.A[1],context.B[1],&result->Normal);
810 result->Normal.Normalize();
811 break;
812
813 case AXIS_A1B2:
814 Vector3::Cross_Product(context.A[1],context.B[2],&result->Normal);
815 result->Normal.Normalize();
816 break;
817
818 case AXIS_A2B0:
819 Vector3::Cross_Product(context.A[2],context.B[0],&result->Normal);
820 result->Normal.Normalize();
821 break;
822
823 case AXIS_A2B1:
824 Vector3::Cross_Product(context.A[2],context.B[1],&result->Normal);
825 result->Normal.Normalize();
826 break;
827
828 case AXIS_A2B2:
829 Vector3::Cross_Product(context.A[2],context.B[2],&result->Normal);
830 result->Normal.Normalize();
831 break;
832 }
833
834 result->Normal *= -context.Side;
835}
836
837
838/***********************************************************************************************
839 * eval_side -- returns -1,0,1 depending on ab and side *
840 * *
841 * INPUT: *
842 * *
843 * OUTPUT: *
844 * *
845 * WARNINGS: *
846 * *
847 * HISTORY: *
848 * 4/8/99 GTH : Created. *
849 *=============================================================================================*/
850static inline float eval_side(float ab,float side)
851{
852 if (ab > 0.0f) {
853 return side;
854 } else if (ab < 0.0f) {
855 return -side;
856 } else {
857 return 0.0f;
858 }
859}
860
861
862/***********************************************************************************************
863 * compute_contact_point -- computes the contact point (after contact is detected) *
864 * *
865 * INPUT: *
866 * *
867 * OUTPUT: *
868 * *
869 * WARNINGS: *
870 * *
871 * HISTORY: *
872 * 4/8/99 GTH : Created. *
873 *=============================================================================================*/
874static inline void compute_contact_point(ObbCollisionStruct & context,CastResultStruct * result)
875{
876 int i,j;
877 float x[3]; // box0 parameters
878 float y[3]; // box1 parameters
879 float den;
880 Vector3 dcnew(0,0,0);
881
882//again:
883
884 if (context.AxisId >= AXIS_A0B0) {
885 Vector3 cnew0;
886 Vector3 cnew1;
887 Vector3::Add(context.Box0.Center,context.MaxFrac * context.Move0,&cnew0);
888 Vector3::Add(context.Box1.Center,context.MaxFrac * context.Move1,&cnew1);
889 Vector3::Subtract(cnew1,cnew0,&dcnew);
890 }
891
892 //PROBLEMS:
893 //in case of edge-face or face-face or perfectly aligned edge-edge this
894 //routine is only computing a single point.
895 switch(context.AxisId)
896 {
897 case AXIS_A0:
898 case AXIS_A1:
899 case AXIS_A2:
900 i = context.AxisId - AXIS_A0;
901 for (j=0; j<3; j++) {
902 y[j] = -eval_side(context.AB[i][j],context.Side);
903 }
904 context.Box1.Compute_Point(y,&(result->ContactPoint));
905 result->ContactPoint += result->Fraction * context.Move1;
906 return;
907
908 case AXIS_B0:
909 case AXIS_B1:
910 case AXIS_B2:
911 j = context.AxisId - AXIS_B0;
912 for (i=0; i<3; i++) {
913 x[i] = eval_side(context.AB[i][j],context.Side);
914 }
915 context.Box0.Compute_Point(x,&(result->ContactPoint));
916 result->ContactPoint += result->Fraction * context.Move0;
917 return;
918
919 case AXIS_A0B0:
920 x[1] = -eval_side(context.AB[2][0],context.Side) * context.Box0.Extent[1];
921 x[2] = eval_side(context.AB[1][0],context.Side) * context.Box0.Extent[2];
922 y[1] = -eval_side(context.AB[0][2],context.Side) * context.Box1.Extent[1];
923 y[2] = eval_side(context.AB[0][1],context.Side) * context.Box1.Extent[2];
924
925 den = (1.0f - context.AB[0][0] * context.AB[0][0]);
926 if (WWMath::Fabs(den) > 0.0f) {
927 x[0] = Vector3::Dot_Product(context.A[0],dcnew);
928 x[0] += context.AB[0][0] * (Vector3::Dot_Product(-context.B[0],dcnew) + context.AB[1][0]*x[1] + context.AB[2][0]*x[2]);
929 x[0] += context.AB[0][1] * y[1] + context.AB[0][2] * y[2];
930 x[0] /= den;
931 } else {
932 x[0] = 0.0f;
933 }
934 break;
935
936 case AXIS_A0B1:
937 x[1] = -eval_side(context.AB[2][1],context.Side) * context.Box0.Extent[1];
938 x[2] = eval_side(context.AB[1][1],context.Side) * context.Box0.Extent[2];
939 y[0] = eval_side(context.AB[0][2],context.Side) * context.Box1.Extent[0];
940 y[2] = -eval_side(context.AB[0][0],context.Side) * context.Box1.Extent[2];
941
942 den = (1.0f - context.AB[0][1] * context.AB[0][1]);
943 if (WWMath::Fabs(den) > 0.0f) {
944 x[0] = Vector3::Dot_Product(context.A[0],dcnew);
945 x[0] += context.AB[0][1] * (Vector3::Dot_Product(-context.B[1],dcnew) + context.AB[1][1]*x[1] + context.AB[2][1]*x[2]);
946 x[0] += context.AB[0][0] * y[0] + context.AB[0][2] * y[2];
947 x[0] /= den;
948 } else {
949 x[0] = 0.0f;
950 }
951 break;
952
953 case AXIS_A0B2:
954 x[1] = -eval_side(context.AB[2][2],context.Side) * context.Box0.Extent[1];
955 x[2] = eval_side(context.AB[1][2],context.Side) * context.Box0.Extent[2];
956 y[0] = -eval_side(context.AB[0][1],context.Side) * context.Box1.Extent[0];
957 y[1] = eval_side(context.AB[0][0],context.Side) * context.Box1.Extent[1];
958
959 den = (1.0f - context.AB[0][2] * context.AB[0][2]);
960 if (WWMath::Fabs(den) > 0.0f) {
961 x[0] = Vector3::Dot_Product(context.A[0],dcnew);
962 x[0] += context.AB[0][2] * (Vector3::Dot_Product(-context.B[2],dcnew) + context.AB[1][2]*x[1] + context.AB[2][2]*x[2]);
963 x[0] += context.AB[0][0] * y[0] + context.AB[0][1] * y[1];
964 x[0] /= den;
965 } else {
966 x[0] = 0.0f;
967 }
968 break;
969
970 case AXIS_A1B0:
971 x[0] = eval_side(context.AB[2][0],context.Side) * context.Box0.Extent[0];
972 x[2] = -eval_side(context.AB[0][0],context.Side) * context.Box0.Extent[2];
973 y[1] = -eval_side(context.AB[1][2],context.Side) * context.Box1.Extent[1];
974 y[2] = eval_side(context.AB[1][1],context.Side) * context.Box1.Extent[2];
975
976 den = (1.0f - context.AB[1][0] * context.AB[1][0]);
977 if (WWMath::Fabs(den) > 0.0f) {
978 x[1] = Vector3::Dot_Product(context.A[1],dcnew);
979 x[1] += context.AB[1][0] * (Vector3::Dot_Product(-context.B[0],dcnew) + context.AB[0][0]*x[0] + context.AB[2][0]*x[2]);
980 x[1] += context.AB[1][1] * y[1] + context.AB[1][2] * y[2];
981 x[1] /= den;
982 } else {
983 x[1] = 0.0f;
984 }
985 break;
986
987 case AXIS_A1B1:
988 x[0] = eval_side(context.AB[2][1],context.Side) * context.Box0.Extent[0];
989 x[2] = -eval_side(context.AB[0][1],context.Side) * context.Box0.Extent[2];
990 y[0] = eval_side(context.AB[1][2],context.Side) * context.Box1.Extent[0];
991 y[2] = -eval_side(context.AB[1][0],context.Side) * context.Box1.Extent[2];
992
993 den = 1.0f / (1.0f - context.AB[1][1] * context.AB[1][1]);
994 if (WWMath::Fabs(den) > 0.0f) {
995 x[1] = Vector3::Dot_Product(context.A[1],dcnew);
996 x[1] += context.AB[1][1] * (Vector3::Dot_Product(-context.B[1],dcnew) + context.AB[0][1]*x[0] + context.AB[2][1]*x[2]);
997 x[1] += context.AB[1][0] * y[0] + context.AB[1][2] * y[2];
998 x[1] /= den;
999 } else {
1000 x[1] = 0.0f;
1001 }
1002 break;
1003
1004 case AXIS_A1B2:
1005 x[0] = eval_side(context.AB[2][2],context.Side) * context.Box0.Extent[0];
1006 x[2] = -eval_side(context.AB[0][2],context.Side) * context.Box0.Extent[2];
1007 y[0] = -eval_side(context.AB[1][1],context.Side) * context.Box1.Extent[0];
1008 y[1] = eval_side(context.AB[1][0],context.Side) * context.Box1.Extent[1];
1009
1010 den = (1.0f - context.AB[1][2] * context.AB[1][2]);
1011 if (WWMath::Fabs(den) > 0.0f) {
1012 x[1] = Vector3::Dot_Product(context.A[1],dcnew);
1013 x[1] += context.AB[1][2] * (Vector3::Dot_Product(-context.B[2],dcnew) + context.AB[0][2]*x[0] + context.AB[2][2]*x[2]);
1014 x[1] += context.AB[1][0] * y[0] + context.AB[1][1] * y[1];
1015 x[1] /= den;
1016 } else {
1017 x[1] = 0.0f;
1018 }
1019 break;
1020
1021 case AXIS_A2B0:
1022 x[0] = -eval_side(context.AB[1][0],context.Side) * context.Box0.Extent[0];
1023 x[1] = eval_side(context.AB[0][0],context.Side) * context.Box0.Extent[1];
1024 y[1] = -eval_side(context.AB[2][2],context.Side) * context.Box1.Extent[1];
1025 y[2] = eval_side(context.AB[2][1],context.Side) * context.Box1.Extent[2];
1026
1027 den = (1.0f - context.AB[2][0] * context.AB[2][0]);
1028 if (WWMath::Fabs(den) > 0.0f) {
1029 x[2] = Vector3::Dot_Product(context.A[2],dcnew);
1030 x[2] += context.AB[2][0] * (Vector3::Dot_Product(-context.B[0],dcnew) + context.AB[0][0]*x[0] + context.AB[1][0]*x[1]);
1031 x[2] += context.AB[2][1] * y[1] + context.AB[2][2] * y[2];
1032 x[2] /= den;
1033 } else {
1034 x[2] = 0.0f;
1035 }
1036 break;
1037
1038 case AXIS_A2B1:
1039 x[0] = -eval_side(context.AB[1][1],context.Side) * context.Box0.Extent[0];
1040 x[1] = eval_side(context.AB[0][1],context.Side) * context.Box0.Extent[1];
1041 y[0] = eval_side(context.AB[2][2],context.Side) * context.Box1.Extent[0];
1042 y[2] = -eval_side(context.AB[2][0],context.Side) * context.Box1.Extent[2];
1043
1044 den = (1.0f - context.AB[2][1] * context.AB[2][1]);
1045 if (WWMath::Fabs(den) > 0.0f) {
1046 x[2] = Vector3::Dot_Product(context.A[2],dcnew);
1047 x[2] += context.AB[2][1] * (Vector3::Dot_Product(-context.B[1],dcnew) + context.AB[0][1]*x[0] + context.AB[1][1]*x[1]);
1048 x[2] += context.AB[2][0] * y[0] + context.AB[2][2] * y[2];
1049 x[2] /= den;
1050 } else {
1051 x[2] = 0.0f;
1052 }
1053 break;
1054
1055 case AXIS_A2B2:
1056 x[0] = -eval_side(context.AB[1][2],context.Side) * context.Box0.Extent[0];
1057 x[1] = eval_side(context.AB[0][2],context.Side) * context.Box0.Extent[1];
1058 y[0] = -eval_side(context.AB[2][1],context.Side) * context.Box1.Extent[0];
1059 y[1] = eval_side(context.AB[2][0],context.Side) * context.Box1.Extent[1];
1060
1061 den = (1.0f - context.AB[2][2] * context.AB[2][2]);
1062 if (WWMath::Fabs(den) > 0.0f) {
1063 x[2] = Vector3::Dot_Product(context.A[2],dcnew);
1064 x[2] += context.AB[2][2] * (Vector3::Dot_Product(-context.B[2],dcnew) + context.AB[0][2]*x[0] + context.AB[1][2]*x[1]);
1065 x[2] += context.AB[2][0] * y[0] + context.AB[2][1] * y[1];
1066 x[2] /= den;
1067 } else {
1068 x[2] = 0.0f;
1069 }
1070 break;
1071 }
1072
1073 // all but the first two cases fall through to here
1074 result->ContactPoint.X = context.Box0.Center.X +
1075 x[0]*context.A[0].X +
1076 x[1]*context.A[1].X +
1077 x[2]*context.A[2].X;
1078
1079 result->ContactPoint.Y = context.Box0.Center.Y +
1080 x[0]*context.A[0].Y +
1081 x[1]*context.A[1].Y +
1082 x[2]*context.A[2].Y;
1083
1084 result->ContactPoint.Z = context.Box0.Center.Z +
1085 x[0]*context.A[0].Z +
1086 x[1]*context.A[1].Z +
1087 x[2]*context.A[2].Z;
1088
1089 Vector3::Add(result->ContactPoint,result->Fraction * context.Move0,&(result->ContactPoint));
1090
1091}
1092
1093
1094/***********************************************************************************************
1095 * collide_obb_obb -- test two obb's for collision *
1096 * *
1097 * INPUT: *
1098 * *
1099 * OUTPUT: *
1100 * *
1101 * WARNINGS: *
1102 * *
1103 * HISTORY: *
1104 * 5/25/99 GTH : Created. *
1105 *=============================================================================================*/
1107(
1108 ObbCollisionStruct & context,
1109 CastResultStruct * result
1110)
1111{
1112 Vector3 axis;
1113 float ra,rb;
1114
1116 // Axis = A0
1117 // Projecting the two boxes onto Box0's X axis. If their intervals
1118 // on this line do not intersect, the boxes are not intersecting!
1119 // Each of the tests in this function work in a similar way.
1120 // For this function I compute the AB's that are needed. The first
1121 // three tests compute all of these constants.
1123 context.TestAxisId = AXIS_A0;
1124 context.AB[0][0] = Vector3::Dot_Product(context.A[0],context.B[0]);
1125 context.AB[0][1] = Vector3::Dot_Product(context.A[0],context.B[1]);
1126 context.AB[0][2] = Vector3::Dot_Product(context.A[0],context.B[2]);
1127 if (obb_check_box0_basis(context,0)) goto exit;
1128
1130 // Axsis A1
1132 context.TestAxisId = AXIS_A1;
1133 context.AB[1][0] = Vector3::Dot_Product(context.A[1],context.B[0]);
1134 context.AB[1][1] = Vector3::Dot_Product(context.A[1],context.B[1]);
1135 context.AB[1][2] = Vector3::Dot_Product(context.A[1],context.B[2]);
1136 if (obb_check_box0_basis(context,1)) goto exit;
1137
1139 // Axis = A2
1141 context.TestAxisId = AXIS_A2;
1142 context.AB[2][0] = Vector3::Dot_Product(context.A[2],context.B[0]);
1143 context.AB[2][1] = Vector3::Dot_Product(context.A[2],context.B[1]);
1144 context.AB[2][2] = Vector3::Dot_Product(context.A[2],context.B[2]);
1145 if (obb_check_box0_basis(context,2)) goto exit;
1146
1148 // Axis = B0
1150 context.TestAxisId = AXIS_B0;
1151 if (obb_check_box1_basis(context,0)) goto exit;
1152
1154 // Axis = B1
1156 context.TestAxisId = AXIS_B1;
1157 if (obb_check_box1_basis(context,1)) goto exit;
1158
1160 // Axis = B2
1162 context.TestAxisId = AXIS_B2;
1163 if (obb_check_box1_basis(context,2)) goto exit;
1164
1166 // Axis = A0xB0
1167 // The axes defined by the cross product between the boxes' basis
1168 // vectors are optimized in a similar way to this one:
1169 //
1170 // ra = |ex*A0*(A0xB0)| + |ey*A1*(A0xB0)| + |ez*A2*(A0xB0)|
1171 // = |ey*A1*(A0xB0)| + |ez*A2*(A0xB0)| A0*(A0xB0)=0
1172 // = |ey*B0*(A1xA0)| + |ez*B0*(A2xA0)| A*(BxC)=B*(CxA)=C*(AxB)
1173 // = |-ey*A2*B0| + |ez*A1*B0| A0xA1=A2
1174 // = |ey*AB[2][0]| + |ez*AB[1][0]| already computed these dot products!
1175 //
1177 Vector3::Cross_Product(context.A[0],context.B[0],&context.TestAxis);
1178 context.TestAxisId = AXIS_A0B0;
1179 if (context.TestAxis.Length2() > AXISLEN_EPSILON2) {
1180 ra = WWMath::Fabs(context.Box0.Extent[1]*context.AB[2][0])+WWMath::Fabs(context.Box0.Extent[2]*context.AB[1][0]);
1181 rb = WWMath::Fabs(context.Box1.Extent[1]*context.AB[0][2])+WWMath::Fabs(context.Box1.Extent[2]*context.AB[0][1]);
1182 if (obb_check_axis(context,ra,rb)) goto exit;
1183 }
1184
1186 // Axis = A0xB1
1188 Vector3::Cross_Product(context.A[0],context.B[1],&context.TestAxis);
1189 context.TestAxisId = AXIS_A0B1;
1190 if (context.TestAxis.Length2() > AXISLEN_EPSILON2) {
1191 ra = WWMath::Fabs(context.Box0.Extent[1]*context.AB[2][1])+WWMath::Fabs(context.Box0.Extent[2]*context.AB[1][1]);
1192 rb = WWMath::Fabs(context.Box1.Extent[0]*context.AB[0][2])+WWMath::Fabs(context.Box1.Extent[2]*context.AB[0][0]);
1193 if (obb_check_axis(context,ra,rb)) goto exit;
1194 }
1195
1197 // Axis = A0xB2
1199 Vector3::Cross_Product(context.A[0],context.B[2],&context.TestAxis);
1200 context.TestAxisId = AXIS_A0B2;
1201 if (context.TestAxis.Length2() > AXISLEN_EPSILON2) {
1202 ra = WWMath::Fabs(context.Box0.Extent[1]*context.AB[2][2])+WWMath::Fabs(context.Box0.Extent[2]*context.AB[1][2]);
1203 rb = WWMath::Fabs(context.Box1.Extent[0]*context.AB[0][1])+WWMath::Fabs(context.Box1.Extent[1]*context.AB[0][0]);
1204 if (obb_check_axis(context,ra,rb)) goto exit;
1205 }
1206
1208 // Axis = A1xB0
1210 Vector3::Cross_Product(context.A[1],context.B[0],&context.TestAxis);
1211 context.TestAxisId = AXIS_A1B0;
1212 if (context.TestAxis.Length2() > AXISLEN_EPSILON2) {
1213 ra = WWMath::Fabs(context.Box0.Extent[0]*context.AB[2][0])+WWMath::Fabs(context.Box0.Extent[2]*context.AB[0][0]);
1214 rb = WWMath::Fabs(context.Box1.Extent[1]*context.AB[1][2])+WWMath::Fabs(context.Box1.Extent[2]*context.AB[1][1]);
1215 if (obb_check_axis(context,ra,rb)) goto exit;
1216 }
1217
1219 // Axis = A1xB1
1221 Vector3::Cross_Product(context.A[1],context.B[1],&context.TestAxis);
1222 context.TestAxisId = AXIS_A1B1;
1223 if (context.TestAxis.Length2() > AXISLEN_EPSILON2) {
1224 ra = WWMath::Fabs(context.Box0.Extent[0]*context.AB[2][1])+WWMath::Fabs(context.Box0.Extent[2]*context.AB[0][1]);
1225 rb = WWMath::Fabs(context.Box1.Extent[0]*context.AB[1][2])+WWMath::Fabs(context.Box1.Extent[2]*context.AB[1][0]);
1226 if (obb_check_axis(context,ra,rb)) goto exit;
1227 }
1228
1230 // Axis = A1xB2
1232 Vector3::Cross_Product(context.A[1],context.B[2],&context.TestAxis);
1233 context.TestAxisId = AXIS_A1B2;
1234 if (context.TestAxis.Length2() > AXISLEN_EPSILON2) {
1235 ra = WWMath::Fabs(context.Box0.Extent[0]*context.AB[2][2])+WWMath::Fabs(context.Box0.Extent[2]*context.AB[0][2]);
1236 rb = WWMath::Fabs(context.Box1.Extent[0]*context.AB[1][1])+WWMath::Fabs(context.Box1.Extent[1]*context.AB[1][0]);
1237 if (obb_check_axis(context,ra,rb)) goto exit;
1238 }
1239
1241 // Axis = A2xB0
1243 Vector3::Cross_Product(context.A[2],context.B[0],&context.TestAxis);
1244 context.TestAxisId = AXIS_A2B0;
1245 if (context.TestAxis.Length2() > AXISLEN_EPSILON2) {
1246 ra = WWMath::Fabs(context.Box0.Extent[0]*context.AB[1][0])+WWMath::Fabs(context.Box0.Extent[1]*context.AB[0][0]);
1247 rb = WWMath::Fabs(context.Box1.Extent[1]*context.AB[2][2])+WWMath::Fabs(context.Box1.Extent[2]*context.AB[2][1]);
1248 if (obb_check_axis(context,ra,rb)) goto exit;
1249 }
1250
1252 // Axis = A2xB1
1254 Vector3::Cross_Product(context.A[2],context.B[1],&context.TestAxis);
1255 context.TestAxisId = AXIS_A2B1;
1256 if (context.TestAxis.Length2() > AXISLEN_EPSILON2) {
1257 ra = WWMath::Fabs(context.Box0.Extent[0]*context.AB[1][1])+WWMath::Fabs(context.Box0.Extent[1]*context.AB[0][1]);
1258 rb = WWMath::Fabs(context.Box1.Extent[0]*context.AB[2][2])+WWMath::Fabs(context.Box1.Extent[2]*context.AB[2][0]);
1259 if (obb_check_axis(context,ra,rb)) goto exit;
1260 }
1261
1263 // Axis = A2xB2
1265 Vector3::Cross_Product(context.A[2],context.B[2],&context.TestAxis);
1266 context.TestAxisId = AXIS_A2B2;
1267 if (context.TestAxis.Length2() > AXISLEN_EPSILON2) {
1268 ra = WWMath::Fabs(context.Box0.Extent[0]*context.AB[1][2])+WWMath::Fabs(context.Box0.Extent[1]*context.AB[0][2]);
1269 rb = WWMath::Fabs(context.Box1.Extent[0]*context.AB[2][1])+WWMath::Fabs(context.Box1.Extent[1]*context.AB[2][0]);
1270 if (obb_check_axis(context,ra,rb)) goto exit;
1271 }
1272
1273 if (!result->StartBad) {
1274
1275 context.TestAxisId = context.AxisId;
1276
1278 // Final three checks are for eliminating false collisions
1279 // Axis = A0xMove
1281 Vector3::Cross_Product(context.A[0],context.Move0,&context.TestAxis);
1282 if (context.TestAxis.Length2() > AXISLEN_EPSILON2) {
1283 obb_compute_projections(context,&ra,&rb);
1284 if (obb_check_axis(context,ra,rb)) goto exit;
1285 }
1286
1288 // Axis = A1xMove
1290 Vector3::Cross_Product(context.A[1],context.Move0,&context.TestAxis);
1291 if (context.TestAxis.Length2() > AXISLEN_EPSILON2) {
1292 obb_compute_projections(context,&ra,&rb);
1293 if (obb_check_axis(context,ra,rb)) goto exit;
1294 }
1295
1297 // Axis = A2xMove
1299 Vector3::Cross_Product(context.A[2],context.Move0,&context.TestAxis);
1300 if (context.TestAxis.Length2() > AXISLEN_EPSILON2) {
1301 obb_compute_projections(context,&ra,&rb);
1302 if (obb_check_axis(context,ra,rb)) goto exit;
1303 }
1304 }
1305
1306exit:
1307
1308 if (context.StartBad) {
1309 result->StartBad = true;
1310 result->Fraction = 0.0f;
1311 return true;
1312 }
1313
1314
1315 /*
1316 ** If our fraction is smaller, override the previous
1317 ** values because our collision occured first.
1318 */
1319 if (context.MaxFrac < result->Fraction) {
1320
1321 result->Fraction = context.MaxFrac;
1322
1323 compute_contact_normal(context,result);
1324 if (result->ComputeContactPoint) {
1325 compute_contact_point(context,result);
1326 }
1327 return true;
1328 }
1329 return false;
1330}
1331
1332/***********************************************************************************************
1333 * CollisionMath::Collide -- collide two obb's *
1334 * *
1335 * INPUT: *
1336 * *
1337 * OUTPUT: *
1338 * *
1339 * WARNINGS: *
1340 * *
1341 * HISTORY: *
1342 * 4/8/99 GTH : Created. *
1343 *=============================================================================================*/
1345(
1346 const OBBoxClass & box0,
1347 const Vector3 & move0,
1348 const OBBoxClass & box1,
1349 const Vector3 & move1,
1350 CastResultStruct * result
1351)
1352{
1353 ObbCollisionStruct context(box0,move0,box1,move1);
1354 return collide_obb_obb(context,result);
1355}
1356
1357
1358/***********************************************************************************************
1359 * CollisionMath::Collide -- collide an OBB with an AAB *
1360 * *
1361 * INPUT: *
1362 * *
1363 * OUTPUT: *
1364 * *
1365 * WARNINGS: *
1366 * *
1367 * HISTORY: *
1368 * 5/25/99 GTH : Created. *
1369 *=============================================================================================*/
1371(
1372 const OBBoxClass & box0,
1373 const Vector3 & move0,
1374 const AABoxClass & box1,
1375 const Vector3 & move1,
1376 CastResultStruct * result
1377)
1378{
1379 OBBoxClass obbox1(box1.Center,box1.Extent);
1380 ObbCollisionStruct context(box0,move0,obbox1,move1);
1381 return collide_obb_obb(context,result);
1382}
1383
1384
1385/***********************************************************************************************
1386 * CollisionMath::Collide -- collide an AAB with an OBB *
1387 * *
1388 * INPUT: *
1389 * *
1390 * OUTPUT: *
1391 * *
1392 * WARNINGS: *
1393 * *
1394 * HISTORY: *
1395 * 5/25/99 GTH : Created. *
1396 *=============================================================================================*/
1398(
1399 const AABoxClass & box0,
1400 const Vector3 & move0,
1401 const OBBoxClass & box1,
1402 const Vector3 & move1,
1403 CastResultStruct * result
1404)
1405{
1406 OBBoxClass obbox0(box0.Center,box0.Extent);
1407 ObbCollisionStruct context(obbox0,move0,box1,move1);
1408 return collide_obb_obb(context,result);
1409}
@ true
Definition bool.h:59
#define WWMATH_EPSILON
Definition wwmath.h:54
Vector3 Center
Definition aabox.h:123
Vector3 Extent
Definition aabox.h:124
static bool Collide(const LineSegClass &line, const AAPlaneClass &plane, CastResultStruct *result)
static bool Intersection_Test(const AABoxClass &box, const TriClass &tri)
Vector3 Extent
Definition obbox.h:114
void Compute_Point(float params[3], Vector3 *set_point) const
Definition obbox.h:192
Matrix3x3 Basis
Definition obbox.h:112
Vector3 Center
Definition obbox.h:113
static WWINLINE float Dot_Product(const Vector3 &a, const Vector3 &b)
Definition vector3.h:293
float X
Definition vector3.h:90
WWINLINE float Length2(void) const
Definition vector3.h:469
float Z
Definition vector3.h:92
float Y
Definition vector3.h:91
static WWINLINE void Subtract(const Vector3 &a, const Vector3 &b, Vector3 *c)
Definition vector3.h:576
void Normalize(void)
Definition vector3.h:417
static WWINLINE void Add(const Vector3 &a, const Vector3 &b, Vector3 *c)
Definition vector3.h:555
static WWINLINE void Cross_Product(const Vector3 &a, const Vector3 &b, Vector3 *result)
Definition vector3.h:374
static WWINLINE float Fabs(float val)
Definition wwmath.h:113
@ AXIS_A1
@ INTERSECTION
@ AXIS_A0
@ AXIS_A2
#define AXISLEN_EPSILON2
bool intersect_obb_obb(ObbIntersectionStruct &context)
bool collide_obb_obb(ObbCollisionStruct &context, CastResultStruct *result)
@ AXIS_A2B0
@ AXIS_A0B0
@ AXIS_A1B0
@ INTERSECTION
@ AXIS_A1B1
@ AXIS_A2B2
@ AXIS_B0
@ AXIS_A1B2
@ AXIS_B1
@ AXIS_B2
@ AXIS_A2B1
@ AXIS_A0B1
@ AXIS_A0B2
Vector3 ContactPoint
Definition castres.h:70
bool ComputeContactPoint
Definition castres.h:69
Vector3 Normal
Definition castres.h:66
const OBBoxClass & Box0
const Vector3 & Move0
const Vector3 & Move1
const OBBoxClass & Box1
ObbCollisionStruct(const OBBoxClass &box0, const Vector3 &move0, const OBBoxClass &box1, const Vector3 &move1)
ObbIntersectionStruct(const OBBoxClass &box0, const OBBoxClass &box1)
const OBBoxClass & Box1
const OBBoxClass & Box0