forked from LeenkxTeam/LNXSDK
		
	
		
			
				
	
	
		
			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());
 | |
| }
 | |
| 
 | |
| 
 |