aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/libraries/ode-0.9/OPCODE/OPC_RayCollider.cpp
diff options
context:
space:
mode:
authordan miller2007-10-19 05:24:38 +0000
committerdan miller2007-10-19 05:24:38 +0000
commitf205de7847da7ae1c10212d82e7042d0100b4ce0 (patch)
tree9acc9608a6880502aaeda43af52c33e278e95b9c /libraries/ode-0.9/OPCODE/OPC_RayCollider.cpp
parenttrying to fix my screwup part deux (diff)
downloadopensim-SC_OLD-f205de7847da7ae1c10212d82e7042d0100b4ce0.zip
opensim-SC_OLD-f205de7847da7ae1c10212d82e7042d0100b4ce0.tar.gz
opensim-SC_OLD-f205de7847da7ae1c10212d82e7042d0100b4ce0.tar.bz2
opensim-SC_OLD-f205de7847da7ae1c10212d82e7042d0100b4ce0.tar.xz
from the start... checking in ode-0.9
Diffstat (limited to 'libraries/ode-0.9/OPCODE/OPC_RayCollider.cpp')
-rw-r--r--libraries/ode-0.9/OPCODE/OPC_RayCollider.cpp762
1 files changed, 762 insertions, 0 deletions
diff --git a/libraries/ode-0.9/OPCODE/OPC_RayCollider.cpp b/libraries/ode-0.9/OPCODE/OPC_RayCollider.cpp
new file mode 100644
index 0000000..5828ce4
--- /dev/null
+++ b/libraries/ode-0.9/OPCODE/OPC_RayCollider.cpp
@@ -0,0 +1,762 @@
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 ray collider.
12 * \file OPC_RayCollider.cpp
13 * \author Pierre Terdiman
14 * \date June, 2, 2001
15 */
16///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
17
18///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
19/**
20 * Contains a ray-vs-tree collider.
21 * This class performs a stabbing query on an AABB tree, i.e. does a ray-mesh collision.
22 *
23 * HIGHER DISTANCE BOUND:
24 *
25 * If P0 and P1 are two 3D points, let's define:
26 * - d = distance between P0 and P1
27 * - Origin = P0
28 * - Direction = (P1 - P0) / d = normalized direction vector
29 * - A parameter t such as a point P on the line (P0,P1) is P = Origin + t * Direction
30 * - t = 0 --> P = P0
31 * - t = d --> P = P1
32 *
33 * Then we can define a general "ray" as:
34 *
35 * struct Ray
36 * {
37 * Point Origin;
38 * Point Direction;
39 * };
40 *
41 * But it actually maps three different things:
42 * - a segment, when 0 <= t <= d
43 * - a half-line, when 0 <= t < +infinity, or -infinity < t <= d
44 * - a line, when -infinity < t < +infinity
45 *
46 * In Opcode, we support segment queries, which yield half-line queries by setting d = +infinity.
47 * We don't support line-queries. If you need them, shift the origin along the ray by an appropriate margin.
48 *
49 * In short, the lower bound is always 0, and you can setup the higher bound "d" with RayCollider::SetMaxDist().
50 *
51 * Query |segment |half-line |line
52 * --------|-------------------|---------------|----------------
53 * Usages |-shadow feelers |-raytracing |-
54 * |-sweep tests |-in/out tests |
55 *
56 * FIRST CONTACT:
57 *
58 * - You can setup "first contact" mode or "all contacts" mode with RayCollider::SetFirstContact().
59 * - In "first contact" mode we return as soon as the ray hits one face. If can be useful e.g. for shadow feelers, where
60 * you want to know whether the path to the light is free or not (a boolean answer is enough).
61 * - In "all contacts" mode we return all faces hit by the ray.
62 *
63 * TEMPORAL COHERENCE:
64 *
65 * - You can enable or disable temporal coherence with RayCollider::SetTemporalCoherence().
66 * - It currently only works in "first contact" mode.
67 * - If temporal coherence is enabled, the previously hit triangle is cached during the first query. Then, next queries
68 * start by colliding the ray against the cached triangle. If they still collide, we return immediately.
69 *
70 * CLOSEST HIT:
71 *
72 * - You can enable or disable "closest hit" with RayCollider::SetClosestHit().
73 * - It currently only works in "all contacts" mode.
74 * - If closest hit is enabled, faces are sorted by distance on-the-fly and the closest one only is reported.
75 *
76 * BACKFACE CULLING:
77 *
78 * - You can enable or disable backface culling with RayCollider::SetCulling().
79 * - If culling is enabled, ray will not hit back faces (only front faces).
80 *
81 *
82 *
83 * \class RayCollider
84 * \author Pierre Terdiman
85 * \version 1.3
86 * \date June, 2, 2001
87*/
88///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
89
90///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
91/**
92 * This class describes a face hit by a ray or segment.
93 * This is a particular class dedicated to stabbing queries.
94 *
95 * \class CollisionFace
96 * \author Pierre Terdiman
97 * \version 1.3
98 * \date March, 20, 2001
99*/
100///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
101
102///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
103/**
104 * This class is a dedicated collection of CollisionFace.
105 *
106 * \class CollisionFaces
107 * \author Pierre Terdiman
108 * \version 1.3
109 * \date March, 20, 2001
110*/
111///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
112
113///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
114// Precompiled Header
115#include "Stdafx.h"
116
117using namespace Opcode;
118
119#include "OPC_RayAABBOverlap.h"
120#include "OPC_RayTriOverlap.h"
121
122#define SET_CONTACT(prim_index, flag) \
123 mNbIntersections++; \
124 /* Set contact status */ \
125 mFlags |= flag; \
126 /* In any case the contact has been found and recorded in mStabbedFace */ \
127 mStabbedFace.mFaceID = prim_index;
128
129#ifdef OPC_RAYHIT_CALLBACK
130
131 #define HANDLE_CONTACT(prim_index, flag) \
132 SET_CONTACT(prim_index, flag) \
133 \
134 if(mHitCallback) (mHitCallback)(mStabbedFace, mUserData);
135
136 #define UPDATE_CACHE \
137 if(cache && GetContactStatus()) \
138 { \
139 *cache = mStabbedFace.mFaceID; \
140 }
141#else
142
143 #define HANDLE_CONTACT(prim_index, flag) \
144 SET_CONTACT(prim_index, flag) \
145 \
146 /* Now we can also record it in mStabbedFaces if available */ \
147 if(mStabbedFaces) \
148 { \
149 /* If we want all faces or if that's the first one we hit */ \
150 if(!mClosestHit || !mStabbedFaces->GetNbFaces()) \
151 { \
152 mStabbedFaces->AddFace(mStabbedFace); \
153 } \
154 else \
155 { \
156 /* We only keep closest hit */ \
157 CollisionFace* Current = const_cast<CollisionFace*>(mStabbedFaces->GetFaces()); \
158 if(Current && mStabbedFace.mDistance<Current->mDistance) \
159 { \
160 *Current = mStabbedFace; \
161 } \
162 } \
163 }
164
165 #define UPDATE_CACHE \
166 if(cache && GetContactStatus() && mStabbedFaces) \
167 { \
168 const CollisionFace* Current = mStabbedFaces->GetFaces(); \
169 if(Current) *cache = Current->mFaceID; \
170 else *cache = INVALID_ID; \
171 }
172#endif
173
174#define SEGMENT_PRIM(prim_index, flag) \
175 /* Request vertices from the app */ \
176 VertexPointers VP; mIMesh->GetTriangle(VP, prim_index); \
177 \
178 /* Perform ray-tri overlap test and return */ \
179 if(RayTriOverlap(*VP.Vertex[0], *VP.Vertex[1], *VP.Vertex[2])) \
180 { \
181 /* Intersection point is valid if dist < segment's length */ \
182 /* We know dist>0 so we can use integers */ \
183 if(IR(mStabbedFace.mDistance)<IR(mMaxDist)) \
184 { \
185 HANDLE_CONTACT(prim_index, flag) \
186 } \
187 }
188
189#define RAY_PRIM(prim_index, flag) \
190 /* Request vertices from the app */ \
191 VertexPointers VP; mIMesh->GetTriangle(VP, prim_index); \
192 \
193 /* Perform ray-tri overlap test and return */ \
194 if(RayTriOverlap(*VP.Vertex[0], *VP.Vertex[1], *VP.Vertex[2])) \
195 { \
196 HANDLE_CONTACT(prim_index, flag) \
197 }
198
199
200///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
201/**
202 * Constructor.
203 */
204///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
205RayCollider::RayCollider() :
206 mNbRayBVTests (0),
207 mNbRayPrimTests (0),
208 mNbIntersections (0),
209 mCulling (true),
210#ifdef OPC_RAYHIT_CALLBACK
211 mHitCallback (null),
212 mUserData (0),
213#else
214 mClosestHit (false),
215 mStabbedFaces (null),
216#endif
217 mMaxDist (MAX_FLOAT)
218{
219}
220
221///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
222/**
223 * Destructor.
224 */
225///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
226RayCollider::~RayCollider()
227{
228}
229
230///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
231/**
232 * Validates current settings. You should call this method after all the settings and callbacks have been defined.
233 * \return null if everything is ok, else a string describing the problem
234 */
235///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
236const char* RayCollider::ValidateSettings()
237{
238 if(mMaxDist<0.0f) return "Higher distance bound must be positive!";
239 if(TemporalCoherenceEnabled() && !FirstContactEnabled()) return "Temporal coherence only works with ""First contact"" mode!";
240#ifndef OPC_RAYHIT_CALLBACK
241 if(mClosestHit && FirstContactEnabled()) return "Closest hit doesn't work with ""First contact"" mode!";
242 if(TemporalCoherenceEnabled() && mClosestHit) return "Temporal coherence can't guarantee to report closest hit!";
243#endif
244 if(SkipPrimitiveTests()) return "SkipPrimitiveTests not possible for RayCollider ! (not implemented)";
245 return null;
246}
247
248///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
249/**
250 * Generic stabbing query for generic OPCODE models. After the call, access the results:
251 * - with GetContactStatus()
252 * - in the user-provided destination array
253 *
254 * \param world_ray [in] stabbing ray in world space
255 * \param model [in] Opcode model to collide with
256 * \param world [in] model's world matrix, or null
257 * \param cache [in] a possibly cached face index, or null
258 * \return true if success
259 * \warning SCALE NOT SUPPORTED. The matrices must contain rotation & translation parts only.
260 */
261///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
262bool RayCollider::Collide(const Ray& world_ray, const Model& model, const Matrix4x4* world, udword* cache)
263{
264 // Checkings
265 if(!Setup(&model)) return false;
266
267 // Init collision query
268 if(InitQuery(world_ray, world, cache)) return true;
269
270 if(!model.HasLeafNodes())
271 {
272 if(model.IsQuantized())
273 {
274 const AABBQuantizedNoLeafTree* Tree = (const AABBQuantizedNoLeafTree*)model.GetTree();
275
276 // Setup dequantization coeffs
277 mCenterCoeff = Tree->mCenterCoeff;
278 mExtentsCoeff = Tree->mExtentsCoeff;
279
280 // Perform stabbing query
281 if(IR(mMaxDist)!=IEEE_MAX_FLOAT) _SegmentStab(Tree->GetNodes());
282 else _RayStab(Tree->GetNodes());
283 }
284 else
285 {
286 const AABBNoLeafTree* Tree = (const AABBNoLeafTree*)model.GetTree();
287
288 // Perform stabbing query
289 if(IR(mMaxDist)!=IEEE_MAX_FLOAT) _SegmentStab(Tree->GetNodes());
290 else _RayStab(Tree->GetNodes());
291 }
292 }
293 else
294 {
295 if(model.IsQuantized())
296 {
297 const AABBQuantizedTree* Tree = (const AABBQuantizedTree*)model.GetTree();
298
299 // Setup dequantization coeffs
300 mCenterCoeff = Tree->mCenterCoeff;
301 mExtentsCoeff = Tree->mExtentsCoeff;
302
303 // Perform stabbing query
304 if(IR(mMaxDist)!=IEEE_MAX_FLOAT) _SegmentStab(Tree->GetNodes());
305 else _RayStab(Tree->GetNodes());
306 }
307 else
308 {
309 const AABBCollisionTree* Tree = (const AABBCollisionTree*)model.GetTree();
310
311 // Perform stabbing query
312 if(IR(mMaxDist)!=IEEE_MAX_FLOAT) _SegmentStab(Tree->GetNodes());
313 else _RayStab(Tree->GetNodes());
314 }
315 }
316
317 // Update cache if needed
318 UPDATE_CACHE
319 return true;
320}
321
322
323///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
324/**
325 * Initializes a stabbing query :
326 * - reset stats & contact status
327 * - compute ray in local space
328 * - check temporal coherence
329 *
330 * \param world_ray [in] stabbing ray in world space
331 * \param world [in] object's world matrix, or null
332 * \param face_id [in] index of previously stabbed triangle
333 * \return TRUE if we can return immediately
334 * \warning SCALE NOT SUPPORTED. The matrix must contain rotation & translation parts only.
335 */
336///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
337BOOL RayCollider::InitQuery(const Ray& world_ray, const Matrix4x4* world, udword* face_id)
338{
339 // Reset stats & contact status
340 Collider::InitQuery();
341 mNbRayBVTests = 0;
342 mNbRayPrimTests = 0;
343 mNbIntersections = 0;
344#ifndef OPC_RAYHIT_CALLBACK
345 if(mStabbedFaces) mStabbedFaces->Reset();
346#endif
347
348 // Compute ray in local space
349 // The (Origin/Dir) form is needed for the ray-triangle test anyway (even for segment tests)
350 if(world)
351 {
352 Matrix3x3 InvWorld = *world;
353 mDir = InvWorld * world_ray.mDir;
354
355 Matrix4x4 World;
356 InvertPRMatrix(World, *world);
357 mOrigin = world_ray.mOrig * World;
358 }
359 else
360 {
361 mDir = world_ray.mDir;
362 mOrigin = world_ray.mOrig;
363 }
364
365 // 4) Special case: 1-triangle meshes [Opcode 1.3]
366 if(mCurrentModel && mCurrentModel->HasSingleNode())
367 {
368 // We simply perform the BV-Prim overlap test each time. We assume single triangle has index 0.
369 if(!SkipPrimitiveTests())
370 {
371 // Perform overlap test between the unique triangle and the ray (and set contact status if needed)
372 SEGMENT_PRIM(udword(0), OPC_CONTACT)
373
374 // Return immediately regardless of status
375 return TRUE;
376 }
377 }
378
379 // Check temporal coherence :
380
381 // Test previously colliding primitives first
382 if(TemporalCoherenceEnabled() && FirstContactEnabled() && face_id && *face_id!=INVALID_ID)
383 {
384#ifdef OLD_CODE
385#ifndef OPC_RAYHIT_CALLBACK
386 if(!mClosestHit)
387#endif
388 {
389 // Request vertices from the app
390 VertexPointers VP;
391 mIMesh->GetTriangle(VP, *face_id);
392 // Perform ray-cached tri overlap test
393 if(RayTriOverlap(*VP.Vertex[0], *VP.Vertex[1], *VP.Vertex[2]))
394 {
395 // Intersection point is valid if:
396 // - distance is positive (else it can just be a face behind the orig point)
397 // - distance is smaller than a given max distance (useful for shadow feelers)
398// if(mStabbedFace.mDistance>0.0f && mStabbedFace.mDistance<mMaxDist)
399 if(IR(mStabbedFace.mDistance)<IR(mMaxDist)) // The other test is already performed in RayTriOverlap
400 {
401 // Set contact status
402 mFlags |= OPC_TEMPORAL_CONTACT;
403
404 mStabbedFace.mFaceID = *face_id;
405
406#ifndef OPC_RAYHIT_CALLBACK
407 if(mStabbedFaces) mStabbedFaces->AddFace(mStabbedFace);
408#endif
409 return TRUE;
410 }
411 }
412 }
413#else
414 // New code
415 // We handle both Segment/ray queries with the same segment code, and a possible infinite limit
416 SEGMENT_PRIM(*face_id, OPC_TEMPORAL_CONTACT)
417
418 // Return immediately if possible
419 if(GetContactStatus()) return TRUE;
420#endif
421 }
422
423 // Precompute data (moved after temporal coherence since only needed for ray-AABB)
424 if(IR(mMaxDist)!=IEEE_MAX_FLOAT)
425 {
426 // For Segment-AABB overlap
427 mData = 0.5f * mDir * mMaxDist;
428 mData2 = mOrigin + mData;
429
430 // Precompute mFDir;
431 mFDir.x = fabsf(mData.x);
432 mFDir.y = fabsf(mData.y);
433 mFDir.z = fabsf(mData.z);
434 }
435 else
436 {
437 // For Ray-AABB overlap
438// udword x = SIR(mDir.x)-1;
439// udword y = SIR(mDir.y)-1;
440// udword z = SIR(mDir.z)-1;
441// mData.x = FR(x);
442// mData.y = FR(y);
443// mData.z = FR(z);
444
445 // Precompute mFDir;
446 mFDir.x = fabsf(mDir.x);
447 mFDir.y = fabsf(mDir.y);
448 mFDir.z = fabsf(mDir.z);
449 }
450
451 return FALSE;
452}
453
454///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
455/**
456 * Stabbing query for vanilla AABB trees.
457 * \param world_ray [in] stabbing ray in world space
458 * \param tree [in] AABB tree
459 * \param box_indices [out] indices of stabbed boxes
460 * \return true if success
461 */
462///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
463bool RayCollider::Collide(const Ray& world_ray, const AABBTree* tree, Container& box_indices)
464{
465 // ### bad design here
466
467 // This is typically called for a scene tree, full of -AABBs-, not full of triangles.
468 // So we don't really have "primitives" to deal with. Hence it doesn't work with
469 // "FirstContact" + "TemporalCoherence".
470 ASSERT( !(FirstContactEnabled() && TemporalCoherenceEnabled()) );
471
472 // Checkings
473 if(!tree) return false;
474
475 // Init collision query
476 // Basically this is only called to initialize precomputed data
477 if(InitQuery(world_ray)) return true;
478
479 // Perform stabbing query
480 if(IR(mMaxDist)!=IEEE_MAX_FLOAT) _SegmentStab(tree, box_indices);
481 else _RayStab(tree, box_indices);
482
483 return true;
484}
485
486
487///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
488/**
489 * Recursive stabbing query for normal AABB trees.
490 * \param node [in] current collision node
491 */
492///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
493void RayCollider::_SegmentStab(const AABBCollisionNode* node)
494{
495 // Perform Segment-AABB overlap test
496 if(!SegmentAABBOverlap(node->mAABB.mCenter, node->mAABB.mExtents)) return;
497
498 if(node->IsLeaf())
499 {
500 SEGMENT_PRIM(node->GetPrimitive(), OPC_CONTACT)
501 }
502 else
503 {
504 _SegmentStab(node->GetPos());
505
506 if(ContactFound()) return;
507
508 _SegmentStab(node->GetNeg());
509 }
510}
511
512///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
513/**
514 * Recursive stabbing query for quantized AABB trees.
515 * \param node [in] current collision node
516 */
517///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
518void RayCollider::_SegmentStab(const AABBQuantizedNode* node)
519{
520 // Dequantize box
521 const QuantizedAABB& Box = node->mAABB;
522 const Point Center(float(Box.mCenter[0]) * mCenterCoeff.x, float(Box.mCenter[1]) * mCenterCoeff.y, float(Box.mCenter[2]) * mCenterCoeff.z);
523 const Point Extents(float(Box.mExtents[0]) * mExtentsCoeff.x, float(Box.mExtents[1]) * mExtentsCoeff.y, float(Box.mExtents[2]) * mExtentsCoeff.z);
524
525 // Perform Segment-AABB overlap test
526 if(!SegmentAABBOverlap(Center, Extents)) return;
527
528 if(node->IsLeaf())
529 {
530 SEGMENT_PRIM(node->GetPrimitive(), OPC_CONTACT)
531 }
532 else
533 {
534 _SegmentStab(node->GetPos());
535
536 if(ContactFound()) return;
537
538 _SegmentStab(node->GetNeg());
539 }
540}
541
542///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
543/**
544 * Recursive stabbing query for no-leaf AABB trees.
545 * \param node [in] current collision node
546 */
547///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
548void RayCollider::_SegmentStab(const AABBNoLeafNode* node)
549{
550 // Perform Segment-AABB overlap test
551 if(!SegmentAABBOverlap(node->mAABB.mCenter, node->mAABB.mExtents)) return;
552
553 if(node->HasPosLeaf())
554 {
555 SEGMENT_PRIM(node->GetPosPrimitive(), OPC_CONTACT)
556 }
557 else _SegmentStab(node->GetPos());
558
559 if(ContactFound()) return;
560
561 if(node->HasNegLeaf())
562 {
563 SEGMENT_PRIM(node->GetNegPrimitive(), OPC_CONTACT)
564 }
565 else _SegmentStab(node->GetNeg());
566}
567
568///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
569/**
570 * Recursive stabbing query for quantized no-leaf AABB trees.
571 * \param node [in] current collision node
572 */
573///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
574void RayCollider::_SegmentStab(const AABBQuantizedNoLeafNode* node)
575{
576 // Dequantize box
577 const QuantizedAABB& Box = node->mAABB;
578 const Point Center(float(Box.mCenter[0]) * mCenterCoeff.x, float(Box.mCenter[1]) * mCenterCoeff.y, float(Box.mCenter[2]) * mCenterCoeff.z);
579 const Point Extents(float(Box.mExtents[0]) * mExtentsCoeff.x, float(Box.mExtents[1]) * mExtentsCoeff.y, float(Box.mExtents[2]) * mExtentsCoeff.z);
580
581 // Perform Segment-AABB overlap test
582 if(!SegmentAABBOverlap(Center, Extents)) return;
583
584 if(node->HasPosLeaf())
585 {
586 SEGMENT_PRIM(node->GetPosPrimitive(), OPC_CONTACT)
587 }
588 else _SegmentStab(node->GetPos());
589
590 if(ContactFound()) return;
591
592 if(node->HasNegLeaf())
593 {
594 SEGMENT_PRIM(node->GetNegPrimitive(), OPC_CONTACT)
595 }
596 else _SegmentStab(node->GetNeg());
597}
598
599///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
600/**
601 * Recursive stabbing query for vanilla AABB trees.
602 * \param node [in] current collision node
603 * \param box_indices [out] indices of stabbed boxes
604 */
605///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
606void RayCollider::_SegmentStab(const AABBTreeNode* node, Container& box_indices)
607{
608 // Test the box against the segment
609 Point Center, Extents;
610 node->GetAABB()->GetCenter(Center);
611 node->GetAABB()->GetExtents(Extents);
612 if(!SegmentAABBOverlap(Center, Extents)) return;
613
614 if(node->IsLeaf())
615 {
616 box_indices.Add(node->GetPrimitives(), node->GetNbPrimitives());
617 }
618 else
619 {
620 _SegmentStab(node->GetPos(), box_indices);
621 _SegmentStab(node->GetNeg(), box_indices);
622 }
623}
624
625///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
626/**
627 * Recursive stabbing query for normal AABB trees.
628 * \param node [in] current collision node
629 */
630///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
631void RayCollider::_RayStab(const AABBCollisionNode* node)
632{
633 // Perform Ray-AABB overlap test
634 if(!RayAABBOverlap(node->mAABB.mCenter, node->mAABB.mExtents)) return;
635
636 if(node->IsLeaf())
637 {
638 RAY_PRIM(node->GetPrimitive(), OPC_CONTACT)
639 }
640 else
641 {
642 _RayStab(node->GetPos());
643
644 if(ContactFound()) return;
645
646 _RayStab(node->GetNeg());
647 }
648}
649
650///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
651/**
652 * Recursive stabbing query for quantized AABB trees.
653 * \param node [in] current collision node
654 */
655///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
656void RayCollider::_RayStab(const AABBQuantizedNode* node)
657{
658 // Dequantize box
659 const QuantizedAABB& Box = node->mAABB;
660 const Point Center(float(Box.mCenter[0]) * mCenterCoeff.x, float(Box.mCenter[1]) * mCenterCoeff.y, float(Box.mCenter[2]) * mCenterCoeff.z);
661 const Point Extents(float(Box.mExtents[0]) * mExtentsCoeff.x, float(Box.mExtents[1]) * mExtentsCoeff.y, float(Box.mExtents[2]) * mExtentsCoeff.z);
662
663 // Perform Ray-AABB overlap test
664 if(!RayAABBOverlap(Center, Extents)) return;
665
666 if(node->IsLeaf())
667 {
668 RAY_PRIM(node->GetPrimitive(), OPC_CONTACT)
669 }
670 else
671 {
672 _RayStab(node->GetPos());
673
674 if(ContactFound()) return;
675
676 _RayStab(node->GetNeg());
677 }
678}
679
680///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
681/**
682 * Recursive stabbing query for no-leaf AABB trees.
683 * \param node [in] current collision node
684 */
685///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
686void RayCollider::_RayStab(const AABBNoLeafNode* node)
687{
688 // Perform Ray-AABB overlap test
689 if(!RayAABBOverlap(node->mAABB.mCenter, node->mAABB.mExtents)) return;
690
691 if(node->HasPosLeaf())
692 {
693 RAY_PRIM(node->GetPosPrimitive(), OPC_CONTACT)
694 }
695 else _RayStab(node->GetPos());
696
697 if(ContactFound()) return;
698
699 if(node->HasNegLeaf())
700 {
701 RAY_PRIM(node->GetNegPrimitive(), OPC_CONTACT)
702 }
703 else _RayStab(node->GetNeg());
704}
705
706///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
707/**
708 * Recursive stabbing query for quantized no-leaf AABB trees.
709 * \param node [in] current collision node
710 */
711///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
712void RayCollider::_RayStab(const AABBQuantizedNoLeafNode* node)
713{
714 // Dequantize box
715 const QuantizedAABB& Box = node->mAABB;
716 const Point Center(float(Box.mCenter[0]) * mCenterCoeff.x, float(Box.mCenter[1]) * mCenterCoeff.y, float(Box.mCenter[2]) * mCenterCoeff.z);
717 const Point Extents(float(Box.mExtents[0]) * mExtentsCoeff.x, float(Box.mExtents[1]) * mExtentsCoeff.y, float(Box.mExtents[2]) * mExtentsCoeff.z);
718
719 // Perform Ray-AABB overlap test
720 if(!RayAABBOverlap(Center, Extents)) return;
721
722 if(node->HasPosLeaf())
723 {
724 RAY_PRIM(node->GetPosPrimitive(), OPC_CONTACT)
725 }
726 else _RayStab(node->GetPos());
727
728 if(ContactFound()) return;
729
730 if(node->HasNegLeaf())
731 {
732 RAY_PRIM(node->GetNegPrimitive(), OPC_CONTACT)
733 }
734 else _RayStab(node->GetNeg());
735}
736
737///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
738/**
739 * Recursive stabbing query for vanilla AABB trees.
740 * \param node [in] current collision node
741 * \param box_indices [out] indices of stabbed boxes
742 */
743///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
744void RayCollider::_RayStab(const AABBTreeNode* node, Container& box_indices)
745{
746 // Test the box against the ray
747 Point Center, Extents;
748 node->GetAABB()->GetCenter(Center);
749 node->GetAABB()->GetExtents(Extents);
750 if(!RayAABBOverlap(Center, Extents)) return;
751
752 if(node->IsLeaf())
753 {
754 mFlags |= OPC_CONTACT;
755 box_indices.Add(node->GetPrimitives(), node->GetNbPrimitives());
756 }
757 else
758 {
759 _RayStab(node->GetPos(), box_indices);
760 _RayStab(node->GetNeg(), box_indices);
761 }
762}