~ubuntu-branches/debian/sid/ember/sid

« back to all changes in this revision

Viewing changes to src/components/ogre/ogreopcode/src/Opcode/OPC_LSSCollider.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Michael Koch
  • Date: 2009-07-23 07:46:40 UTC
  • Revision ID: james.westby@ubuntu.com-20090723074640-wh0ukzis0kda36qv
Tags: upstream-0.5.6
ImportĀ upstreamĀ versionĀ 0.5.6

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
2
/*
 
3
 *      OPCODE - Optimized Collision Detection
 
4
 *      Copyright (C) 2001 Pierre Terdiman
 
5
 *      Homepage: http://www.codercorner.com/Opcode.htm
 
6
 *
 
7
 *  OPCODE modifications for scaled model support (and other things)
 
8
 *  Copyright (C) 2004 Gilvan Maia (gilvan 'at' vdl.ufc.br)
 
9
 *      Check http://www.vdl.ufc.br/gilvan/coll/opcode/index.htm for updates.
 
10
 *
 
11
 */
 
12
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
13
 
 
14
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
15
/**
 
16
 *      Contains code for an LSS collider.
 
17
 *      \file           OPC_LSSCollider.cpp
 
18
 *      \author         Pierre Terdiman
 
19
 *      \date           December, 28, 2002
 
20
 */
 
21
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
22
 
 
23
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
24
/**
 
25
 *      Contains a lss-vs-tree collider.
 
26
 *
 
27
 *      \class          LSSCollider
 
28
 *      \author         Pierre Terdiman
 
29
 *      \version        1.3
 
30
 *      \date           December, 28, 2002
 
31
*/
 
32
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
33
 
 
34
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
35
// Precompiled Header
 
36
#include "Opcode/Stdafx.h"
 
37
 
 
38
using namespace Opcode;
 
39
 
 
40
#include "Opcode/OPC_LSSAABBOverlap.h"
 
41
#include "Opcode/OPC_LSSTriOverlap.h"
 
42
 
 
43
#define SET_CONTACT(prim_index, flag)                                                                   \
 
44
        /* Set contact status */                                                                                        \
 
45
        mFlags |= flag;                                                                                                         \
 
46
        mTouchedPrimitives->Add(prim_index);
 
47
 
 
48
//! LSS-triangle overlap test
 
49
#define LSS_PRIM(prim_index, flag)                                                                              \
 
50
        /* Request vertices from the app */                                                                     \
 
51
        VertexPointers VP;      mIMesh->GetTriangle(VP, prim_index);                    \
 
52
                                                                                                                                                \
 
53
        /* Perform LSS-tri overlap test */                                                                      \
 
54
        if(LSSTriOverlap(*VP.Vertex[0], *VP.Vertex[1], *VP.Vertex[2]))          \
 
55
        {                                                                                                                                       \
 
56
                SET_CONTACT(prim_index, flag)                                                                   \
 
57
        }
 
58
 
 
59
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
60
/**
 
61
 *      Constructor.
 
62
 */
 
63
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
64
LSSCollider::LSSCollider()
 
65
{
 
66
//      mCenter.Zero();
 
67
//      mRadius2 = 0.0f;
 
68
}
 
69
 
 
70
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
71
/**
 
72
 *      Destructor.
 
73
 */
 
74
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
75
LSSCollider::~LSSCollider()
 
76
{
 
77
}
 
78
 
 
79
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
80
/**
 
81
 *      Generic collision query for generic OPCODE models. After the call, access the results:
 
82
 *      - with GetContactStatus()
 
83
 *      - with GetNbTouchedPrimitives()
 
84
 *      - with GetTouchedPrimitives()
 
85
 *
 
86
 *      \param          cache                   [in/out] an lss cache
 
87
 *      \param          lss                             [in] collision lss in local space
 
88
 *      \param          model                   [in] Opcode model to collide with
 
89
 *      \param          worldl                  [in] lss world matrix, or null
 
90
 *      \param          worldm                  [in] model's world matrix, or null
 
91
 *      \return         true if success
 
92
 *      \warning        SCALE NOT SUPPORTED IN LSS WORLD MATRIX. The LSS matrix must contain rotation & translation parts only.
 
93
 */
 
