Vegastrike 0.5.1 rc1  1.0
Original sources for Vegastrike Evolved
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
OPC_TreeCollider.cpp
Go to the documentation of this file.
1 /*
3  * OPCODE - Optimized Collision Detection
4  * Copyright (C) 2001 Pierre Terdiman
5  * Homepage: http://www.codercorner.com/Opcode.htm
6  */
8 
10 
16 
19 
28 
31 // Precompiled Header
32 #include "Stdafx.h"
33 
34 
35 using namespace Opcode;
36 
37 #include "OPC_BoxBoxOverlap.h"
38 #include "OPC_TriBoxOverlap.h"
39 #include "OPC_TriTriOverlap.h"
40 
42 
47  mIMesh0 (null),
48  mIMesh1 (null),
49  mNbBVBVTests (0),
50  mNbPrimPrimTests (0),
51  mNbBVPrimTests (0),
52  mFullBoxBoxTest (true),
53  mFullPrimBoxTest (true)
54 {
55 }
56 
58 
63 {
64 }
65 
67 
73 {
74  if(TemporalCoherenceEnabled() && !FirstContactEnabled()) return "Temporal coherence only works with ""First contact"" mode!";
75  return null;
76 }
77 
79 
91 bool AABBTreeCollider::Collide(BVTCache& cache, const Matrix4x4* world0, const Matrix4x4* world1)
93 {
94  // Checkings
95  if(!cache.Model0 || !cache.Model1) return false;
96  if(cache.Model0->HasLeafNodes()!=cache.Model1->HasLeafNodes()) return false;
97  if(cache.Model0->IsQuantized()!=cache.Model1->IsQuantized()) return false;
98 
99  /*
100 
101  Rules:
102  - perform hull test
103  - when hulls collide, disable hull test
104  - if meshes overlap, reset countdown
105  - if countdown reaches 0, enable hull test
106 
107  */
108 
109 #ifdef __MESHMERIZER_H__
110  // Handle hulls
111  if(cache.HullTest)
112  {
113  if(cache.Model0->GetHull() && cache.Model1->GetHull())
114  {
115  struct Local
116  {
117  static Point* SVCallback(const Point& sv, udword& previndex, udword user_data)
118  {
119  CollisionHull* Hull = (CollisionHull*)user_data;
120  previndex = Hull->ComputeSupportingVertex(sv, previndex);
121  return (Point*)&Hull->GetVerts()[previndex];
122  }
123  };
124 
125  bool Collide;
126 
127  if(0)
128  {
129  static GJKEngine GJK;
130  static bool GJKInitDone=false;
131  if(!GJKInitDone)
132  {
133  GJK.Enable(GJK_BACKUP_PROCEDURE);
134  GJK.Enable(GJK_DEGENERATE);
135  GJK.Enable(GJK_HILLCLIMBING);
136  GJKInitDone = true;
137  }
138  GJK.SetCallbackObj0(Local::SVCallback);
139  GJK.SetCallbackObj1(Local::SVCallback);
140  GJK.SetUserData0(udword(cache.Model0->GetHull()));
141  GJK.SetUserData1(udword(cache.Model1->GetHull()));
142  Collide = GJK.Collide(*world0, *world1, &cache.SepVector);
143  }
144  else
145  {
146  static SVEngine SVE;
147  SVE.SetCallbackObj0(Local::SVCallback);
148  SVE.SetCallbackObj1(Local::SVCallback);
149  SVE.SetUserData0(udword(cache.Model0->GetHull()));
150  SVE.SetUserData1(udword(cache.Model1->GetHull()));
151  Collide = SVE.Collide(*world0, *world1, &cache.SepVector);
152  }
153 
154  if(!Collide)
155  {
156  // Reset stats & contact status
157  mFlags &= ~OPC_CONTACT;
158  mNbBVBVTests = 0;
159  mNbPrimPrimTests = 0;
160  mNbBVPrimTests = 0;
161  mPairs.Reset();
162  return true;
163  }
164  }
165  }
166 
167  // Here, hulls collide
168  cache.HullTest = false;
169 #endif // __MESHMERIZER_H__
170 
171  // Checkings
172  if(!Setup(cache.Model0->GetMeshInterface(), cache.Model1->GetMeshInterface())) return false;
173 
174  // Simple double-dispatch
175  bool Status;
176  if(!cache.Model0->HasLeafNodes())
177  {
178  if(cache.Model0->IsQuantized())
179  {
182  Status = Collide(T0, T1, world0, world1, &cache);
183  }
184  else
185  {
186  const AABBNoLeafTree* T0 = (const AABBNoLeafTree*)cache.Model0->GetTree();
187  const AABBNoLeafTree* T1 = (const AABBNoLeafTree*)cache.Model1->GetTree();
188  Status = Collide(T0, T1, world0, world1, &cache);
189  }
190  }
191  else
192  {
193  if(cache.Model0->IsQuantized())
194  {
195  const AABBQuantizedTree* T0 = (const AABBQuantizedTree*)cache.Model0->GetTree();
196  const AABBQuantizedTree* T1 = (const AABBQuantizedTree*)cache.Model1->GetTree();
197  Status = Collide(T0, T1, world0, world1, &cache);
198  }
199  else
200  {
201  const AABBCollisionTree* T0 = (const AABBCollisionTree*)cache.Model0->GetTree();
202  const AABBCollisionTree* T1 = (const AABBCollisionTree*)cache.Model1->GetTree();
203  Status = Collide(T0, T1, world0, world1, &cache);
204  }
205  }
206 
207 #ifdef __MESHMERIZER_H__
208  if(Status)
209  {
210  // Reset counter as long as overlap occurs
211  if(GetContactStatus()) cache.ResetCountDown();
212 
213  // Enable hull test again when counter reaches zero
214  cache.CountDown--;
215  if(!cache.CountDown)
216  {
217  cache.ResetCountDown();
218  cache.HullTest = true;
219  }
220  }
221 #endif
222  return Status;
223 }
224 
226 
235 void AABBTreeCollider::InitQuery(const Matrix4x4* world0, const Matrix4x4* world1)
237 {
238  // Reset stats & contact status
240  mNbBVBVTests = 0;
241  mNbPrimPrimTests = 0;
242  mNbBVPrimTests = 0;
243  mPairs.Reset();
244 
245  // Setup matrices
246  Matrix4x4 InvWorld0, InvWorld1;
247  if(world0) InvertPRMatrix(InvWorld0, *world0);
248  else InvWorld0.Identity();
249 
250  if(world1) InvertPRMatrix(InvWorld1, *world1);
251  else InvWorld1.Identity();
252 
253  Matrix4x4 World0to1 = world0 ? (*world0 * InvWorld1) : InvWorld1;
254  Matrix4x4 World1to0 = world1 ? (*world1 * InvWorld0) : InvWorld0;
255 
256  mR0to1 = World0to1; World0to1.GetTrans(mT0to1);
257  mR1to0 = World1to0; World1to0.GetTrans(mT1to0);
258 
259  // Precompute absolute 1-to-0 rotation matrix
260  for(udword i=0;i<3;i++)
261  {
262  for(udword j=0;j<3;j++)
263  {
264  // Epsilon value prevents floating-point inaccuracies (strategy borrowed from RAPID)
265  mAR.m[i][j] = 1e-6f + fabsf(mR1to0.m[i][j]);
266  }
267  }
268 }
269 
271 
279 {
280  // Checkings
281  if(!cache) return false;
282 
283  // Test previously colliding primitives first
285  {
286  PrimTest(cache->id0, cache->id1);
287  if(GetContactStatus()) return true;
288  }
289  return false;
290 }
291 
292 #define UPDATE_CACHE \
293  if(cache && GetContactStatus()) \
294  { \
295  cache->id0 = mPairs.GetEntry(0); \
296  cache->id1 = mPairs.GetEntry(1); \
297  }
298 
300 
310 bool AABBTreeCollider::Collide(const AABBCollisionTree* tree0, const AABBCollisionTree* tree1, const Matrix4x4* world0, const Matrix4x4* world1, Pair* cache)
312 {
313  // Init collision query
314  InitQuery(world0, world1);
315 
316  // Check previous state
317  if(CheckTemporalCoherence(cache)) return true;
318 
319  // Perform collision query
320  _Collide(tree0->GetNodes(), tree1->GetNodes());
321 
323 
324  return true;
325 }
326 
328 
338 bool AABBTreeCollider::Collide(const AABBNoLeafTree* tree0, const AABBNoLeafTree* tree1, const Matrix4x4* world0, const Matrix4x4* world1, Pair* cache)
340 {
341  // Init collision query
342  InitQuery(world0, world1);
343 
344  // Check previous state
345  if(CheckTemporalCoherence(cache)) return true;
346 
347  // Perform collision query
348  _Collide(tree0->GetNodes(), tree1->GetNodes());
349 
351 
352  return true;
353 }
354 
356 
366 bool AABBTreeCollider::Collide(const AABBQuantizedTree* tree0, const AABBQuantizedTree* tree1, const Matrix4x4* world0, const Matrix4x4* world1, Pair* cache)
368 {
369  // Init collision query
370  InitQuery(world0, world1);
371 
372  // Check previous state
373  if(CheckTemporalCoherence(cache)) return true;
374 
375  // Setup dequantization coeffs
376  mCenterCoeff0 = tree0->mCenterCoeff;
377  mExtentsCoeff0 = tree0->mExtentsCoeff;
378  mCenterCoeff1 = tree1->mCenterCoeff;
379  mExtentsCoeff1 = tree1->mExtentsCoeff;
380 
381  // Dequantize box A
382  const AABBQuantizedNode* N0 = tree0->GetNodes();
383  const Point a(float(N0->mAABB.mExtents[0]) * mExtentsCoeff0.x, float(N0->mAABB.mExtents[1]) * mExtentsCoeff0.y, float(N0->mAABB.mExtents[2]) * mExtentsCoeff0.z);
384  const Point Pa(float(N0->mAABB.mCenter[0]) * mCenterCoeff0.x, float(N0->mAABB.mCenter[1]) * mCenterCoeff0.y, float(N0->mAABB.mCenter[2]) * mCenterCoeff0.z);
385  // Dequantize box B
386  const AABBQuantizedNode* N1 = tree1->GetNodes();
387  const Point b(float(N1->mAABB.mExtents[0]) * mExtentsCoeff1.x, float(N1->mAABB.mExtents[1]) * mExtentsCoeff1.y, float(N1->mAABB.mExtents[2]) * mExtentsCoeff1.z);
388  const Point Pb(float(N1->mAABB.mCenter[0]) * mCenterCoeff1.x, float(N1->mAABB.mCenter[1]) * mCenterCoeff1.y, float(N1->mAABB.mCenter[2]) * mCenterCoeff1.z);
389 
390  // Perform collision query
391  _Collide(N0, N1, a, Pa, b, Pb);
392 
394 
395  return true;
396 }
397 
399 
409 bool AABBTreeCollider::Collide(const AABBQuantizedNoLeafTree* tree0, const AABBQuantizedNoLeafTree* tree1, const Matrix4x4* world0, const Matrix4x4* world1, Pair* cache)
411 {
412  // Init collision query
413  InitQuery(world0, world1);
414 
415  // Check previous state
416  if(CheckTemporalCoherence(cache)) return true;
417 
418  // Setup dequantization coeffs
419  mCenterCoeff0 = tree0->mCenterCoeff;
420  mExtentsCoeff0 = tree0->mExtentsCoeff;
421  mCenterCoeff1 = tree1->mCenterCoeff;
422  mExtentsCoeff1 = tree1->mExtentsCoeff;
423 
424  // Perform collision query
425  _Collide(tree0->GetNodes(), tree1->GetNodes());
426 
428 
429  return true;
430 }
431 
433 // Standard trees
435 
436 // The normal AABB tree can use 2 different descent rules (with different performances)
437 //#define ORIGINAL_CODE //!< UNC-like descent rules
438 #define ALTERNATIVE_CODE
439 
440 #ifdef ORIGINAL_CODE
441 
449 {
450  // Perform BV-BV overlap test
451  if(!BoxBoxOverlap(b0->mAABB.mExtents, b0->mAABB.mCenter, b1->mAABB.mExtents, b1->mAABB.mCenter)) return;
452 
453  if(b0->IsLeaf() && b1->IsLeaf()) { PrimTest(b0->GetPrimitive(), b1->GetPrimitive()); return; }
454 
455  if(b1->IsLeaf() || (!b0->IsLeaf() && (b0->GetSize() > b1->GetSize())))
456  {
457  _Collide(b0->GetNeg(), b1);
458  if(ContactFound()) return;
459  _Collide(b0->GetPos(), b1);
460  }
461  else
462  {
463  _Collide(b0, b1->GetNeg());
464  if(ContactFound()) return;
465  _Collide(b0, b1->GetPos());
466  }
467 }
468 #endif
469 
470 #ifdef ALTERNATIVE_CODE
471 
479 {
480  // Perform BV-BV overlap test
481  if(!BoxBoxOverlap(b0->mAABB.mExtents, b0->mAABB.mCenter, b1->mAABB.mExtents, b1->mAABB.mCenter))
482  {
483  return;
484  }
485 
486  if(b0->IsLeaf())
487  {
488  if(b1->IsLeaf())
489  {
490  PrimTest(b0->GetPrimitive(), b1->GetPrimitive());
491  }
492  else
493  {
494  _Collide(b0, b1->GetNeg());
495  if(ContactFound()) return;
496  _Collide(b0, b1->GetPos());
497  }
498  }
499  else if(b1->IsLeaf())
500  {
501  _Collide(b0->GetNeg(), b1);
502  if(ContactFound()) return;
503  _Collide(b0->GetPos(), b1);
504  }
505  else
506  {
507  _Collide(b0->GetNeg(), b1->GetNeg());
508  if(ContactFound()) return;
509  _Collide(b0->GetNeg(), b1->GetPos());
510  if(ContactFound()) return;
511  _Collide(b0->GetPos(), b1->GetNeg());
512  if(ContactFound()) return;
513  _Collide(b0->GetPos(), b1->GetPos());
514  }
515 }
516 #endif
517 
519 // No-leaf trees
521 
523 
530 {
531  // Request vertices from the app
532  VertexPointers VP0;
533  VertexPointers VP1;
534  mIMesh0->GetTriangle(VP0, id0);
535  mIMesh1->GetTriangle(VP1, id1);
536 
537  // Transform from space 1 to space 0
538  Point u0,u1,u2;
539  TransformPoint(u0, *VP1.Vertex[0], mR1to0, mT1to0);
540  TransformPoint(u1, *VP1.Vertex[1], mR1to0, mT1to0);
541  TransformPoint(u2, *VP1.Vertex[2], mR1to0, mT1to0);
542 
543  // Perform triangle-triangle overlap test
544  if(TriTriOverlap(*VP0.Vertex[0], *VP0.Vertex[1], *VP0.Vertex[2], u0, u1, u2))
545  {
546  // Keep track of colliding pairs
547  mPairs.Add(id0).Add(id1);
548  // Set contact status
549  mFlags |= OPC_CONTACT;
550  }
551 }
552 
554 
560 {
561  // Request vertices from the app
562  VertexPointers VP;
563  mIMesh1->GetTriangle(VP, id1);
564 
565  // Perform triangle-triangle overlap test
566  if(TriTriOverlap(mLeafVerts[0], mLeafVerts[1], mLeafVerts[2], *VP.Vertex[0], *VP.Vertex[1], *VP.Vertex[2]))
567  {
568  // Keep track of colliding pairs
569  mPairs.Add(mLeafIndex).Add(id1);
570  // Set contact status
571  mFlags |= OPC_CONTACT;
572  }
573 }
574 
576 
582 {
583  // Request vertices from the app
584  VertexPointers VP;
585  mIMesh0->GetTriangle(VP, id0);
586 
587  // Perform triangle-triangle overlap test
588  if(TriTriOverlap(mLeafVerts[0], mLeafVerts[1], mLeafVerts[2], *VP.Vertex[0], *VP.Vertex[1], *VP.Vertex[2]))
589  {
590  // Keep track of colliding pairs
591  mPairs.Add(id0).Add(mLeafIndex);
592  // Set contact status
593  mFlags |= OPC_CONTACT;
594  }
595 }
596 
598 
604 {
605  // Perform triangle-box overlap test
606  if(!TriBoxOverlap(b->mAABB.mCenter, b->mAABB.mExtents)) return;
607 
608  // Keep same triangle, deal with first child
609  if(b->HasPosLeaf()) PrimTestTriIndex(b->GetPosPrimitive());
610  else _CollideTriBox(b->GetPos());
611 
612  if(ContactFound()) return;
613 
614  // Keep same triangle, deal with second child
615  if(b->HasNegLeaf()) PrimTestTriIndex(b->GetNegPrimitive());
616  else _CollideTriBox(b->GetNeg());
617 }
618 
620 
626 {
627  // Perform triangle-box overlap test
628  if(!TriBoxOverlap(b->mAABB.mCenter, b->mAABB.mExtents)) return;
629 
630  // Keep same triangle, deal with first child
631  if(b->HasPosLeaf()) PrimTestIndexTri(b->GetPosPrimitive());
632  else _CollideBoxTri(b->GetPos());
633 
634  if(ContactFound()) return;
635 
636  // Keep same triangle, deal with second child
637  if(b->HasNegLeaf()) PrimTestIndexTri(b->GetNegPrimitive());
638  else _CollideBoxTri(b->GetNeg());
639 }
640 
642 #define FETCH_LEAF(prim_index, imesh, rot, trans) \
643  mLeafIndex = prim_index; \
644  /* Request vertices from the app */ \
645  VertexPointers VP; imesh->GetTriangle(VP, prim_index); \
646  /* Transform them in a common space */ \
647  TransformPoint(mLeafVerts[0], *VP.Vertex[0], rot, trans); \
648  TransformPoint(mLeafVerts[1], *VP.Vertex[1], rot, trans); \
649  TransformPoint(mLeafVerts[2], *VP.Vertex[2], rot, trans);
650 
652 
659 {
660  // Perform BV-BV overlap test
661  if(!BoxBoxOverlap(a->mAABB.mExtents, a->mAABB.mCenter, b->mAABB.mExtents, b->mAABB.mCenter)) return;
662 
663  // Catch leaf status
664  BOOL BHasPosLeaf = b->HasPosLeaf();
665  BOOL BHasNegLeaf = b->HasNegLeaf();
666 
667  if(a->HasPosLeaf())
668  {
669  FETCH_LEAF(a->GetPosPrimitive(), mIMesh0, mR0to1, mT0to1)
670 
671  if(BHasPosLeaf) PrimTestTriIndex(b->GetPosPrimitive());
672  else _CollideTriBox(b->GetPos());
673 
674  if(ContactFound()) return;
675 
676  if(BHasNegLeaf) PrimTestTriIndex(b->GetNegPrimitive());
677  else _CollideTriBox(b->GetNeg());
678  }
679  else
680  {
681  if(BHasPosLeaf)
682  {
683  FETCH_LEAF(b->GetPosPrimitive(), mIMesh1, mR1to0, mT1to0)
684 
685  _CollideBoxTri(a->GetPos());
686  }
687  else _Collide(a->GetPos(), b->GetPos());
688 
689  if(ContactFound()) return;
690 
691  if(BHasNegLeaf)
692  {
693  FETCH_LEAF(b->GetNegPrimitive(), mIMesh1, mR1to0, mT1to0)
694 
695  _CollideBoxTri(a->GetPos());
696  }
697  else _Collide(a->GetPos(), b->GetNeg());
698  }
699 
700  if(ContactFound()) return;
701 
702  if(a->HasNegLeaf())
703  {
704  FETCH_LEAF(a->GetNegPrimitive(), mIMesh0, mR0to1, mT0to1)
705 
706  if(BHasPosLeaf) PrimTestTriIndex(b->GetPosPrimitive());
707  else _CollideTriBox(b->GetPos());
708 
709  if(ContactFound()) return;
710 
711  if(BHasNegLeaf) PrimTestTriIndex(b->GetNegPrimitive());
712  else _CollideTriBox(b->GetNeg());
713  }
714  else
715  {
716  if(BHasPosLeaf)
717  {
718  // ### That leaf has possibly already been fetched
719  FETCH_LEAF(b->GetPosPrimitive(), mIMesh1, mR1to0, mT1to0)
720 
721  _CollideBoxTri(a->GetNeg());
722  }
723  else _Collide(a->GetNeg(), b->GetPos());
724 
725  if(ContactFound()) return;
726 
727  if(BHasNegLeaf)
728  {
729  // ### That leaf has possibly already been fetched
730  FETCH_LEAF(b->GetNegPrimitive(), mIMesh1, mR1to0, mT1to0)
731 
732  _CollideBoxTri(a->GetNeg());
733  }
734  else _Collide(a->GetNeg(), b->GetNeg());
735  }
736 }
737 
739 // Quantized trees
741 
743 
752 void AABBTreeCollider::_Collide(const AABBQuantizedNode* b0, const AABBQuantizedNode* b1, const Point& a, const Point& Pa, const Point& b, const Point& Pb)
754 {
755  // Perform BV-BV overlap test
756  if(!BoxBoxOverlap(a, Pa, b, Pb)) return;
757 
758  if(b0->IsLeaf() && b1->IsLeaf()) { PrimTest(b0->GetPrimitive(), b1->GetPrimitive()); return; }
759 
760  if(b1->IsLeaf() || (!b0->IsLeaf() && (b0->GetSize() > b1->GetSize())))
761  {
762  // Dequantize box
763  const QuantizedAABB* Box = &b0->GetNeg()->mAABB;
764  const Point negPa(float(Box->mCenter[0]) * mCenterCoeff0.x, float(Box->mCenter[1]) * mCenterCoeff0.y, float(Box->mCenter[2]) * mCenterCoeff0.z);
765  const Point nega(float(Box->mExtents[0]) * mExtentsCoeff0.x, float(Box->mExtents[1]) * mExtentsCoeff0.y, float(Box->mExtents[2]) * mExtentsCoeff0.z);
766  _Collide(b0->GetNeg(), b1, nega, negPa, b, Pb);
767 
768  if(ContactFound()) return;
769 
770  // Dequantize box
771  Box = &b0->GetPos()->mAABB;
772  const Point posPa(float(Box->mCenter[0]) * mCenterCoeff0.x, float(Box->mCenter[1]) * mCenterCoeff0.y, float(Box->mCenter[2]) * mCenterCoeff0.z);
773  const Point posa(float(Box->mExtents[0]) * mExtentsCoeff0.x, float(Box->mExtents[1]) * mExtentsCoeff0.y, float(Box->mExtents[2]) * mExtentsCoeff0.z);
774  _Collide(b0->GetPos(), b1, posa, posPa, b, Pb);
775  }
776  else
777  {
778  // Dequantize box
779  const QuantizedAABB* Box = &b1->GetNeg()->mAABB;
780  const Point negPb(float(Box->mCenter[0]) * mCenterCoeff1.x, float(Box->mCenter[1]) * mCenterCoeff1.y, float(Box->mCenter[2]) * mCenterCoeff1.z);
781  const Point negb(float(Box->mExtents[0]) * mExtentsCoeff1.x, float(Box->mExtents[1]) * mExtentsCoeff1.y, float(Box->mExtents[2]) * mExtentsCoeff1.z);
782  _Collide(b0, b1->GetNeg(), a, Pa, negb, negPb);
783 
784  if(ContactFound()) return;
785 
786  // Dequantize box
787  Box = &b1->GetPos()->mAABB;
788  const Point posPb(float(Box->mCenter[0]) * mCenterCoeff1.x, float(Box->mCenter[1]) * mCenterCoeff1.y, float(Box->mCenter[2]) * mCenterCoeff1.z);
789  const Point posb(float(Box->mExtents[0]) * mExtentsCoeff1.x, float(Box->mExtents[1]) * mExtentsCoeff1.y, float(Box->mExtents[2]) * mExtentsCoeff1.z);
790  _Collide(b0, b1->GetPos(), a, Pa, posb, posPb);
791  }
792 }
793 
795 // Quantized no-leaf trees
797 
799 
806 {
807  // Dequantize box
808  const QuantizedAABB* bb = &b->mAABB;
809  const Point Pb(float(bb->mCenter[0]) * mCenterCoeff1.x, float(bb->mCenter[1]) * mCenterCoeff1.y, float(bb->mCenter[2]) * mCenterCoeff1.z);
810  const Point eb(float(bb->mExtents[0]) * mExtentsCoeff1.x, float(bb->mExtents[1]) * mExtentsCoeff1.y, float(bb->mExtents[2]) * mExtentsCoeff1.z);
811 
812  // Perform triangle-box overlap test
813  if(!TriBoxOverlap(Pb, eb)) return;
814 
815  if(b->HasPosLeaf()) PrimTestTriIndex(b->GetPosPrimitive());
816  else _CollideTriBox(b->GetPos());
817 
818  if(ContactFound()) return;
819 
820  if(b->HasNegLeaf()) PrimTestTriIndex(b->GetNegPrimitive());
821  else _CollideTriBox(b->GetNeg());
822 }
823 
825 
832 {
833  // Dequantize box
834  const QuantizedAABB* bb = &b->mAABB;
835  const Point Pa(float(bb->mCenter[0]) * mCenterCoeff0.x, float(bb->mCenter[1]) * mCenterCoeff0.y, float(bb->mCenter[2]) * mCenterCoeff0.z);
836  const Point ea(float(bb->mExtents[0]) * mExtentsCoeff0.x, float(bb->mExtents[1]) * mExtentsCoeff0.y, float(bb->mExtents[2]) * mExtentsCoeff0.z);
837 
838  // Perform triangle-box overlap test
839  if(!TriBoxOverlap(Pa, ea)) return;
840 
841  if(b->HasPosLeaf()) PrimTestIndexTri(b->GetPosPrimitive());
842  else _CollideBoxTri(b->GetPos());
843 
844  if(ContactFound()) return;
845 
846  if(b->HasNegLeaf()) PrimTestIndexTri(b->GetNegPrimitive());
847  else _CollideBoxTri(b->GetNeg());
848 }
849 
851 
858 {
859  // Dequantize box A
860  const QuantizedAABB* ab = &a->mAABB;
861  const Point Pa(float(ab->mCenter[0]) * mCenterCoeff0.x, float(ab->mCenter[1]) * mCenterCoeff0.y, float(ab->mCenter[2]) * mCenterCoeff0.z);
862  const Point ea(float(ab->mExtents[0]) * mExtentsCoeff0.x, float(ab->mExtents[1]) * mExtentsCoeff0.y, float(ab->mExtents[2]) * mExtentsCoeff0.z);
863  // Dequantize box B
864  const QuantizedAABB* bb = &b->mAABB;
865  const Point Pb(float(bb->mCenter[0]) * mCenterCoeff1.x, float(bb->mCenter[1]) * mCenterCoeff1.y, float(bb->mCenter[2]) * mCenterCoeff1.z);
866  const Point eb(float(bb->mExtents[0]) * mExtentsCoeff1.x, float(bb->mExtents[1]) * mExtentsCoeff1.y, float(bb->mExtents[2]) * mExtentsCoeff1.z);
867 
868  // Perform BV-BV overlap test
869  if(!BoxBoxOverlap(ea, Pa, eb, Pb)) return;
870 
871  // Catch leaf status
872  BOOL BHasPosLeaf = b->HasPosLeaf();
873  BOOL BHasNegLeaf = b->HasNegLeaf();
874 
875  if(a->HasPosLeaf())
876  {
877  FETCH_LEAF(a->GetPosPrimitive(), mIMesh0, mR0to1, mT0to1)
878 
879  if(BHasPosLeaf) PrimTestTriIndex(b->GetPosPrimitive());
880  else _CollideTriBox(b->GetPos());
881 
882  if(ContactFound()) return;
883 
884  if(BHasNegLeaf) PrimTestTriIndex(b->GetNegPrimitive());
885  else _CollideTriBox(b->GetNeg());
886  }
887  else
888  {
889  if(BHasPosLeaf)
890  {
891  FETCH_LEAF(b->GetPosPrimitive(), mIMesh1, mR1to0, mT1to0)
892 
893  _CollideBoxTri(a->GetPos());
894  }
895  else _Collide(a->GetPos(), b->GetPos());
896 
897  if(ContactFound()) return;
898 
899  if(BHasNegLeaf)
900  {
901  FETCH_LEAF(b->GetNegPrimitive(), mIMesh1, mR1to0, mT1to0)
902 
903  _CollideBoxTri(a->GetPos());
904  }
905  else _Collide(a->GetPos(), b->GetNeg());
906  }
907 
908  if(ContactFound()) return;
909 
910  if(a->HasNegLeaf())
911  {
912  FETCH_LEAF(a->GetNegPrimitive(), mIMesh0, mR0to1, mT0to1)
913 
914  if(BHasPosLeaf) PrimTestTriIndex(b->GetPosPrimitive());
915  else _CollideTriBox(b->GetPos());
916 
917  if(ContactFound()) return;
918 
919  if(BHasNegLeaf) PrimTestTriIndex(b->GetNegPrimitive());
920  else _CollideTriBox(b->GetNeg());
921  }
922  else
923  {
924  if(BHasPosLeaf)
925  {
926  // ### That leaf has possibly already been fetched
927  FETCH_LEAF(b->GetPosPrimitive(), mIMesh1, mR1to0, mT1to0)
928 
929  _CollideBoxTri(a->GetNeg());
930  }
931  else _Collide(a->GetNeg(), b->GetPos());
932 
933  if(ContactFound()) return;
934 
935  if(BHasNegLeaf)
936  {
937  // ### That leaf has possibly already been fetched
938  FETCH_LEAF(b->GetNegPrimitive(), mIMesh1, mR1to0, mT1to0)
939 
940  _CollideBoxTri(a->GetNeg());
941  }
942  else _Collide(a->GetNeg(), b->GetNeg());
943  }
944 }
945