2 * OPCODE - Optimized Collision Detection
3 * http://www.codercorner.com/Opcode.htm
5 * Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
7 This software is provided 'as-is', without any express or implied warranty.
8 In no event will the authors be held liable for any damages arising from the use of this software.
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute it freely,
11 subject to the following restrictions:
13 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
14 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
15 3. This notice may not be removed or altered from any source distribution.
18 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
20 * Contains code for an LSS collider.
21 * \file OPC_LSSCollider.cpp
22 * \author Pierre Terdiman
23 * \date December, 28, 2002
25 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
27 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
29 * Contains a lss-vs-tree collider.
32 * \author Pierre Terdiman
34 * \date December, 28, 2002
36 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
38 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
42 using namespace Opcode;
44 #include "OPC_LSSAABBOverlap.h"
45 #include "OPC_LSSTriOverlap.h"
47 #define SET_CONTACT(prim_index, flag) \
48 /* Set contact status */ \
50 mTouchedPrimitives->Add(prim_index);
52 //! LSS-triangle overlap test
53 #define LSS_PRIM(prim_index, flag) \
54 /* Request vertices from the app */ \
55 VertexPointers VP; mIMesh->GetTriangle(VP, prim_index); \
57 /* Perform LSS-tri overlap test */ \
58 if(LSSTriOverlap(*VP.Vertex[0], *VP.Vertex[1], *VP.Vertex[2])) \
60 SET_CONTACT(prim_index, flag) \
63 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
67 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
68 LSSCollider::LSSCollider()
74 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
78 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
79 LSSCollider::~LSSCollider()
83 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
85 * Generic collision query for generic OPCODE models. After the call, access the results:
86 * - with GetContactStatus()
87 * - with GetNbTouchedPrimitives()
88 * - with GetTouchedPrimitives()
90 * \param cache [in/out] an lss cache
91 * \param lss [in] collision lss in local space
92 * \param model [in] Opcode model to collide with
93 * \param worldl [in] lss world matrix, or null
94 * \param worldm [in] model's world matrix, or null
95 * \return true if success
96 * \warning SCALE NOT SUPPORTED. The matrices must contain rotation & translation parts only.
98 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
99 bool LSSCollider::Collide(LSSCache& cache, const LSS& lss, const Model& model, const Matrix4x4* worldl, const Matrix4x4* worldm)
102 if(!Setup(&model)) return false;
104 // Init collision query
105 if(InitQuery(cache, lss, worldl, worldm)) return true;
107 if(!model.HasLeafNodes())
109 if(model.IsQuantized())
111 const AABBQuantizedNoLeafTree* Tree = (const AABBQuantizedNoLeafTree*)model.GetTree();
113 // Setup dequantization coeffs
114 mCenterCoeff = Tree->mCenterCoeff;
115 mExtentsCoeff = Tree->mExtentsCoeff;
117 // Perform collision query
118 if(SkipPrimitiveTests()) _CollideNoPrimitiveTest(Tree->GetNodes());
119 else _Collide(Tree->GetNodes());
123 const AABBNoLeafTree* Tree = (const AABBNoLeafTree*)model.GetTree();
125 // Perform collision query
126 if(SkipPrimitiveTests()) _CollideNoPrimitiveTest(Tree->GetNodes());
127 else _Collide(Tree->GetNodes());
132 if(model.IsQuantized())
134 const AABBQuantizedTree* Tree = (const AABBQuantizedTree*)model.GetTree();
136 // Setup dequantization coeffs
137 mCenterCoeff = Tree->mCenterCoeff;
138 mExtentsCoeff = Tree->mExtentsCoeff;
140 // Perform collision query
141 if(SkipPrimitiveTests()) _CollideNoPrimitiveTest(Tree->GetNodes());
142 else _Collide(Tree->GetNodes());
146 const AABBCollisionTree* Tree = (const AABBCollisionTree*)model.GetTree();
148 // Perform collision query
149 if(SkipPrimitiveTests()) _CollideNoPrimitiveTest(Tree->GetNodes());
150 else _Collide(Tree->GetNodes());
157 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
159 * Initializes a collision query :
160 * - reset stats & contact status
162 * - check temporal coherence
164 * \param cache [in/out] an lss cache
165 * \param lss [in] lss in local space
166 * \param worldl [in] lss world matrix, or null
167 * \param worldm [in] model's world matrix, or null
168 * \return TRUE if we can return immediately
169 * \warning SCALE NOT SUPPORTED. The matrices must contain rotation & translation parts only.
171 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
172 BOOL LSSCollider::InitQuery(LSSCache& cache, const LSS& lss, const Matrix4x4* worldl, const Matrix4x4* worldm)
174 // 1) Call the base method
175 VolumeCollider::InitQuery();
177 // 2) Compute LSS in model space:
179 mRadius2 = lss.mRadius * lss.mRadius;
192 // Invert model matrix
194 InvertPRMatrix(InvWorldM, *worldm);
196 mSeg.mP0 *= InvWorldM;
197 mSeg.mP1 *= InvWorldM;
200 // 3) Setup destination pointer
201 mTouchedPrimitives = &cache.TouchedPrimitives;
203 // 4) Special case: 1-triangle meshes [Opcode 1.3]
204 if(mCurrentModel && mCurrentModel->HasSingleNode())
206 if(!SkipPrimitiveTests())
208 // We simply perform the BV-Prim overlap test each time. We assume single triangle has index 0.
209 mTouchedPrimitives->Reset();
211 // Perform overlap test between the unique triangle and the LSS (and set contact status if needed)
212 LSS_PRIM(udword(0), OPC_CONTACT)
214 // Return immediately regardless of status
219 // 5) Check temporal coherence :
220 if(TemporalCoherenceEnabled())
222 // Here we use temporal coherence
223 // => check results from previous frame before performing the collision query
224 if(FirstContactEnabled())
226 // We're only interested in the first contact found => test the unique previously touched face
227 if(mTouchedPrimitives->GetNbEntries())
229 // Get index of previously touched face = the first entry in the array
230 udword PreviouslyTouchedFace = mTouchedPrimitives->GetEntry(0);
232 // Then reset the array:
233 // - if the overlap test below is successful, the index we'll get added back anyway
234 // - if it isn't, then the array should be reset anyway for the normal query
235 mTouchedPrimitives->Reset();
237 // Perform overlap test between the cached triangle and the LSS (and set contact status if needed)
238 LSS_PRIM(PreviouslyTouchedFace, OPC_TEMPORAL_CONTACT)
240 // Return immediately if possible
241 if(GetContactStatus()) return TRUE;
243 // else no face has been touched during previous query
244 // => we'll have to perform a normal query
248 // We're interested in all contacts =>test the new real LSS N(ew) against the previous fat LSS P(revious):
252 LSS Test(mSeg, lss.mRadius); // in model space
253 LSS Previous(cache.Previous, sqrtf(cache.Previous.mRadius));
255 // if(cache.Previous.Contains(Test))
256 if(IsCacheValid(cache) && Previous.Contains(Test))
258 // - if N is included in P, return previous list
259 // => we simply leave the list (mTouchedFaces) unchanged
261 // Set contact status if needed
262 if(mTouchedPrimitives->GetNbEntries()) mFlags |= OPC_TEMPORAL_CONTACT;
264 // In any case we don't need to do a query
269 // - else do the query using a fat N
271 // Reset cache since we'll about to perform a real query
272 mTouchedPrimitives->Reset();
274 // Make a fat sphere so that coherence will work for subsequent frames
275 mRadius2 *= cache.FatCoeff;
276 // mRadius2 = (lss.mRadius * cache.FatCoeff)*(lss.mRadius * cache.FatCoeff);
279 // Update cache with query data (signature for cached faces)
280 cache.Previous.mP0 = mSeg.mP0;
281 cache.Previous.mP1 = mSeg.mP1;
282 cache.Previous.mRadius = mRadius2;
288 // Here we don't use temporal coherence => do a normal query
289 mTouchedPrimitives->Reset();
295 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
297 * Collision query for vanilla AABB trees.
298 * \param cache [in/out] an lss cache
299 * \param lss [in] collision lss in world space
300 * \param tree [in] AABB tree
301 * \return true if success
303 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
304 bool LSSCollider::Collide(LSSCache& cache, const LSS& lss, const AABBTree* tree)
306 // This is typically called for a scene tree, full of -AABBs-, not full of triangles.
307 // So we don't really have "primitives" to deal with. Hence it doesn't work with
308 // "FirstContact" + "TemporalCoherence".
309 ASSERT( !(FirstContactEnabled() && TemporalCoherenceEnabled()) );
312 if(!tree) return false;
314 // Init collision query
315 if(InitQuery(cache, lss)) return true;
317 // Perform collision query
323 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
325 * Checks the LSS completely contains the box. In which case we can end the query sooner.
326 * \param bc [in] box center
327 * \param be [in] box extents
328 * \return true if the LSS contains the whole box
330 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
331 inline_ BOOL LSSCollider::LSSContainsBox(const Point& bc, const Point& be)
337 #define TEST_BOX_IN_LSS(center, extents) \
338 if(LSSContainsBox(center, extents)) \
340 /* Set contact status */ \
341 mFlags |= OPC_CONTACT; \
346 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
348 * Recursive collision query for normal AABB trees.
349 * \param node [in] current collision node
351 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
352 void LSSCollider::_Collide(const AABBCollisionNode* node)
354 // Perform LSS-AABB overlap test
355 if(!LSSAABBOverlap(node->mAABB.mCenter, node->mAABB.mExtents)) return;
357 TEST_BOX_IN_LSS(node->mAABB.mCenter, node->mAABB.mExtents)
361 LSS_PRIM(node->GetPrimitive(), OPC_CONTACT)
365 _Collide(node->GetPos());
367 if(ContactFound()) return;
369 _Collide(node->GetNeg());
373 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
375 * Recursive collision query for normal AABB trees, without primitive tests.
376 * \param node [in] current collision node
378 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
379 void LSSCollider::_CollideNoPrimitiveTest(const AABBCollisionNode* node)
381 // Perform LSS-AABB overlap test
382 if(!LSSAABBOverlap(node->mAABB.mCenter, node->mAABB.mExtents)) return;
384 TEST_BOX_IN_LSS(node->mAABB.mCenter, node->mAABB.mExtents)
388 SET_CONTACT(node->GetPrimitive(), OPC_CONTACT)
392 _CollideNoPrimitiveTest(node->GetPos());
394 if(ContactFound()) return;
396 _CollideNoPrimitiveTest(node->GetNeg());
400 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
402 * Recursive collision query for quantized AABB trees.
403 * \param node [in] current collision node
405 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
406 void LSSCollider::_Collide(const AABBQuantizedNode* node)
409 const QuantizedAABB& Box = node->mAABB;
410 const Point Center(float(Box.mCenter[0]) * mCenterCoeff.x, float(Box.mCenter[1]) * mCenterCoeff.y, float(Box.mCenter[2]) * mCenterCoeff.z);
411 const Point Extents(float(Box.mExtents[0]) * mExtentsCoeff.x, float(Box.mExtents[1]) * mExtentsCoeff.y, float(Box.mExtents[2]) * mExtentsCoeff.z);
413 // Perform LSS-AABB overlap test
414 if(!LSSAABBOverlap(Center, Extents)) return;
416 TEST_BOX_IN_LSS(Center, Extents)
420 LSS_PRIM(node->GetPrimitive(), OPC_CONTACT)
424 _Collide(node->GetPos());
426 if(ContactFound()) return;
428 _Collide(node->GetNeg());
432 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
434 * Recursive collision query for quantized AABB trees, without primitive tests.
435 * \param node [in] current collision node
437 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
438 void LSSCollider::_CollideNoPrimitiveTest(const AABBQuantizedNode* node)
441 const QuantizedAABB& Box = node->mAABB;
442 const Point Center(float(Box.mCenter[0]) * mCenterCoeff.x, float(Box.mCenter[1]) * mCenterCoeff.y, float(Box.mCenter[2]) * mCenterCoeff.z);
443 const Point Extents(float(Box.mExtents[0]) * mExtentsCoeff.x, float(Box.mExtents[1]) * mExtentsCoeff.y, float(Box.mExtents[2]) * mExtentsCoeff.z);
445 // Perform LSS-AABB overlap test
446 if(!LSSAABBOverlap(Center, Extents)) return;
448 TEST_BOX_IN_LSS(Center, Extents)
452 SET_CONTACT(node->GetPrimitive(), OPC_CONTACT)
456 _CollideNoPrimitiveTest(node->GetPos());
458 if(ContactFound()) return;
460 _CollideNoPrimitiveTest(node->GetNeg());
464 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
466 * Recursive collision query for no-leaf AABB trees.
467 * \param node [in] current collision node
469 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
470 void LSSCollider::_Collide(const AABBNoLeafNode* node)
472 // Perform LSS-AABB overlap test
473 if(!LSSAABBOverlap(node->mAABB.mCenter, node->mAABB.mExtents)) return;
475 TEST_BOX_IN_LSS(node->mAABB.mCenter, node->mAABB.mExtents)
477 if(node->HasPosLeaf()) { LSS_PRIM(node->GetPosPrimitive(), OPC_CONTACT) }
478 else _Collide(node->GetPos());
480 if(ContactFound()) return;
482 if(node->HasNegLeaf()) { LSS_PRIM(node->GetNegPrimitive(), OPC_CONTACT) }
483 else _Collide(node->GetNeg());
486 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
488 * Recursive collision query for no-leaf AABB trees, without primitive tests.
489 * \param node [in] current collision node
491 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
492 void LSSCollider::_CollideNoPrimitiveTest(const AABBNoLeafNode* node)
494 // Perform LSS-AABB overlap test
495 if(!LSSAABBOverlap(node->mAABB.mCenter, node->mAABB.mExtents)) return;
497 TEST_BOX_IN_LSS(node->mAABB.mCenter, node->mAABB.mExtents)
499 if(node->HasPosLeaf()) { SET_CONTACT(node->GetPosPrimitive(), OPC_CONTACT) }
500 else _CollideNoPrimitiveTest(node->GetPos());
502 if(ContactFound()) return;
504 if(node->HasNegLeaf()) { SET_CONTACT(node->GetNegPrimitive(), OPC_CONTACT) }
505 else _CollideNoPrimitiveTest(node->GetNeg());
508 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
510 * Recursive collision query for quantized no-leaf AABB trees.
511 * \param node [in] current collision node
513 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
514 void LSSCollider::_Collide(const AABBQuantizedNoLeafNode* node)
517 const QuantizedAABB& Box = node->mAABB;
518 const Point Center(float(Box.mCenter[0]) * mCenterCoeff.x, float(Box.mCenter[1]) * mCenterCoeff.y, float(Box.mCenter[2]) * mCenterCoeff.z);
519 const Point Extents(float(Box.mExtents[0]) * mExtentsCoeff.x, float(Box.mExtents[1]) * mExtentsCoeff.y, float(Box.mExtents[2]) * mExtentsCoeff.z);
521 // Perform LSS-AABB overlap test
522 if(!LSSAABBOverlap(Center, Extents)) return;
524 TEST_BOX_IN_LSS(Center, Extents)
526 if(node->HasPosLeaf()) { LSS_PRIM(node->GetPosPrimitive(), OPC_CONTACT) }
527 else _Collide(node->GetPos());
529 if(ContactFound()) return;
531 if(node->HasNegLeaf()) { LSS_PRIM(node->GetNegPrimitive(), OPC_CONTACT) }
532 else _Collide(node->GetNeg());
535 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
537 * Recursive collision query for quantized no-leaf AABB trees, without primitive tests.
538 * \param node [in] current collision node
540 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
541 void LSSCollider::_CollideNoPrimitiveTest(const AABBQuantizedNoLeafNode* node)
544 const QuantizedAABB& Box = node->mAABB;
545 const Point Center(float(Box.mCenter[0]) * mCenterCoeff.x, float(Box.mCenter[1]) * mCenterCoeff.y, float(Box.mCenter[2]) * mCenterCoeff.z);
546 const Point Extents(float(Box.mExtents[0]) * mExtentsCoeff.x, float(Box.mExtents[1]) * mExtentsCoeff.y, float(Box.mExtents[2]) * mExtentsCoeff.z);
548 // Perform LSS-AABB overlap test
549 if(!LSSAABBOverlap(Center, Extents)) return;
551 TEST_BOX_IN_LSS(Center, Extents)
553 if(node->HasPosLeaf()) { SET_CONTACT(node->GetPosPrimitive(), OPC_CONTACT) }
554 else _CollideNoPrimitiveTest(node->GetPos());
556 if(ContactFound()) return;
558 if(node->HasNegLeaf()) { SET_CONTACT(node->GetNegPrimitive(), OPC_CONTACT) }
559 else _CollideNoPrimitiveTest(node->GetNeg());
562 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
564 * Recursive collision query for vanilla AABB trees.
565 * \param node [in] current collision node
567 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
568 void LSSCollider::_Collide(const AABBTreeNode* node)
570 // Perform LSS-AABB overlap test
571 Point Center, Extents;
572 node->GetAABB()->GetCenter(Center);
573 node->GetAABB()->GetExtents(Extents);
574 if(!LSSAABBOverlap(Center, Extents)) return;
576 if(node->IsLeaf() || LSSContainsBox(Center, Extents))
578 mFlags |= OPC_CONTACT;
579 mTouchedPrimitives->Add(node->GetPrimitives(), node->GetNbPrimitives());
583 _Collide(node->GetPos());
584 _Collide(node->GetNeg());
593 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
597 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
598 HybridLSSCollider::HybridLSSCollider()
602 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
606 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
607 HybridLSSCollider::~HybridLSSCollider()
611 bool HybridLSSCollider::Collide(LSSCache& cache, const LSS& lss, const HybridModel& model, const Matrix4x4* worldl, const Matrix4x4* worldm)
613 // We don't want primitive tests here!
614 mFlags |= OPC_NO_PRIMITIVE_TESTS;
617 if(!Setup(&model)) return false;
619 // Init collision query
620 if(InitQuery(cache, lss, worldl, worldm)) return true;
622 // Special case for 1-leaf trees
623 if(mCurrentModel && mCurrentModel->HasSingleNode())
625 // Here we're supposed to perform a normal query, except our tree has a single node, i.e. just a few triangles
626 udword Nb = mIMesh->GetNbTriangles();
628 // Loop through all triangles
629 for(udword i=0;i<Nb;i++)
631 LSS_PRIM(i, OPC_CONTACT)
636 // Override destination array since we're only going to get leaf boxes here
637 mTouchedBoxes.Reset();
638 mTouchedPrimitives = &mTouchedBoxes;
640 // Now, do the actual query against leaf boxes
641 if(!model.HasLeafNodes())
643 if(model.IsQuantized())
645 const AABBQuantizedNoLeafTree* Tree = (const AABBQuantizedNoLeafTree*)model.GetTree();
647 // Setup dequantization coeffs
648 mCenterCoeff = Tree->mCenterCoeff;
649 mExtentsCoeff = Tree->mExtentsCoeff;
651 // Perform collision query - we don't want primitive tests here!
652 _CollideNoPrimitiveTest(Tree->GetNodes());
656 const AABBNoLeafTree* Tree = (const AABBNoLeafTree*)model.GetTree();
658 // Perform collision query - we don't want primitive tests here!
659 _CollideNoPrimitiveTest(Tree->GetNodes());
664 if(model.IsQuantized())
666 const AABBQuantizedTree* Tree = (const AABBQuantizedTree*)model.GetTree();
668 // Setup dequantization coeffs
669 mCenterCoeff = Tree->mCenterCoeff;
670 mExtentsCoeff = Tree->mExtentsCoeff;
672 // Perform collision query - we don't want primitive tests here!
673 _CollideNoPrimitiveTest(Tree->GetNodes());
677 const AABBCollisionTree* Tree = (const AABBCollisionTree*)model.GetTree();
679 // Perform collision query - we don't want primitive tests here!
680 _CollideNoPrimitiveTest(Tree->GetNodes());
684 // We only have a list of boxes so far
685 if(GetContactStatus())
687 // Reset contact status, since it currently only reflects collisions with leaf boxes
688 Collider::InitQuery();
690 // Change dest container so that we can use built-in overlap tests and get collided primitives
691 cache.TouchedPrimitives.Reset();
692 mTouchedPrimitives = &cache.TouchedPrimitives;
694 // Read touched leaf boxes
695 udword Nb = mTouchedBoxes.GetNbEntries();
696 const udword* Touched = mTouchedBoxes.GetEntries();
698 const LeafTriangles* LT = model.GetLeafTriangles();
699 const udword* Indices = model.GetIndices();
701 // Loop through touched leaves
704 const LeafTriangles& CurrentLeaf = LT[*Touched++];
706 // Each leaf box has a set of triangles
707 udword NbTris = CurrentLeaf.GetNbTriangles();
710 const udword* T = &Indices[CurrentLeaf.GetTriangleIndex()];
712 // Loop through triangles and test each of them
715 udword TriangleIndex = *T++;
716 LSS_PRIM(TriangleIndex, OPC_CONTACT)
721 udword BaseIndex = CurrentLeaf.GetTriangleIndex();
723 // Loop through triangles and test each of them
726 udword TriangleIndex = BaseIndex++;
727 LSS_PRIM(TriangleIndex, OPC_CONTACT)