forked from LeenkxTeam/LNXSDK
		
	
		
			
				
	
	
		
			325 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			325 lines
		
	
	
		
			10 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 "btCollisionDispatcher.h"
 | |
| #include "LinearMath/btQuickprof.h"
 | |
| 
 | |
| #include "BulletCollision/BroadphaseCollision/btCollisionAlgorithm.h"
 | |
| 
 | |
| #include "BulletCollision/CollisionShapes/btCollisionShape.h"
 | |
| #include "BulletCollision/CollisionDispatch/btCollisionObject.h"
 | |
| #include "BulletCollision/BroadphaseCollision/btOverlappingPairCache.h"
 | |
| #include "LinearMath/btPoolAllocator.h"
 | |
| #include "BulletCollision/CollisionDispatch/btCollisionConfiguration.h"
 | |
| #include "BulletCollision/CollisionDispatch/btCollisionObjectWrapper.h"
 | |
| 
 | |
| int gNumManifold = 0;
 | |
| 
 | |
| #ifdef BT_DEBUG
 | |
| #include <stdio.h>
 | |
| #endif
 | |
| 
 | |
| 
 | |
| btCollisionDispatcher::btCollisionDispatcher (btCollisionConfiguration* collisionConfiguration): 
 | |
| m_dispatcherFlags(btCollisionDispatcher::CD_USE_RELATIVE_CONTACT_BREAKING_THRESHOLD),
 | |
| 	m_collisionConfiguration(collisionConfiguration)
 | |
| {
 | |
| 	int i;
 | |
| 
 | |
| 	setNearCallback(defaultNearCallback);
 | |
| 	
 | |
| 	m_collisionAlgorithmPoolAllocator = collisionConfiguration->getCollisionAlgorithmPool();
 | |
| 
 | |
| 	m_persistentManifoldPoolAllocator = collisionConfiguration->getPersistentManifoldPool();
 | |
| 
 | |
| 	for (i=0;i<MAX_BROADPHASE_COLLISION_TYPES;i++)
 | |
| 	{
 | |
| 		for (int j=0;j<MAX_BROADPHASE_COLLISION_TYPES;j++)
 | |
| 		{
 | |
| 			m_doubleDispatchContactPoints[i][j] = m_collisionConfiguration->getCollisionAlgorithmCreateFunc(i,j);
 | |
| 			btAssert(m_doubleDispatchContactPoints[i][j]);
 | |
| 			m_doubleDispatchClosestPoints[i][j] = m_collisionConfiguration->getClosestPointsAlgorithmCreateFunc(i, j);
 | |
| 
 | |
| 		}
 | |
| 	}
 | |
| 	
 | |
| 	
 | |
| }
 | |
| 
 | |
| 
 | |
| void btCollisionDispatcher::registerCollisionCreateFunc(int proxyType0, int proxyType1, btCollisionAlgorithmCreateFunc *createFunc)
 | |
| {
 | |
| 	m_doubleDispatchContactPoints[proxyType0][proxyType1] = createFunc;
 | |
| }
 | |
| 
 | |
| void btCollisionDispatcher::registerClosestPointsCreateFunc(int proxyType0, int proxyType1, btCollisionAlgorithmCreateFunc *createFunc)
 | |
| {
 | |
| 	m_doubleDispatchClosestPoints[proxyType0][proxyType1] = createFunc;
 | |
| }
 | |
| 
 | |
| btCollisionDispatcher::~btCollisionDispatcher()
 | |
| {
 | |
| }
 | |
| 
 | |
| btPersistentManifold*	btCollisionDispatcher::getNewManifold(const btCollisionObject* body0,const btCollisionObject* body1) 
 | |