94
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
95
bool LSSCollider::Collide(LSSCache& cache, const IceMaths::LSS& lss, const Model& model, const IceMaths::Matrix4x4* worldl, const IceMaths::Matrix4x4* worldm)
 
96
{
 
97
        // Checkings
 
98
        if(!Setup(&model))      return false;
 
99
 
 
100
        // Init collision query
 
101
        if(InitQuery(cache, lss, worldl, worldm))       return true;
 
102
 
 
103
        if(!model.HasLeafNodes())
 
104
        {
 
105
                if(model.IsQuantized())
 
106
                {
 
107
                        const AABBQuantizedNoLeafTree* Tree = (const AABBQuantizedNoLeafTree*)model.GetTree();
 
108
 
 
109
                        // Setup dequantization coeffs
 
110
                        mCenterCoeff    = Tree->mCenterCoeff;
 
111
                        mExtentsCoeff   = Tree->mExtentsCoeff;
 
112
 
 
113
                        // Perform collision query
 
114
                        if(SkipPrimitiveTests())        _CollideNoPrimitiveTest(Tree->GetNodes());
 
115
                        else                                            _Collide(Tree->GetNodes());
 
116
                }
 
117
                else
 
118
                {
 
119
                        const AABBNoLeafTree* Tree = (const AABBNoLeafTree*)model.GetTree();
 
120
 
 
121
                        // Perform collision query
 
122
                        if(SkipPrimitiveTests())        _CollideNoPrimitiveTest(Tree->GetNodes());
 
123
                        else                                            _Collide(Tree->GetNodes());
 
124
                }
 
125
        }
 
126
        else
 
127
        {
 
128
                if(model.IsQuantized())
 
129
                {
 
130
                        const AABBQuantizedTree* Tree = (const AABBQuantizedTree*)model.GetTree();
 
131
 
 
132
                        // Setup dequantization coeffs
 
133
                        mCenterCoeff    = Tree->mCenterCoeff;
 
134
                        mExtentsCoeff   = Tree->mExtentsCoeff;
 
135
 
 
136
                        // Perform collision query
 
137
                        if(SkipPrimitiveTests())        _CollideNoPrimitiveTest(Tree->GetNodes());
 
138
                        else                                            _Collide(Tree->GetNodes());
 
139
                }
 
140
                else
 
141
                {
 
142
                        const AABBCollisionTree* Tree = (const AABBCollisionTree*)model.GetTree();
 
143
 
 
144
                        // Perform collision query
 
145
                        if(SkipPrimitiveTests())        _CollideNoPrimitiveTest(Tree->GetNodes());
 
146
                        else                                            _Collide(Tree->GetNodes());
 
147
                }
 
148
        }
 
149
 
 
150
        return true;
 
151
}
 
152
 
 
153
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
154
/**
 
155
 *      Initializes a collision query :
 
156
 *      - reset stats & contact status
 
157
 *      - setup matrices
 
158
 *      - check temporal coherence
 
159
 *
 
160
 *      \param          cache           [in/out] an lss cache
 
161
 *      \param          lss                     [in] lss in local space
 
162
 *      \param          worldl          [in] lss world matrix, or null
 
163
 *      \param          worldm          [in] model's world matrix, or null
 
164
 *      \return         TRUE if we can return immediately
 
165
 *      \warning        SCALE NOT SUPPORTED IN LSS WORLD MATRIX. The matrix must contain rotation & translation parts only.
 
166
 */
 
167
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
168
BOOL LSSCollider::InitQuery(LSSCache& cache, const IceMaths::LSS& lss, const IceMaths::Matrix4x4* worldl, const IceMaths::Matrix4x4* worldm)
 
