451 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			451 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
 | 
						|
/*
 | 
						|
Bullet Continuous Collision Detection and Physics Library
 | 
						|
Copyright (c) 2003-2006 Erwin Coumans  http://continuousphysics.com/Bullet/
 | 
						|
 | 
						|
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.
 | 
						|
*/
 | 
						|
 | 
						|
 | 
						|
#include "LinearMath/btScalar.h"
 | 
						|
#include "btSimulationIslandManager.h"
 | 
						|
#include "BulletCollision/BroadphaseCollision/btDispatcher.h"
 | 
						|
#include "BulletCollision/NarrowPhaseCollision/btPersistentManifold.h"
 | 
						|
#include "BulletCollision/CollisionDispatch/btCollisionObject.h"
 | 
						|
#include "BulletCollision/CollisionDispatch/btCollisionWorld.h"
 | 
						|
 | 
						|
//#include <stdio.h>
 | 
						|
#include "LinearMath/btQuickprof.h"
 | 
						|
 | 
						|
btSimulationIslandManager::btSimulationIslandManager():
 | 
						|
m_splitIslands(true)
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
btSimulationIslandManager::~btSimulationIslandManager()
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
void btSimulationIslandManager::initUnionFind(int n)
 | 
						|
{
 | 
						|
		m_unionFind.reset(n);
 | 
						|
}
 | 
						|
		
 | 
						|
 | 
						|
