diff options
author | dan miller | 2007-10-19 05:20:48 +0000 |
---|---|---|
committer | dan miller | 2007-10-19 05:20:48 +0000 |
commit | d48ea5bb797037069d641da41da0f195f0124491 (patch) | |
tree | 40ff433d94859d629aac933d5ec73b382f62ba1a /libraries/ode-0.9/OPCODE/OPC_OptimizedTree.cpp | |
parent | dont ask (diff) | |
download | opensim-SC-d48ea5bb797037069d641da41da0f195f0124491.zip opensim-SC-d48ea5bb797037069d641da41da0f195f0124491.tar.gz opensim-SC-d48ea5bb797037069d641da41da0f195f0124491.tar.bz2 opensim-SC-d48ea5bb797037069d641da41da0f195f0124491.tar.xz |
one more for the gipper
Diffstat (limited to 'libraries/ode-0.9/OPCODE/OPC_OptimizedTree.cpp')
-rw-r--r-- | libraries/ode-0.9/OPCODE/OPC_OptimizedTree.cpp | 782 |
1 files changed, 782 insertions, 0 deletions
diff --git a/libraries/ode-0.9/OPCODE/OPC_OptimizedTree.cpp b/libraries/ode-0.9/OPCODE/OPC_OptimizedTree.cpp new file mode 100644 index 0000000..11b92f9 --- /dev/null +++ b/libraries/ode-0.9/OPCODE/OPC_OptimizedTree.cpp | |||
@@ -0,0 +1,782 @@ | |||
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 optimized trees. Implements 4 trees: | ||
12 | * - normal | ||
13 | * - no leaf | ||
14 | * - quantized | ||
15 | * - no leaf / quantized | ||
16 | * | ||
17 | * \file OPC_OptimizedTree.cpp | ||
18 | * \author Pierre Terdiman | ||
19 | * \date March, 20, 2001 | ||
20 | */ | ||
21 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
22 | |||
23 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
24 | /** | ||
25 | * A standard AABB tree. | ||
26 | * | ||
27 | * \class AABBCollisionTree | ||
28 | * \author Pierre Terdiman | ||
29 | * \version 1.3 | ||
30 | * \date March, 20, 2001 | ||
31 | */ | ||
32 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
33 | |||
34 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
35 | /** | ||
36 | * A no-leaf AABB tree. | ||
37 | * | ||
38 | * \class AABBNoLeafTree | ||
39 | * \author Pierre Terdiman | ||
40 | * \version 1.3 | ||
41 | * \date March, 20, 2001 | ||
42 | */ | ||
43 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
44 | |||
45 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
46 | /** | ||
47 | * A quantized AABB tree. | ||
48 | * | ||
49 | * \class AABBQuantizedTree | ||
50 | * \author Pierre Terdiman | ||
51 | * \version 1.3 | ||
52 | * \date March, 20, 2001 | ||
53 | */ | ||
54 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
55 | |||
56 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
57 | /** | ||
58 | * A quantized no-leaf AABB tree. | ||
59 | * | ||
60 | * \class AABBQuantizedNoLeafTree | ||
61 | * \author Pierre Terdiman | ||
62 | * \version 1.3 | ||
63 | * \date March, 20, 2001 | ||
64 | */ | ||
65 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
66 | |||
67 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
68 | // Precompiled Header | ||
69 | #include "Stdafx.h" | ||
70 | |||
71 | using namespace Opcode; | ||
72 | |||
73 | //! Compilation flag: | ||
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 bool gFixQuantized = true; | ||
77 | |||
78 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
79 | /** | ||
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. | ||
82 | * | ||
83 | * Layout for implicit trees: | ||
84 | * Node: | ||
85 | * - box | ||
86 | * - data (32-bits value) | ||
87 | * | ||
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 | ||
90 | * | ||
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 | ||
97 | */ | ||
98 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
99 | static void _BuildCollisionTree(AABBCollisionNode* linear, const udword box_id, udword& current_id, const AABBTreeNode* current_node) | ||
100 | { | ||
101 | // Current node from input tree is "current_node". Must be flattened into "linear[boxid]". | ||
102 | |||
103 | // Store the AABB | ||
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()) | ||
108 | { | ||
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; | ||
115 | } | ||
116 | else | ||
117 | { | ||
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()); | ||
128 | } | ||
129 | } | ||
130 | |||
131 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
132 | /** | ||
133 | * Builds a "no-leaf" tree from a standard one. This is a tree whose leaf nodes have been removed. | ||
134 | * | ||
135 | * Layout for no-leaf trees: | ||
136 | * | ||
137 | * Node: | ||
138 | * - box | ||
139 | * - P pointer => a node (LSB=0) or a primitive (LSB=1) | ||
140 | * - N pointer => a node (LSB=0) or a primitive (LSB=1) | ||
141 | * | ||
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 | ||
148 | */ | ||
149 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
150 | static void _BuildNoLeafTree(AABBNoLeafNode* linear, const udword box_id, udword& current_id, const AABBTreeNode* current_node) | ||
151 | { | ||
152 | const AABBTreeNode* P = current_node->GetPos(); | ||
153 | const AABBTreeNode* N = current_node->GetNeg(); | ||
154 | // Leaf nodes here?! | ||
155 | ASSERT(P); | ||
156 | ASSERT(N); | ||
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); | ||
160 | |||
161 | if(P->IsLeaf()) | ||
162 | { | ||
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; | ||
169 | } | ||
170 | else | ||
171 | { | ||
172 | // Get a new id for positive child | ||
173 | udword PosID = current_id++; | ||
174 | // Setup box data | ||
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)); | ||
178 | // Recurse | ||
179 | _BuildNoLeafTree(linear, PosID, current_id, P); | ||
180 | } | ||
181 | |||
182 | if(N->IsLeaf()) | ||
183 | { | ||
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; | ||
190 | } | ||
191 | else | ||
192 | { | ||
193 | // Get a new id for negative child | ||
194 | udword NegID = current_id++; | ||
195 | // Setup box data | ||
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)); | ||
199 | // Recurse | ||
200 | _BuildNoLeafTree(linear, NegID, current_id, N); | ||
201 | } | ||
202 | } | ||
203 | |||
204 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
205 | /** | ||
206 | * Constructor. | ||
207 | */ | ||
208 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
209 | AABBCollisionTree::AABBCollisionTree() : mNodes(null) | ||
210 | { | ||
211 | } | ||
212 | |||
213 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
214 | /** | ||
215 | * Destructor. | ||
216 | */ | ||
217 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
218 | AABBCollisionTree::~AABBCollisionTree() | ||
219 | { | ||
220 | DELETEARRAY(mNodes); | ||
221 | } | ||
222 | |||
223 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
224 | /** | ||
225 | * Builds the collision tree from a generic AABB tree. | ||
226 | * \param tree [in] generic AABB tree | ||
227 | * \return true if success | ||
228 | */ | ||
229 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
230 | bool AABBCollisionTree::Build(AABBTree* tree) | ||
231 | { | ||
232 | // Checkings | ||
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; | ||
238 | |||
239 | // Get nodes | ||
240 | if(mNbNodes!=NbNodes) // Same number of nodes => keep moving | ||
241 | { | ||
242 | mNbNodes = NbNodes; | ||
243 | DELETEARRAY(mNodes); | ||
244 | mNodes = new AABBCollisionNode[mNbNodes]; | ||
245 | CHECKALLOC(mNodes); | ||
246 | } | ||
247 | |||
248 | // Build the tree | ||
249 | udword CurID = 1; | ||
250 | _BuildCollisionTree(mNodes, 0, CurID, tree); | ||
251 | ASSERT(CurID==mNbNodes); | ||
252 | |||
253 | return true; | ||
254 | } | ||
255 | |||
256 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
257 | /** | ||
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 | ||
261 | */ | ||
262 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
263 | bool AABBCollisionTree::Refit(const MeshInterface* mesh_interface) | ||
264 | { | ||
265 | ASSERT(!"Not implemented since AABBCollisionTrees have twice as more nodes to refit as AABBNoLeafTrees!"); | ||
266 | return false; | ||
267 | } | ||
268 | |||
269 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
270 | /** | ||
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 | ||
275 | */ | ||
276 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
277 | bool AABBCollisionTree::Walk(GenericWalkingCallback callback, void* user_data) const | ||
278 | { | ||
279 | if(!callback) return false; | ||
280 | |||
281 | struct Local | ||
282 | { | ||
283 | static void _Walk(const AABBCollisionNode* current_node, GenericWalkingCallback callback, void* user_data) | ||
284 | { | ||
285 | if(!current_node || !(callback)(current_node, user_data)) return; | ||
286 | |||
287 | if(!current_node->IsLeaf()) | ||
288 | { | ||
289 | _Walk(current_node->GetPos(), callback, user_data); | ||
290 | _Walk(current_node->GetNeg(), callback, user_data); | ||
291 | } | ||
292 | } | ||
293 | }; | ||
294 | Local::_Walk(mNodes, callback, user_data); | ||
295 | return true; | ||
296 | } | ||
297 | |||
298 | |||
299 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
300 | /** | ||
301 | * Constructor. | ||
302 | */ | ||
303 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
304 | AABBNoLeafTree::AABBNoLeafTree() : mNodes(null) | ||
305 | { | ||
306 | } | ||
307 | |||
308 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
309 | /** | ||
310 | * Destructor. | ||
311 | */ | ||
312 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
313 | AABBNoLeafTree::~AABBNoLeafTree() | ||
314 | { | ||
315 | DELETEARRAY(mNodes); | ||
316 | } | ||
317 | |||
318 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
319 | /** | ||
320 | * Builds the collision tree from a generic AABB tree. | ||
321 | * \param tree [in] generic AABB tree | ||
322 | * \return true if success | ||
323 | */ | ||
324 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
325 | bool AABBNoLeafTree::Build(AABBTree* tree) | ||
326 | { | ||
327 | // Checkings | ||
328 | if(!tree) return false; | ||
329 | // Check the input tree is complete | ||
330 | udword NbTriangles = tree->GetNbPrimitives(); | ||
331 | udword NbNodes = tree->GetNbNodes(); | ||
332 | if(NbNodes!=NbTriangles*2-1) return false; | ||
333 | |||
334 | // Get nodes | ||
335 | if(mNbNodes!=NbTriangles-1) // Same number of nodes => keep moving | ||
336 | { | ||
337 | mNbNodes = NbTriangles-1; | ||
338 | DELETEARRAY(mNodes); | ||
339 | mNodes = new AABBNoLeafNode[mNbNodes]; | ||
340 | CHECKALLOC(mNodes); | ||
341 | } | ||
342 | |||
343 | // Build the tree | ||
344 | udword CurID = 1; | ||
345 | _BuildNoLeafTree(mNodes, 0, CurID, tree); | ||
346 | ASSERT(CurID==mNbNodes); | ||
347 | |||
348 | return true; | ||
349 | } | ||
350 | |||
351 | inline_ void ComputeMinMax(Point& min, Point& max, const VertexPointers& vp) | ||
352 | { | ||
353 | // Compute triangle's AABB = a leaf box | ||
354 | #ifdef OPC_USE_FCOMI // a 15% speedup on my machine, not much | ||
355 | min.x = FCMin3(vp.Vertex[0]->x, vp.Vertex[1]->x, vp.Vertex[2]->x); | ||
356 | max.x = FCMax3(vp.Vertex[0]->x, vp.Vertex[1]->x, vp.Vertex[2]->x); | ||
357 | |||
358 | min.y = FCMin3(vp.Vertex[0]->y, vp.Vertex[1]->y, vp.Vertex[2]->y); | ||
359 | max.y = FCMax3(vp.Vertex[0]->y, vp.Vertex[1]->y, vp.Vertex[2]->y); | ||
360 | |||
361 | min.z = FCMin3(vp.Vertex[0]->z, vp.Vertex[1]->z, vp.Vertex[2]->z); | ||
362 | max.z = FCMax3(vp.Vertex[0]->z, vp.Vertex[1]->z, vp.Vertex[2]->z); | ||
363 | #else | ||
364 | min = *vp.Vertex[0]; | ||
365 | max = *vp.Vertex[0]; | ||
366 | min.Min(*vp.Vertex[1]); | ||
367 | max.Max(*vp.Vertex[1]); | ||
368 | min.Min(*vp.Vertex[2]); | ||
369 | max.Max(*vp.Vertex[2]); | ||
370 | #endif | ||
371 | } | ||
372 | |||
373 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
374 | /** | ||
375 | * Refits the collision tree after vertices have been modified. | ||
376 | * \param mesh_interface [in] mesh interface for current model | ||
377 | * \return true if success | ||
378 | */ | ||
379 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
380 | bool AABBNoLeafTree::Refit(const MeshInterface* mesh_interface) | ||
381 | { | ||
382 | // Checkings | ||
383 | if(!mesh_interface) return false; | ||
384 | |||
385 | // Bottom-up update | ||
386 | VertexPointers VP; | ||
387 | Point Min,Max; | ||
388 | Point Min_,Max_; | ||
389 | udword Index = mNbNodes; | ||
390 | while(Index--) | ||
391 | { | ||
392 | AABBNoLeafNode& Current = mNodes[Index]; | ||
393 | |||
394 | if(Current.HasPosLeaf()) | ||
395 | { | ||
396 | mesh_interface->GetTriangle(VP, Current.GetPosPrimitive()); | ||
397 | ComputeMinMax(Min, Max, VP); | ||
398 | } | ||
399 | else | ||
400 | { | ||
401 | const CollisionAABB& CurrentBox = Current.GetPos()->mAABB; | ||
402 | CurrentBox.GetMin(Min); | ||
403 | CurrentBox.GetMax(Max); | ||
404 | } | ||
405 | |||
406 | if(Current.HasNegLeaf()) | ||
407 | { | ||
408 | mesh_interface->GetTriangle(VP, Current.GetNegPrimitive()); | ||
409 | ComputeMinMax(Min_, Max_, VP); | ||
410 | } | ||
411 | else | ||
412 | { | ||
413 | const CollisionAABB& CurrentBox = Current.GetNeg()->mAABB; | ||
414 | CurrentBox.GetMin(Min_); | ||
415 | CurrentBox.GetMax(Max_); | ||
416 | } | ||
417 | #ifdef OPC_USE_FCOMI | ||
418 | Min.x = FCMin2(Min.x, Min_.x); | ||
419 | Max.x = FCMax2(Max.x, Max_.x); | ||
420 | Min.y = FCMin2(Min.y, Min_.y); | ||
421 | Max.y = FCMax2(Max.y, Max_.y); | ||
422 | Min.z = FCMin2(Min.z, Min_.z); | ||
423 | Max.z = FCMax2(Max.z, Max_.z); | ||
424 | #else | ||
425 | Min.Min(Min_); | ||
426 | Max.Max(Max_); | ||
427 | #endif | ||
428 | Current.mAABB.SetMinMax(Min, Max); | ||
429 | } | ||
430 | return true; | ||
431 | } | ||
432 | |||
433 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
434 | /** | ||
435 | * Walks the tree and call the user back for each node. | ||
436 | * \param callback [in] walking callback | ||
437 | * \param user_data [in] callback's user data | ||
438 | * \return true if success | ||
439 | */ | ||
440 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
441 | bool AABBNoLeafTree::Walk(GenericWalkingCallback callback, void* user_data) const | ||
442 | { | ||
443 | if(!callback) return false; | ||
444 | |||
445 | struct Local | ||
446 | { | ||
447 | static void _Walk(const AABBNoLeafNode* current_node, GenericWalkingCallback callback, void* user_data) | ||
448 | { | ||
449 | if(!current_node || !(callback)(current_node, user_data)) return; | ||
450 | |||
451 | if(!current_node->HasPosLeaf()) _Walk(current_node->GetPos(), callback, user_data); | ||
452 | if(!current_node->HasNegLeaf()) _Walk(current_node->GetNeg(), callback, user_data); | ||
453 | } | ||
454 | }; | ||
455 | Local::_Walk(mNodes, callback, user_data); | ||
456 | return true; | ||
457 | } | ||
458 | |||
459 | // Quantization notes: | ||
460 | // - We could use the highest bits of mData to store some more quantized bits. Dequantization code | ||
461 | // would be slightly more complex, but number of overlap tests would be reduced (and anyhow those | ||
462 | // bits are currently wasted). Of course it's not possible if we move to 16 bits mData. | ||
463 | // - Something like "16 bits floats" could be tested, to bypass the int-to-float conversion. | ||
464 | // - A dedicated BV-BV test could be used, dequantizing while testing for overlap. (i.e. it's some | ||
465 | // lazy-dequantization which may save some work in case of early exits). At the very least some | ||
466 | // muls could be saved by precomputing several more matrices. But maybe not worth the pain. | ||
467 | // - Do we need to dequantize anyway? Not doing the extents-related muls only implies the box has | ||
468 | // been scaled, for example. | ||
469 | // - The deeper we move into the hierarchy, the smaller the extents should be. May not need a fixed | ||
470 | // number of quantization bits. Even better, could probably be best delta-encoded. | ||
471 | |||
472 | |||
473 | // Find max values. Some people asked why I wasn't simply using the first node. Well, I can't. | ||
474 | // I'm not looking for (min, max) values like in a standard AABB, I'm looking for the extremal | ||
475 | // centers/extents in order to quantize them. The first node would only give a single center and | ||
476 | // a single extents. While extents would be the biggest, the center wouldn't. | ||
477 | #define FIND_MAX_VALUES \ | ||
478 | /* Get max values */ \ | ||
479 | Point CMax(MIN_FLOAT, MIN_FLOAT, MIN_FLOAT); \ | ||
480 | Point EMax(MIN_FLOAT, MIN_FLOAT, MIN_FLOAT); \ | ||
481 | for(udword i=0;i<mNbNodes;i++) \ | ||
482 | { \ | ||
483 | if(fabsf(Nodes[i].mAABB.mCenter.x)>CMax.x) CMax.x = fabsf(Nodes[i].mAABB.mCenter.x); \ | ||
484 | if(fabsf(Nodes[i].mAABB.mCenter.y)>CMax.y) CMax.y = fabsf(Nodes[i].mAABB.mCenter.y); \ | ||
485 | if(fabsf(Nodes[i].mAABB.mCenter.z)>CMax.z) CMax.z = fabsf(Nodes[i].mAABB.mCenter.z); \ | ||
486 | if(fabsf(Nodes[i].mAABB.mExtents.x)>EMax.x) EMax.x = fabsf(Nodes[i].mAABB.mExtents.x); \ | ||
487 | if(fabsf(Nodes[i].mAABB.mExtents.y)>EMax.y) EMax.y = fabsf(Nodes[i].mAABB.mExtents.y); \ | ||
488 | if(fabsf(Nodes[i].mAABB.mExtents.z)>EMax.z) EMax.z = fabsf(Nodes[i].mAABB.mExtents.z); \ | ||
489 | } | ||
490 | |||
491 | #define INIT_QUANTIZATION \ | ||
492 | udword nbc=15; /* Keep one bit for sign */ \ | ||
493 | udword nbe=15; /* Keep one bit for fix */ \ | ||
494 | if(!gFixQuantized) nbe++; \ | ||
495 | \ | ||
496 | /* Compute quantization coeffs */ \ | ||
497 | Point CQuantCoeff, EQuantCoeff; \ | ||
498 | CQuantCoeff.x = CMax.x!=0.0f ? float((1<<nbc)-1)/CMax.x : 0.0f; \ | ||
499 | CQuantCoeff.y = CMax.y!=0.0f ? float((1<<nbc)-1)/CMax.y : 0.0f; \ | ||
500 | CQuantCoeff.z = CMax.z!=0.0f ? float((1<<nbc)-1)/CMax.z : 0.0f; \ | ||
501 | EQuantCoeff.x = EMax.x!=0.0f ? float((1<<nbe)-1)/EMax.x : 0.0f; \ | ||
502 | EQuantCoeff.y = EMax.y!=0.0f ? float((1<<nbe)-1)/EMax.y : 0.0f; \ | ||
503 | EQuantCoeff.z = EMax.z!=0.0f ? float((1<<nbe)-1)/EMax.z : 0.0f; \ | ||
504 | /* Compute and save dequantization coeffs */ \ | ||
505 | mCenterCoeff.x = CQuantCoeff.x!=0.0f ? 1.0f / CQuantCoeff.x : 0.0f; \ | ||
506 | mCenterCoeff.y = CQuantCoeff.y!=0.0f ? 1.0f / CQuantCoeff.y : 0.0f; \ | ||
507 | mCenterCoeff.z = CQuantCoeff.z!=0.0f ? 1.0f / CQuantCoeff.z : 0.0f; \ | ||
508 | mExtentsCoeff.x = EQuantCoeff.x!=0.0f ? 1.0f / EQuantCoeff.x : 0.0f; \ | ||
509 | mExtentsCoeff.y = EQuantCoeff.y!=0.0f ? 1.0f / EQuantCoeff.y : 0.0f; \ | ||
510 | mExtentsCoeff.z = EQuantCoeff.z!=0.0f ? 1.0f / EQuantCoeff.z : 0.0f; \ | ||
511 | |||
512 | #define PERFORM_QUANTIZATION \ | ||
513 | /* Quantize */ \ | ||
514 | mNodes[i].mAABB.mCenter[0] = sword(Nodes[i].mAABB.mCenter.x * CQuantCoeff.x); \ | ||
515 | mNodes[i].mAABB.mCenter[1] = sword(Nodes[i].mAABB.mCenter.y * CQuantCoeff.y); \ | ||
516 | mNodes[i].mAABB.mCenter[2] = sword(Nodes[i].mAABB.mCenter.z * CQuantCoeff.z); \ | ||
517 | mNodes[i].mAABB.mExtents[0] = uword(Nodes[i].mAABB.mExtents.x * EQuantCoeff.x); \ | ||
518 | mNodes[i].mAABB.mExtents[1] = uword(Nodes[i].mAABB.mExtents.y * EQuantCoeff.y); \ | ||
519 | mNodes[i].mAABB.mExtents[2] = uword(Nodes[i].mAABB.mExtents.z * EQuantCoeff.z); \ | ||
520 | /* Fix quantized boxes */ \ | ||
521 | if(gFixQuantized) \ | ||
522 | { \ | ||
523 | /* Make sure the quantized box is still valid */ \ | ||
524 | Point Max = Nodes[i].mAABB.mCenter + Nodes[i].mAABB.mExtents; \ | ||
525 | Point Min = Nodes[i].mAABB.mCenter - Nodes[i].mAABB.mExtents; \ | ||
526 | /* For each axis */ \ | ||
527 | for(udword j=0;j<3;j++) \ | ||
528 | { /* Dequantize the box center */ \ | ||
529 | float qc = float(mNodes[i].mAABB.mCenter[j]) * mCenterCoeff[j]; \ | ||
530 | bool FixMe=true; \ | ||
531 | do \ | ||
532 | { /* Dequantize the box extent */ \ | ||
533 | float qe = float(mNodes[i].mAABB.mExtents[j]) * mExtentsCoeff[j]; \ | ||
534 | /* Compare real & dequantized values */ \ | ||
535 | if(qc+qe<Max[j] || qc-qe>Min[j]) mNodes[i].mAABB.mExtents[j]++; \ | ||
536 | else FixMe=false; \ | ||
537 | /* Prevent wrapping */ \ | ||
538 | if(!mNodes[i].mAABB.mExtents[j]) \ | ||
539 | { \ | ||
540 | mNodes[i].mAABB.mExtents[j]=0xffff; \ | ||
541 | FixMe=false; \ | ||
542 | } \ | ||
543 | }while(FixMe); \ | ||
544 | } \ | ||
545 | } | ||
546 | |||
547 | #define REMAP_DATA(member) \ | ||
548 | /* Fix data */ \ | ||
549 | Data = Nodes[i].member; \ | ||
550 | if(!(Data&1)) \ | ||
551 | { \ | ||
552 | /* Compute box number */ \ | ||
553 | size_t Nb = (Data - size_t(Nodes))/Nodes[i].GetNodeSize(); \ | ||
554 | Data = (size_t) &mNodes[Nb]; \ | ||
555 | } \ | ||
556 | /* ...remapped */ \ | ||
557 | mNodes[i].member = Data; | ||
558 | |||
559 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
560 | /** | ||
561 | * Constructor. | ||
562 | */ | ||
563 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
564 | AABBQuantizedTree::AABBQuantizedTree() : mNodes(null) | ||
565 | { | ||
566 | } | ||
567 | |||
568 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
569 | /** | ||
570 | * Destructor. | ||
571 | */ | ||
572 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
573 | AABBQuantizedTree::~AABBQuantizedTree() | ||
574 | { | ||
575 | DELETEARRAY(mNodes); | ||
576 | } | ||
577 | |||
578 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
579 | /** | ||
580 | * Builds the collision tree from a generic AABB tree. | ||
581 | * \param tree [in] generic AABB tree | ||
582 | * \return true if success | ||
583 | */ | ||
584 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
585 | bool AABBQuantizedTree::Build(AABBTree* tree) | ||
586 | { | ||
587 | // Checkings | ||
588 | if(!tree) return false; | ||
589 | // Check the input tree is complete | ||
590 | udword NbTriangles = tree->GetNbPrimitives(); | ||
591 | udword NbNodes = tree->GetNbNodes(); | ||
592 | if(NbNodes!=NbTriangles*2-1) return false; | ||
593 | |||
594 | // Get nodes | ||
595 | mNbNodes = NbNodes; | ||
596 | DELETEARRAY(mNodes); | ||
597 | AABBCollisionNode* Nodes = new AABBCollisionNode[mNbNodes]; | ||
598 | CHECKALLOC(Nodes); | ||
599 | |||
600 | // Build the tree | ||
601 | udword CurID = 1; | ||
602 | _BuildCollisionTree(Nodes, 0, CurID, tree); | ||
603 | |||
604 | // Quantize | ||
605 | { | ||
606 | mNodes = new AABBQuantizedNode[mNbNodes]; | ||
607 | CHECKALLOC(mNodes); | ||
608 | |||
609 | // Get max values | ||
610 | FIND_MAX_VALUES | ||
611 | |||
612 | // Quantization | ||
613 | INIT_QUANTIZATION | ||
614 | |||
615 | // Quantize | ||
616 | size_t Data; | ||
617 | for(udword i=0;i<mNbNodes;i++) | ||
618 | { | ||
619 | PERFORM_QUANTIZATION | ||
620 | REMAP_DATA(mData) | ||
621 | } | ||
622 | |||
623 | DELETEARRAY(Nodes); | ||
624 | } | ||
625 | |||
626 | return true; | ||
627 | } | ||
628 | |||
629 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
630 | /** | ||
631 | * Refits the collision tree after vertices have been modified. | ||
632 | * \param mesh_interface [in] mesh interface for current model | ||
633 | * \return true if success | ||
634 | */ | ||
635 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
636 | bool AABBQuantizedTree::Refit(const MeshInterface* mesh_interface) | ||
637 | { | ||
638 | ASSERT(!"Not implemented since requantizing is painful !"); | ||
639 | return false; | ||
640 | } | ||
641 | |||
642 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
643 | /** | ||
644 | * Walks the tree and call the user back for each node. | ||
645 | * \param callback [in] walking callback | ||
646 | * \param user_data [in] callback's user data | ||
647 | * \return true if success | ||
648 | */ | ||
649 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
650 | bool AABBQuantizedTree::Walk(GenericWalkingCallback callback, void* user_data) const | ||
651 | { | ||
652 | if(!callback) return false; | ||
653 | |||
654 | struct Local | ||
655 | { | ||
656 | static void _Walk(const AABBQuantizedNode* current_node, GenericWalkingCallback callback, void* user_data) | ||
657 | { | ||
658 | if(!current_node || !(callback)(current_node, user_data)) return; | ||
659 | |||
660 | if(!current_node->IsLeaf()) | ||
661 | { | ||
662 | _Walk(current_node->GetPos(), callback, user_data); | ||
663 | _Walk(current_node->GetNeg(), callback, user_data); | ||
664 | } | ||
665 | } | ||
666 | }; | ||
667 | Local::_Walk(mNodes, callback, user_data); | ||
668 | return true; | ||
669 | } | ||
670 | |||
671 | |||
672 | |||
673 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
674 | /** | ||
675 | * Constructor. | ||
676 | */ | ||
677 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
678 | AABBQuantizedNoLeafTree::AABBQuantizedNoLeafTree() : mNodes(null) | ||
679 | { | ||
680 | } | ||
681 | |||
682 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
683 | /** | ||
684 | * Destructor. | ||
685 | */ | ||
686 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
687 | AABBQuantizedNoLeafTree::~AABBQuantizedNoLeafTree() | ||
688 | { | ||
689 | DELETEARRAY(mNodes); | ||
690 | } | ||
691 | |||
692 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
693 | /** | ||
694 | * Builds the collision tree from a generic AABB tree. | ||
695 | * \param tree [in] generic AABB tree | ||
696 | * \return true if success | ||
697 | */ | ||
698 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
699 | bool AABBQuantizedNoLeafTree::Build(AABBTree* tree) | ||
700 | { | ||
701 | // Checkings | ||
702 | if(!tree) return false; | ||
703 | // Check the input tree is complete | ||
704 | udword NbTriangles = tree->GetNbPrimitives(); | ||
705 | udword NbNodes = tree->GetNbNodes(); | ||
706 | if(NbNodes!=NbTriangles*2-1) return false; | ||
707 | |||
708 | // Get nodes | ||
709 | mNbNodes = NbTriangles-1; | ||
710 | DELETEARRAY(mNodes); | ||
711 | AABBNoLeafNode* Nodes = new AABBNoLeafNode[mNbNodes]; | ||
712 | CHECKALLOC(Nodes); | ||
713 | |||
714 | // Build the tree | ||
715 | udword CurID = 1; | ||
716 | _BuildNoLeafTree(Nodes, 0, CurID, tree); | ||
717 | ASSERT(CurID==mNbNodes); | ||
718 | |||
719 | // Quantize | ||
720 | { | ||
721 | mNodes = new AABBQuantizedNoLeafNode[mNbNodes]; | ||
722 | CHECKALLOC(mNodes); | ||
723 | |||
724 | // Get max values | ||
725 | FIND_MAX_VALUES | ||
726 | |||
727 | // Quantization | ||
728 | INIT_QUANTIZATION | ||
729 | |||
730 | // Quantize | ||
731 | size_t Data; | ||
732 | for(udword i=0;i<mNbNodes;i++) | ||
733 | { | ||
734 | PERFORM_QUANTIZATION | ||
735 | REMAP_DATA(mPosData) | ||
736 | REMAP_DATA(mNegData) | ||
737 | } | ||
738 | |||
739 | DELETEARRAY(Nodes); | ||
740 | } | ||
741 | |||
742 | return true; | ||
743 | } | ||
744 | |||
745 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
746 | /** | ||
747 | * Refits the collision tree after vertices have been modified. | ||
748 | * \param mesh_interface [in] mesh interface for current model | ||
749 | * \return true if success | ||
750 | */ | ||
751 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
752 | bool AABBQuantizedNoLeafTree::Refit(const MeshInterface* mesh_interface) | ||
753 | { | ||
754 | ASSERT(!"Not implemented since requantizing is painful !"); | ||
755 | return false; | ||
756 | } | ||
757 | |||
758 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
759 | /** | ||
760 | * Walks the tree and call the user back for each node. | ||
761 | * \param callback [in] walking callback | ||
762 | * \param user_data [in] callback's user data | ||
763 | * \return true if success | ||
764 | */ | ||
765 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
766 | bool AABBQuantizedNoLeafTree::Walk(GenericWalkingCallback callback, void* user_data) const | ||
767 | { | ||
768 | if(!callback) return false; | ||
769 | |||
770 | struct Local | ||
771 | { | ||
772 | static void _Walk(const AABBQuantizedNoLeafNode* current_node, GenericWalkingCallback callback, void* user_data) | ||
773 | { | ||
774 | if(!current_node || !(callback)(current_node, user_data)) return; | ||
775 | |||
776 | if(!current_node->HasPosLeaf()) _Walk(current_node->GetPos(), callback, user_data); | ||
777 | if(!current_node->HasNegLeaf()) _Walk(current_node->GetNeg(), callback, user_data); | ||
778 | } | ||
779 | }; | ||
780 | Local::_Walk(mNodes, callback, user_data); | ||
781 | return true; | ||
782 | } | ||