183 lines
5.6 KiB
C++
183 lines
5.6 KiB
C++
|
|
||
|
/*
|
||
|
-----------------------------------------------------------------------------
|
||
|
This source file is part of GIMPACT Library.
|
||
|
|
||
|
For the latest info, see http://gimpact.sourceforge.net/
|
||
|
|
||
|
Copyright (c) 2006 Francisco Leon Najera. C.C. 80087371.
|
||
|
email: projectileman@yahoo.com
|
||
|
|
||
|
This library is free software; you can redistribute it and/or
|
||
|
modify it under the terms of EITHER:
|
||
|
(1) The GNU Lesser General Public License as published by the Free
|
||
|
Software Foundation; either version 2.1 of the License, or (at
|
||
|
your option) any later version. The text of the GNU Lesser
|
||
|
General Public License is included with this library in the
|
||
|
file GIMPACT-LICENSE-LGPL.TXT.
|
||
|
(2) The BSD-style license that is included with this library in
|
||
|
the file GIMPACT-LICENSE-BSD.TXT.
|
||
|
(3) The zlib/libpng license that is included with this library in
|
||
|
the file GIMPACT-LICENSE-ZLIB.TXT.
|
||
|
|
||
|
This library is distributed in the hope that it will be useful,
|
||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files
|
||
|
GIMPACT-LICENSE-LGPL.TXT, GIMPACT-LICENSE-ZLIB.TXT and GIMPACT-LICENSE-BSD.TXT for more details.
|
||
|
|
||
|
-----------------------------------------------------------------------------
|
||
|
*/
|
||
|
|
||
|
|
||
|
#include "gim_box_set.h"
|
||
|
|
||
|
|
||
|
GUINT GIM_BOX_TREE::_calc_splitting_axis(
|
||
|
gim_array<GIM_AABB_DATA> & primitive_boxes, GUINT startIndex, GUINT endIndex)
|
||
|
{
|
||
|
GUINT i;
|
||
|
|
||
|
btVector3 means(btScalar(0.),btScalar(0.),btScalar(0.));
|
||
|
btVector3 variance(btScalar(0.),btScalar(0.),btScalar(0.));
|
||
|
GUINT numIndices = endIndex-startIndex;
|
||
|
|
||
|
for (i=startIndex;i<endIndex;i++)
|
||
|
{
|
||
|
btVector3 center = btScalar(0.5)*(primitive_boxes[i].m_bound.m_max +
|
||
|
primitive_boxes[i].m_bound.m_min);
|
||
|
means+=center;
|
||
|
}
|
||
|
means *= (btScalar(1.)/(btScalar)numIndices);
|
||
|
|
||
|
for (i=startIndex;i<endIndex;i++)
|
||
|
{
|
||
|
btVector3 center = btScalar(0.5)*(primitive_boxes[i].m_bound.m_max +
|
||
|
primitive_boxes[i].m_bound.m_min);
|
||
|
btVector3 diff2 = center-means;
|
||
|
diff2 = diff2 * diff2;
|
||
|
variance += diff2;
|
||
|
}
|
||
|
variance *= (btScalar(1.)/ ((btScalar)numIndices-1) );
|
||
|
|
||
|
return variance.maxAxis();
|
||
|
}
|
||
|
|
||
|
|
||
|
GUINT GIM_BOX_TREE::_sort_and_calc_splitting_index(
|
||
|
gim_array<GIM_AABB_DATA> & primitive_boxes, GUINT startIndex,
|
||
|
GUINT endIndex, GUINT splitAxis)
|
||
|
{
|
||
|
GUINT i;
|
||
|
GUINT splitIndex =startIndex;
|
||
|
GUINT numIndices = endIndex - startIndex;
|
||
|
|
||
|
// average of centers
|
||
|
btScalar splitValue = 0.0f;
|
||
|
for (i=startIndex;i<endIndex;i++)
|
||
|
{
|
||
|
splitValue+= 0.5f*(primitive_boxes[i].m_bound.m_max[splitAxis] +
|
||
|
primitive_boxes[i].m_bound.m_min[splitAxis]);
|
||
|
}
|
||
|
splitValue /= (btScalar)numIndices;
|
||
|
|
||
|
//sort leafNodes so all values larger then splitValue comes first, and smaller values start from 'splitIndex'.
|
||
|
for (i=startIndex;i<endIndex;i++)
|
||
|
{
|
||
|
btScalar center = 0.5f*(primitive_boxes[i].m_bound.m_max[splitAxis] +
|
||
|
primitive_boxes[i].m_bound.m_min[splitAxis]);
|
||
|
if (center > splitValue)
|
||
|
{
|
||
|
//swap
|
||
|
primitive_boxes.swap(i,splitIndex);
|
||
|
splitIndex++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//if the splitIndex causes unbalanced trees, fix this by using the center in between startIndex and endIndex
|
||
|
//otherwise the tree-building might fail due to stack-overflows in certain cases.
|
||
|
//unbalanced1 is unsafe: it can cause stack overflows
|
||
|
//bool unbalanced1 = ((splitIndex==startIndex) || (splitIndex == (endIndex-1)));
|
||
|
|
||
|
//unbalanced2 should work too: always use center (perfect balanced trees)
|
||
|
//bool unbalanced2 = true;
|
||
|
|
||
|
//this should be safe too:
|
||
|
GUINT rangeBalancedIndices = numIndices/3;
|
||
|
bool unbalanced = ((splitIndex<=(startIndex+rangeBalancedIndices)) || (splitIndex >=(endIndex-1-rangeBalancedIndices)));
|
||
|
|
||
|
if (unbalanced)
|
||
|
{
|
||
|
splitIndex = startIndex+ (numIndices>>1);
|
||
|
}
|
||
|
|
||
|
btAssert(!((splitIndex==startIndex) || (splitIndex == (endIndex))));
|
||
|
|
||
|
return splitIndex;
|
||
|
}
|
||
|
|
||
|
|
||
|
void GIM_BOX_TREE::_build_sub_tree(gim_array<GIM_AABB_DATA> & primitive_boxes, GUINT startIndex, GUINT endIndex)
|
||
|
{
|
||
|
GUINT current_index = m_num_nodes++;
|
||
|
|
||
|
btAssert((endIndex-startIndex)>0);
|
||
|
|
||
|
if((endIndex-startIndex) == 1) //we got a leaf
|
||
|
{
|
||
|
m_node_array[current_index].m_left = 0;
|
||
|
m_node_array[current_index].m_right = 0;
|
||
|
m_node_array[current_index].m_escapeIndex = 0;
|
||
|
|
||
|
m_node_array[current_index].m_bound = primitive_boxes[startIndex].m_bound;
|
||
|
m_node_array[current_index].m_data = primitive_boxes[startIndex].m_data;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
//configure inner node
|
||
|
|
||
|
GUINT splitIndex;
|
||
|
|
||
|
//calc this node bounding box
|
||
|
m_node_array[current_index].m_bound.invalidate();
|
||
|
for (splitIndex=startIndex;splitIndex<endIndex;splitIndex++)
|
||
|
{
|
||
|
m_node_array[current_index].m_bound.merge(primitive_boxes[splitIndex].m_bound);
|
||
|
}
|
||
|
|
||
|
//calculate Best Splitting Axis and where to split it. Sort the incoming 'leafNodes' array within range 'startIndex/endIndex'.
|
||
|
|
||
|
//split axis
|
||
|
splitIndex = _calc_splitting_axis(primitive_boxes,startIndex,endIndex);
|
||
|
|
||
|
splitIndex = _sort_and_calc_splitting_index(
|
||
|
primitive_boxes,startIndex,endIndex,splitIndex);
|
||
|
|
||
|
//configure this inner node : the left node index
|
||
|
m_node_array[current_index].m_left = m_num_nodes;
|
||
|
//build left child tree
|
||
|
_build_sub_tree(primitive_boxes, startIndex, splitIndex );
|
||
|
|
||
|
//configure this inner node : the right node index
|
||
|
m_node_array[current_index].m_right = m_num_nodes;
|
||
|
|
||
|
//build right child tree
|
||
|
_build_sub_tree(primitive_boxes, splitIndex ,endIndex);
|
||
|
|
||
|
//configure this inner node : the escape index
|
||
|
m_node_array[current_index].m_escapeIndex = m_num_nodes - current_index;
|
||
|
}
|
||
|
|
||
|
//! stackless build tree
|
||
|
void GIM_BOX_TREE::build_tree(
|
||
|
gim_array<GIM_AABB_DATA> & primitive_boxes)
|
||
|
{
|
||
|
// initialize node count to 0
|
||
|
m_num_nodes = 0;
|
||
|
// allocate nodes
|
||
|
m_node_array.resize(primitive_boxes.size()*2);
|
||
|
|
||
|
_build_sub_tree(primitive_boxes, 0, primitive_boxes.size());
|
||
|
}
|
||
|
|
||
|
|