text: /*
  Bullet Continuous Collision Detection and Physics Library
  Copyright (c) 2003-2009 Erwin Coumans  http://bulletphysics.org
  
  This software is provided 'as-is', without any express or implied warranty.
  In no event will the authors be held liable for any damages arising from the use of this software.
  Permission is granted to anyone to use this software for any purpose, 
  including commercial applications, and to alter it and redistribute it freely, 
  subject to the following restrictions:
  
  1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
  2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
  3. This notice may not be removed or altered from any source distribution.
  */
  
  ///btDbvtBroadphase implementation by Nathanael Presson
  
  #include "btDbvtBroadphase.h"
  
  //
  // Profiling
  //
  
  #if DBVT_BP_PROFILE||DBVT_BP_ENABLE_BENCHMARK
  #include <stdio.h>
  #endif
  
  #if DBVT_BP_PROFILE
  struct	ProfileScope
  {
  	__forceinline ProfileScope(btClock& clock,unsigned long& value) :
  	m_clock(&clock),m_value(&value),m_base(clock.getTimeMicroseconds())
  	{
  	}
  	__forceinline ~ProfileScope()
  	{
  		(*m_value)+=m_clock->getTimeMicroseconds()-m_base;
  	}
  	btClock*		m_clock;
  	unsigned long*	m_value;
  	unsigned long	m_base;
  };
  #define	SPC(_value_)	ProfileScope	spc_scope(m_clock,_value_)
  #else
  #define	SPC(_value_)
  #endif
  
  //
  // Helpers
  //
  
  //
  template <typename T>
  static inline void	listappend(T* item,T*& list)
  {
  	item->links[0]=0;
  	item->links[1]=list;
  	if(list) list->links[0]=item;
  	list=item;
  }
  
  //
  template <typename T>
  static inline void	listremove(T* item,T*& list)
  {
  	if(item->links[0]) item->links[0]->links[1]=item->links[1]; else list=item->links[1];
  	if(item->links[1]) item->links[1]->links[0]=item->links[0];
  }
  
  //
  template <typename T>
  static inline int	listcount(T* root)
  {
  	int	n=0;
  	while(root) { ++n;root=root->links[1]; }
  	return(n);
  }
  
  //
  template <typename T>
  static inline void	clear(T& value)
  {
  	static const struct ZeroDummy : T {} zerodummy;
  	value=zerodummy;
  }
  
  //
  // Colliders
  //
  
  /* Tree collider	*/ 
  struct	btDbvtTreeCollider : btDbvt::ICollide
  {
  	btDbvtBroadphase*	pbp;
  	btDbvtProxy*		proxy;
  	btDbvtTreeCollider(btDbvtBroadphase* p) : pbp(p) {}
  	void	Process(const btDbvtNode* na,const btDbvtNode* nb)
  	{
  		if(na!=nb)
  		{
  			btDbvtProxy*	pa=(btDbvtProxy*)na->data;
  			btDbvtProxy*	pb=(btDbvtProxy*)nb->data;
  #if DBVT_BP_SORTPAIRS
  			if(pa->m_uniqueId>pb->m_uniqueId) 
  				btSwap(pa,pb);
  #endif
  			pbp->m_paircache->addOverlappingPair(pa,pb);
  			++pbp->m_newpairs;
  		}
  	}
  	void	Process(const btDbvtNode* n)
  	{
  		Process(n,proxy->leaf);
  	}
  };
  
  //
  // btDbvtBroadphase
  //
  
  //
  btDbvtBroadphase::btDbvtBroadphase(btOverlappingPairCache* paircache)
  {
  	m_deferedcollide	=	false;
  	m_needcleanup		=	true;
  	m_releasepaircache	=	(paircache!=0)?false:true;
  	m_prediction		=	0;
  	m_stageCurrent		=	0;
  	m_fixedleft			=	0;
  	m_fupdates			=	1;
  	m_dupdates			=	0;
  	m_cupdates			=	10;
  	m_newpairs			=	1;
  	m_updates_call		=	0;
  	m_updates_done		=	0;
  	m_updates_ratio		=	0;
  	m_paircache			=	paircache? paircache	: new(btAlignedAlloc(sizeof(btHashedOverlappingPairCache),16)) btHashedOverlappingPairCache();
  	m_gid				=	0;
  	m_pid				=	0;
  	m_cid				=	0;
  	for(int i=0;i<=STAGECOUNT;++i)
  	{
  		m_stageRoots[i]=0;
  	}
  #if DBVT_BP_PROFILE
  	clear(m_profiling);
  #endif
  }
  
  //
  btDbvtBroadphase::~btDbvtBroadphase()
  {
  	if(m_releasepaircache) 
  	{
  		m_paircache->~btOverlappingPairCache();
  		btAlignedFree(m_paircache);
  	}
  }
  
  //
  btBroadphaseProxy*				btDbvtBroadphase::createProxy(	const btVector3& aabbMin,
  															  const btVector3& aabbMax,
  															  int /*shapeType*/,
  															  void* userPtr,
  															  short int collisionFilterGroup,
  															  short int collisionFilterMask,
  															  btDispatcher* /*dispatcher*/,
  															  void* /*multiSapProxy*/)
  {
  	btDbvtProxy*		proxy=new(btAlignedAlloc(sizeof(btDbvtProxy),16)) btDbvtProxy(	aabbMin,aabbMax,userPtr,
  		collisionFilterGroup,
  		collisionFilterMask);
  
  	btDbvtAabbMm aabb = btDbvtVolume::FromMM(aabbMin,aabbMax);
  
  	//bproxy->aabb			=	btDbvtVolume::FromMM(aabbMin,aabbMax);
  	proxy->stage		=	m_stageCurrent;
  	proxy->m_uniqueId	=	++m_gid;
  	proxy->leaf			=	m_sets[0].insert(aabb,proxy);
  	listappend(proxy,m_stageRoots[m_stageCurrent]);
  	if(!m_deferedcollide)
  	{
  		btDbvtTreeCollider	collider(this);
  		collider.proxy=proxy;
  		m_sets[0].collideTV(m_sets[0].m_root,aabb,collider);
  		m_sets[1].collideTV(m_sets[1].m_root,aabb,collider);
  	}
  	return(proxy);
  }
  
  //
  void							btDbvtBroadphase::destroyProxy(	btBroadphaseProxy* absproxy,
  															   btDispatcher* dispatcher)
  {
  	btDbvtProxy*	proxy=(btDbvtProxy*)absproxy;
  	if(proxy->stage==STAGECOUNT)
  		m_sets[1].remove(proxy->leaf);
  	else
  		m_sets[0].remove(proxy->leaf);
  	listremove(proxy,m_stageRoots[proxy->stage]);
  	m_paircache->removeOverlappingPairsContainingProxy(proxy,dispatcher);
  	btAlignedFree(proxy);
  	m_needcleanup=true;
  }
  
  void	btDbvtBroadphase::getAabb(btBroadphaseProxy* absproxy,btVector3& aabbMin, btVector3& aabbMax ) const
  {
  	btDbvtProxy*						proxy=(btDbvtProxy*)absproxy;
  	aabbMin = proxy->m_aabbMin;
  	aabbMax = proxy->m_aabbMax;
  }
  
  struct	BroadphaseRayTester : btDbvt::ICollide
  {
  	btBroadphaseRayCallback& m_rayCallback;
  	BroadphaseRayTester(btBroadphaseRayCallback& orgCallback)
  		:m_rayCallback(orgCallback)
  	{
  	}
  	void					Process(const btDbvtNode* leaf)
  	{
  		btDbvtProxy*	proxy=(btDbvtProxy*)leaf->data;
  		m_rayCallback.process(proxy);
  	}
  };	
  
  void	btDbvtBroadphase::rayTest(const btVector3& rayFrom,const btVector3& rayTo, btBroadphaseRayCallback& rayCallback,const btVector3& aabbMin,const btVector3& aabbMax)
  {
  	BroadphaseRayTester callback(rayCallback);
  
  	m_sets[0].rayTestInternal(	m_sets[0].m_root,
  		rayFrom,
  		rayTo,
  		rayCallback.m_rayDirectionInverse,
  		rayCallback.m_signs,
  		rayCallback.m_lambda_max,
  		aabbMin,
  		aabbMax,
  		callback);
  
  	m_sets[1].rayTestInternal(	m_sets[1].m_root,
  		rayFrom,
  		rayTo,
  		rayCallback.m_rayDirectionInverse,
  		rayCallback.m_signs,
  		rayCallback.m_lambda_max,
  		aabbMin,
  		aabbMax,
  		callback);
  
  }
  
  
  struct	BroadphaseAabbTester : btDbvt::ICollide
  {
  	btBroadphaseAabbCallback& m_aabbCallback;
  	BroadphaseAabbTester(btBroadphaseAabbCallback& orgCallback)
  		:m_aabbCallback(orgCallback)
  	{
  	}
  	void					Process(const btDbvtNode* leaf)
  	{
  		btDbvtProxy*	proxy=(btDbvtProxy*)leaf->data;
  		m_aabbCallback.process(proxy);
  	}
  };	
  
  void	btDbvtBroadphase::aabbTest(const btVector3& aabbMin,const btVector3& aabbMax,btBroadphaseAabbCallback& aabbCallback)
  {
  	BroadphaseAabbTester callback(aabbCallback);
  
  	const ATTRIBUTE_ALIGNED16(btDbvtVolume)	bounds=btDbvtVolume::FromMM(aabbMin,aabbMax);
  		//process all children, that overlap with  the given AABB bounds
  	m_sets[0].collideTV(m_sets[0].m_root,bounds,callback);
  	m_sets[1].collideTV(m_sets[1].m_root,bounds,callback);
  
  }
  
  
  
  //
  void							btDbvtBroadphase::setAabb(		btBroadphaseProxy* absproxy,
  														  const btVector3& aabbMin,
  														  const btVector3& aabbMax,
  														  btDispatcher* /*dispatcher*/)
  {
  	btDbvtProxy*						proxy=(btDbvtProxy*)absproxy;
  	ATTRIBUTE_ALIGNED16(btDbvtVolume)	aabb=btDbvtVolume::FromMM(aabbMin,aabbMax);
  #if DBVT_BP_PREVENTFALSEUPDATE
  	if(NotEqual(aabb,proxy->leaf->volume))
  #endif
  	{
  		bool	docollide=false;
  		if(proxy->stage==STAGECOUNT)
  		{/* fixed -> dynamic set	*/ 
  			m_sets[1].remove(proxy->leaf);
  			proxy->leaf=m_sets[0].insert(aabb,proxy);
  			docollide=true;
  		}
  		else
  		{/* dynamic set				*/ 
  			++m_updates_call;
  			if(Intersect(proxy->leaf->volume,aabb))
  			{/* Moving				*/ 
  
  				const btVector3	delta=aabbMin-proxy->m_aabbMin;
  				btVector3		velocity(((proxy->m_aabbMax-proxy->m_aabbMin)/2)*m_prediction);
  				if(delta[0]<0) velocity[0]=-velocity[0];
  				if(delta[1]<0) velocity[1]=-velocity[1];
  				if(delta[2]<0) velocity[2]=-velocity[2];
  				if	(
  #ifdef DBVT_BP_MARGIN				
  					m_sets[0].update(proxy->leaf,aabb,velocity,DBVT_BP_MARGIN)
  #else
  					m_sets[0].update(proxy->leaf,aabb,velocity)
  #endif
  					)
  				{
  					++m_updates_done;
  					docollide=true;
  				}
  			}
  			else
  			{/* Teleporting			*/ 
  				m_sets[0].update(proxy->leaf,aabb);
  				++m_updates_done;
  				docollide=true;
  			}	
  		}
  		listremove(proxy,m_stageRoots[proxy->stage]);
  		proxy->m_aabbMin = aabbMin;
  		proxy->m_aabbMax = aabbMax;
  		proxy->stage	=	m_stageCurrent;
  		listappend(proxy,m_stageRoots[m_stageCurrent]);
  		if(docollide)
  		{
  			m_needcleanup=true;
  			if(!m_deferedcollide)
  			{
  				btDbvtTreeCollider	collider(this);
  				m_sets[1].collideTTpersistentStack(m_sets[1].m_root,proxy->leaf,collider);
  				m_sets[0].collideTTpersistentStack(m_sets[0].m_root,proxy->leaf,collider);
  			}
  		}	
  	}
  }
  
  
  //
  void							btDbvtBroadphase::setAabbForceUpdate(		btBroadphaseProxy* absproxy,
  														  const btVector3& aabbMin,
  														  const btVector3& aabbMax,
  														  btDispatcher* /*dispatcher*/)
  {
  	btDbvtProxy*						proxy=(btDbvtProxy*)absproxy;
  	ATTRIBUTE_ALIGNED16(btDbvtVolume)	aabb=btDbvtVolume::FromMM(aabbMin,aabbMax);
  	bool	docollide=false;
  	if(proxy->stage==STAGECOUNT)
  	{/* fixed -> dynamic set	*/ 
  		m_sets[1].remove(proxy->leaf);
  		proxy->leaf=m_sets[0].insert(aabb,proxy);
  		docollide=true;
  	}
  	else
  	{/* dynamic set				*/ 
  		++m_updates_call;
  		/* Teleporting			*/ 
  		m_sets[0].update(proxy->leaf,aabb);
  		++m_updates_done;
  		docollide=true;
  	}
  	listremove(proxy,m_stageRoots[proxy->stage]);
  	proxy->m_aabbMin = aabbMin;
  	proxy->m_aabbMax = aabbMax;
  	proxy->stage	=	m_stageCurrent;
  	listappend(proxy,m_stageRoots[m_stageCurrent]);
  	if(docollide)
  	{
  		m_needcleanup=true;
  		if(!m_deferedcollide)
  		{
  			btDbvtTreeCollider	collider(this);
  			m_sets[1].collideTTpersistentStack(m_sets[1].m_root,proxy->leaf,collider);
  			m_sets[0].collideTTpersistentStack(m_sets[0].m_root,proxy->leaf,collider);
  		}
  	}	
  }
  
  //
  void							btDbvtBroadphase::calculateOverlappingPairs(btDispatcher* dispatcher)
  {
  	collide(dispatcher);
  #if DBVT_BP_PROFILE
  	if(0==(m_pid%DBVT_BP_PROFILING_RATE))
  	{	
  		printf("fixed(%u) dynamics(%u) pairs(%u)\r\n",m_sets[1].m_leaves,m_sets[0].m_leaves,m_paircache->getNumOverlappingPairs());
  		unsigned int	total=m_profiling.m_total;
  		if(total<=0) total=1;
  		printf("ddcollide: %u%% (%uus)\r\n",(50+m_profiling.m_ddcollide*100)/total,m_profiling.m_ddcollide/DBVT_BP_PROFILING_RATE);
  		printf("fdcollide: %u%% (%uus)\r\n",(50+m_profiling.m_fdcollide*100)/total,m_profiling.m_fdcollide/DBVT_BP_PROFILING_RATE);
  		printf("cleanup:   %u%% (%uus)\r\n",(50+m_profiling.m_cleanup*100)/total,m_profiling.m_cleanup/DBVT_BP_PROFILING_RATE);
  		printf("total:     %uus\r\n",total/DBVT_BP_PROFILING_RATE);
  		const unsigned long	sum=m_profiling.m_ddcollide+
  			m_profiling.m_fdcollide+
  			m_profiling.m_cleanup;
  		printf("leaked: %u%% (%uus)\r\n",100-((50+sum*100)/total),(total-sum)/DBVT_BP_PROFILING_RATE);
  		printf("job counts: %u%%\r\n",(m_profiling.m_jobcount*100)/((m_sets[0].m_leaves+m_sets[1].m_leaves)*DBVT_BP_PROFILING_RATE));
  		clear(m_profiling);
  		m_clock.reset();
  	}
  #endif
  
  	performDeferredRemoval(dispatcher);
  
  }
  
  void btDbvtBroadphase::performDeferredRemoval(btDispatcher* dispatcher)
  {
  
  	if (m_paircache->hasDeferredRemoval())
  	{
  
  		btBroadphasePairArray&	overlappingPairArray = m_paircache->getOverlappingPairArray();
  
  		//perform a sort, to find duplicates and to sort 'invalid' pairs to the end
  		overlappingPairArray.quickSort(btBroadphasePairSortPredicate());
  
  		int invalidPair = 0;
  
  		
  		int i;
  
  		btBroadphasePair previousPair;
  		previousPair.m_pProxy0 = 0;
  		previousPair.m_pProxy1 = 0;
  		previousPair.m_algorithm = 0;
  		
  		
  		for (i=0;i<overlappingPairArray.size();i++)
  		{
  		
  			btBroadphasePair& pair = overlappingPairArray[i];
  
  			bool isDuplicate = (pair == previousPair);
  
  			previousPair = pair;
  
  			bool needsRemoval = false;
  
  			if (!isDuplicate)
  			{
  				//important to perform AABB check that is consistent with the broadphase
  				btDbvtProxy*		pa=(btDbvtProxy*)pair.m_pProxy0;
  				btDbvtProxy*		pb=(btDbvtProxy*)pair.m_pProxy1;
  				bool hasOverlap = Intersect(pa->leaf->volume,pb->leaf->volume);
  
  				if (hasOverlap)
  				{
  					needsRemoval = false;
  				} else
  				{
  					needsRemoval = true;
  				}
  			} else
  			{
  				//remove duplicate
  				needsRemoval = true;
  				//should have no algorithm
  				btAssert(!pair.m_algorithm);
  			}
  			
  			if (needsRemoval)
  			{
  				m_paircache->cleanOverlappingPair(pair,dispatcher);
  
  				pair.m_pProxy0 = 0;
  				pair.m_pProxy1 = 0;
  				invalidPair++;
  			} 
  			
  		}
  
  		//perform a sort, to sort 'invalid' pairs to the end
  		overlappingPairArray.quickSort(btBroadphasePairSortPredicate());
  		overlappingPairArray.resize(overlappingPairArray.size() - invalidPair);
  	}
  }
  
  //
  void							btDbvtBroadphase::collide(btDispatcher* dispatcher)
  {
  	/*printf("---------------------------------------------------------\n");
  	printf("m_sets[0].m_leaves=%d\n",m_sets[0].m_leaves);
  	printf("m_sets[1].m_leaves=%d\n",m_sets[1].m_leaves);
  	printf("numPairs = %d\n",getOverlappingPairCache()->getNumOverlappingPairs());
  	{
  		int i;
  		for (i=0;i<getOverlappingPairCache()->getNumOverlappingPairs();i++)
  		{
  			printf("pair[%d]=(%d,%d),",i,getOverlappingPairCache()->getOverlappingPairArray()[i].m_pProxy0->getUid(),
  				getOverlappingPairCache()->getOverlappingPairArray()[i].m_pProxy1->getUid());
  		}
  		printf("\n");
  	}
  */
  
  
  
  	SPC(m_profiling.m_total);
  	/* optimize				*/ 
  	m_sets[0].optimizeIncremental(1+(m_sets[0].m_leaves*m_dupdates)/100);
  	if(m_fixedleft)
  	{
  		const int count=1+(m_sets[1].m_leaves*m_fupdates)/100;
  		m_sets[1].optimizeIncremental(1+(m_sets[1].m_leaves*m_fupdates)/100);
  		m_fixedleft=btMax<int>(0,m_fixedleft-count);
  	}
  	/* dynamic -> fixed set	*/ 
  	m_stageCurrent=(m_stageCurrent+1)%STAGECOUNT;
  	btDbvtProxy*	current=m_stageRoots[m_stageCurrent];
  	if(current)
  	{
  		btDbvtTreeCollider	collider(this);
  		do	{
  			btDbvtProxy*	next=current->links[1];
  			listremove(current,m_stageRoots[current->stage]);
  			listappend(current,m_stageRoots[STAGECOUNT]);
  #if DBVT_BP_ACCURATESLEEPING
  			m_paircache->removeOverlappingPairsContainingProxy(current,dispatcher);
  			collider.proxy=current;
  			btDbvt::collideTV(m_sets[0].m_root,current->aabb,collider);
  			btDbvt::collideTV(m_sets[1].m_root,current->aabb,collider);
  #endif
  			m_sets[0].remove(current->leaf);
  			ATTRIBUTE_ALIGNED16(btDbvtVolume)	curAabb=btDbvtVolume::FromMM(current->m_aabbMin,current->m_aabbMax);
  			current->leaf	=	m_sets[1].insert(curAabb,current);
  			current->stage	=	STAGECOUNT;	
  			current			=	next;
  		} while(current);
  		m_fixedleft=m_sets[1].m_leaves;
  		m_needcleanup=true;
  	}
  	/* collide dynamics		*/ 
  	{
  		btDbvtTreeCollider	collider(this);
  		if(m_deferedcollide)
  		{
  			SPC(m_profiling.m_fdcollide);
  			m_sets[0].collideTTpersistentStack(m_sets[0].m_root,m_sets[1].m_root,collider);
  		}
  		if(m_deferedcollide)
  		{
  			SPC(m_profiling.m_ddcollide);
  			m_sets[0].collideTTpersistentStack(m_sets[0].m_root,m_sets[0].m_root,collider);
  		}
  	}
  	/* clean up				*/ 
  	if(m_needcleanup)
  	{
  		SPC(m_profiling.m_cleanup);
  		btBroadphasePairArray&	pairs=m_paircache->getOverlappingPairArray();
  		if(pairs.size()>0)
  		{
  
  			int			ni=btMin(pairs.size(),btMax<int>(m_newpairs,(pairs.size()*m_cupdates)/100));
  			for(int i=0;i<ni;++i)
  			{
  				btBroadphasePair&	p=pairs[(m_cid+i)%pairs.size()];
  				btDbvtProxy*		pa=(btDbvtProxy*)p.m_pProxy0;
  				btDbvtProxy*		pb=(btDbvtProxy*)p.m_pProxy1;
  				if(!Intersect(pa->leaf->volume,pb->leaf->volume))
  				{
  #if DBVT_BP_SORTPAIRS
  					if(pa->m_uniqueId>pb->m_uniqueId) 
  						btSwap(pa,pb);
  #endif
  					m_paircache->removeOverlappingPair(pa,pb,dispatcher);
  					--ni;--i;
  				}
  			}
  			if(pairs.size()>0) m_cid=(m_cid+ni)%pairs.size(); else m_cid=0;
  		}
  	}
  	++m_pid;
  	m_newpairs=1;
  	m_needcleanup=false;
  	if(m_updates_call>0)
  	{ m_updates_ratio=m_updates_done/(btScalar)m_updates_call; }
  	else
  	{ m_updates_ratio=0; }
  	m_updates_done/=2;
  	m_updates_call/=2;
  }
  
  //
  void							btDbvtBroadphase::optimize()
  {
  	m_sets[0].optimizeTopDown();
  	m_sets[1].optimizeTopDown();
  }
  
  //
  btOverlappingPairCache*			btDbvtBroadphase::getOverlappingPairCache()
  {
  	return(m_paircache);
  }
  
  //
  const btOverlappingPairCache*	btDbvtBroadphase::getOverlappingPairCache() const
  {
  	return(m_paircache);
  }
  
  //
  void							btDbvtBroadphase::getBroadphaseAabb(btVector3& aabbMin,btVector3& aabbMax) const
  {
  
  	ATTRIBUTE_ALIGNED16(btDbvtVolume)	bounds;
  
  	if(!m_sets[0].empty())
  		if(!m_sets[1].empty())	Merge(	m_sets[0].m_root->volume,
  			m_sets[1].m_root->volume,bounds);
  		else
  			bounds=m_sets[0].m_root->volume;
  	else if(!m_sets[1].empty())	bounds=m_sets[1].m_root->volume;
  	else
  		bounds=btDbvtVolume::FromCR(btVector3(0,0,0),0);
  	aabbMin=bounds.Mins();
  	aabbMax=bounds.Maxs();
  }
  
  void btDbvtBroadphase::resetPool(btDispatcher* dispatcher)
  {
  	
  	int totalObjects = m_sets[0].m_leaves + m_sets[1].m_leaves;
  	if (!totalObjects)
  	{
  		//reset internal dynamic tree data structures
  		m_sets[0].clear();
  		m_sets[1].clear();
  		
  		m_deferedcollide	=	false;
  		m_needcleanup		=	true;
  		m_stageCurrent		=	0;
  		m_fixedleft			=	0;
  		m_fupdates			=	1;
  		m_dupdates			=	0;
  		m_cupdates			=	10;
  		m_newpairs			=	1;
  		m_updates_call		=	0;
  		m_updates_done		=	0;
  		m_updates_ratio		=	0;
  		
  		m_gid				=	0;
  		m_pid				=	0;
  		m_cid				=	0;
  		for(int i=0;i<=STAGECOUNT;++i)
  		{
  			m_stageRoots[i]=0;
  		}
  	}
  }
  
  //
  void							btDbvtBroadphase::printStats()
  {}
  
  //
  #if DBVT_BP_ENABLE_BENCHMARK
  
  struct	btBroadphaseBenchmark
  {
  	struct	Experiment
  	{
  		const char*			name;
  		int					object_count;
  		int					update_count;
  		int					spawn_count;
  		int					iterations;
  		btScalar			speed;
  		btScalar			amplitude;
  	};
  	struct	Object
  	{
  		btVector3			center;
  		btVector3			extents;
  		btBroadphaseProxy*	proxy;
  		btScalar			time;
  		void				update(btScalar speed,btScalar amplitude,btBroadphaseInterface* pbi)
  		{
  			time		+=	speed;
  			center[0]	=	btCos(time*(btScalar)2.17)*amplitude+
  				btSin(time)*amplitude/2;
  			center[1]	=	btCos(time*(btScalar)1.38)*amplitude+
  				btSin(time)*amplitude;
  			center[2]	=	btSin(time*(btScalar)0.777)*amplitude;
  			pbi->setAabb(proxy,center-extents,center+extents,0);
  		}
  	};
  	static int		UnsignedRand(int range=RAND_MAX-1)	{ return(rand()%(range+1)); }
  	static btScalar	UnitRand()							{ return(UnsignedRand(16384)/(btScalar)16384); }
  	static void		OutputTime(const char* name,btClock& c,unsigned count=0)
  	{
  		const unsigned long	us=c.getTimeMicroseconds();
  		const unsigned long	ms=(us+500)/1000;
  		const btScalar		sec=us/(btScalar)(1000*1000);
  		if(count>0)
  			printf("%s : %u us (%u ms), %.2f/s\r\n",name,us,ms,count/sec);
  		else
  			printf("%s : %u us (%u ms)\r\n",name,us,ms);
  	}
  };
  
  void							btDbvtBroadphase::benchmark(btBroadphaseInterface* pbi)
  {
  	static const btBroadphaseBenchmark::Experiment		experiments[]=
  	{
  		{"1024o.10%",1024,10,0,8192,(btScalar)0.005,(btScalar)100},
  		/*{"4096o.10%",4096,10,0,8192,(btScalar)0.005,(btScalar)100},
  		{"8192o.10%",8192,10,0,8192,(btScalar)0.005,(btScalar)100},*/
  	};
  	static const int										nexperiments=sizeof(experiments)/sizeof(experiments[0]);
  	btAlignedObjectArray<btBroadphaseBenchmark::Object*>	objects;
  	btClock													wallclock;
  	/* Begin			*/ 
  	for(int iexp=0;iexp<nexperiments;++iexp)
  	{
  		const btBroadphaseBenchmark::Experiment&	experiment=experiments[iexp];
  		const int									object_count=experiment.object_count;
  		const int									update_count=(object_count*experiment.update_count)/100;
  		const int									spawn_count=(object_count*experiment.spawn_count)/100;
  		const btScalar								speed=experiment.speed;	
  		const btScalar								amplitude=experiment.amplitude;
  		printf("Experiment #%u '%s':\r\n",iexp,experiment.name);
  		printf("\tObjects: %u\r\n",object_count);
  		printf("\tUpdate: %u\r\n",update_count);
  		printf("\tSpawn: %u\r\n",spawn_count);
  		printf("\tSpeed: %f\r\n",speed);
  		printf("\tAmplitude: %f\r\n",amplitude);
  		srand(180673);
  		/* Create objects	*/ 
  		wallclock.reset();
  		objects.reserve(object_count);
  		for(int i=0;i<object_count;++i)
  		{
  			btBroadphaseBenchmark::Object*	po=new btBroadphaseBenchmark::Object();
  			po->center[0]=btBroadphaseBenchmark::UnitRand()*50;
  			po->center[1]=btBroadphaseBenchmark::UnitRand()*50;
  			po->center[2]=btBroadphaseBenchmark::UnitRand()*50;
  			po->extents[0]=btBroadphaseBenchmark::UnitRand()*2+2;
  			po->extents[1]=btBroadphaseBenchmark::UnitRand()*2+2;
  			po->extents[2]=btBroadphaseBenchmark::UnitRand()*2+2;
  			po->time=btBroadphaseBenchmark::UnitRand()*2000;
  			po->proxy=pbi->createProxy(po->center-po->extents,po->center+po->extents,0,po,1,1,0,0);
  			objects.push_back(po);
  		}
  		btBroadphaseBenchmark::OutputTime("\tInitialization",wallclock);
  		/* First update		*/ 
  		wallclock.reset();
  		for(int i=0;i<objects.size();++i)
  		{
  			objects[i]->update(speed,amplitude,pbi);
  		}
  		btBroadphaseBenchmark::OutputTime("\tFirst update",wallclock);
  		/* Updates			*/ 
  		wallclock.reset();
  		for(int i=0;i<experiment.iterations;++i)
  		{
  			for(int j=0;j<update_count;++j)
  			{				
  				objects[j]->update(speed,amplitude,pbi);
  			}
  			pbi->calculateOverlappingPairs(0);
  		}
  		btBroadphaseBenchmark::OutputTime("\tUpdate",wallclock,experiment.iterations);
  		/* Clean up			*/ 
  		wallclock.reset();
  		for(int i=0;i<objects.size();++i)
  		{
  			pbi->destroyProxy(objects[i]->proxy,0);
  			delete objects[i];
  		}
  		objects.resize(0);
  		btBroadphaseBenchmark::OutputTime("\tRelease",wallclock);
  	}
  
  }
  #else
  void							btDbvtBroadphase::benchmark(btBroadphaseInterface*)
  {}
  #endif
  
  #if DBVT_BP_PROFILE
  #undef	SPC
  #endif
  
  