Vegastrike 0.5.1 rc1  1.0
Original sources for Vegastrike Evolved
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
OPC_AABBTree.cpp
Go to the documentation of this file.
1 /*
3  * OPCODE - Optimized Collision Detection
4  * Copyright (C) 2001 Pierre Terdiman
5  * Homepage: http://www.codercorner.com/Opcode.htm
6  */
8 
10 
16 
19 
27 
30 
43 
46 // Precompiled Header
47 #include "Stdafx.h"
48 
49 using namespace Opcode;
50 
52 
55 AABBTreeNode::AABBTreeNode() :
57  mPos (null),
59  mNeg (null),
60 #endif
61  mNodePrimitives (null),
62  mNbPrimitives (0)
63 {
64 #ifdef OPC_USE_TREE_COHERENCE
65  mBitmask = 0;
66 #endif
67 }
68 
70 
73 AABBTreeNode::~AABBTreeNode()
75 {
76  // Opcode 1.3:
77  const AABBTreeNode* Pos = GetPos();
78 #ifndef OPC_NO_NEG_VANILLA_TREE
79  const AABBTreeNode* Neg = GetNeg();
80  if(!(mPos&1)) DELETESINGLE(Pos);
81  if(!(mNeg&1)) DELETESINGLE(Neg);
82 #else
83  if(!(mPos&1)) DELETEARRAY(Pos);
84 #endif
85  mNodePrimitives = null; // This was just a shortcut to the global list => no release
86  mNbPrimitives = 0;
87 }
88 
90 
100 {
101  // Get node split value
102  float SplitValue = builder->GetSplittingValue(mNodePrimitives, mNbPrimitives, mBV, axis);
103 
104  udword NbPos = 0;
105  // Loop through all node-related primitives. Their indices range from mNodePrimitives[0] to mNodePrimitives[mNbPrimitives-1].
106  // Those indices map the global list in the tree builder.
107  for(udword i=0;i<mNbPrimitives;i++)
108  {
109  // Get index in global list
110  udword Index = mNodePrimitives[i];
111 
112  // Test against the splitting value. The primitive value is tested against the enclosing-box center.
113  // [We only need an approximate partition of the enclosing box here.]
114  float PrimitiveValue = builder->GetSplittingValue(Index, axis);
115 
116  // Reorganize the list of indices in this order: positive - negative.
117  if(PrimitiveValue > SplitValue)
118  {
119  // Swap entries
120  udword Tmp = mNodePrimitives[i];
122  mNodePrimitives[NbPos] = Tmp;
123  // Count primitives assigned to positive space
124  NbPos++;
125  }
126  }
127  return NbPos;
128 }
129 
131 
151 {
152  // Checkings
153  if(!builder) return false;
154 
155  // Stop subdividing if we reach a leaf node. This is always performed here,
156  // else we could end in trouble if user overrides this.
157  if(mNbPrimitives==1) return true;
158 
159  // Let the user validate the subdivision
160  if(!builder->ValidateSubdivision(mNodePrimitives, mNbPrimitives, mBV)) return true;
161 
162  bool ValidSplit = true; // Optimism...
163  udword NbPos;
164  if(builder->mSettings.mRules & SPLIT_LARGEST_AXIS)
165  {
166  // Find the largest axis to split along
167  Point Extents; mBV.GetExtents(Extents); // Box extents
168  udword Axis = Extents.LargestAxis(); // Index of largest axis
169 
170  // Split along the axis
171  NbPos = Split(Axis, builder);
172 
173  // Check split validity
174  if(!NbPos || NbPos==mNbPrimitives) ValidSplit = false;
175  }
176  else if(builder->mSettings.mRules & SPLIT_SPLATTER_POINTS)
177  {
178  udword i;
179  // Compute the means
180  Point Means(0.0f, 0.0f, 0.0f);
181  for(i=0;i<mNbPrimitives;i++)
182  {
183  udword Index = mNodePrimitives[i];
184  Means.x+=builder->GetSplittingValue(Index, 0);
185  Means.y+=builder->GetSplittingValue(Index, 1);
186  Means.z+=builder->GetSplittingValue(Index, 2);
187  }
188  Means/=float(mNbPrimitives);
189 
190  // Compute variances
191  Point Vars(0.0f, 0.0f, 0.0f);
192  for(i=0;i<mNbPrimitives;i++)
193  {
194  udword Index = mNodePrimitives[i];
195  float Cx = builder->GetSplittingValue(Index, 0);
196  float Cy = builder->GetSplittingValue(Index, 1);
197  float Cz = builder->GetSplittingValue(Index, 2);
198  Vars.x += (Cx - Means.x)*(Cx - Means.x);
199  Vars.y += (Cy - Means.y)*(Cy - Means.y);
200  Vars.z += (Cz - Means.z)*(Cz - Means.z);
201  }
202  Vars/=float(mNbPrimitives-1);
203 
204  // Choose axis with greatest variance
205  udword Axis = Vars.LargestAxis();
206 
207  // Split along the axis
208  NbPos = Split(Axis, builder);
209 
210  // Check split validity
211  if(!NbPos || NbPos==mNbPrimitives) ValidSplit = false;
212  }
213  else if(builder->mSettings.mRules & SPLIT_BALANCED)
214  {
215  // Test 3 axis, take the best
216  float Results[3];
217  NbPos = Split(0, builder); Results[0] = float(NbPos)/float(mNbPrimitives);
218  NbPos = Split(1, builder); Results[1] = float(NbPos)/float(mNbPrimitives);
219  NbPos = Split(2, builder); Results[2] = float(NbPos)/float(mNbPrimitives);
220  Results[0]-=0.5f; Results[0]*=Results[0];
221  Results[1]-=0.5f; Results[1]*=Results[1];
222  Results[2]-=0.5f; Results[2]*=Results[2];
223  udword Min=0;
224  if(Results[1]<Results[Min]) Min = 1;
225  if(Results[2]<Results[Min]) Min = 2;
226 
227  // Split along the axis
228  NbPos = Split(Min, builder);
229 
230  // Check split validity
231  if(!NbPos || NbPos==mNbPrimitives) ValidSplit = false;
232  }
233  else if(builder->mSettings.mRules & SPLIT_BEST_AXIS)
234  {
235  // Test largest, then middle, then smallest axis...
236 
237  // Sort axis
238  Point Extents; mBV.GetExtents(Extents); // Box extents
239  udword SortedAxis[] = { 0, 1, 2 };
240  float* Keys = (float*)&Extents.x;
241  for(udword j=0;j<3;j++)
242  {
243  for(udword i=0;i<2;i++)
244  {
245  if(Keys[SortedAxis[i]]<Keys[SortedAxis[i+1]])
246  {
247  udword Tmp = SortedAxis[i];
248  SortedAxis[i] = SortedAxis[i+1];
249  SortedAxis[i+1] = Tmp;
250  }
251  }
252  }
253 
254  // Find the largest axis to split along
255  udword CurAxis = 0;
256  ValidSplit = false;
257  while(!ValidSplit && CurAxis!=3)
258  {
259  NbPos = Split(SortedAxis[CurAxis], builder);
260  // Check the subdivision has been successful
261  if(!NbPos || NbPos==mNbPrimitives) CurAxis++;
262  else ValidSplit = true;
263  }
264  }
265  else if(builder->mSettings.mRules & SPLIT_FIFTY)
266  {
267  // Don't even bother splitting (mainly a performance test)
268  NbPos = mNbPrimitives>>1;
269  }
270  else return false; // Unknown splitting rules
271 
272  // Check the subdivision has been successful
273  if(!ValidSplit)
274  {
275  // Here, all boxes lie in the same sub-space. Two strategies:
276  // - if the tree *must* be complete, make an arbitrary 50-50 split
277  // - else stop subdividing
278 // if(builder->mSettings.mRules&SPLIT_COMPLETE)
279  if(builder->mSettings.mLimit==1)
280  {
281  builder->IncreaseNbInvalidSplits();
282  NbPos = mNbPrimitives>>1;
283  }
284  else return true;
285  }
286 
287  // Now create children and assign their pointers.
288  if(builder->mNodeBase)
289  {
290  // We use a pre-allocated linear pool for complete trees [Opcode 1.3]
291  AABBTreeNode* Pool = (AABBTreeNode*)builder->mNodeBase;
292  udword Count = builder->GetCount() - 1; // Count begins to 1...
293  // Set last bit to tell it shouldn't be freed ### pretty ugly, find a better way. Maybe one bit in mNbPrimitives
294  OPASSERT(!(uintptr_t(&Pool[Count+0])&1));
295  OPASSERT(!(uintptr_t(&Pool[Count+1])&1));
296  mPos = uintptr_t(&Pool[Count+0])|1;
297 #ifndef OPC_NO_NEG_VANILLA_TREE
298  mNeg = uintptr_t(&Pool[Count+1])|1;
299 #endif
300  }
301  else
302  {
303  // Non-complete trees and/or Opcode 1.2 allocate nodes on-the-fly
304 #ifndef OPC_NO_NEG_VANILLA_TREE
305  mPos = (uintptr_t)new AABBTreeNode; CHECKALLOC(mPos);
306  mNeg = (uintptr_t)new AABBTreeNode; CHECKALLOC(mNeg);
307 #else
308  AABBTreeNode* PosNeg = new AABBTreeNode[2];
309  CHECKALLOC(PosNeg);
310  mPos = (uintptr_t)PosNeg;
311 #endif
312  }
313 
314  // Update stats
315  builder->IncreaseCount(2);
316 
317  // Assign children
318  AABBTreeNode* Pos = (AABBTreeNode*)GetPos();
319  AABBTreeNode* Neg = (AABBTreeNode*)GetNeg();
320  Pos->mNodePrimitives = &mNodePrimitives[0];
321  Pos->mNbPrimitives = NbPos;
322  Neg->mNodePrimitives = &mNodePrimitives[NbPos];
323  Neg->mNbPrimitives = mNbPrimitives - NbPos;
324 
325  return true;
326 }
327 
329 
335 {
336  // 1) Compute the global box for current node. The box is stored in mBV.
337  builder->ComputeGlobalBox(mNodePrimitives, mNbPrimitives, mBV);
338 
339  // 2) Subdivide current node
340  Subdivide(builder);
341 
342  // 3) Recurse
343  AABBTreeNode* Pos = (AABBTreeNode*)GetPos();
344  AABBTreeNode* Neg = (AABBTreeNode*)GetNeg();
345  if(Pos) Pos->_BuildHierarchy(builder);
346  if(Neg) Neg->_BuildHierarchy(builder);
347 }
348 
350 
356 {
357  // 1) Recompute the new global box for current node
358  builder->ComputeGlobalBox(mNodePrimitives, mNbPrimitives, mBV);
359 
360  // 2) Recurse
361  AABBTreeNode* Pos = (AABBTreeNode*)GetPos();
362  AABBTreeNode* Neg = (AABBTreeNode*)GetNeg();
363  if(Pos) Pos->_Refit(builder);
364  if(Neg) Neg->_Refit(builder);
365 }
366 
367 
368 
370 
373 AABBTree::AABBTree() : mIndices(null), mPool(null), mTotalNbNodes(0)
375 {
376 }
377 
379 
384 {
385  Release();
386 }
387 
389 
392 void AABBTree::Release()
394 {
395  DELETEARRAY(mPool);
396  DELETEARRAY(mIndices);
397 }
398 
400 
405 bool AABBTree::Build(AABBTreeBuilder* builder)
407 {
408  // Checkings
409  if(!builder || !builder->mNbPrimitives) return false;
410 
411  // Release previous tree
412  Release();
413 
414  // Init stats
415  builder->SetCount(1);
416  builder->SetNbInvalidSplits(0);
417 
418  // Initialize indices. This list will be modified during build.
419  mIndices = new udword[builder->mNbPrimitives];
420  CHECKALLOC(mIndices);
421  // Identity permutation
422  for(udword i=0;i<builder->mNbPrimitives;i++) mIndices[i] = i;
423 
424  // Setup initial node. Here we have a complete permutation of the app's primitives.
425  mNodePrimitives = mIndices;
426  mNbPrimitives = builder->mNbPrimitives;
427 
428  // Use a linear array for complete trees (since we can predict the final number of nodes) [Opcode 1.3]
429 // if(builder->mRules&SPLIT_COMPLETE)
430  if(builder->mSettings.mLimit==1)
431  {
432  // Allocate a pool of nodes
433  mPool = new AABBTreeNode[builder->mNbPrimitives*2 - 1];
434 
435  builder->mNodeBase = mPool; // ### ugly !
436  }
437 
438  // Build the hierarchy
439  _BuildHierarchy(builder);
440 
441  // Get back total number of nodes
442  mTotalNbNodes = builder->GetCount();
443 
444  // For complete trees, check the correct number of nodes has been created [Opcode 1.3]
445  if(mPool) OPASSERT(mTotalNbNodes==builder->mNbPrimitives*2 - 1);
446 
447  return true;
448 }
449 
451 
458 {
459  return Walk(null, null); // Use the walking code without callback
460 }
461 
463 
466 udword AABBTree::Walk(WalkingCallback callback, void* user_data) const
468 {
469  // Call it without callback to compute max depth
470  udword MaxDepth = 0;
471  udword CurrentDepth = 0;
472 
473  struct Local
474  {
475  static void _Walk(const AABBTreeNode* current_node, udword& max_depth, udword& current_depth, WalkingCallback callback, void* user_data)
476  {
477  // Checkings
478  if(!current_node) return;
479  // Entering a new node => increase depth
480  current_depth++;
481  // Keep track of max depth
482  if(current_depth>max_depth) max_depth = current_depth;
483 
484  // Callback
485  if(callback && !(callback)(current_node, current_depth, user_data)) return;
486 
487  // Recurse
488  if(current_node->GetPos()) { _Walk(current_node->GetPos(), max_depth, current_depth, callback, user_data); current_depth--; }
489  if(current_node->GetNeg()) { _Walk(current_node->GetNeg(), max_depth, current_depth, callback, user_data); current_depth--; }
490  }
491  };
492  Local::_Walk(this, MaxDepth, CurrentDepth, callback, user_data);
493  return MaxDepth;
494 }
495 
497 
501 bool AABBTree::Refit(AABBTreeBuilder* builder)
503 {
504  if(!builder) return false;
505  _Refit(builder);
506  return true;
507 }
508 
510 
514 bool AABBTree::Refit2(AABBTreeBuilder* builder)
516 {
517  // Checkings
518  if(!builder) return false;
519 
520  OPASSERT(mPool);
521 
522  // Bottom-up update
523  Point Min,Max;
524  Point Min_,Max_;
525  udword Index = mTotalNbNodes;
526  while(Index--)
527  {
528  AABBTreeNode& Current = mPool[Index];
529 
530  if(Current.IsLeaf())
531  {
532  builder->ComputeGlobalBox(Current.GetPrimitives(), Current.GetNbPrimitives(), *(AABB*)Current.GetAABB());
533  }
534  else
535  {
536  Current.GetPos()->GetAABB()->GetMin(Min);
537  Current.GetPos()->GetAABB()->GetMax(Max);
538 
539  Current.GetNeg()->GetAABB()->GetMin(Min_);
540  Current.GetNeg()->GetAABB()->GetMax(Max_);
541 
542  Min.Min(Min_);
543  Max.Max(Max_);
544 
545  ((AABB*)Current.GetAABB())->SetMinMax(Min, Max);
546  }
547  }
548  return true;
549 }
550 
552 
558 {
559  udword TotalSize = mTotalNbNodes*GetNodeSize();
560  if(mIndices) TotalSize+=mNbPrimitives*sizeof(udword);
561  return TotalSize;
562 }
563 
565 
570 bool AABBTree::IsComplete() const
572 {
573  return (GetNbNodes()==GetNbPrimitives()*2-1);
574 }
575