169
{
 
170
        // 1) Call the base method
 
171
        VolumeCollider::InitQuery();
 
172
 
 
173
        // 2) Compute LSS in model space:
 
174
        // - Precompute R^2
 
175
        mRadius2 = lss.mRadius * lss.mRadius;
 
176
        // - Compute segment
 
177
        mSeg.mP0 = lss.mP0;
 
178
        mSeg.mP1 = lss.mP1;
 
179
        // -> to world space
 
180
        if(worldl)
 
181
        {
 
182
                mSeg.mP0 *= *worldl;
 
183
                mSeg.mP1 *= *worldl;
 
184
        }
 
185
        // -> to model space
 
186
        if(worldm)
 
187
        {
 
188
                // Matrix normalization & scaling stripping
 
189
                IceMaths::Matrix4x4 normWorldm;
 
190
                IceMaths::NormalizePRSMatrix( normWorldm, mLocalScale, *worldm );
 
191
                
 
192
                // Invert model matrix
 
193
                IceMaths::Matrix4x4 InvWorldM;
 
194
                IceMaths::InvertPRMatrix(InvWorldM, normWorldm); 
 
195
 
 
196
                mSeg.mP0 *= InvWorldM;
 
197
                mSeg.mP1 *= InvWorldM;
 
198
        }else
 
199
        {
 
200
                mLocalScale.Set(1.0,1.0,1.0);
 
201
        }
 
202
 
 
203
        // 3) Setup destination pointer
 
204
        mTouchedPrimitives = &cache.TouchedPrimitives;
 
205
 
 
206
        // 4) Special case: 1-triangle meshes [Opcode 1.3]
 
207
        if(mCurrentModel && mCurrentModel->HasSingleNode())
 
208
        {
 
209
                if(!SkipPrimitiveTests())
 
210
                {
 
211
                        // We simply perform the BV-Prim overlap test each time. We assume single triangle has index 0.
 
212
                        mTouchedPrimitives->Reset();
 
213
 
 
214
                        // Perform overlap test between the unique triangle and the LSS (and set contact status if needed)
 
215
                        LSS_PRIM(udword(0), OPC_CONTACT)
 
216
 
 
217
                        // Return immediately regardless of status
 
218
                        return TRUE;
 
219
                }
 
220
        }
 
221
 
 
222
        // 5) Check temporal coherence :
 
223
        if(TemporalCoherenceEnabled())
 
224
        {
 
225
                // Here we use temporal coherence
 
226
                // => check results from previous frame before performing the collision query
 
227
                if(FirstContactEnabled())
 
228
                {
 
229
                        // We're only interested in the first contact found => test the unique previously touched face
 
230
                        if(mTouchedPrimitives->GetNbEntries())
 
231
                        {
 
232
                                // Get index of previously touched face = the first entry in the array
 
233
                                udword PreviouslyTouchedFace = mTouchedPrimitives->GetEntry(0);
 
234
 
 
235
                                // Then reset the array:
 
236
                                // - if the overlap test below is successful, the index we'll get added back anyway
 
237
                                // - if it isn't, then the array should be reset anyway for the normal query
 
238
                                mTouchedPrimitives->Reset();
 
239
 
 
240
                                // Perform overlap test between the cached triangle and the LSS (and set contact status if needed)
 
241
                                LSS_PRIM(PreviouslyTouchedFace, OPC_TEMPORAL_CONTACT)
 
242
 
 
243
                                // Return immediately if possible
 
244
                                if(GetContactStatus())  return TRUE;
 
245
                        }
 
246
                        // else no face has been touched during previous query
 
247
                        // => we'll have to perform a normal query
 
248
                }
 
249
                else
 
250
                {
 
251
                        // We're interested in all contacts =>test the new real LSS N(ew) against the previous fat LSS P(revious):
 
252
 
 
253
                        // ### rewrite this
 
254
 
 
255
                        IceMaths::LSS Test(mSeg, lss.mRadius);  // in model space
 
256
                        IceMaths::LSS Previous(cache.Previous, sqrtf(cache.Previous.mRadius));
 
257
 
 
258
//                      if(cache.Previous.Contains(Test))
 
259
                        if(IsCacheValid(cache) && Previous.Contains(Test))
 
260
                        {
 
261
                                // - if N is included in P, return previous list
 
262
                                // => we simply leave the list (mTouchedFaces) unchanged
 
263
 
 
264
                                // Set contact status if needed
 
265
                                if(mTouchedPrimitives->GetNbEntries())  mFlags |= OPC_TEMPORAL_CONTACT;
 
266
 
 
267
                                // In any case we don't need to do a query
 
268
                                return TRUE;
 
269
                        }
 
270
                        else
 
271
                        {
 
272
                                // - else do the query using a fat N
 
273
 
 
274
                                // Reset cache since we'll about to perform a real query
 
275
                                mTouchedPrimitives->Reset();
 
276
 
 
277
                                // Make a fat sphere so that coherence will work for subsequent frames
 
278
                                mRadius2 *= cache.FatCoeff;
 
279
//                              mRadius2 = (lss.mRadius * cache.FatCoeff)*(lss.mRadius * cache.FatCoeff);
 
280
 
 
281
 
 
282
                                // Update cache with query data (signature for cached faces)
 
283
                                cache.Previous.mP0 = mSeg.mP0;
 
284
                                cache.Previous.mP1 = mSeg.mP1;
 
285
                                cache.Previous.mRadius = mRadius2;
 
286
                        }
 
287
                }
 
288
        }
 
289
        else
 
290
        {
 
291
                // Here we don't use temporal coherence => do a normal query
 
292
                mTouchedPrimitives->Reset();
 
293
        }
 
294
 
 
295
        return FALSE;
 
296
}
 