| { 
 | |
| 	gNumManifold++;
 | |
| 	
 | |
| 	//btAssert(gNumManifold < 65535);
 | |
| 	
 | |
| 
 | |
| 
 | |
| 	//optional relative contact breaking threshold, turned on by default (use setDispatcherFlags to switch off feature for improved performance)
 | |
| 	
 | |
| 	btScalar contactBreakingThreshold =  (m_dispatcherFlags & btCollisionDispatcher::CD_USE_RELATIVE_CONTACT_BREAKING_THRESHOLD) ? 
 | |
| 		btMin(body0->getCollisionShape()->getContactBreakingThreshold(gContactBreakingThreshold) , body1->getCollisionShape()->getContactBreakingThreshold(gContactBreakingThreshold))
 | |
| 		: gContactBreakingThreshold ;
 | |
| 
 | |
| 	btScalar contactProcessingThreshold = btMin(body0->getContactProcessingThreshold(),body1->getContactProcessingThreshold());
 | |
| 		
 | |
|  	void* mem = m_persistentManifoldPoolAllocator->allocate( sizeof( btPersistentManifold ) );
 | |
|     if (NULL == mem)
 | |
| 	{
 | |
|         //we got a pool memory overflow, by default we fallback to dynamically allocate memory. If we require a contiguous contact pool then assert.
 | |
| 		if ((m_dispatcherFlags&CD_DISABLE_CONTACTPOOL_DYNAMIC_ALLOCATION)==0)
 | |
| 		{
 | |
| 			mem = btAlignedAlloc(sizeof(btPersistentManifold),16);
 | |
| 		} else
 | |
| 		{
 | |
| 			btAssert(0);
 | |
| 			//make sure to increase the m_defaultMaxPersistentManifoldPoolSize in the btDefaultCollisionConstructionInfo/btDefaultCollisionConfiguration
 | |
| 			return 0;
 | |
| 		}
 | |
| 	}
 | |
| 	btPersistentManifold* manifold = new(mem) btPersistentManifold (body0,body1,0,contactBreakingThreshold,contactProcessingThreshold);
 | |
| 	manifold->m_index1a = m_manifoldsPtr.size();
 | |
| 	m_manifoldsPtr.push_back(manifold);
 | |
| 
 | |
| 	return manifold;
 | |
| }
 | |
| 
 | |
| void btCollisionDispatcher::clearManifold(btPersistentManifold* manifold)
 | |
| {
 | |
| 	manifold->clearManifold();
 | |
| }
 | |
| 
 | |
| 	
 | |
| void btCollisionDispatcher::releaseManifold(btPersistentManifold* manifold)
 | |
| {
 | |
| 	
 | |
| 	gNumManifold--;
 | |
| 
 | |
| 	//printf("releaseManifold: gNumManifold %d\n",gNumManifold);
 | |
| 	clearManifold(manifold);
 | |
| 
 | |
| 	int findIndex = manifold->m_index1a;
 | |
| 	btAssert(findIndex < m_manifoldsPtr.size());
 | |
| 	m_manifoldsPtr.swap(findIndex,m_manifoldsPtr.size()-1);
 | |
| 	m_manifoldsPtr[findIndex]->m_index1a = findIndex;
 | |
| 	m_manifoldsPtr.pop_back();
 | |
| 
 | |
| 	manifold->~btPersistentManifold();
 | |
| 	if (m_persistentManifoldPoolAllocator->validPtr(manifold))
 | |
| 	{
 | |
| 		m_persistentManifoldPoolAllocator->freeMemory(manifold);
 | |
| 	} else
 | |
| 	{
 | |
| 		btAlignedFree(manifold);
 | |
| 	}
 | |
| 	
 | |
| }
 | |
| 
 | |
| 	
 | |
| 
 | |
| 
 | |
| btCollisionAlgorithm* btCollisionDispatcher::findAlgorithm(const btCollisionObjectWrapper* body0Wrap,const btCollisionObjectWrapper* body1Wrap,btPersistentManifold* sharedManifold, ebtDispatcherQueryType algoType)
 | |
