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