297
 
 
298
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
299
/**
 
300
 *      Collision query for vanilla AABB trees.
 
301
 *      \param          cache           [in/out] an lss cache
 
302
 *      \param          lss                     [in] collision lss in world space
 
303
 *      \param          tree            [in] AABB tree
 
304
 *      \return         true if success
 
305
 */
 
306
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
307
bool LSSCollider::Collide(LSSCache& cache, const IceMaths::LSS& lss, const AABBTree* tree)
 
308
{
 
309
        // This is typically called for a scene tree, full of -AABBs-, not full of triangles.
 
310
        // So we don't really have "primitives" to deal with. Hence it doesn't work with
 
311
        // "FirstContact" + "TemporalCoherence".
 
312
        ASSERT( !(FirstContactEnabled() && TemporalCoherenceEnabled()) );
 
313
 
 
314
        // Checkings
 
315
        if(!tree)       return false;
 
316
 
 
317
        // Init collision query
 
318
        if(InitQuery(cache, lss))       return true;
 
319
 
 
320
        // Perform collision query
 
321
        _Collide(tree);
 
322
 
 
323
        return true;
 
324
}
 
325
 
 
326
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
327
/**
 
328
 *      Checks the LSS completely contains the box. In which case we can end the query sooner.
 
329
 *      \param          bc      [in] box center
 
330
 *      \param          be      [in] box extents
 
331
 *      \return         true if the LSS contains the whole box
 
332
 */
 
333
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
334
inline_ BOOL LSSCollider::LSSContainsBox(const IceMaths::Point& bc, const IceMaths::Point& be)
 
335
{
 
336
        // Not implemented
 
337
        return FALSE;
 
338
}
 
339
 
 
340
#define TEST_BOX_IN_LSS(center, extents)        \
 
341
        if(LSSContainsBox(center, extents))             \
 
342
        {                                                                               \
 
343
                /* Set contact status */                        \
 
344
                mFlags |= OPC_CONTACT;                          \
 
345
                _Dump(node);                                            \
 
346
                return;                                                         \
 
347
        }
 
348
 
 
349
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
350
/**
 
351
 *      Recursive collision query for normal AABB trees.
 
352
 *      \param          node    [in] current collision node
 
353
 */
 
354
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
355
void LSSCollider::_Collide(const AABBCollisionNode* node)
 
356
{
 
357
        // Perform LSS-AABB overlap test
 
358
        if(!LSSAABBOverlap(node->mAABB.mCenter, node->mAABB.mExtents))  return;
 
359
 
 
360
        TEST_BOX_IN_LSS(node->mAABB.mCenter, node->mAABB.mExtents)
 
361
 
 
362
        if(node->IsLeaf())
 
363
        {
 
364
                LSS_PRIM(node->GetPrimitive(), OPC_CONTACT)
 
365
        }
 
366
        else
 
367
        {
 
368
                _Collide(node->GetPos());
 
369
 
 
370
                if(ContactFound()) return;
 
371
 
 
372
                _Collide(node->GetNeg());
 
373
        }
 
374
}
 
