679 lines
		
	
	
		
			23 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			679 lines
		
	
	
		
			23 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 "LinearMath/btThreads.h"
 | |
| #include "btSimulationIslandManagerMt.h"
 | |
| #include "BulletCollision/BroadphaseCollision/btDispatcher.h"
 | |
| #include "BulletCollision/NarrowPhaseCollision/btPersistentManifold.h"
 | |
| #include "BulletCollision/CollisionDispatch/btCollisionObject.h"
 | |
| #include "BulletCollision/CollisionDispatch/btCollisionWorld.h"
 | |
| #include "BulletDynamics/ConstraintSolver/btTypedConstraint.h"
 | |
| 
 | |
| //#include <stdio.h>
 | |
| #include "LinearMath/btQuickprof.h"
 | |
| 
 | |
| 
 | |
| SIMD_FORCE_INLINE int calcBatchCost( int bodies, int manifolds, int constraints )
 | |
| {
 | |
|     // rough estimate of the cost of a batch, used for merging
 | |
|     int batchCost = bodies + 8 * manifolds + 4 * constraints;
 | |
|     return batchCost;
 | |
| }
 | |
| 
 | |
| 
 | |
| SIMD_FORCE_INLINE int calcBatchCost( const btSimulationIslandManagerMt::Island* island )
 | |
| {
 | |
|     return calcBatchCost( island->bodyArray.size(), island->manifoldArray.size(), island->constraintArray.size() );
 | |
| }
 | |
| 
 | |
| 
 | |
| btSimulationIslandManagerMt::btSimulationIslandManagerMt()
 | |
| {
 | |
|     m_minimumSolverBatchSize = calcBatchCost(0, 128, 0);
 | |
|     m_batchIslandMinBodyCount = 32;
 | |
|     m_islandDispatch = parallelIslandDispatch;
 | |
|     m_batchIsland = NULL;
 | |
| }
 | |
| 
 | |
| 
 | |
| btSimulationIslandManagerMt::~btSimulationIslandManagerMt()
 | |
| {
 | |
|     for ( int i = 0; i < m_allocatedIslands.size(); ++i )
 | |
|     {
 | |
|         delete m_allocatedIslands[ i ];
 | |
|     }
 | |
|     m_allocatedIslands.resize( 0 );
 | |
|     m_activeIslands.resize( 0 );
 | |
|     m_freeIslands.resize( 0 );
 | |
| }
 | |
| 
 | |
| 
 | |
| inline	int	getIslandId(const btPersistentManifold* lhs)
 | |
| {
 | |
| 	const btCollisionObject* rcolObj0 = static_cast<const btCollisionObject*>(lhs->getBody0());
 | |
| 	const btCollisionObject* rcolObj1 = static_cast<const btCollisionObject*>(lhs->getBody1());
 | |
|     int islandId = rcolObj0->getIslandTag() >= 0 ? rcolObj0->getIslandTag() : rcolObj1->getIslandTag();
 | |
| 	return islandId;
 | |
| }
 | |
| 
 | |
| 
 | |
| SIMD_FORCE_INLINE	int	btGetConstraintIslandId( const btTypedConstraint* lhs )
 | |
| {
 | |
|     const btCollisionObject& rcolObj0 = lhs->getRigidBodyA();
 | |
|     const btCollisionObject& rcolObj1 = lhs->getRigidBodyB();
 | |
|     int islandId = rcolObj0.getIslandTag() >= 0 ? rcolObj0.getIslandTag() : rcolObj1.getIslandTag();
 | |
|     return islandId;
 | |
| }
 | |
| 
 | |
| /// function object that routes calls to operator<
 | |
| class IslandBatchSizeSortPredicate
 | |
| {
 | |
| public:
 | |
|     bool operator() ( const btSimulationIslandManagerMt::Island* lhs, const btSimulationIslandManagerMt::Island* rhs ) const
 | |
|     {
 | |
|         int lCost = calcBatchCost( lhs );
 | |
|         int rCost = calcBatchCost( rhs );
 | |
|         return lCost > rCost;
 | |
|     }
 | |
| };
 | |
