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()); | ||
|  | } | ||
|  | 
 | ||
|  | 
 |