375
 
 
376
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
377
/**
 
378
 *      Recursive collision query for normal AABB trees, without primitive tests.
 
379
 *      \param          node    [in] current collision node
 
380
 */
 
381
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
382
void LSSCollider::_CollideNoPrimitiveTest(const AABBCollisionNode* node)
 
383
{
 
384
        // Perform LSS-AABB overlap test
 
385
        if(!LSSAABBOverlap(node->mAABB.mCenter, node->mAABB.mExtents))  return;
 
386
 
 
387
        TEST_BOX_IN_LSS(node->mAABB.mCenter, node->mAABB.mExtents)
 
388
 
 
389
        if(node->IsLeaf())
 
390
        {
 
391
                SET_CONTACT(node->GetPrimitive(), OPC_CONTACT)
 
392
        }
 
393
        else
 
394
        {
 
395
                _CollideNoPrimitiveTest(node->GetPos());
 
396
 
 
397
                if(ContactFound()) return;
 
398
 
 
399
                _CollideNoPrimitiveTest(node->GetNeg());
 
400
        }
 
401
}
 
402
 
 
403
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
404
/**
 
405
 *      Recursive collision query for quantized AABB trees.
 
406
 *      \param          node    [in] current collision node
 
407
 */
 
408
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
409
void LSSCollider::_Collide(const AABBQuantizedNode* node)
 
410
{
 
411
        // Dequantize box
 
412
        const QuantizedAABB& Box = node->mAABB;
 
413
        const IceMaths::Point Center(float(Box.mCenter[0]) * mCenterCoeff.x, float(Box.mCenter[1]) * mCenterCoeff.y, float(Box.mCenter[2]) * mCenterCoeff.z);
 
414
        const IceMaths::Point Extents(float(Box.mExtents[0]) * mExtentsCoeff.x, float(Box.mExtents[1]) * mExtentsCoeff.y, float(Box.mExtents[2]) * mExtentsCoeff.z);
 
415
 
 
416
        // Perform LSS-AABB overlap test
 
417
        if(!LSSAABBOverlap(Center, Extents))    return;
 
418
 
 
419
        TEST_BOX_IN_LSS(Center, Extents)
 
420
 
 
421
        if(node->IsLeaf())
 
422
        {
 
423
                LSS_PRIM(node->GetPrimitive(), OPC_CONTACT)
 
424
        }
 
425
        else
 
426
        {
 
427
                _Collide(node->GetPos());
 
428
 
 
429
                if(ContactFound()) return;
 
430
 
 
431
                _Collide(node->GetNeg());
 
432
        }
 
433
}
 
434
 
 
435
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
436
/**
 
437
 *      Recursive collision query for quantized AABB trees, without primitive tests.
 
438
 *      \param          node    [in] current collision node
 
439
 */
 
440
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
441
void LSSCollider::_CollideNoPrimitiveTest(const AABBQuantizedNode* node)
 
442
{
 
443
        // Dequantize box
 
444
        const QuantizedAABB& Box = node->mAABB;
 
445
        const IceMaths::Point Center(float(Box.mCenter[0]) * mCenterCoeff.x, float(Box.mCenter[1]) * mCenterCoeff.y, float(Box.mCenter[2]) * mCenterCoeff.z);
 
446
        const IceMaths::Point Extents(float(Box.mExtents[0]) * mExtentsCoeff.x, float(Box.mExtents[1]) * mExtentsCoeff.y, float(Box.mExtents[2]) * mExtentsCoeff.z);
 
447
 
 
448
        // Perform LSS-AABB overlap test
 
449
        if(!LSSAABBOverlap(Center, Extents))    return;
 
450
 
 
451
        TEST_BOX_IN_LSS(Center, Extents)
 
452
 
 
453
        if(node->IsLeaf())
 
454
        {
 
455
                SET_CONTACT(node->GetPrimitive(), OPC_CONTACT)
 
456
        }
 
457
        else
 
458
        {
 
459
                _CollideNoPrimitiveTest(node->GetPos());
 
460
 
 
461
                if(ContactFound()) return;
 
462
 
 
463
                _CollideNoPrimitiveTest(node->GetNeg());
 
464
        }
 
465
}
 
