1 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3 * OPCODE - Optimized Collision Detection
4 * Copyright (C) 2001 Pierre Terdiman
5 * Homepage: http://www.codercorner.com/Opcode.htm
7 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
9 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
11 * Contains code for a planes collider.
12 * \file OPC_PlanesCollider.cpp
13 * \author Pierre Terdiman
14 * \date January, 1st, 2002
16 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
18 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
20 * Contains a Planes-vs-tree collider.
22 * \class PlanesCollider
23 * \author Pierre Terdiman
25 * \date January, 1st, 2002
27 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
29 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
33 using namespace Opcode
;
35 #include "OPC_PlanesAABBOverlap.h"
36 #include "OPC_PlanesTriOverlap.h"
38 #define SET_CONTACT(prim_index, flag) \
39 /* Set contact status */ \
41 mTouchedPrimitives->Add(udword(prim_index));
43 //! Planes-triangle test
44 #define PLANES_PRIM(prim_index, flag) \
45 /* Request vertices from the app */ \
46 mIMesh->GetTriangle(mVP, prim_index, mVC); \
47 /* Perform triangle-box overlap test */ \
48 if(PlanesTriOverlap(clip_mask)) \
50 SET_CONTACT(prim_index, flag) \
53 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
57 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
58 PlanesCollider::PlanesCollider() :
64 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
68 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
69 PlanesCollider::~PlanesCollider()
74 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
76 * Validates current settings. You should call this method after all the settings and callbacks have been defined.
77 * \return null if everything is ok, else a string describing the problem
79 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
80 const char* PlanesCollider::ValidateSettings()
82 if(TemporalCoherenceEnabled() && !FirstContactEnabled()) return "Temporal coherence only works with ""First contact"" mode!";
84 return VolumeCollider::ValidateSettings();
87 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
89 * Generic collision query for generic OPCODE models. After the call, access the results:
90 * - with GetContactStatus()
91 * - with GetNbTouchedPrimitives()
92 * - with GetTouchedPrimitives()
94 * \param cache [in/out] a planes cache
95 * \param planes [in] list of planes in world space
96 * \param nb_planes [in] number of planes
97 * \param model [in] Opcode model to collide with
98 * \param worldm [in] model's world matrix, or null
99 * \return true if success
100 * \warning SCALE NOT SUPPORTED. The matrices must contain rotation & translation parts only.
102 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
103 bool PlanesCollider::Collide(PlanesCache
& cache
, const Plane
* planes
, udword nb_planes
, const Model
& model
, const Matrix4x4
* worldm
)
106 if(!Setup(&model
)) return false;
108 // Init collision query
109 if(InitQuery(cache
, planes
, nb_planes
, worldm
)) return true;
111 udword PlaneMask
= (1<<nb_planes
)-1;
113 if(!model
.HasLeafNodes())
115 if(model
.IsQuantized())
117 const AABBQuantizedNoLeafTree
* Tree
= static_cast<const AABBQuantizedNoLeafTree
*>(model
.GetTree());
119 // Setup dequantization coeffs
120 mCenterCoeff
= Tree
->mCenterCoeff
;
121 mExtentsCoeff
= Tree
->mExtentsCoeff
;
123 // Perform collision query
124 if(SkipPrimitiveTests()) _CollideNoPrimitiveTest(Tree
->GetNodes(), PlaneMask
);
125 else _Collide(Tree
->GetNodes(), PlaneMask
);
129 const AABBNoLeafTree
* Tree
= static_cast<const AABBNoLeafTree
*>(model
.GetTree());
131 // Perform collision query
132 if(SkipPrimitiveTests()) _CollideNoPrimitiveTest(Tree
->GetNodes(), PlaneMask
);
133 else _Collide(Tree
->GetNodes(), PlaneMask
);
138 if(model
.IsQuantized())
140 const AABBQuantizedTree
* Tree
= static_cast<const AABBQuantizedTree
*>(model
.GetTree());
142 // Setup dequantization coeffs
143 mCenterCoeff
= Tree
->mCenterCoeff
;
144 mExtentsCoeff
= Tree
->mExtentsCoeff
;
146 // Perform collision query
147 if(SkipPrimitiveTests()) _CollideNoPrimitiveTest(Tree
->GetNodes(), PlaneMask
);
148 else _Collide(Tree
->GetNodes(), PlaneMask
);
152 const AABBCollisionTree
* Tree
= static_cast<const AABBCollisionTree
*>(model
.GetTree());
154 // Perform collision query
155 if(SkipPrimitiveTests()) _CollideNoPrimitiveTest(Tree
->GetNodes(), PlaneMask
);
156 else _Collide(Tree
->GetNodes(), PlaneMask
);
162 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
164 * Initializes a collision query :
165 * - reset stats & contact status
166 * - compute planes in model space
167 * - check temporal coherence
169 * \param cache [in/out] a planes cache
170 * \param planes [in] list of planes
171 * \param nb_planes [in] number of planes
172 * \param worldm [in] model's world matrix, or null
173 * \return TRUE if we can return immediately
174 * \warning SCALE NOT SUPPORTED. The matrix must contain rotation & translation parts only.
176 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
177 BOOL
PlanesCollider::InitQuery(PlanesCache
& cache
, const Plane
* planes
, udword nb_planes
, const Matrix4x4
* worldm
)
179 // 1) Call the base method
180 VolumeCollider::InitQuery();
182 // 2) Compute planes in model space
183 if(nb_planes
>mNbPlanes
)
185 DELETEARRAY(mPlanes
);
186 mPlanes
= new Plane
[nb_planes
];
188 mNbPlanes
= nb_planes
;
193 InvertPRMatrix(InvWorldM
, *worldm
);
195 // for(udword i=0;i<nb_planes;i++) mPlanes[i] = planes[i] * InvWorldM;
196 for(udword i
=0;i
<nb_planes
;i
++) TransformPlane(mPlanes
[i
], planes
[i
], InvWorldM
);
198 else CopyMemory(mPlanes
, planes
, nb_planes
*sizeof(Plane
));
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 planes (and set contact status if needed)
212 udword clip_mask
= (1<<mNbPlanes
)-1;
213 PLANES_PRIM(udword(0), OPC_CONTACT
)
215 // Return immediately regardless of status
220 // 4) Check temporal coherence:
221 if(TemporalCoherenceEnabled())
223 // Here we use temporal coherence
224 // => check results from previous frame before performing the collision query
225 if(FirstContactEnabled())
227 // We're only interested in the first contact found => test the unique previously touched face
228 if(mTouchedPrimitives
->GetNbEntries())
230 // Get index of previously touched face = the first entry in the array
231 udword PreviouslyTouchedFace
= mTouchedPrimitives
->GetEntry(0);
233 // Then reset the array:
234 // - if the overlap test below is successful, the index we'll get added back anyway
235 // - if it isn't, then the array should be reset anyway for the normal query
236 mTouchedPrimitives
->Reset();
238 // Perform overlap test between the cached triangle and the planes (and set contact status if needed)
239 udword clip_mask
= (1<<mNbPlanes
)-1;
240 PLANES_PRIM(PreviouslyTouchedFace
, OPC_TEMPORAL_CONTACT
)
242 // Return immediately if possible
243 if(GetContactStatus()) return TRUE
;
245 // else no face has been touched during previous query
246 // => we'll have to perform a normal query
248 else mTouchedPrimitives
->Reset();
252 // Here we don't use temporal coherence => do a normal query
253 mTouchedPrimitives
->Reset();
259 #define TEST_CLIP_MASK \
260 /* If the box is completely included, so are its children. We don't need to do extra tests, we */ \
261 /* can immediately output a list of visible children. Those ones won't need to be clipped. */ \
264 /* Set contact status */ \
265 mFlags |= OPC_CONTACT; \
270 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
272 * Recursive collision query for normal AABB trees.
273 * \param node [in] current collision node
275 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
276 void PlanesCollider::_Collide(const AABBCollisionNode
* node
, udword clip_mask
)
278 // Test the box against the planes. If the box is completely culled, so are its children, hence we exit.
280 if(!PlanesAABBOverlap(node
->mAABB
.mCenter
, node
->mAABB
.mExtents
, OutClipMask
, clip_mask
)) return;
284 // Else the box straddles one or several planes, so we need to recurse down the tree.
287 PLANES_PRIM(node
->GetPrimitive(), OPC_CONTACT
)
291 _Collide(node
->GetPos(), OutClipMask
);
293 if(ContactFound()) return;
295 _Collide(node
->GetNeg(), OutClipMask
);
299 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
301 * Recursive collision query for normal AABB trees.
302 * \param node [in] current collision node
304 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
305 void PlanesCollider::_CollideNoPrimitiveTest(const AABBCollisionNode
* node
, udword clip_mask
)
307 // Test the box against the planes. If the box is completely culled, so are its children, hence we exit.
309 if(!PlanesAABBOverlap(node
->mAABB
.mCenter
, node
->mAABB
.mExtents
, OutClipMask
, clip_mask
)) return;
313 // Else the box straddles one or several planes, so we need to recurse down the tree.
316 SET_CONTACT(node
->GetPrimitive(), OPC_CONTACT
)
320 _CollideNoPrimitiveTest(node
->GetPos(), OutClipMask
);
322 if(ContactFound()) return;
324 _CollideNoPrimitiveTest(node
->GetNeg(), OutClipMask
);
328 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
330 * Recursive collision query for quantized AABB trees.
331 * \param node [in] current collision node
333 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
334 void PlanesCollider::_Collide(const AABBQuantizedNode
* node
, udword clip_mask
)
337 const QuantizedAABB
& Box
= node
->mAABB
;
338 const Point
Center(float(Box
.mCenter
[0]) * mCenterCoeff
.x
, float(Box
.mCenter
[1]) * mCenterCoeff
.y
, float(Box
.mCenter
[2]) * mCenterCoeff
.z
);
339 const Point
Extents(float(Box
.mExtents
[0]) * mExtentsCoeff
.x
, float(Box
.mExtents
[1]) * mExtentsCoeff
.y
, float(Box
.mExtents
[2]) * mExtentsCoeff
.z
);
341 // Test the box against the planes. If the box is completely culled, so are its children, hence we exit.
343 if(!PlanesAABBOverlap(Center
, Extents
, OutClipMask
, clip_mask
)) return;
347 // Else the box straddles one or several planes, so we need to recurse down the tree.
350 PLANES_PRIM(node
->GetPrimitive(), OPC_CONTACT
)
354 _Collide(node
->GetPos(), OutClipMask
);
356 if(ContactFound()) return;
358 _Collide(node
->GetNeg(), OutClipMask
);
362 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
364 * Recursive collision query for quantized AABB trees.
365 * \param node [in] current collision node
367 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
368 void PlanesCollider::_CollideNoPrimitiveTest(const AABBQuantizedNode
* node
, udword clip_mask
)
371 const QuantizedAABB
& Box
= node
->mAABB
;
372 const Point
Center(float(Box
.mCenter
[0]) * mCenterCoeff
.x
, float(Box
.mCenter
[1]) * mCenterCoeff
.y
, float(Box
.mCenter
[2]) * mCenterCoeff
.z
);
373 const Point
Extents(float(Box
.mExtents
[0]) * mExtentsCoeff
.x
, float(Box
.mExtents
[1]) * mExtentsCoeff
.y
, float(Box
.mExtents
[2]) * mExtentsCoeff
.z
);
375 // Test the box against the planes. If the box is completely culled, so are its children, hence we exit.
377 if(!PlanesAABBOverlap(Center
, Extents
, OutClipMask
, clip_mask
)) return;
381 // Else the box straddles one or several planes, so we need to recurse down the tree.
384 SET_CONTACT(node
->GetPrimitive(), OPC_CONTACT
)
388 _CollideNoPrimitiveTest(node
->GetPos(), OutClipMask
);
390 if(ContactFound()) return;
392 _CollideNoPrimitiveTest(node
->GetNeg(), OutClipMask
);
396 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
398 * Recursive collision query for no-leaf AABB trees.
399 * \param node [in] current collision node
401 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
402 void PlanesCollider::_Collide(const AABBNoLeafNode
* node
, udword clip_mask
)
404 // Test the box against the planes. If the box is completely culled, so are its children, hence we exit.
406 if(!PlanesAABBOverlap(node
->mAABB
.mCenter
, node
->mAABB
.mExtents
, OutClipMask
, clip_mask
)) return;
410 // Else the box straddles one or several planes, so we need to recurse down the tree.
411 if(node
->HasPosLeaf()) { PLANES_PRIM(node
->GetPosPrimitive(), OPC_CONTACT
) }
412 else _Collide(node
->GetPos(), OutClipMask
);
414 if(ContactFound()) return;
416 if(node
->HasNegLeaf()) { PLANES_PRIM(node
->GetNegPrimitive(), OPC_CONTACT
) }
417 else _Collide(node
->GetNeg(), OutClipMask
);
420 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
422 * Recursive collision query for no-leaf AABB trees.
423 * \param node [in] current collision node
425 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
426 void PlanesCollider::_CollideNoPrimitiveTest(const AABBNoLeafNode
* node
, udword clip_mask
)
428 // Test the box against the planes. If the box is completely culled, so are its children, hence we exit.
430 if(!PlanesAABBOverlap(node
->mAABB
.mCenter
, node
->mAABB
.mExtents
, OutClipMask
, clip_mask
)) return;
434 // Else the box straddles one or several planes, so we need to recurse down the tree.
435 if(node
->HasPosLeaf()) { SET_CONTACT(node
->GetPosPrimitive(), OPC_CONTACT
) }
436 else _CollideNoPrimitiveTest(node
->GetPos(), OutClipMask
);
438 if(ContactFound()) return;
440 if(node
->HasNegLeaf()) { SET_CONTACT(node
->GetNegPrimitive(), OPC_CONTACT
) }
441 else _CollideNoPrimitiveTest(node
->GetNeg(), OutClipMask
);
444 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
446 * Recursive collision query for quantized no-leaf AABB trees.
447 * \param node [in] current collision node
449 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
450 void PlanesCollider::_Collide(const AABBQuantizedNoLeafNode
* node
, udword clip_mask
)
453 const QuantizedAABB
& Box
= node
->mAABB
;
454 const Point
Center(float(Box
.mCenter
[0]) * mCenterCoeff
.x
, float(Box
.mCenter
[1]) * mCenterCoeff
.y
, float(Box
.mCenter
[2]) * mCenterCoeff
.z
);
455 const Point
Extents(float(Box
.mExtents
[0]) * mExtentsCoeff
.x
, float(Box
.mExtents
[1]) * mExtentsCoeff
.y
, float(Box
.mExtents
[2]) * mExtentsCoeff
.z
);
457 // Test the box against the planes. If the box is completely culled, so are its children, hence we exit.
459 if(!PlanesAABBOverlap(Center
, Extents
, OutClipMask
, clip_mask
)) return;
463 // Else the box straddles one or several planes, so we need to recurse down the tree.
464 if(node
->HasPosLeaf()) { PLANES_PRIM(node
->GetPosPrimitive(), OPC_CONTACT
) }
465 else _Collide(node
->GetPos(), OutClipMask
);
467 if(ContactFound()) return;
469 if(node
->HasNegLeaf()) { PLANES_PRIM(node
->GetNegPrimitive(), OPC_CONTACT
) }
470 else _Collide(node
->GetNeg(), OutClipMask
);
473 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
475 * Recursive collision query for quantized no-leaf AABB trees.
476 * \param node [in] current collision node
478 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
479 void PlanesCollider::_CollideNoPrimitiveTest(const AABBQuantizedNoLeafNode
* node
, udword clip_mask
)
482 const QuantizedAABB
& Box
= node
->mAABB
;
483 const Point
Center(float(Box
.mCenter
[0]) * mCenterCoeff
.x
, float(Box
.mCenter
[1]) * mCenterCoeff
.y
, float(Box
.mCenter
[2]) * mCenterCoeff
.z
);
484 const Point
Extents(float(Box
.mExtents
[0]) * mExtentsCoeff
.x
, float(Box
.mExtents
[1]) * mExtentsCoeff
.y
, float(Box
.mExtents
[2]) * mExtentsCoeff
.z
);
486 // Test the box against the planes. If the box is completely culled, so are its children, hence we exit.
488 if(!PlanesAABBOverlap(Center
, Extents
, OutClipMask
, clip_mask
)) return;
492 // Else the box straddles one or several planes, so we need to recurse down the tree.
493 if(node
->HasPosLeaf()) { SET_CONTACT(node
->GetPosPrimitive(), OPC_CONTACT
) }
494 else _CollideNoPrimitiveTest(node
->GetPos(), OutClipMask
);
496 if(ContactFound()) return;
498 if(node
->HasNegLeaf()) { SET_CONTACT(node
->GetNegPrimitive(), OPC_CONTACT
) }
499 else _CollideNoPrimitiveTest(node
->GetNeg(), OutClipMask
);
508 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
512 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
513 HybridPlanesCollider::HybridPlanesCollider()
517 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
521 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
522 HybridPlanesCollider::~HybridPlanesCollider()
526 bool HybridPlanesCollider::Collide(PlanesCache
& cache
, const Plane
* planes
, udword nb_planes
, const HybridModel
& model
, const Matrix4x4
* worldm
)
528 // We don't want primitive tests here!
529 mFlags
|= OPC_NO_PRIMITIVE_TESTS
;
532 if(!Setup(&model
)) return false;
534 // Init collision query
535 if(InitQuery(cache
, planes
, nb_planes
, worldm
)) return true;
537 // Special case for 1-leaf trees
538 if(mCurrentModel
&& mCurrentModel
->HasSingleNode())
540 // Here we're supposed to perform a normal query, except our tree has a single node, i.e. just a few triangles
541 udword Nb
= mIMesh
->GetNbTriangles();
543 // Loop through all triangles
544 udword clip_mask
= (1<<mNbPlanes
)-1;
545 for(udword i
=0;i
<Nb
;i
++)
547 PLANES_PRIM(i
, OPC_CONTACT
)
552 // Override destination array since we're only going to get leaf boxes here
553 mTouchedBoxes
.Reset();
554 mTouchedPrimitives
= &mTouchedBoxes
;
556 udword PlaneMask
= (1<<nb_planes
)-1;
558 // Now, do the actual query against leaf boxes
559 if(!model
.HasLeafNodes())
561 if(model
.IsQuantized())
563 const AABBQuantizedNoLeafTree
* Tree
= static_cast<const AABBQuantizedNoLeafTree
*>(model
.GetTree());
565 // Setup dequantization coeffs
566 mCenterCoeff
= Tree
->mCenterCoeff
;
567 mExtentsCoeff
= Tree
->mExtentsCoeff
;
569 // Perform collision query - we don't want primitive tests here!
570 _CollideNoPrimitiveTest(Tree
->GetNodes(), PlaneMask
);
574 const AABBNoLeafTree
* Tree
= static_cast<const AABBNoLeafTree
*>(model
.GetTree());
576 // Perform collision query - we don't want primitive tests here!
577 _CollideNoPrimitiveTest(Tree
->GetNodes(), PlaneMask
);
582 if(model
.IsQuantized())
584 const AABBQuantizedTree
* Tree
= static_cast<const AABBQuantizedTree
*>(model
.GetTree());
586 // Setup dequantization coeffs
587 mCenterCoeff
= Tree
->mCenterCoeff
;
588 mExtentsCoeff
= Tree
->mExtentsCoeff
;
590 // Perform collision query - we don't want primitive tests here!
591 _CollideNoPrimitiveTest(Tree
->GetNodes(), PlaneMask
);
595 const AABBCollisionTree
* Tree
= static_cast<const AABBCollisionTree
*>(model
.GetTree());
597 // Perform collision query - we don't want primitive tests here!
598 _CollideNoPrimitiveTest(Tree
->GetNodes(), PlaneMask
);
602 // We only have a list of boxes so far
603 if(GetContactStatus())
605 // Reset contact status, since it currently only reflects collisions with leaf boxes
606 Collider::InitQuery();
608 // Change dest container so that we can use built-in overlap tests and get collided primitives
609 cache
.TouchedPrimitives
.Reset();
610 mTouchedPrimitives
= &cache
.TouchedPrimitives
;
612 // Read touched leaf boxes
613 udword Nb
= mTouchedBoxes
.GetNbEntries();
614 const udword
* Touched
= mTouchedBoxes
.GetEntries();
616 const LeafTriangles
* LT
= model
.GetLeafTriangles();
617 const udword
* Indices
= model
.GetIndices();
619 // Loop through touched leaves
620 udword clip_mask
= (1<<mNbPlanes
)-1;
623 const LeafTriangles
& CurrentLeaf
= LT
[*Touched
++];
625 // Each leaf box has a set of triangles
626 udword NbTris
= CurrentLeaf
.GetNbTriangles();
629 const udword
* T
= &Indices
[CurrentLeaf
.GetTriangleIndex()];
631 // Loop through triangles and test each of them
634 udword TriangleIndex
= *T
++;
635 PLANES_PRIM(TriangleIndex
, OPC_CONTACT
)
640 udword BaseIndex
= CurrentLeaf
.GetTriangleIndex();
642 // Loop through triangles and test each of them
645 udword TriangleIndex
= BaseIndex
++;
646 PLANES_PRIM(TriangleIndex
, OPC_CONTACT
)