| 
 | |
| 
 | |
| class IslandBodyCapacitySortPredicate
 | |
| {
 | |
| public:
 | |
|     bool operator() ( const btSimulationIslandManagerMt::Island* lhs, const btSimulationIslandManagerMt::Island* rhs ) const
 | |
|     {
 | |
|         return lhs->bodyArray.capacity() > rhs->bodyArray.capacity();
 | |
|     }
 | |
| };
 | |
| 
 | |
| 
 | |
| void btSimulationIslandManagerMt::Island::append( const Island& other )
 | |
| {
 | |
|     // append bodies
 | |
|     for ( int i = 0; i < other.bodyArray.size(); ++i )
 | |
|     {
 | |
|         bodyArray.push_back( other.bodyArray[ i ] );
 | |
|     }
 | |
|     // append manifolds
 | |
|     for ( int i = 0; i < other.manifoldArray.size(); ++i )
 | |
|     {
 | |
|         manifoldArray.push_back( other.manifoldArray[ i ] );
 | |
|     }
 | |
|     // append constraints
 | |
|     for ( int i = 0; i < other.constraintArray.size(); ++i )
 | |
|     {
 | |
|         constraintArray.push_back( other.constraintArray[ i ] );
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| bool btIsBodyInIsland( const btSimulationIslandManagerMt::Island& island, const btCollisionObject* obj )
 | |
| {
 | |
|     for ( int i = 0; i < island.bodyArray.size(); ++i )
 | |
|     {
 | |
|         if ( island.bodyArray[ i ] == obj )
 | |
|         {
 | |
|             return true;
 | |
|         }
 | |
|     }
 | |
|     return false;
 | |
| }
 | |
| 
 | |
| 
 | |
| void btSimulationIslandManagerMt::initIslandPools()
 | |
| {
 | |
|     // reset island pools
 | |
|     int numElem = getUnionFind().getNumElements();
 | |
|     m_lookupIslandFromId.resize( numElem );
 | |
|     for ( int i = 0; i < m_lookupIslandFromId.size(); ++i )
 | |
|     {
 | |
|         m_lookupIslandFromId[ i ] = NULL;
 | |
|     }
 | |
|     m_activeIslands.resize( 0 );
 | |
|     m_freeIslands.resize( 0 );
 | |
|     // check whether allocated islands are sorted by body capacity (largest to smallest)
 | |
|     int lastCapacity = 0;
 | |
|     bool isSorted = true;
 | |
|     for ( int i = 0; i < m_allocatedIslands.size(); ++i )
 | |
|     {
 | |
|         Island* island = m_allocatedIslands[ i ];
 | |
|         int cap = island->bodyArray.capacity();
 | |
|         if ( cap > lastCapacity )
 | |
|         {
 | |
|             isSorted = false;
 | |
|             break;
 | |
|         }
 | |
|         lastCapacity = cap;
 | |
|     }
 | |
|     if ( !isSorted )
 | |
|     {
 | |
|         m_allocatedIslands.quickSort( IslandBodyCapacitySortPredicate() );
 | |
|     }
 | |
| 
 | |
|     m_batchIsland = NULL;
 | |
|     // mark all islands free (but avoid deallocation)
 | |
|     for ( int i = 0; i < m_allocatedIslands.size(); ++i )
 | |
|     {
 | |
|         Island* island = m_allocatedIslands[ i ];
 | |
|         island->bodyArray.resize( 0 );
 | |
|         island->manifoldArray.resize( 0 );
 | |
|         island->constraintArray.resize( 0 );
 | |
|         island->id = -1;
 | |
|         island->isSleeping = true;
 | |
|         m_freeIslands.push_back( island );
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| btSimulationIslandManagerMt::Island* btSimulationIslandManagerMt::getIsland( int id )
 | |
| {
 | |
|     Island* island = m_lookupIslandFromId[ id ];
 | |
|     if ( island == NULL )
 | |
|     {
 | |
|         // search for existing island
 | |
|         for ( int i = 0; i < m_activeIslands.size(); ++i )
 | |
|         {
 | |
|             if ( m_activeIslands[ i ]->id == id )
 | |
|             {
 | |
|                 island = m_activeIslands[ i ];
 | |
|                 break;
 | |
|             }
 | |
|         }
 | |
|         m_lookupIslandFromId[ id ] = island;
 | |
|     }
 | |
|     return island;
 | |
| }
 | |
| 
 | |
| 
 | |
| btSimulationIslandManagerMt::Island* btSimulationIslandManagerMt::allocateIsland( int id, int numBodies )
 | |
| {
 | |
|     Island* island = NULL;
 | |
|     int allocSize = numBodies;
 | |
|     if ( numBodies < m_batchIslandMinBodyCount )
 | |
|     {
 | |
|         if ( m_batchIsland )
 | |
|         {
 | |
|             island = m_batchIsland;
 | |
|             m_lookupIslandFromId[ id ] = island;
 | |
|             // if we've made a large enough batch,
 | |
|             if ( island->bodyArray.size() + numBodies >= m_batchIslandMinBodyCount )
 | |
|             {
 | |
|                 // next time start a new batch
 | |
|                 m_batchIsland = NULL;
 | |
|             }
 | |
|             return island;
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             // need to allocate a batch island
 | |
|             allocSize = m_batchIslandMinBodyCount * 2;
 | |
|         }
 | |
|     }
 | |
|     btAlignedObjectArray<Island*>& freeIslands = m_freeIslands;
 | |
| 
 | |
|     // search for free island
 | |
|     if ( freeIslands.size() > 0 )
 | |
|     {
 | |
|         // try to reuse a previously allocated island
 | |
|         int iFound = freeIslands.size();
 | |
|         // linear search for smallest island that can hold our bodies
 | |
|         for ( int i = freeIslands.size() - 1; i >= 0; --i )
 | |
|         {
 | |
|             if ( freeIslands[ i ]->bodyArray.capacity() >= allocSize )
 | |
|             {
 | |
|                 iFound = i;
 | |
|                 island = freeIslands[ i ];
 | |
|                 island->id = id;
 | |
|                 break;
 | |
|             }
 | |
|         }
 | |
|         // if found, shrink array while maintaining ordering
 | |
|         if ( island )
 | |
|         {
 | |
|             int iDest = iFound;
 | |
|             int iSrc = iDest + 1;
 | |
|             while ( iSrc < freeIslands.size() )
 | |
|             {
 | |
|                 freeIslands[ iDest++ ] = freeIslands[ iSrc++ ];
 | |
|             }
 | |
|             freeIslands.pop_back();
 | |
|         }
 | |
|     }
 | |
|     if ( island == NULL )
 | |
|     {
 | |
|         // no free island found, allocate
 | |
|         island = new Island();  // TODO: change this to use the pool allocator
 | |
|         island->id = id;
 | |
|         island->bodyArray.reserve( allocSize );
 | |
|         m_allocatedIslands.push_back( island );
 | |
|     }
 | |
|     m_lookupIslandFromId[ id ] = island;
 | |
|     if ( numBodies < m_batchIslandMinBodyCount )
 | |
|     {
 | |
|         m_batchIsland = island;
 | |
|     }
 | |
|     m_activeIslands.push_back( island );
 | |
|     return island;
 | |
| }
 | |
| 
 | |
| 
 | |
| void btSimulationIslandManagerMt::buildIslands( btDispatcher* dispatcher, btCollisionWorld* collisionWorld )
 | |
| {
 | |
| 
 | |
| 	BT_PROFILE("islandUnionFindAndQuickSort");
 | |
| 	
 | |
| 	btCollisionObjectArray& collisionObjects = collisionWorld->getCollisionObjectArray();
 | |
| 
 | |
| 	//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);
 | |
| 					}
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| 
 | |
| void btSimulationIslandManagerMt::addBodiesToIslands( btCollisionWorld* collisionWorld )
 | |
| {
 | |
|     btCollisionObjectArray& collisionObjects = collisionWorld->getCollisionObjectArray();
 | |
|     int endIslandIndex = 1;
 | |
|     int startIslandIndex;
 | |
|     int numElem = getUnionFind().getNumElements();
 | |
| 
 | |
|     // create explicit islands and add bodies to each
 | |
|     for ( startIslandIndex = 0; startIslandIndex < numElem; startIslandIndex = endIslandIndex )
 | |
|     {
 | |
|         int islandId = getUnionFind().getElement( startIslandIndex ).m_id;
 | |
| 
 | |
|         // find end index
 | |
|         for ( endIslandIndex = startIslandIndex; ( endIslandIndex < numElem ) && ( getUnionFind().getElement( endIslandIndex ).m_id == islandId ); endIslandIndex++ )
 | |
|         {
 | |
|         }
 | |
|         // check if island is sleeping
 | |
|         bool islandSleeping = true;
 | |
|         for ( int iElem = startIslandIndex; iElem < endIslandIndex; iElem++ )
 | |
|         {
 | |
|             int i = getUnionFind().getElement( iElem ).m_sz;
 | |
|             btCollisionObject* colObj = collisionObjects[ i ];
 | |
|             if ( colObj->isActive() )
 | |
|             {
 | |
|                 islandSleeping = false;
 | |
|             }
 | |
|         }
 | |
|         if ( !islandSleeping )
 | |
|         {
 | |
|             // want to count the number of bodies before allocating the island to optimize memory usage of the Island structures
 | |
|             int numBodies = endIslandIndex - startIslandIndex;
 | |
|             Island* island = allocateIsland( islandId, numBodies );
 | |
|             island->isSleeping = false;
 | |
| 
 | |
|             // add bodies to island
 | |
|             for ( int iElem = startIslandIndex; iElem < endIslandIndex; iElem++ )
 | |
|             {
 | |
|                 int i = getUnionFind().getElement( iElem ).m_sz;
 | |
|                 btCollisionObject* colObj = collisionObjects[ i ];
 | |
|                 island->bodyArray.push_back( colObj );
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
| }
 | |
| 
 | |
| 
 | |
| void btSimulationIslandManagerMt::addManifoldsToIslands( btDispatcher* dispatcher )
 | |
| {
 | |
|     // walk all the manifolds, activating bodies touched by kinematic objects, and add each manifold to its Island
 | |
|     int maxNumManifolds = dispatcher->getNumManifolds();
 | |
|     for ( int 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();
 | |
|             }
 | |
|             //filtering for response
 | |
|             if ( dispatcher->needsResponse( colObj0, colObj1 ) )
 | |
|             {
 | |
|                 // scatter manifolds into various islands
 | |
|                 int islandId = getIslandId( manifold );
 | |
|                 // if island not sleeping,
 | |
|                 if ( Island* island = getIsland( islandId ) )
 | |
|                 {
 | |
|                     island->manifoldArray.push_back( manifold );
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| void btSimulationIslandManagerMt::addConstraintsToIslands( btAlignedObjectArray<btTypedConstraint*>& constraints )
 | |
| {
 | |
|     // walk constraints
 | |
|     for ( int i = 0; i < constraints.size(); i++ )
 | |
|     {
 | |
|         // scatter constraints into various islands
 | |
|         btTypedConstraint* constraint = constraints[ i ];
 | |
|         if ( constraint->isEnabled() )
 | |
|         {
 | |
|             int islandId = btGetConstraintIslandId( constraint );
 | |
|             // if island is not sleeping,
 | |
|             if ( Island* island = getIsland( islandId ) )
 | |
|             {
 | |
|                 island->constraintArray.push_back( constraint );
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| void btSimulationIslandManagerMt::mergeIslands()
 | |
| {
 | |
|     // sort islands in order of decreasing batch size
 | |
|     m_activeIslands.quickSort( IslandBatchSizeSortPredicate() );
 | |
| 
 | |
|     // merge small islands to satisfy minimum batch size
 | |
|     // find first small batch island
 | |
|     int destIslandIndex = m_activeIslands.size();
 | |
|     for ( int i = 0; i < m_activeIslands.size(); ++i )
 | |
|     {
 | |
|         Island* island = m_activeIslands[ i ];
 | |
|         int batchSize = calcBatchCost( island );
 | |
|         if ( batchSize < m_minimumSolverBatchSize )
 | |
|         {
 | |
|             destIslandIndex = i;
 | |
|             break;
 | |
|         }
 | |
|     }
 | |
|     int lastIndex = m_activeIslands.size() - 1;
 | |
|     while ( destIslandIndex < lastIndex )
 | |
|     {
 | |
|         // merge islands from the back of the list
 | |
|         Island* island = m_activeIslands[ destIslandIndex ];
 | |
|         int numBodies = island->bodyArray.size();
 | |
|         int numManifolds = island->manifoldArray.size();
 | |
|         int numConstraints = island->constraintArray.size();
 | |
|         int firstIndex = lastIndex;
 | |
|         // figure out how many islands we want to merge and find out how many bodies, manifolds and constraints we will have
 | |
|         while ( true )
 | |
|         {
 | |
|             Island* src = m_activeIslands[ firstIndex ];
 | |
|             numBodies += src->bodyArray.size();
 | |
|             numManifolds += src->manifoldArray.size();
 | |
|             numConstraints += src->constraintArray.size();
 | |
|             int batchCost = calcBatchCost( numBodies, numManifolds, numConstraints );
 | |
|             if ( batchCost >= m_minimumSolverBatchSize )
 | |
|             {
 | |
|                 break;
 | |
|             }
 | |
|             if ( firstIndex - 1 == destIslandIndex )
 | |
|             {
 | |
|                 break;
 | |
|             }
 | |
|             firstIndex--;
 | |
|         }
 | |
|         // reserve space for these pointers to minimize reallocation
 | |
|         island->bodyArray.reserve( numBodies );
 | |
|         island->manifoldArray.reserve( numManifolds );
 | |
|         island->constraintArray.reserve( numConstraints );
 | |
|         // merge islands
 | |
|         for ( int i = firstIndex; i <= lastIndex; ++i )
 | |
|         {
 | |
|             island->append( *m_activeIslands[ i ] );
 | |
|         }
 | |
|         // shrink array to exclude the islands that were merged from
 | |
|         m_activeIslands.resize( firstIndex );
 | |
|         lastIndex = firstIndex - 1;
 | |
|         destIslandIndex++;
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| void btSimulationIslandManagerMt::serialIslandDispatch( btAlignedObjectArray<Island*>* islandsPtr, IslandCallback* callback )
 | |
| {
 | |
|     BT_PROFILE( "serialIslandDispatch" );
 | |
|     // serial dispatch
 | |
|     btAlignedObjectArray<Island*>& islands = *islandsPtr;
 | |
|     for ( int i = 0; i < islands.size(); ++i )
 | |
|     {
 | |
|         Island* island = islands[ i ];
 | |
|         btPersistentManifold** manifolds = island->manifoldArray.size() ? &island->manifoldArray[ 0 ] : NULL;
 | |
|         btTypedConstraint** constraintsPtr = island->constraintArray.size() ? &island->constraintArray[ 0 ] : NULL;
 | |
|         callback->processIsland( &island->bodyArray[ 0 ],
 | |
|                                  island->bodyArray.size(),
 | |
|                                  manifolds,
 | |
|                                  island->manifoldArray.size(),
 | |
|                                  constraintsPtr,
 | |
|                                  island->constraintArray.size(),
 | |
|                                  island->id
 | |
|                                  );
 | |
|     }
 | |
| }
 | |
| 
 | |
| struct UpdateIslandDispatcher : public btIParallelForBody
 | |
| {
 | |
|     btAlignedObjectArray<btSimulationIslandManagerMt::Island*>* islandsPtr;
 | |
|     btSimulationIslandManagerMt::IslandCallback* callback;
 | |
| 
 | |
|     void forLoop( int iBegin, int iEnd ) const BT_OVERRIDE
 | |
|     {
 | |
|         for ( int i = iBegin; i < iEnd; ++i )
 | |
|         {
 | |
|             btSimulationIslandManagerMt::Island* island = ( *islandsPtr )[ i ];
 | |
|             btPersistentManifold** manifolds = island->manifoldArray.size() ? &island->manifoldArray[ 0 ] : NULL;
 | |
|             btTypedConstraint** constraintsPtr = island->constraintArray.size() ? &island->constraintArray[ 0 ] : NULL;
 | |
|             callback->processIsland( &island->bodyArray[ 0 ],
 | |
|                 island->bodyArray.size(),
 | |
|                 manifolds,
 | |
|                 island->manifoldArray.size(),
 | |
|                 constraintsPtr,
 | |
|                 island->constraintArray.size(),
 | |
|                 island->id
 | |
|             );
 | |
|         }
 | |
|     }
 | |
| };
 | |
| 
 | |
| void btSimulationIslandManagerMt::parallelIslandDispatch( btAlignedObjectArray<Island*>* islandsPtr, IslandCallback* callback )
 | |
| {
 | |
|     BT_PROFILE( "parallelIslandDispatch" );
 | |
|     int grainSize = 1;  // iterations per task
 | |
|     UpdateIslandDispatcher dispatcher;
 | |
|     dispatcher.islandsPtr = islandsPtr;
 | |
|     dispatcher.callback = callback;
 | |
|     btParallelFor( 0, islandsPtr->size(), grainSize, dispatcher );
 | |
| }
 | |
| 
 | |
| 
 | |
| ///@todo: this is random access, it can be walked 'cache friendly'!
 | |
| void btSimulationIslandManagerMt::buildAndProcessIslands( btDispatcher* dispatcher,
 | |
|                                                         btCollisionWorld* collisionWorld,
 | |
|                                                         btAlignedObjectArray<btTypedConstraint*>& constraints,
 | |
|                                                         IslandCallback* callback
 | |
|                                                         )
 | |
| {
 | |
| 	btCollisionObjectArray& collisionObjects = collisionWorld->getCollisionObjectArray();
 | |
| 
 | |
| 	buildIslands(dispatcher,collisionWorld);
 | |
| 
 | |
| 	BT_PROFILE("processIslands");
 | |
| 
 | |
| 	if(!getSplitIslands())
 | |
| 	{
 | |
|         btPersistentManifold** manifolds = dispatcher->getInternalManifoldPointer();
 | |
|         int maxNumManifolds = dispatcher->getNumManifolds();
 | |
| 
 | |
|         for ( int i = 0; i < maxNumManifolds; i++ )
 | |
|         {
 | |
|             btPersistentManifold* manifold = manifolds[ 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();
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|         btTypedConstraint** constraintsPtr = constraints.size() ? &constraints[ 0 ] : NULL;
 | |
| 		callback->processIsland(&collisionObjects[0],
 | |
|                                  collisionObjects.size(),
 | |
|                                  manifolds,
 | |
|                                  maxNumManifolds,
 | |
|                                  constraintsPtr,
 | |
|                                  constraints.size(),
 | |
|                                  -1
 | |
|                                  );
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
|         initIslandPools();
 | |
| 
 | |
|         //traverse the simulation islands, and call the solver, unless all objects are sleeping/deactivated
 | |
|         addBodiesToIslands( collisionWorld );
 | |
|         addManifoldsToIslands( dispatcher );
 | |
|         addConstraintsToIslands( constraints );
 | |
| 
 | |
|         // m_activeIslands array should now contain all non-sleeping Islands, and each Island should
 | |
|         // have all the necessary bodies, manifolds and constraints.
 | |
| 
 | |
|         // if we want to merge islands with small batch counts,
 | |
|         if ( m_minimumSolverBatchSize > 1 )
 | |
|         {
 | |
|             mergeIslands();
 | |
|         }
 | |
|         // dispatch islands to solver
 | |
|         m_islandDispatch( &m_activeIslands, callback );
 | |
| 	}
 | |
| }
 |