466
 
 
467
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
468
/**
 
469
 *      Recursive collision query for no-leaf AABB trees.
 
470
 *      \param          node    [in] current collision node
 
471
 */
 
472
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
473
void LSSCollider::_Collide(const AABBNoLeafNode* node)
 
474
{
 
475
        // Perform LSS-AABB overlap test
 
476
        if(!LSSAABBOverlap(node->mAABB.mCenter, node->mAABB.mExtents))  return;
 
477
 
 
478
        TEST_BOX_IN_LSS(node->mAABB.mCenter, node->mAABB.mExtents)
 
479
 
 
480
        if(node->HasPosLeaf())  { LSS_PRIM(node->GetPosPrimitive(), OPC_CONTACT) }
 
481
        else                                    _Collide(node->GetPos());
 
482
 
 
483
        if(ContactFound()) return;
 
484
 
 
485
        if(node->HasNegLeaf())  { LSS_PRIM(node->GetNegPrimitive(), OPC_CONTACT) }
 
486
        else                                    _Collide(node->GetNeg());
 
487
}
 
488
 
 
489
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
490
/**
 
491
 *      Recursive collision query for no-leaf AABB trees, without primitive tests.
 
492
 *      \param          node    [in] current collision node
 
493
 */
 
494
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
495
void LSSCollider::_CollideNoPrimitiveTest(const AABBNoLeafNode* node)
 
496
{
 
497
        // Perform LSS-AABB overlap test
 
498
        if(!LSSAABBOverlap(node->mAABB.mCenter, node->mAABB.mExtents))  return;
 
499
 
 
500
        TEST_BOX_IN_LSS(node->mAABB.mCenter, node->mAABB.mExtents)
 
501
 
 
502
        if(node->HasPosLeaf())  { SET_CONTACT(node->GetPosPrimitive(), OPC_CONTACT) }
 
503
        else                                    _CollideNoPrimitiveTest(node->GetPos());
 
504
 
 
505
        if(ContactFound()) return;
 
506
 
 
507
        if(node->HasNegLeaf())  { SET_CONTACT(node->GetNegPrimitive(), OPC_CONTACT) }
 
508
        else                                    _CollideNoPrimitiveTest(node->GetNeg());
 
509
}
 
510
 
 
511
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
512
/**
 
513
 *      Recursive collision query for quantized no-leaf AABB trees.
 
514
 *      \param          node    [in] current collision node
 
515
 */
 
516
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
517
void LSSCollider::_Collide(const AABBQuantizedNoLeafNode* node)
 
518
{
 
519
        // Dequantize box
 
520
        const QuantizedAABB& Box = node->mAABB;
 
521
        const IceMaths::Point Center(float(Box.mCenter[0]) * mCenterCoeff.x, float(Box.mCenter[1]) * mCenterCoeff.y, float(Box.mCenter[2]) * mCenterCoeff.z);
 
522
        const IceMaths::Point Extents(float(Box.mExtents[0]) * mExtentsCoeff.x, float(Box.mExtents[1]) * mExtentsCoeff.y, float(Box.mExtents[2]) * mExtentsCoeff.z);
 
523
 
 
524
        // Perform LSS-AABB overlap test
 
525
        if(!LSSAABBOverlap(Center, Extents))    return;
 
526
 
 
527
        TEST_BOX_IN_LSS(Center, Extents)
 
528
 
 
529
        if(node->HasPosLeaf())  { LSS_PRIM(node->GetPosPrimitive(), OPC_CONTACT) }
 
530
        else                                    _Collide(node->GetPos());
 
531
 
 
532
        if(ContactFound()) return;
 
533
 
 
534
        if(node->HasNegLeaf())  { LSS_PRIM(node->GetNegPrimitive(), OPC_CONTACT) }
 
535
        else                                    _Collide(node->GetNeg());
 
536
}
 
537
 
 
538
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
539
/**
 
540
 *      Recursive collision query for quantized no-leaf AABB trees, without primitive tests.
 
541
 *      \param          node    [in] current collision node
 
542
 */
 
543
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
544
void LSSCollider::_CollideNoPrimitiveTest(const AABBQuantizedNoLeafNode* node)
 