void btSimulationIslandManager::findUnions(btDispatcher* /* dispatcher */,btCollisionWorld* colWorld)
 | 
						|
{
 | 
						|
	
 | 
						|
	{
 | 
						|
		btOverlappingPairCache* pairCachePtr = colWorld->getPairCache();
 | 
						|
		const int numOverlappingPairs = pairCachePtr->getNumOverlappingPairs();
 | 
						|
		if (numOverlappingPairs)
 | 
						|
		{
 | 
						|
		btBroadphasePair* pairPtr = pairCachePtr->getOverlappingPairArrayPtr();
 | 
						|
		
 | 
						|
		for (int i=0;i<numOverlappingPairs;i++)
 | 
						|
		{
 | 
						|
			const btBroadphasePair& collisionPair = pairPtr[i];
 | 
						|
			btCollisionObject* colObj0 = (btCollisionObject*)collisionPair.m_pProxy0->m_clientObject;
 | 
						|
			btCollisionObject* colObj1 = (btCollisionObject*)collisionPair.m_pProxy1->m_clientObject;
 | 
						|
 | 
						|
			if (((colObj0) && ((colObj0)->mergesSimulationIslands())) &&
 | 
						|
				((colObj1) && ((colObj1)->mergesSimulationIslands())))
 | 
						|
			{
 | 
						|
 | 
						|
				m_unionFind.unite((colObj0)->getIslandTag(),
 | 
						|
					(colObj1)->getIslandTag());
 | 
						|
			}
 | 
						|
		}
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
#ifdef STATIC_SIMULATION_ISLAND_OPTIMIZATION
 | 
						|
void   btSimulationIslandManager::updateActivationState(btCollisionWorld* colWorld,btDispatcher* dispatcher)
 | 
						|
{
 | 
						|
 | 
						|
	// put the index into m_controllers into m_tag   
 | 
						|
	int index = 0;
 | 
						|
	{
 | 
						|
 | 
						|
		int i;
 | 
						|
		for (i=0;i<colWorld->getCollisionObjectArray().size(); i++)
 | 
						|
		{
 | 
						|
			btCollisionObject*   collisionObject= colWorld->getCollisionObjectArray()[i];
 | 
						|
			//Adding filtering here
 | 
						|
			if (!collisionObject->isStaticOrKinematicObject())
 | 
						|
			{
 | 
						|
				collisionObject->setIslandTag(index++);
 | 
						|
			}
 | 
						|
			collisionObject->setCompanionId(-1);
 | 
						|
			collisionObject->setHitFraction(btScalar(1.));
 | 
						|
		}
 | 
						|
	}
 | 
						|
	// do the union find
 | 
						|
 | 
						|
	initUnionFind( index );
 | 
						|
 | 
						|
	findUnions(dispatcher,colWorld);
 | 
						|
}
 | 
						|
 | 
						|
void   btSimulationIslandManager::storeIslandActivationState(btCollisionWorld* colWorld)
 | 
						|
{
 | 
						|
	// put the islandId ('find' value) into m_tag   
 | 
						|
	{
 | 
						|
		int index = 0;
 | 
						|
		int i;
 | 
						|
		for (i=0;i<colWorld->getCollisionObjectArray().size();i++)
 | 
						|
		{
 | 
						|
			btCollisionObject* collisionObject= colWorld->getCollisionObjectArray()[i];
 | 
						|
			if (!collisionObject->isStaticOrKinematicObject())
 | 
						|
			{
 | 
						|
				collisionObject->setIslandTag( m_unionFind.find(index) );
 | 
						|
				//Set the correct object offset in Collision Object Array
 | 
						|
				m_unionFind.getElement(index).m_sz = i;
 | 
						|
				collisionObject->setCompanionId(-1);
 | 
						|
				index++;
 | 
						|
			} else
 | 
						|
			{
 | 
						|
				collisionObject->setIslandTag(-1);
 | 
						|
				collisionObject->setCompanionId(-2);
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
#else //STATIC_SIMULATION_ISLAND_OPTIMIZATION
 | 
						|
void	btSimulationIslandManager::updateActivationState(btCollisionWorld* colWorld,btDispatcher* dispatcher)
 | 
						|
{
 | 
						|
 | 
						|
	initUnionFind( int (colWorld->getCollisionObjectArray().size()));
 | 
						|
 | 
						|
	// put the index into m_controllers into m_tag	
 | 
						|
	{
 | 
						|
 | 
						|
		int index = 0;
 | 
						|
		int i;
 | 
						|
		for (i=0;i<colWorld->getCollisionObjectArray().size(); i++)
 | 
						|
		{
 | 
						|
			btCollisionObject*	collisionObject= colWorld->getCollisionObjectArray()[i];
 | 
						|
			collisionObject->setIslandTag(index);
 | 
						|
			collisionObject->setCompanionId(-1);
 | 
						|
			collisionObject->setHitFraction(btScalar(1.));
 | 
						|
			index++;
 | 
						|
 | 
						|
		}
 | 
						|
	}
 | 
						|
	// do the union find
 | 
						|
 | 
						|
	findUnions(dispatcher,colWorld);
 | 
						|
}
 | 
						|
 | 
						|
void	btSimulationIslandManager::storeIslandActivationState(btCollisionWorld* colWorld)
 | 
						|
{
 | 
						|
	// put the islandId ('find' value) into m_tag	
 | 
						|
	{
 | 
						|
 | 
						|
 | 
						|
		int index = 0;
 | 
						|
		int i;
 | 
						|
		for (i=0;i<colWorld->getCollisionObjectArray().size();i++)
 | 
						|
		{
 | 
						|
			btCollisionObject* collisionObject= colWorld->getCollisionObjectArray()[i];
 | 
						|
			if (!collisionObject->isStaticOrKinematicObject())
 | 
						|
			{
 | 
						|
				collisionObject->setIslandTag( m_unionFind.find(index) );
 | 
						|
				collisionObject->setCompanionId(-1);
 | 
						|
			} else
 | 
						|
			{
 | 
						|
				collisionObject->setIslandTag(-1);
 | 
						|
				collisionObject->setCompanionId(-2);
 | 
						|
			}
 | 
						|
			index++;
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
#endif //STATIC_SIMULATION_ISLAND_OPTIMIZATION
 | 
						|
 | 
						|
inline	int	getIslandId(const btPersistentManifold* lhs)
 | 
						|
{
 | 
						|
	int islandId;
 | 
						|
	const btCollisionObject* rcolObj0 = static_cast<const btCollisionObject*>(lhs->getBody0());
 | 
						|
	const btCollisionObject* rcolObj1 = static_cast<const btCollisionObject*>(lhs->getBody1());
 | 
						|
	islandId= rcolObj0->getIslandTag()>=0?rcolObj0->getIslandTag():rcolObj1->getIslandTag();
 | 
						|
	return islandId;
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
/// function object that routes calls to operator<
 | 
						|
class btPersistentManifoldSortPredicate
 | 
						|
{
 | 
						|
	public:
 | 
						|
 | 
						|
		SIMD_FORCE_INLINE bool operator() ( const btPersistentManifold* lhs, const btPersistentManifold* rhs ) const
 | 
						|
		{
 | 
						|
			return getIslandId(lhs) < getIslandId(rhs);
 | 
						|
		}
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
void btSimulationIslandManager::buildIslands(btDispatcher* dispatcher,btCollisionWorld* collisionWorld)
 | 
						|
{
 | 
						|
 | 
						|
	BT_PROFILE("islandUnionFindAndQuickSort");
 | 
						|
	
 | 
						|
	btCollisionObjectArray& collisionObjects = collisionWorld->getCollisionObjectArray();
 | 
						|
 | 
						|
	m_islandmanifold.resize(0);
 | 
						|
 | 
						|
	//we are going to sort the unionfind array, and store the element id in the size
 | 
						|
	//afterwards, we clean unionfind, to make sure no-one uses it anymore
 | 
						|
	
 | 
						|
	getUnionFind().sortIslands();
 | 
						|
	int numElem = getUnionFind().getNumElements();
 | 
						|
 | 
						|
	int endIslandIndex=1;
 | 
						|
	int startIslandIndex;
 | 
						|
 | 
						|
 | 
						|
	//update the sleeping state for bodies, if all are sleeping
 | 
						|
	for ( startIslandIndex=0;startIslandIndex<numElem;startIslandIndex = endIslandIndex)
 | 
						|
	{
 | 
						|
		int islandId = getUnionFind().getElement(startIslandIndex).m_id;
 | 
						|
		for (endIslandIndex = startIslandIndex+1;(endIslandIndex<numElem) && (getUnionFind().getElement(endIslandIndex).m_id == islandId);endIslandIndex++)
 | 
						|
		{
 | 
						|
		}
 | 
						|
 | 
						|
		//int numSleeping = 0;
 | 
						|
 | 
						|
		bool allSleeping = true;
 | 
						|
 | 
						|
		int idx;
 | 
						|
		for (idx=startIslandIndex;idx<endIslandIndex;idx++)
 | 
						|
		{
 | 
						|
			int i = getUnionFind().getElement(idx).m_sz;
 | 
						|
 | 
						|
			btCollisionObject* colObj0 = collisionObjects[i];
 | 
						|
			if ((colObj0->getIslandTag() != islandId) && (colObj0->getIslandTag() != -1))
 | 
						|
			{
 | 
						|
//				printf("error in island management\n");
 | 
						|
			}
 | 
						|
 | 
						|
			btAssert((colObj0->getIslandTag() == islandId) || (colObj0->getIslandTag() == -1));
 | 
						|
			if (colObj0->getIslandTag() == islandId)
 | 
						|
			{
 | 
						|
				if (colObj0->getActivationState()== ACTIVE_TAG)
 | 
						|
				{
 | 
						|
					allSleeping = false;
 | 
						|
				}
 | 
						|
				if (colObj0->getActivationState()== DISABLE_DEACTIVATION)
 | 
						|
				{
 | 
						|
					allSleeping = false;
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
			
 | 
						|
 | 
						|
		if (allSleeping)
 | 
						|
		{
 | 
						|
			int idx;
 | 
						|
			for (idx=startIslandIndex;idx<endIslandIndex;idx++)
 | 
						|
			{
 | 
						|
				int i = getUnionFind().getElement(idx).m_sz;
 | 
						|
				btCollisionObject* colObj0 = collisionObjects[i];
 | 
						|
				if ((colObj0->getIslandTag() != islandId) && (colObj0->getIslandTag() != -1))
 | 
						|
				{
 | 
						|
//					printf("error in island management\n");
 | 
						|
				}
 | 
						|
 | 
						|
				btAssert((colObj0->getIslandTag() == islandId) || (colObj0->getIslandTag() == -1));
 | 
						|
 | 
						|
				if (colObj0->getIslandTag() == islandId)
 | 
						|
				{
 | 
						|
					colObj0->setActivationState( ISLAND_SLEEPING );
 | 
						|
				}
 | 
						|
			}
 | 
						|
		} else
 | 
						|
		{
 | 
						|
 | 
						|
			int idx;
 | 
						|
			for (idx=startIslandIndex;idx<endIslandIndex;idx++)
 | 
						|
			{
 | 
						|
				int i = getUnionFind().getElement(idx).m_sz;
 | 
						|
 | 
						|
				btCollisionObject* colObj0 = collisionObjects[i];
 | 
						|
				if ((colObj0->getIslandTag() != islandId) && (colObj0->getIslandTag() != -1))
 | 
						|
				{
 | 
						|
//					printf("error in island management\n");
 | 
						|
				}
 | 
						|
 | 
						|
				btAssert((colObj0->getIslandTag() == islandId) || (colObj0->getIslandTag() == -1));
 | 
						|
 | 
						|
				if (colObj0->getIslandTag() == islandId)
 | 
						|
				{
 | 
						|
					if ( colObj0->getActivationState() == ISLAND_SLEEPING)
 | 
						|
					{
 | 
						|
						colObj0->setActivationState( WANTS_DEACTIVATION);
 | 
						|
						colObj0->setDeactivationTime(0.f);
 | 
						|
					}
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	
 | 
						|
	int i;
 | 
						|
	int maxNumManifolds = dispatcher->getNumManifolds();
 | 
						|
 | 
						|
//#define SPLIT_ISLANDS 1
 | 
						|
//#ifdef SPLIT_ISLANDS
 | 
						|
 | 
						|
	
 | 
						|
//#endif //SPLIT_ISLANDS
 | 
						|
 | 
						|
	
 | 
						|
	for (i=0;i<maxNumManifolds ;i++)
 | 
						|
	{
 | 
						|
		 btPersistentManifold* manifold = dispatcher->getManifoldByIndexInternal(i);
 | 
						|
		 
 | 
						|
		 const btCollisionObject* colObj0 = static_cast<const btCollisionObject*>(manifold->getBody0());
 | 
						|
		 const btCollisionObject* colObj1 = static_cast<const btCollisionObject*>(manifold->getBody1());
 | 
						|
		
 | 
						|
		 ///@todo: check sleeping conditions!
 | 
						|
		 if (((colObj0) && colObj0->getActivationState() != ISLAND_SLEEPING) ||
 | 
						|
			((colObj1) && colObj1->getActivationState() != ISLAND_SLEEPING))
 | 
						|
		{
 | 
						|
		
 | 
						|
			//kinematic objects don't merge islands, but wake up all connected objects
 | 
						|
			if (colObj0->isKinematicObject() && colObj0->getActivationState() != ISLAND_SLEEPING)
 | 
						|
			{
 | 
						|
				if (colObj0->hasContactResponse())
 | 
						|
					colObj1->activate();
 | 
						|
			}
 | 
						|
			if (colObj1->isKinematicObject() && colObj1->getActivationState() != ISLAND_SLEEPING)
 | 
						|
			{
 | 
						|
				if (colObj1->hasContactResponse())
 | 
						|
					colObj0->activate();
 | 
						|
			}
 | 
						|
			if(m_splitIslands)
 | 
						|
			{ 
 | 
						|
				//filtering for response
 | 
						|
				if (dispatcher->needsResponse(colObj0,colObj1))
 | 
						|
					m_islandmanifold.push_back(manifold);
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
///@todo: this is random access, it can be walked 'cache friendly'!
 | 
						|
void btSimulationIslandManager::buildAndProcessIslands(btDispatcher* dispatcher,btCollisionWorld* collisionWorld, IslandCallback* callback)
 | 
						|
{
 | 
						|
	btCollisionObjectArray& collisionObjects = collisionWorld->getCollisionObjectArray();
 | 
						|
 | 
						|
	buildIslands(dispatcher,collisionWorld);
 | 
						|
 | 
						|
	int endIslandIndex=1;
 | 
						|
	int startIslandIndex;
 | 
						|
	int numElem = getUnionFind().getNumElements();
 | 
						|
 | 
						|
	BT_PROFILE("processIslands");
 | 
						|
 | 
						|
	if(!m_splitIslands)
 | 
						|
	{
 | 
						|
		btPersistentManifold** manifold = dispatcher->getInternalManifoldPointer();
 | 
						|
		int maxNumManifolds = dispatcher->getNumManifolds();
 | 
						|
		callback->processIsland(&collisionObjects[0],collisionObjects.size(),manifold,maxNumManifolds, -1);
 | 
						|
	}
 | 
						|
	else
 | 
						|
	{
 | 
						|
		// Sort manifolds, based on islands
 | 
						|
		// Sort the vector using predicate and std::sort
 | 
						|
		//std::sort(islandmanifold.begin(), islandmanifold.end(), btPersistentManifoldSortPredicate);
 | 
						|
 | 
						|
		int numManifolds = int (m_islandmanifold.size());
 | 
						|
 | 
						|
		//tried a radix sort, but quicksort/heapsort seems still faster
 | 
						|
		//@todo rewrite island management
 | 
						|
		m_islandmanifold.quickSort(btPersistentManifoldSortPredicate());
 | 
						|
		//m_islandmanifold.heapSort(btPersistentManifoldSortPredicate());
 | 
						|
 | 
						|
		//now process all active islands (sets of manifolds for now)
 | 
						|
 | 
						|
		int startManifoldIndex = 0;
 | 
						|
		int endManifoldIndex = 1;
 | 
						|
 | 
						|
		//int islandId;
 | 
						|
 | 
						|
		
 | 
						|
 | 
						|
	//	printf("Start Islands\n");
 | 
						|
 | 
						|
		//traverse the simulation islands, and call the solver, unless all objects are sleeping/deactivated
 | 
						|
		for ( startIslandIndex=0;startIslandIndex<numElem;startIslandIndex = endIslandIndex)
 | 
						|
		{
 | 
						|
			int islandId = getUnionFind().getElement(startIslandIndex).m_id;
 | 
						|
 | 
						|
 | 
						|
			   bool islandSleeping = true;
 | 
						|
	                
 | 
						|
					for (endIslandIndex = startIslandIndex;(endIslandIndex<numElem) && (getUnionFind().getElement(endIslandIndex).m_id == islandId);endIslandIndex++)
 | 
						|
					{
 | 
						|
							int i = getUnionFind().getElement(endIslandIndex).m_sz;
 | 
						|
							btCollisionObject* colObj0 = collisionObjects[i];
 | 
						|
							m_islandBodies.push_back(colObj0);
 | 
						|
							if (colObj0->isActive())
 | 
						|
									islandSleeping = false;
 | 
						|
					}
 | 
						|
	                
 | 
						|
 | 
						|
			//find the accompanying contact manifold for this islandId
 | 
						|
			int numIslandManifolds = 0;
 | 
						|
			btPersistentManifold** startManifold = 0;
 | 
						|
 | 
						|
			if (startManifoldIndex<numManifolds)
 | 
						|
			{
 | 
						|
				int curIslandId = getIslandId(m_islandmanifold[startManifoldIndex]);
 | 
						|
				if (curIslandId == islandId)
 | 
						|
				{
 | 
						|
					startManifold = &m_islandmanifold[startManifoldIndex];
 | 
						|
				
 | 
						|
					for (endManifoldIndex = startManifoldIndex+1;(endManifoldIndex<numManifolds) && (islandId == getIslandId(m_islandmanifold[endManifoldIndex]));endManifoldIndex++)
 | 
						|
					{
 | 
						|
 | 
						|
					}
 | 
						|
					/// Process the actual simulation, only if not sleeping/deactivated
 | 
						|
					numIslandManifolds = endManifoldIndex-startManifoldIndex;
 | 
						|
				}
 | 
						|
 | 
						|
			}
 | 
						|
 | 
						|
			if (!islandSleeping)
 | 
						|
			{
 | 
						|
				callback->processIsland(&m_islandBodies[0],m_islandBodies.size(),startManifold,numIslandManifolds, islandId);
 | 
						|
	//			printf("Island callback of size:%d bodies, %d manifolds\n",islandBodies.size(),numIslandManifolds);
 | 
						|
			}
 | 
						|
			
 | 
						|
			if (numIslandManifolds)
 | 
						|
			{
 | 
						|
				startManifoldIndex = endManifoldIndex;
 | 
						|
			}
 | 
						|
 | 
						|
			m_islandBodies.resize(0);
 | 
						|
		}
 | 
						|
	} // else if(!splitIslands) 
 | 
						|
 | 
						|
}
 |