Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/ode/ode-0.9/OPCODE/OPC_PlanesCollider.cpp @ 216

Last change on this file since 216 was 216, checked in by mathiask, 16 years ago

[Physik] add ode-0.9

File size: 25.4 KB
Line 
1///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2/*
3 *      OPCODE - Optimized Collision Detection
4 *      Copyright (C) 2001 Pierre Terdiman
5 *      Homepage: http://www.codercorner.com/Opcode.htm
6 */
7///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
8
9///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
10/**
11 *      Contains code for a planes collider.
12 *      \file           OPC_PlanesCollider.cpp
13 *      \author         Pierre Terdiman
14 *      \date           January, 1st, 2002
15 */
16///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
17
18///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
19/**
20 *      Contains a Planes-vs-tree collider.
21 *
22 *      \class          PlanesCollider
23 *      \author         Pierre Terdiman
24 *      \version        1.3
25 *      \date           January, 1st, 2002
26*/
27///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
28
29///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
30// Precompiled Header
31#include "Stdafx.h"
32
33using namespace Opcode;
34
35#include "OPC_PlanesAABBOverlap.h"
36#include "OPC_PlanesTriOverlap.h"
37
38#define SET_CONTACT(prim_index, flag)           \
39        /* Set contact status */                                \
40        mFlags |= flag;                                                 \
41        mTouchedPrimitives->Add(udword(prim_index));
42
43//! Planes-triangle test
44#define PLANES_PRIM(prim_index, flag)           \
45        /* Request vertices from the app */             \
46        mIMesh->GetTriangle(mVP, prim_index);   \
47        /* Perform triangle-box overlap test */ \
48        if(PlanesTriOverlap(clip_mask))                 \
49        {                                                                               \
50                SET_CONTACT(prim_index, flag)           \
51        }
52
53///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
54/**
55 *      Constructor.
56 */
57///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
58PlanesCollider::PlanesCollider() :
59        mPlanes         (null),
60        mNbPlanes       (0)
61{
62}
63
64///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
65/**
66 *      Destructor.
67 */
68///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
69PlanesCollider::~PlanesCollider()
70{
71        DELETEARRAY(mPlanes);
72}
73
74///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
75/**
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
78 */
79///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
80const char* PlanesCollider::ValidateSettings()
81{
82        if(TemporalCoherenceEnabled() && !FirstContactEnabled())        return "Temporal coherence only works with ""First contact"" mode!";
83
84        return VolumeCollider::ValidateSettings();
85}
86
87///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
88/**
89 *      Generic collision query for generic OPCODE models. After the call, access the results:
90 *      - with GetContactStatus()
91 *      - with GetNbTouchedPrimitives()
92 *      - with GetTouchedPrimitives()
93 *
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.
101 */
102///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
103bool PlanesCollider::Collide(PlanesCache& cache, const Plane* planes, udword nb_planes, const Model& model, const Matrix4x4* worldm)
104{
105        // Checkings
106        if(!Setup(&model))      return false;
107
108        // Init collision query
109        if(InitQuery(cache, planes, nb_planes, worldm)) return true;
110
111        udword PlaneMask = (1<<nb_planes)-1;
112
113        if(!model.HasLeafNodes())
114        {
115                if(model.IsQuantized())
116                {
117                        const AABBQuantizedNoLeafTree* Tree = (const AABBQuantizedNoLeafTree*)model.GetTree();
118
119                        // Setup dequantization coeffs
120                        mCenterCoeff    = Tree->mCenterCoeff;
121                        mExtentsCoeff   = Tree->mExtentsCoeff;
122
123                        // Perform collision query
124                        if(SkipPrimitiveTests())        _CollideNoPrimitiveTest(Tree->GetNodes(), PlaneMask);
125                        else                                            _Collide(Tree->GetNodes(), PlaneMask);
126                }
127                else
128                {
129                        const AABBNoLeafTree* Tree = (const AABBNoLeafTree*)model.GetTree();
130
131                        // Perform collision query
132                        if(SkipPrimitiveTests())        _CollideNoPrimitiveTest(Tree->GetNodes(), PlaneMask);
133                        else                                            _Collide(Tree->GetNodes(), PlaneMask);
134                }
135        }
136        else
137        {
138                if(model.IsQuantized())
139                {
140                        const AABBQuantizedTree* Tree = (const AABBQuantizedTree*)model.GetTree();
141
142                        // Setup dequantization coeffs
143                        mCenterCoeff    = Tree->mCenterCoeff;
144                        mExtentsCoeff   = Tree->mExtentsCoeff;
145
146                        // Perform collision query
147                        if(SkipPrimitiveTests())        _CollideNoPrimitiveTest(Tree->GetNodes(), PlaneMask);
148                        else                                            _Collide(Tree->GetNodes(), PlaneMask);
149                }
150                else
151                {
152                        const AABBCollisionTree* Tree = (const AABBCollisionTree*)model.GetTree();
153
154                        // Perform collision query
155                        if(SkipPrimitiveTests())        _CollideNoPrimitiveTest(Tree->GetNodes(), PlaneMask);
156                        else                                            _Collide(Tree->GetNodes(), PlaneMask);
157                }
158        }
159        return true;
160}
161
162///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
163/**
164 *      Initializes a collision query :
165 *      - reset stats & contact status
166 *      - compute planes in model space
167 *      - check temporal coherence
168 *
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.
175 */
176///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
177BOOL PlanesCollider::InitQuery(PlanesCache& cache, const Plane* planes, udword nb_planes, const Matrix4x4* worldm)
178{
179        // 1) Call the base method
180        VolumeCollider::InitQuery();
181
182        // 2) Compute planes in model space
183        if(nb_planes>mNbPlanes)
184        {
185                DELETEARRAY(mPlanes);
186                mPlanes = new Plane[nb_planes];
187        }
188        mNbPlanes = nb_planes;
189
190        if(worldm)
191        {
192                Matrix4x4 InvWorldM;
193                InvertPRMatrix(InvWorldM, *worldm);
194
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);
197        }
198        else CopyMemory(mPlanes, planes, nb_planes*sizeof(Plane));
199
200        // 3) Setup destination pointer
201        mTouchedPrimitives = &cache.TouchedPrimitives;
202
203        // 4) Special case: 1-triangle meshes [Opcode 1.3]
204        if(mCurrentModel && mCurrentModel->HasSingleNode())
205        {
206                if(!SkipPrimitiveTests())
207                {
208                        // We simply perform the BV-Prim overlap test each time. We assume single triangle has index 0.
209                        mTouchedPrimitives->Reset();
210
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)
214
215                        // Return immediately regardless of status
216                        return TRUE;
217                }
218        }
219
220        // 4) Check temporal coherence:
221        if(TemporalCoherenceEnabled())
222        {
223                // Here we use temporal coherence
224                // => check results from previous frame before performing the collision query
225                if(FirstContactEnabled())
226                {
227                        // We're only interested in the first contact found => test the unique previously touched face
228                        if(mTouchedPrimitives->GetNbEntries())
229                        {
230                                // Get index of previously touched face = the first entry in the array
231                                udword PreviouslyTouchedFace = mTouchedPrimitives->GetEntry(0);
232
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();
237
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)
241
242                                // Return immediately if possible
243                                if(GetContactStatus())  return TRUE;
244                        }
245                        // else no face has been touched during previous query
246                        // => we'll have to perform a normal query
247                }
248                else mTouchedPrimitives->Reset();
249        }
250        else
251        {
252                // Here we don't use temporal coherence => do a normal query
253                mTouchedPrimitives->Reset();
254        }
255
256        return FALSE;
257}
258
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. */           \
262        if(!OutClipMask)                                                                                                                                                                        \
263        {                                                                                                                                                                                                       \
264                /* Set contact status */                                                                                                                                                \
265                mFlags |= OPC_CONTACT;                                                                                                                                                  \
266                _Dump(node);                                                                                                                                                                    \
267                return;                                                                                                                                                                                 \
268        }
269
270///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
271/**
272 *      Recursive collision query for normal AABB trees.
273 *      \param          node    [in] current collision node
274 */
275///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
276void PlanesCollider::_Collide(const AABBCollisionNode* node, udword clip_mask)
277{
278        // Test the box against the planes. If the box is completely culled, so are its children, hence we exit.
279        udword OutClipMask;
280        if(!PlanesAABBOverlap(node->mAABB.mCenter, node->mAABB.mExtents, OutClipMask, clip_mask))       return;
281
282        TEST_CLIP_MASK
283
284        // Else the box straddles one or several planes, so we need to recurse down the tree.
285        if(node->IsLeaf())
286        {
287                PLANES_PRIM(node->GetPrimitive(), OPC_CONTACT)
288        }
289        else
290        {
291                _Collide(node->GetPos(), OutClipMask);
292
293                if(ContactFound()) return;
294
295                _Collide(node->GetNeg(), OutClipMask);
296        }
297}
298
299///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
300/**
301 *      Recursive collision query for normal AABB trees.
302 *      \param          node    [in] current collision node
303 */
304///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
305void PlanesCollider::_CollideNoPrimitiveTest(const AABBCollisionNode* node, udword clip_mask)
306{
307        // Test the box against the planes. If the box is completely culled, so are its children, hence we exit.
308        udword OutClipMask;
309        if(!PlanesAABBOverlap(node->mAABB.mCenter, node->mAABB.mExtents, OutClipMask, clip_mask))       return;
310
311        TEST_CLIP_MASK
312
313        // Else the box straddles one or several planes, so we need to recurse down the tree.
314        if(node->IsLeaf())
315        {
316                SET_CONTACT(node->GetPrimitive(), OPC_CONTACT)
317        }
318        else
319        {
320                _CollideNoPrimitiveTest(node->GetPos(), OutClipMask);
321
322                if(ContactFound()) return;
323
324                _CollideNoPrimitiveTest(node->GetNeg(), OutClipMask);
325        }
326}
327
328///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
329/**
330 *      Recursive collision query for quantized AABB trees.
331 *      \param          node    [in] current collision node
332 */
333///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
334void PlanesCollider::_Collide(const AABBQuantizedNode* node, udword clip_mask)
335{
336        // Dequantize box
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);
340
341        // Test the box against the planes. If the box is completely culled, so are its children, hence we exit.
342        udword OutClipMask;
343        if(!PlanesAABBOverlap(Center, Extents, OutClipMask, clip_mask)) return;
344
345        TEST_CLIP_MASK
346
347        // Else the box straddles one or several planes, so we need to recurse down the tree.
348        if(node->IsLeaf())
349        {
350                PLANES_PRIM(node->GetPrimitive(), OPC_CONTACT)
351        }
352        else
353        {
354                _Collide(node->GetPos(), OutClipMask);
355
356                if(ContactFound()) return;
357
358                _Collide(node->GetNeg(), OutClipMask);
359        }
360}
361
362///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
363/**
364 *      Recursive collision query for quantized AABB trees.
365 *      \param          node    [in] current collision node
366 */
367///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
368void PlanesCollider::_CollideNoPrimitiveTest(const AABBQuantizedNode* node, udword clip_mask)
369{
370        // Dequantize box
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);
374
375        // Test the box against the planes. If the box is completely culled, so are its children, hence we exit.
376        udword OutClipMask;
377        if(!PlanesAABBOverlap(Center, Extents, OutClipMask, clip_mask)) return;
378
379        TEST_CLIP_MASK
380
381        // Else the box straddles one or several planes, so we need to recurse down the tree.
382        if(node->IsLeaf())
383        {
384                SET_CONTACT(node->GetPrimitive(), OPC_CONTACT)
385        }
386        else
387        {
388                _CollideNoPrimitiveTest(node->GetPos(), OutClipMask);
389
390                if(ContactFound()) return;
391
392                _CollideNoPrimitiveTest(node->GetNeg(), OutClipMask);
393        }
394}
395
396///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
397/**
398 *      Recursive collision query for no-leaf AABB trees.
399 *      \param          node    [in] current collision node
400 */
401///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
402void PlanesCollider::_Collide(const AABBNoLeafNode* node, udword clip_mask)
403{
404        // Test the box against the planes. If the box is completely culled, so are its children, hence we exit.
405        udword OutClipMask;
406        if(!PlanesAABBOverlap(node->mAABB.mCenter, node->mAABB.mExtents, OutClipMask, clip_mask))       return;
407
408        TEST_CLIP_MASK
409
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);
413
414        if(ContactFound()) return;
415
416        if(node->HasNegLeaf())  { PLANES_PRIM(node->GetNegPrimitive(), OPC_CONTACT) }
417        else                                    _Collide(node->GetNeg(), OutClipMask);
418}
419
420///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
421/**
422 *      Recursive collision query for no-leaf AABB trees.
423 *      \param          node    [in] current collision node
424 */
425///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
426void PlanesCollider::_CollideNoPrimitiveTest(const AABBNoLeafNode* node, udword clip_mask)
427{
428        // Test the box against the planes. If the box is completely culled, so are its children, hence we exit.
429        udword OutClipMask;
430        if(!PlanesAABBOverlap(node->mAABB.mCenter, node->mAABB.mExtents, OutClipMask, clip_mask))       return;
431
432        TEST_CLIP_MASK
433
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);
437
438        if(ContactFound()) return;
439
440        if(node->HasNegLeaf())  { SET_CONTACT(node->GetNegPrimitive(), OPC_CONTACT) }
441        else                                    _CollideNoPrimitiveTest(node->GetNeg(), OutClipMask);
442}
443
444///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
445/**
446 *      Recursive collision query for quantized no-leaf AABB trees.
447 *      \param          node    [in] current collision node
448 */
449///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
450void PlanesCollider::_Collide(const AABBQuantizedNoLeafNode* node, udword clip_mask)
451{
452        // Dequantize box
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);
456
457        // Test the box against the planes. If the box is completely culled, so are its children, hence we exit.
458        udword OutClipMask;
459        if(!PlanesAABBOverlap(Center, Extents, OutClipMask, clip_mask)) return;
460
461        TEST_CLIP_MASK
462
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);
466
467        if(ContactFound()) return;
468
469        if(node->HasNegLeaf())  { PLANES_PRIM(node->GetNegPrimitive(), OPC_CONTACT) }
470        else                                    _Collide(node->GetNeg(), OutClipMask);
471}
472
473///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
474/**
475 *      Recursive collision query for quantized no-leaf AABB trees.
476 *      \param          node    [in] current collision node
477 */
478///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
479void PlanesCollider::_CollideNoPrimitiveTest(const AABBQuantizedNoLeafNode* node, udword clip_mask)
480{
481        // Dequantize box
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);
485
486        // Test the box against the planes. If the box is completely culled, so are its children, hence we exit.
487        udword OutClipMask;
488        if(!PlanesAABBOverlap(Center, Extents, OutClipMask, clip_mask)) return;
489
490        TEST_CLIP_MASK
491
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);
495
496        if(ContactFound()) return;
497
498        if(node->HasNegLeaf())  { SET_CONTACT(node->GetNegPrimitive(), OPC_CONTACT) }
499        else                                    _CollideNoPrimitiveTest(node->GetNeg(), OutClipMask);
500}
501
502
503
504
505
506
507
508///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
509/**
510 *      Constructor.
511 */
512///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
513HybridPlanesCollider::HybridPlanesCollider()
514{
515}
516
517///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
518/**
519 *      Destructor.
520 */
521///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
522HybridPlanesCollider::~HybridPlanesCollider()
523{
524}
525
526bool HybridPlanesCollider::Collide(PlanesCache& cache, const Plane* planes, udword nb_planes, const HybridModel& model, const Matrix4x4* worldm)
527{
528        // We don't want primitive tests here!
529        mFlags |= OPC_NO_PRIMITIVE_TESTS;
530
531        // Checkings
532        if(!Setup(&model))      return false;
533
534        // Init collision query
535        if(InitQuery(cache, planes, nb_planes, worldm)) return true;
536
537        // Special case for 1-leaf trees
538        if(mCurrentModel && mCurrentModel->HasSingleNode())
539        {
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();
542
543                // Loop through all triangles
544                udword clip_mask = (1<<mNbPlanes)-1;
545                for(udword i=0;i<Nb;i++)
546                {
547                        PLANES_PRIM(i, OPC_CONTACT)
548                }
549                return true;
550        }
551
552        // Override destination array since we're only going to get leaf boxes here
553        mTouchedBoxes.Reset();
554        mTouchedPrimitives = &mTouchedBoxes;
555
556        udword PlaneMask = (1<<nb_planes)-1;
557
558        // Now, do the actual query against leaf boxes
559        if(!model.HasLeafNodes())
560        {
561                if(model.IsQuantized())
562                {
563                        const AABBQuantizedNoLeafTree* Tree = (const AABBQuantizedNoLeafTree*)model.GetTree();
564
565                        // Setup dequantization coeffs
566                        mCenterCoeff    = Tree->mCenterCoeff;
567                        mExtentsCoeff   = Tree->mExtentsCoeff;
568
569                        // Perform collision query - we don't want primitive tests here!
570                        _CollideNoPrimitiveTest(Tree->GetNodes(), PlaneMask);
571                }
572                else
573                {
574                        const AABBNoLeafTree* Tree = (const AABBNoLeafTree*)model.GetTree();
575
576                        // Perform collision query - we don't want primitive tests here!
577                        _CollideNoPrimitiveTest(Tree->GetNodes(), PlaneMask);
578                }
579        }
580        else
581        {
582                if(model.IsQuantized())
583                {
584                        const AABBQuantizedTree* Tree = (const AABBQuantizedTree*)model.GetTree();
585
586                        // Setup dequantization coeffs
587                        mCenterCoeff    = Tree->mCenterCoeff;
588                        mExtentsCoeff   = Tree->mExtentsCoeff;
589
590                        // Perform collision query - we don't want primitive tests here!
591                        _CollideNoPrimitiveTest(Tree->GetNodes(), PlaneMask);
592                }
593                else
594                {
595                        const AABBCollisionTree* Tree = (const AABBCollisionTree*)model.GetTree();
596
597                        // Perform collision query - we don't want primitive tests here!
598                        _CollideNoPrimitiveTest(Tree->GetNodes(), PlaneMask);
599                }
600        }
601
602        // We only have a list of boxes so far
603        if(GetContactStatus())
604        {
605                // Reset contact status, since it currently only reflects collisions with leaf boxes
606                Collider::InitQuery();
607
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;
611
612                // Read touched leaf boxes
613                udword Nb = mTouchedBoxes.GetNbEntries();
614                const udword* Touched = mTouchedBoxes.GetEntries();
615
616                const LeafTriangles* LT = model.GetLeafTriangles();
617                const udword* Indices = model.GetIndices();
618
619                // Loop through touched leaves
620                udword clip_mask = (1<<mNbPlanes)-1;
621                while(Nb--)
622                {
623                        const LeafTriangles& CurrentLeaf = LT[*Touched++];
624
625                        // Each leaf box has a set of triangles
626                        udword NbTris = CurrentLeaf.GetNbTriangles();
627                        if(Indices)
628                        {
629                                const udword* T = &Indices[CurrentLeaf.GetTriangleIndex()];
630
631                                // Loop through triangles and test each of them
632                                while(NbTris--)
633                                {
634                                        udword TriangleIndex = *T++;
635                                        PLANES_PRIM(TriangleIndex, OPC_CONTACT)
636                                }
637                        }
638                        else
639                        {
640                                udword BaseIndex = CurrentLeaf.GetTriangleIndex();
641
642                                // Loop through triangles and test each of them
643                                while(NbTris--)
644                                {
645                                        udword TriangleIndex = BaseIndex++;
646                                        PLANES_PRIM(TriangleIndex, OPC_CONTACT)
647                                }
648                        }
649                }
650        }
651
652        return true;
653}
Note: See TracBrowser for help on using the repository browser.