545
{
 
546
        // Dequantize box
 
547
        const QuantizedAABB& Box = node->mAABB;
 
548
        const IceMaths::Point Center(float(Box.mCenter[0]) * mCenterCoeff.x, float(Box.mCenter[1]) * mCenterCoeff.y, float(Box.mCenter[2]) * mCenterCoeff.z);
 
549
        const IceMaths::Point Extents(float(Box.mExtents[0]) * mExtentsCoeff.x, float(Box.mExtents[1]) * mExtentsCoeff.y, float(Box.mExtents[2]) * mExtentsCoeff.z);
 
550
 
 
551
        // Perform LSS-AABB overlap test
 
552
        if(!LSSAABBOverlap(Center, Extents))    return;
 
553
 
 
554
        TEST_BOX_IN_LSS(Center, Extents)
 
555
 
 
556
        if(node->HasPosLeaf())  { SET_CONTACT(node->GetPosPrimitive(), OPC_CONTACT) }
 
557
        else                                    _CollideNoPrimitiveTest(node->GetPos());
 
558
 
 
559
        if(ContactFound()) return;
 
560
 
 
561
        if(node->HasNegLeaf())  { SET_CONTACT(node->GetNegPrimitive(), OPC_CONTACT) }
 
562
        else                                    _CollideNoPrimitiveTest(node->GetNeg());
 
563
}
 
564
 
 
565
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
566
/**
 
567
 *      Recursive collision query for vanilla AABB trees.
 
568
 *      \param          node    [in] current collision node
 
569
 */
 
570
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
571
void LSSCollider::_Collide(const AABBTreeNode* node)
 
572
{
 
573
        // Perform LSS-AABB overlap test
 
574
        IceMaths::Point Center, Extents;
 
575
        node->GetAABB()->GetCenter(Center);
 
576
        node->GetAABB()->GetExtents(Extents);
 
577
        if(!LSSAABBOverlap(Center, Extents))    return;
 
578
 
 
579
        if(node->IsLeaf() || LSSContainsBox(Center, Extents))
 
580
        {
 
581
                mFlags |= OPC_CONTACT;
 
582
                mTouchedPrimitives->Add(node->GetPrimitives(), node->GetNbPrimitives());
 
583
        }
 
584
        else
 
585
        {
 
586
                _Collide(node->GetPos());
 
587
                _Collide(node->GetNeg());
 
588
        }
 
589
}
 
590
 
 
591
 
 
592
 
 
593
 
 
594
 
 
595
 
 
596
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
597
/**
 
598
 *      Constructor.
 
599
 */
 
600
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
601
HybridLSSCollider::HybridLSSCollider()
 
602
{
 
603
}
 
604
 
 
605
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
606
/**
 
607
 *      Destructor.
 
608
 */
 
609
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
610
HybridLSSCollider::~HybridLSSCollider()
 
611
{
 
612
}
 
613
 
 
614
bool HybridLSSCollider::Collide(LSSCache& cache, const IceMaths::LSS& lss, const HybridModel& model, const IceMaths::Matrix4x4* worldl, const IceMaths::Matrix4x4* worldm)
 
