1 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3 * OPCODE - Optimized Collision Detection
4 * Copyright (C) 2001 Pierre Terdiman
5 * Homepage: http://www.codercorner.com/Opcode.htm
7 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
9 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
11 * Contains code for optimized trees. Implements 4 trees:
15 * - no leaf / quantized
17 * \file OPC_OptimizedTree.cpp
18 * \author Pierre Terdiman
19 * \date March, 20, 2001
21 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
23 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
25 * A standard AABB tree.
27 * \class AABBCollisionTree
28 * \author Pierre Terdiman
30 * \date March, 20, 2001
32 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
34 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
36 * A no-leaf AABB tree.
38 * \class AABBNoLeafTree
39 * \author Pierre Terdiman
41 * \date March, 20, 2001
43 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
45 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
47 * A quantized AABB tree.
49 * \class AABBQuantizedTree
50 * \author Pierre Terdiman
52 * \date March, 20, 2001
54 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
56 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
58 * A quantized no-leaf AABB tree.
60 * \class AABBQuantizedNoLeafTree
61 * \author Pierre Terdiman
63 * \date March, 20, 2001
65 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
67 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
71 using namespace Opcode
;
74 //! - true to fix quantized boxes (i.e. make sure they enclose the original ones)
75 //! - false to see the effects of quantization errors (faster, but wrong results in some cases)
76 static const bool gFixQuantized
= true;
78 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
80 * Builds an implicit tree from a standard one. An implicit tree is a complete tree (2*N-1 nodes) whose negative
81 * box pointers and primitive pointers have been made implicit, hence packing 3 pointers in one.
83 * Layout for implicit trees:
86 * - data (32-bits value)
88 * if data's LSB = 1 => remaining bits are a primitive pointer
89 * else remaining bits are a P-node pointer, and N = P + 1
91 * \relates AABBCollisionNode
92 * \fn _BuildCollisionTree(AABBCollisionNode* linear, const udword box_id, udword& current_id, const AABBTreeNode* current_node)
93 * \param linear [in] base address of destination nodes
94 * \param box_id [in] index of destination node
95 * \param current_id [in] current running index
96 * \param current_node [in] current node from input tree
98 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
99 static void _BuildCollisionTree(AABBCollisionNode
* linear
, const udword box_id
, udword
& current_id
, const AABBTreeNode
* current_node
)
101 // Current node from input tree is "current_node". Must be flattened into "linear[boxid]".
104 current_node
->GetAABB()->GetCenter(linear
[box_id
].mAABB
.mCenter
);
105 current_node
->GetAABB()->GetExtents(linear
[box_id
].mAABB
.mExtents
);
106 // Store remaining info
107 if(current_node
->IsLeaf())
109 // The input tree must be complete => i.e. one primitive/leaf
110 ASSERT(current_node
->GetNbPrimitives()==1);
111 // Get the primitive index from the input tree
112 udword PrimitiveIndex
= current_node
->GetPrimitives()[0];
113 // Setup box data as the primitive index, marked as leaf
114 linear
[box_id
].mData
= (PrimitiveIndex
<<1)|1;
118 // To make the negative one implicit, we must store P and N in successive order
119 udword PosID
= current_id
++; // Get a new id for positive child
120 udword NegID
= current_id
++; // Get a new id for negative child
121 // Setup box data as the forthcoming new P pointer
122 linear
[box_id
].mData
= (size_t)&linear
[PosID
];
123 // Make sure it's not marked as leaf
124 ASSERT(!(linear
[box_id
].mData
&1));
125 // Recurse with new IDs
126 _BuildCollisionTree(linear
, PosID
, current_id
, current_node
->GetPos());
127 _BuildCollisionTree(linear
, NegID
, current_id
, current_node
->GetNeg());
131 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
133 * Builds a "no-leaf" tree from a standard one. This is a tree whose leaf nodes have been removed.
135 * Layout for no-leaf trees:
139 * - P pointer => a node (LSB=0) or a primitive (LSB=1)
140 * - N pointer => a node (LSB=0) or a primitive (LSB=1)
142 * \relates AABBNoLeafNode
143 * \fn _BuildNoLeafTree(AABBNoLeafNode* linear, const udword box_id, udword& current_id, const AABBTreeNode* current_node)
144 * \param linear [in] base address of destination nodes
145 * \param box_id [in] index of destination node
146 * \param current_id [in] current running index
147 * \param current_node [in] current node from input tree
149 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
150 static void _BuildNoLeafTree(AABBNoLeafNode
* linear
, const udword box_id
, udword
& current_id
, const AABBTreeNode
* current_node
)
152 const AABBTreeNode
* P
= current_node
->GetPos();
153 const AABBTreeNode
* N
= current_node
->GetNeg();
157 // Internal node => keep the box
158 current_node
->GetAABB()->GetCenter(linear
[box_id
].mAABB
.mCenter
);
159 current_node
->GetAABB()->GetExtents(linear
[box_id
].mAABB
.mExtents
);
163 // The input tree must be complete => i.e. one primitive/leaf
164 ASSERT(P
->GetNbPrimitives()==1);
165 // Get the primitive index from the input tree
166 udword PrimitiveIndex
= P
->GetPrimitives()[0];
167 // Setup prev box data as the primitive index, marked as leaf
168 linear
[box_id
].mPosData
= (PrimitiveIndex
<<1)|1;
172 // Get a new id for positive child
173 udword PosID
= current_id
++;
175 linear
[box_id
].mPosData
= (size_t)&linear
[PosID
];
176 // Make sure it's not marked as leaf
177 ASSERT(!(linear
[box_id
].mPosData
&1));
179 _BuildNoLeafTree(linear
, PosID
, current_id
, P
);
184 // The input tree must be complete => i.e. one primitive/leaf
185 ASSERT(N
->GetNbPrimitives()==1);
186 // Get the primitive index from the input tree
187 udword PrimitiveIndex
= N
->GetPrimitives()[0];
188 // Setup prev box data as the primitive index, marked as leaf
189 linear
[box_id
].mNegData
= (PrimitiveIndex
<<1)|1;
193 // Get a new id for negative child
194 udword NegID
= current_id
++;
196 linear
[box_id
].mNegData
= (size_t)&linear
[NegID
];
197 // Make sure it's not marked as leaf
198 ASSERT(!(linear
[box_id
].mNegData
&1));
200 _BuildNoLeafTree(linear
, NegID
, current_id
, N
);
204 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
208 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
209 AABBCollisionTree::AABBCollisionTree() : mNodes(null
)
213 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
217 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
218 AABBCollisionTree::~AABBCollisionTree()
223 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
225 * Builds the collision tree from a generic AABB tree.
226 * \param tree [in] generic AABB tree
227 * \return true if success
229 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
230 bool AABBCollisionTree::Build(AABBTree
* tree
)
233 if(!tree
) return false;
234 // Check the input tree is complete
235 udword NbTriangles
= tree
->GetNbPrimitives();
236 udword NbNodes
= tree
->GetNbNodes();
237 if(NbNodes
!=NbTriangles
*2-1) return false;
240 if(mNbNodes
!=NbNodes
) // Same number of nodes => keep moving
244 mNodes
= new AABBCollisionNode
[NbNodes
];
250 _BuildCollisionTree(mNodes
, 0, CurID
, tree
);
251 ASSERT(CurID
==NbNodes
);
256 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
258 * Refits the collision tree after vertices have been modified.
259 * \param mesh_interface [in] mesh interface for current model
260 * \return true if success
262 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
263 bool AABBCollisionTree::Refit(const MeshInterface
* /*mesh_interface*/)
265 ASSERT(!"Not implemented since AABBCollisionTrees have twice as more nodes to refit as AABBNoLeafTrees!");
269 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
271 * Walks the tree and call the user back for each node.
272 * \param callback [in] walking callback
273 * \param user_data [in] callback's user data
274 * \return true if success
276 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
277 bool AABBCollisionTree::Walk(GenericWalkingCallback callback
, void* user_data
) const
279 if(!callback
) return false;
283 static void _Walk(const AABBCollisionNode
* current_node
, GenericWalkingCallback callback
, void* user_data
)
285 if(!current_node
|| !(callback
)(current_node
, user_data
)) return;
287 if(!current_node
->IsLeaf())
289 _Walk(current_node
->GetPos(), callback
, user_data
);
290 _Walk(current_node
->GetNeg(), callback
, user_data
);
294 Local::_Walk(mNodes
, callback
, user_data
);
299 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
303 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
304 AABBNoLeafTree::AABBNoLeafTree() : mNodes(null
)
308 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
312 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
313 AABBNoLeafTree::~AABBNoLeafTree()
318 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
320 * Builds the collision tree from a generic AABB tree.
321 * \param tree [in] generic AABB tree
322 * \return true if success
324 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
325 bool AABBNoLeafTree::Build(AABBTree
* tree
)
328 if(!tree
) return false;
329 // Check the input tree is complete
330 udword NbTriangles
= tree
->GetNbPrimitives();
331 udword NbExistingNodes
= tree
->GetNbNodes();
332 if(NbExistingNodes
!=NbTriangles
*2-1) return false;
334 udword NbNodes
= NbTriangles
-1;
336 if(mNbNodes
!=NbNodes
) // Same number of nodes => keep moving
340 mNodes
= new AABBNoLeafNode
[NbNodes
];
346 _BuildNoLeafTree(mNodes
, 0, CurID
, tree
);
347 ASSERT(CurID
==NbNodes
);
352 inline_
void ComputeMinMax(Point
& min
, Point
& max
, const VertexPointers
& vp
)
354 // Compute triangle's AABB = a leaf box
355 #ifdef OPC_USE_FCOMI // a 15% speedup on my machine, not much
356 min
.x
= FCMin3(vp
.Vertex
[0]->x
, vp
.Vertex
[1]->x
, vp
.Vertex
[2]->x
);
357 max
.x
= FCMax3(vp
.Vertex
[0]->x
, vp
.Vertex
[1]->x
, vp
.Vertex
[2]->x
);
359 min
.y
= FCMin3(vp
.Vertex
[0]->y
, vp
.Vertex
[1]->y
, vp
.Vertex
[2]->y
);
360 max
.y
= FCMax3(vp
.Vertex
[0]->y
, vp
.Vertex
[1]->y
, vp
.Vertex
[2]->y
);
362 min
.z
= FCMin3(vp
.Vertex
[0]->z
, vp
.Vertex
[1]->z
, vp
.Vertex
[2]->z
);
363 max
.z
= FCMax3(vp
.Vertex
[0]->z
, vp
.Vertex
[1]->z
, vp
.Vertex
[2]->z
);
367 min
.Min(*vp
.Vertex
[1]);
368 max
.Max(*vp
.Vertex
[1]);
369 min
.Min(*vp
.Vertex
[2]);
370 max
.Max(*vp
.Vertex
[2]);
374 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
376 * Refits the collision tree after vertices have been modified.
377 * \param mesh_interface [in] mesh interface for current model
378 * \return true if success
380 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
381 bool AABBNoLeafTree::Refit(const MeshInterface
* mesh_interface
)
384 if(!mesh_interface
) return false;
391 udword Index
= mNbNodes
;
394 AABBNoLeafNode
& Current
= mNodes
[Index
];
396 if(Current
.HasPosLeaf())
398 mesh_interface
->GetTriangle(VP
, Current
.GetPosPrimitive(), VC
);
399 ComputeMinMax(Min
, Max
, VP
);
403 const CollisionAABB
& CurrentBox
= Current
.GetPos()->mAABB
;
404 CurrentBox
.GetMin(Min
);
405 CurrentBox
.GetMax(Max
);
408 if(Current
.HasNegLeaf())
410 mesh_interface
->GetTriangle(VP
, Current
.GetNegPrimitive(), VC
);
411 ComputeMinMax(Min_
, Max_
, VP
);
415 const CollisionAABB
& CurrentBox
= Current
.GetNeg()->mAABB
;
416 CurrentBox
.GetMin(Min_
);
417 CurrentBox
.GetMax(Max_
);
420 Min
.x
= FCMin2(Min
.x
, Min_
.x
);
421 Max
.x
= FCMax2(Max
.x
, Max_
.x
);
422 Min
.y
= FCMin2(Min
.y
, Min_
.y
);
423 Max
.y
= FCMax2(Max
.y
, Max_
.y
);
424 Min
.z
= FCMin2(Min
.z
, Min_
.z
);
425 Max
.z
= FCMax2(Max
.z
, Max_
.z
);
430 Current
.mAABB
.SetMinMax(Min
, Max
);
435 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
437 * Walks the tree and call the user back for each node.
438 * \param callback [in] walking callback
439 * \param user_data [in] callback's user data
440 * \return true if success
442 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
443 bool AABBNoLeafTree::Walk(GenericWalkingCallback callback
, void* user_data
) const
445 if(!callback
) return false;
449 static void _Walk(const AABBNoLeafNode
* current_node
, GenericWalkingCallback callback
, void* user_data
)
451 if(!current_node
|| !(callback
)(current_node
, user_data
)) return;
453 if(!current_node
->HasPosLeaf()) _Walk(current_node
->GetPos(), callback
, user_data
);
454 if(!current_node
->HasNegLeaf()) _Walk(current_node
->GetNeg(), callback
, user_data
);
457 Local::_Walk(mNodes
, callback
, user_data
);
461 // Quantization notes:
462 // - We could use the highest bits of mData to store some more quantized bits. Dequantization code
463 // would be slightly more complex, but number of overlap tests would be reduced (and anyhow those
464 // bits are currently wasted). Of course it's not possible if we move to 16 bits mData.
465 // - Something like "16 bits floats" could be tested, to bypass the int-to-float conversion.
466 // - A dedicated BV-BV test could be used, dequantizing while testing for overlap. (i.e. it's some
467 // lazy-dequantization which may save some work in case of early exits). At the very least some
468 // muls could be saved by precomputing several more matrices. But maybe not worth the pain.
469 // - Do we need to dequantize anyway? Not doing the extents-related muls only implies the box has
470 // been scaled, for example.
471 // - The deeper we move into the hierarchy, the smaller the extents should be. May not need a fixed
472 // number of quantization bits. Even better, could probably be best delta-encoded.
475 // Find max values. Some people asked why I wasn't simply using the first node. Well, I can't.
476 // I'm not looking for (min, max) values like in a standard AABB, I'm looking for the extremal
477 // centers/extents in order to quantize them. The first node would only give a single center and
478 // a single extents. While extents would be the biggest, the center wouldn't.
479 #define FIND_MAX_VALUES \
480 /* Get max values */ \
481 Point CMax(MIN_FLOAT, MIN_FLOAT, MIN_FLOAT); \
482 Point EMax(MIN_FLOAT, MIN_FLOAT, MIN_FLOAT); \
483 const udword NbNodes = mNbNodes; \
484 for(udword i=0;i<NbNodes;i++) \
486 float cx = fabsf(Nodes[i].mAABB.mCenter.x); if(cx>CMax.x) CMax.x = cx; \
487 float cy = fabsf(Nodes[i].mAABB.mCenter.y); if(cy>CMax.y) CMax.y = cy; \
488 float cz = fabsf(Nodes[i].mAABB.mCenter.z); if(cz>CMax.z) CMax.z = cz; \
489 float ex = fabsf(Nodes[i].mAABB.mExtents.x); if(ex>EMax.x) EMax.x = ex; \
490 float ey = fabsf(Nodes[i].mAABB.mExtents.y); if(ey>EMax.y) EMax.y = ey; \
491 float ez = fabsf(Nodes[i].mAABB.mExtents.z); if(ez>EMax.z) EMax.z = ez; \
494 #define INIT_QUANTIZATION \
495 udword nbc=15; /* Keep one bit for sign */ \
496 udword nbe=15; /* Keep one bit for fix */ \
497 if(!gFixQuantized) nbe++; \
499 /* Compute quantization coeffs */ \
500 Point CQuantCoeff, EQuantCoeff; \
501 CQuantCoeff.x = CMax.x!=0.0f ? float((1<<nbc)-1)/CMax.x : 0.0f; \
502 CQuantCoeff.y = CMax.y!=0.0f ? float((1<<nbc)-1)/CMax.y : 0.0f; \
503 CQuantCoeff.z = CMax.z!=0.0f ? float((1<<nbc)-1)/CMax.z : 0.0f; \
504 EQuantCoeff.x = EMax.x!=0.0f ? float((1<<nbe)-1)/EMax.x : 0.0f; \
505 EQuantCoeff.y = EMax.y!=0.0f ? float((1<<nbe)-1)/EMax.y : 0.0f; \
506 EQuantCoeff.z = EMax.z!=0.0f ? float((1<<nbe)-1)/EMax.z : 0.0f; \
507 /* Compute and save dequantization coeffs */ \
508 mCenterCoeff.x = CQuantCoeff.x!=0.0f ? 1.0f / CQuantCoeff.x : 0.0f; \
509 mCenterCoeff.y = CQuantCoeff.y!=0.0f ? 1.0f / CQuantCoeff.y : 0.0f; \
510 mCenterCoeff.z = CQuantCoeff.z!=0.0f ? 1.0f / CQuantCoeff.z : 0.0f; \
511 mExtentsCoeff.x = EQuantCoeff.x!=0.0f ? 1.0f / EQuantCoeff.x : 0.0f; \
512 mExtentsCoeff.y = EQuantCoeff.y!=0.0f ? 1.0f / EQuantCoeff.y : 0.0f; \
513 mExtentsCoeff.z = EQuantCoeff.z!=0.0f ? 1.0f / EQuantCoeff.z : 0.0f; \
515 #define PERFORM_QUANTIZATION \
517 mNodes[i].mAABB.mCenter[0] = sword(Nodes[i].mAABB.mCenter.x * CQuantCoeff.x); \
518 mNodes[i].mAABB.mCenter[1] = sword(Nodes[i].mAABB.mCenter.y * CQuantCoeff.y); \
519 mNodes[i].mAABB.mCenter[2] = sword(Nodes[i].mAABB.mCenter.z * CQuantCoeff.z); \
520 mNodes[i].mAABB.mExtents[0] = uword(Nodes[i].mAABB.mExtents.x * EQuantCoeff.x); \
521 mNodes[i].mAABB.mExtents[1] = uword(Nodes[i].mAABB.mExtents.y * EQuantCoeff.y); \
522 mNodes[i].mAABB.mExtents[2] = uword(Nodes[i].mAABB.mExtents.z * EQuantCoeff.z); \
523 /* Fix quantized boxes */ \
526 /* Make sure the quantized box is still valid */ \
527 Point Max = Nodes[i].mAABB.mCenter + Nodes[i].mAABB.mExtents; \
528 Point Min = Nodes[i].mAABB.mCenter - Nodes[i].mAABB.mExtents; \
529 /* For each axis */ \
530 for(udword j=0;j<3;j++) \
531 { /* Dequantize the box center */ \
532 float qc = float(mNodes[i].mAABB.mCenter[j]) * mCenterCoeff[j]; \
535 { /* Dequantize the box extent */ \
536 float qe = float(mNodes[i].mAABB.mExtents[j]) * mExtentsCoeff[j]; \
537 /* Compare real & dequantized values */ \
538 if(qc+qe<Max[j] || qc-qe>Min[j]) \
540 mNodes[i].mAABB.mExtents[j]++; \
541 /* Prevent wrapping */ \
542 if(!mNodes[i].mAABB.mExtents[j]) \
544 mNodes[i].mAABB.mExtents[j]=0xffff; \
553 #define REMAP_DATA(member, NodeType) \
555 Data = Nodes[i].member; \
558 /* Compute box number */ \
559 size_t Nb = ((NodeType *)(Data) - (Nodes)); \
560 Data = (size_t) &mNodes[Nb]; \
563 mNodes[i].member = Data;
565 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
569 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
570 AABBQuantizedTree::AABBQuantizedTree() : mNodes(null
)
574 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
578 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
579 AABBQuantizedTree::~AABBQuantizedTree()
584 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
586 * Builds the collision tree from a generic AABB tree.
587 * \param tree [in] generic AABB tree
588 * \return true if success
590 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
591 bool AABBQuantizedTree::Build(AABBTree
* tree
)
594 if(!tree
) return false;
595 // Check the input tree is complete
596 udword NbTriangles
= tree
->GetNbPrimitives();
597 udword NbNodes
= tree
->GetNbNodes();
598 if(NbNodes
!=NbTriangles
*2-1) return false;
603 AABBCollisionNode
* Nodes
= new AABBCollisionNode
[NbNodes
];
608 _BuildCollisionTree(Nodes
, 0, CurID
, tree
);
612 mNodes
= new AABBQuantizedNode
[NbNodes
];
624 for(udword i
=0;i
<NbNodes
;i
++)
627 REMAP_DATA(mData
, AABBCollisionNode
)
638 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
640 * Refits the collision tree after vertices have been modified.
641 * \param mesh_interface [in] mesh interface for current model
642 * \return true if success
644 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
645 bool AABBQuantizedTree::Refit(const MeshInterface
* /*mesh_interface*/)
647 ASSERT(!"Not implemented since requantizing is painful !");
651 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
653 * Walks the tree and call the user back for each node.
654 * \param callback [in] walking callback
655 * \param user_data [in] callback's user data
656 * \return true if success
658 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
659 bool AABBQuantizedTree::Walk(GenericWalkingCallback callback
, void* user_data
) const
661 if(!callback
) return false;
665 static void _Walk(const AABBQuantizedNode
* current_node
, GenericWalkingCallback callback
, void* user_data
)
667 if(!current_node
|| !(callback
)(current_node
, user_data
)) return;
669 if(!current_node
->IsLeaf())
671 _Walk(current_node
->GetPos(), callback
, user_data
);
672 _Walk(current_node
->GetNeg(), callback
, user_data
);
676 Local::_Walk(mNodes
, callback
, user_data
);
682 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
686 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
687 AABBQuantizedNoLeafTree::AABBQuantizedNoLeafTree() : mNodes(null
)
691 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
695 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
696 AABBQuantizedNoLeafTree::~AABBQuantizedNoLeafTree()
701 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
703 * Builds the collision tree from a generic AABB tree.
704 * \param tree [in] generic AABB tree
705 * \return true if success
707 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
708 bool AABBQuantizedNoLeafTree::Build(AABBTree
* tree
)
711 if(!tree
) return false;
712 // Check the input tree is complete
713 udword NbTriangles
= tree
->GetNbPrimitives();
714 udword NbExistingNodes
= tree
->GetNbNodes();
715 if(NbExistingNodes
!=NbTriangles
*2-1) return false;
718 udword NbNodes
= NbTriangles
-1;
721 AABBNoLeafNode
* Nodes
= new AABBNoLeafNode
[NbNodes
];
726 _BuildNoLeafTree(Nodes
, 0, CurID
, tree
);
727 ASSERT(CurID
==NbNodes
);
731 mNodes
= new AABBQuantizedNoLeafNode
[NbNodes
];
743 for(udword i
=0;i
<NbNodes
;i
++)
746 REMAP_DATA(mPosData
, AABBNoLeafNode
)
747 REMAP_DATA(mNegData
, AABBNoLeafNode
)
758 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
760 * Refits the collision tree after vertices have been modified.
761 * \param mesh_interface [in] mesh interface for current model
762 * \return true if success
764 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
765 bool AABBQuantizedNoLeafTree::Refit(const MeshInterface
* /*mesh_interface*/)
767 ASSERT(!"Not implemented since requantizing is painful !");
771 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
773 * Walks the tree and call the user back for each node.
774 * \param callback [in] walking callback
775 * \param user_data [in] callback's user data
776 * \return true if success
778 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
779 bool AABBQuantizedNoLeafTree::Walk(GenericWalkingCallback callback
, void* user_data
) const
781 if(!callback
) return false;
785 static void _Walk(const AABBQuantizedNoLeafNode
* current_node
, GenericWalkingCallback callback
, void* user_data
)
787 if(!current_node
|| !(callback
)(current_node
, user_data
)) return;
789 if(!current_node
->HasPosLeaf()) _Walk(current_node
->GetPos(), callback
, user_data
);
790 if(!current_node
->HasNegLeaf()) _Walk(current_node
->GetNeg(), callback
, user_data
);
793 Local::_Walk(mNodes
, callback
, user_data
);