177 lines
5.7 KiB
C++
177 lines
5.7 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());
|
|
}
|