615
{
 
616
        // We don't want primitive tests here!
 
617
        mFlags |= OPC_NO_PRIMITIVE_TESTS;
 
618
 
 
619
        // Checkings
 
620
        if(!Setup(&model))      return false;
 
621
 
 
622
        // Init collision query
 
623
        if(InitQuery(cache, lss, worldl, worldm))       return true;
 
624
 
 
625
        // Special case for 1-leaf trees
 
626
        if(mCurrentModel && mCurrentModel->HasSingleNode())
 
627
        {
 
628
                // Here we're supposed to perform a normal query, except our tree has a single node, i.e. just a few triangles
 
629
                udword Nb = mIMesh->GetNbTriangles();
 
630
 
 
631
                // Loop through all triangles
 
632
                for(udword i=0;i<Nb;i++)
 
633
                {
 
634
                        LSS_PRIM(i, OPC_CONTACT)
 
635
                }
 
636
                return true;
 
637
        }
 
638
 
 
639
        // Override destination array since we're only going to get leaf boxes here
 
640
        mTouchedBoxes.Reset();
 
641
        mTouchedPrimitives = &mTouchedBoxes;
 
642
 
 
643
        // Now, do the actual query against leaf boxes
 
644
        if(!model.HasLeafNodes())
 
645
        {
 
646
                if(model.IsQuantized())
 
647
                {
 
648
                        const AABBQuantizedNoLeafTree* Tree = (const AABBQuantizedNoLeafTree*)model.GetTree();
 
649
 
 
650
                        // Setup dequantization coeffs
 
651
                        mCenterCoeff    = Tree->mCenterCoeff;
 
652
                        mExtentsCoeff   = Tree->mExtentsCoeff;
 
653
 
 
654
                        // Perform collision query - we don't want primitive tests here!
 
655
                        _CollideNoPrimitiveTest(Tree->GetNodes());
 
656
                }
 
657
                else
 
658
                {
 
659
                        const AABBNoLeafTree* Tree = (const AABBNoLeafTree*)model.GetTree();
 
660
 
 
661
                        // Perform collision query - we don't want primitive tests here!
 
662
                        _CollideNoPrimitiveTest(Tree->GetNodes());
 
663
                }
 
664
        }
 
665
        else
 
666
        {
 
667
                if(model.IsQuantized())
 
668
                {
 
669
                        const AABBQuantizedTree* Tree = (const AABBQuantizedTree*)model.GetTree();
 
670
 
 
671
                        // Setup dequantization coeffs
 
672
                        mCenterCoeff    = Tree->mCenterCoeff;
 
673
                        mExtentsCoeff   = Tree->mExtentsCoeff;
 
674
 
 
675
                        // Perform collision query - we don't want primitive tests here!
 
676
                        _CollideNoPrimitiveTest(Tree->GetNodes());
 
677
                }
 
678
                else
 
679
                {
 
680
                        const AABBCollisionTree* Tree = (const AABBCollisionTree*)model.GetTree();
 
681
 
 
682
                        // Perform collision query - we don't want primitive tests here!
 
683
                        _CollideNoPrimitiveTest(Tree->GetNodes());
 
684
                }
 
685
        }
 
686
 
 
687
        // We only have a list of boxes so far
 
688
        if(GetContactStatus())
 
689
        {
 
690
                // Reset contact status, since it currently only reflects collisions with leaf boxes
 
691
                Collider::InitQuery();
 
692
 
 
693
                // Change dest container so that we can use built-in overlap tests and get collided primitives
 
694
                cache.TouchedPrimitives.Reset();
 
695
                mTouchedPrimitives = &cache.TouchedPrimitives;
 
696
 
 
697
                // Read touched leaf boxes
 
698
                udword Nb = mTouchedBoxes.GetNbEntries();
 
699
                const udword* Touched = mTouchedBoxes.GetEntries();
 
700
 
 
701
                const LeafTriangles* LT = model.GetLeafTriangles();
 
702
                const udword* Indices = model.GetIndices();
 
703
 
 
704
                // Loop through touched leaves
 
705
                while(Nb--)
 
706
                {
 
707
                        const LeafTriangles& CurrentLeaf = LT[*Touched++];
 
708
 
 
709
                        // Each leaf box has a set of triangles
 
710
                        udword NbTris = CurrentLeaf.GetNbTriangles();
 
711
                        if(Indices)
 
712
                        {
 
713
                                const udword* T = &Indices[CurrentLeaf.GetTriangleIndex()];
 
714
 
 
715
                                // Loop through triangles and test each of them
 
716
                                while(NbTris--)
 
717
                                {
 
718
                                        udword TriangleIndex = *T++;
 
719
                                        LSS_PRIM(TriangleIndex, OPC_CONTACT)
 
720
                                }
 
721
                        }
 
722
                        else
 
723
                        {
 
724
                                udword BaseIndex = CurrentLeaf.GetTriangleIndex();
 
725
 
 
726
                                // Loop through triangles and test each of them
 
727
                                while(NbTris--)
 
728
                                {
 
729
                                        udword TriangleIndex = BaseIndex++;
 
730
                                        LSS_PRIM(TriangleIndex, OPC_CONTACT)
 
731
                                }
 
732
                        }
 
733
                }
 
734
        }
 
735
 
 
736
        return true;
 
737
}