| {
 | |
| 	
 | |
| 	btCollisionAlgorithmConstructionInfo ci;
 | |
| 
 | |
| 	ci.m_dispatcher1 = this;
 | |
| 	ci.m_manifold = sharedManifold;
 | |
| 	btCollisionAlgorithm* algo = 0;
 | |
| 	if (algoType == BT_CONTACT_POINT_ALGORITHMS)
 | |
| 	{
 | |
| 		algo = m_doubleDispatchContactPoints[body0Wrap->getCollisionShape()->getShapeType()][body1Wrap->getCollisionShape()->getShapeType()]->CreateCollisionAlgorithm(ci, body0Wrap, body1Wrap);
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 		algo = m_doubleDispatchClosestPoints[body0Wrap->getCollisionShape()->getShapeType()][body1Wrap->getCollisionShape()->getShapeType()]->CreateCollisionAlgorithm(ci, body0Wrap, body1Wrap);
 | |
| 	}
 | |
| 
 | |
| 	return algo;
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| bool	btCollisionDispatcher::needsResponse(const btCollisionObject* body0,const btCollisionObject* body1)
 | |
| {
 | |
| 	//here you can do filtering
 | |
| 	bool hasResponse = 
 | |
| 		(body0->hasContactResponse() && body1->hasContactResponse());
 | |
| 	//no response between two static/kinematic bodies:
 | |
| 	hasResponse = hasResponse &&
 | |
| 		((!body0->isStaticOrKinematicObject()) ||(! body1->isStaticOrKinematicObject()));
 | |
| 	return hasResponse;
 | |
| }
 | |
| 
 | |
| bool	btCollisionDispatcher::needsCollision(const btCollisionObject* body0,const btCollisionObject* body1)
 | |
| {
 | |
| 	btAssert(body0);
 | |
| 	btAssert(body1);
 | |
| 
 | |
| 	bool needsCollision = true;
 | |
| 
 | |
| #ifdef BT_DEBUG
 | |
| 	if (!(m_dispatcherFlags & btCollisionDispatcher::CD_STATIC_STATIC_REPORTED))
 | |
| 	{
 | |
| 		//broadphase filtering already deals with this
 | |
| 		if (body0->isStaticOrKinematicObject() && body1->isStaticOrKinematicObject())
 | |
| 		{
 | |
| 			m_dispatcherFlags |= btCollisionDispatcher::CD_STATIC_STATIC_REPORTED;
 | |
| 			printf("warning btCollisionDispatcher::needsCollision: static-static collision!\n");
 | |
| 		}
 | |
| 	}
 | |
| #endif //BT_DEBUG
 | |
| 
 | |
| 	if ((!body0->isActive()) && (!body1->isActive()))
 | |
| 		needsCollision = false;
 | |
| 	else if ((!body0->checkCollideWith(body1)) || (!body1->checkCollideWith(body0)))
 | |
| 		needsCollision = false;
 | |
| 	
 | |
| 	return needsCollision ;
 | |
| 
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| ///interface for iterating all overlapping collision pairs, no matter how those pairs are stored (array, set, map etc)
 | |
| ///this is useful for the collision dispatcher.
 | |
| class btCollisionPairCallback : public btOverlapCallback
 | |
| {
 | |
| 	const btDispatcherInfo& m_dispatchInfo;
 | |
| 	btCollisionDispatcher*	m_dispatcher;
 | |
| 
 | |
| public:
 | |
| 
 | |
| 	btCollisionPairCallback(const btDispatcherInfo& dispatchInfo,btCollisionDispatcher*	dispatcher)
 | |
| 	:m_dispatchInfo(dispatchInfo),
 | |
| 	m_dispatcher(dispatcher)
 | |
| 	{
 | |
| 	}
 | |
| 
 | |
| 	/*btCollisionPairCallback& operator=(btCollisionPairCallback& other)
 | |
| 	{
 | |
| 		m_dispatchInfo = other.m_dispatchInfo;
 | |
| 		m_dispatcher = other.m_dispatcher;
 | |
| 		return *this;
 | |
| 	}
 | |
| 	*/
 | |
| 
 | |
| 
 | |
| 	virtual ~btCollisionPairCallback() {}
 | |
| 
 | |
| 
 | |
| 	virtual bool	processOverlap(btBroadphasePair& pair)
 | |
| 	{
 | |
| 		(*m_dispatcher->getNearCallback())(pair,*m_dispatcher,m_dispatchInfo);
 | |
| 		return false;
 | |
| 	}
 | |
| };
 | |
| 
 | |
| 
 | |
| 
 | |
| void	btCollisionDispatcher::dispatchAllCollisionPairs(btOverlappingPairCache* pairCache,const btDispatcherInfo& dispatchInfo,btDispatcher* dispatcher) 
 | |
| {
 | |
| 	//m_blockedForChanges = true;
 | |
| 
 | |
| 	btCollisionPairCallback	collisionCallback(dispatchInfo,this);
 | |
| 
 | |
| 	pairCache->processAllOverlappingPairs(&collisionCallback,dispatcher);
 | |
| 
 | |
| 	//m_blockedForChanges = false;
 | |
| 
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| //by default, Bullet will use this near callback
 | |
| void btCollisionDispatcher::defaultNearCallback(btBroadphasePair& collisionPair, btCollisionDispatcher& dispatcher, const btDispatcherInfo& dispatchInfo)
 | |
| {
 | |
| 		btCollisionObject* colObj0 = (btCollisionObject*)collisionPair.m_pProxy0->m_clientObject;
 | |
| 		btCollisionObject* colObj1 = (btCollisionObject*)collisionPair.m_pProxy1->m_clientObject;
 | |
| 
 | |
| 		if (dispatcher.needsCollision(colObj0,colObj1))
 | |
| 		{
 | |
| 			btCollisionObjectWrapper obj0Wrap(0,colObj0->getCollisionShape(),colObj0,colObj0->getWorldTransform(),-1,-1);
 | |
| 			btCollisionObjectWrapper obj1Wrap(0,colObj1->getCollisionShape(),colObj1,colObj1->getWorldTransform(),-1,-1);
 | |
| 
 | |
| 
 | |
| 			//dispatcher will keep algorithms persistent in the collision pair
 | |
| 			if (!collisionPair.m_algorithm)
 | |
| 			{
 | |
| 				collisionPair.m_algorithm = dispatcher.findAlgorithm(&obj0Wrap,&obj1Wrap,0, BT_CONTACT_POINT_ALGORITHMS);
 | |
| 			}
 | |
| 
 | |
| 			if (collisionPair.m_algorithm)
 | |
| 			{
 | |
| 				btManifoldResult contactPointResult(&obj0Wrap,&obj1Wrap);
 | |
| 				
 | |
| 				if (dispatchInfo.m_dispatchFunc == 		btDispatcherInfo::DISPATCH_DISCRETE)
 | |
| 				{
 | |
| 					//discrete collision detection query
 | |
| 					
 | |
| 					collisionPair.m_algorithm->processCollision(&obj0Wrap,&obj1Wrap,dispatchInfo,&contactPointResult);
 | |
| 				} else
 | |
| 				{
 | |
| 					//continuous collision detection query, time of impact (toi)
 | |
| 					btScalar toi = collisionPair.m_algorithm->calculateTimeOfImpact(colObj0,colObj1,dispatchInfo,&contactPointResult);
 | |
| 					if (dispatchInfo.m_timeOfImpact > toi)
 | |
| 						dispatchInfo.m_timeOfImpact = toi;
 | |
| 
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| }
 | |
| 
 | |
| 
 | |
| void* btCollisionDispatcher::allocateCollisionAlgorithm(int size)
 | |
| {
 | |
|     void* mem = m_collisionAlgorithmPoolAllocator->allocate( size );
 | |
|     if (NULL == mem)
 | |
|     {
 | |
| 	    //warn user for overflow?
 | |
| 	    return btAlignedAlloc(static_cast<size_t>(size), 16);
 | |
|     }
 | |
|     return mem;
 | |
| }
 | |
| 
 | |
| void btCollisionDispatcher::freeCollisionAlgorithm(void* ptr)
 | |
| {
 | |
| 	if (m_collisionAlgorithmPoolAllocator->validPtr(ptr))
 | |
| 	{
 | |
| 		m_collisionAlgorithmPoolAllocator->freeMemory(ptr);
 | |
| 	} else
 | |
| 	{
 | |
| 		btAlignedFree(ptr);
 | |
| 	}
 | |
| }
 |