1650 lines
		
	
	
		
			60 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
		
		
			
		
	
	
			1650 lines
		
	
	
		
			60 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 "btCollisionWorld.h"
 | ||
|  | #include "btCollisionDispatcher.h"
 | ||
|  | #include "BulletCollision/CollisionDispatch/btCollisionObject.h"
 | ||
|  | #include "BulletCollision/CollisionShapes/btCollisionShape.h"
 | ||
|  | #include "BulletCollision/CollisionShapes/btConvexShape.h"
 | ||
|  | #include "BulletCollision/NarrowPhaseCollision/btGjkEpaPenetrationDepthSolver.h"
 | ||
|  | #include "BulletCollision/CollisionShapes/btSphereShape.h" //for raycasting
 | ||
|  | #include "BulletCollision/CollisionShapes/btBvhTriangleMeshShape.h" //for raycasting
 | ||
|  | #include "BulletCollision/NarrowPhaseCollision/btRaycastCallback.h"
 | ||
|  | #include "BulletCollision/CollisionShapes/btCompoundShape.h"
 | ||
|  | #include "BulletCollision/NarrowPhaseCollision/btSubSimplexConvexCast.h"
 | ||
|  | #include "BulletCollision/NarrowPhaseCollision/btGjkConvexCast.h"
 | ||
|  | #include "BulletCollision/NarrowPhaseCollision/btContinuousConvexCollision.h"
 | ||
|  | #include "BulletCollision/BroadphaseCollision/btCollisionAlgorithm.h"
 | ||
|  | #include "BulletCollision/BroadphaseCollision/btBroadphaseInterface.h"
 | ||
|  | #include "BulletCollision/BroadphaseCollision/btDbvt.h"
 | ||
|  | #include "LinearMath/btAabbUtil2.h"
 | ||
|  | #include "LinearMath/btQuickprof.h"
 | ||
|  | #include "LinearMath/btSerializer.h"
 | ||
|  | #include "BulletCollision/CollisionShapes/btConvexPolyhedron.h"
 | ||
|  | #include "BulletCollision/CollisionDispatch/btCollisionObjectWrapper.h"
 | ||
|  | 
 | ||
|  | //#define DISABLE_DBVT_COMPOUNDSHAPE_RAYCAST_ACCELERATION
 | ||
|  | 
 | ||
|  | 
 | ||
|  | //#define USE_BRUTEFORCE_RAYBROADPHASE 1
 | ||
|  | //RECALCULATE_AABB is slower, but benefit is that you don't need to call 'stepSimulation'  or 'updateAabbs' before using a rayTest
 | ||
|  | //#define RECALCULATE_AABB_RAYCAST 1
 | ||
|  | 
 | ||
|  | //When the user doesn't provide dispatcher or broadphase, create basic versions (and delete them in destructor)
 | ||
|  | #include "BulletCollision/CollisionDispatch/btCollisionDispatcher.h"
 | ||
|  | #include "BulletCollision/BroadphaseCollision/btSimpleBroadphase.h"
 | ||
|  | #include "BulletCollision/CollisionDispatch/btCollisionConfiguration.h"
 | ||
|  | 
 | ||
|  | 
 | ||
|  | ///for debug drawing
 | ||
|  | 
 | ||
|  | //for debug rendering
 | ||
|  | #include "BulletCollision/CollisionShapes/btBoxShape.h"
 | ||
|  | #include "BulletCollision/CollisionShapes/btCapsuleShape.h"
 | ||
|  | #include "BulletCollision/CollisionShapes/btCompoundShape.h"
 | ||
|  | #include "BulletCollision/CollisionShapes/btConeShape.h"
 | ||
|  | #include "BulletCollision/CollisionShapes/btConvexTriangleMeshShape.h"
 | ||
|  | #include "BulletCollision/CollisionShapes/btCylinderShape.h"
 | ||
|  | #include "BulletCollision/CollisionShapes/btMultiSphereShape.h"
 | ||
|  | #include "BulletCollision/CollisionShapes/btPolyhedralConvexShape.h"
 | ||
|  | #include "BulletCollision/CollisionShapes/btSphereShape.h"
 | ||
|  | #include "BulletCollision/CollisionShapes/btTriangleCallback.h"
 | ||
|  | #include "BulletCollision/CollisionShapes/btTriangleMeshShape.h"
 | ||
|  | #include "BulletCollision/CollisionShapes/btStaticPlaneShape.h"
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | btCollisionWorld::btCollisionWorld(btDispatcher* dispatcher,btBroadphaseInterface* pairCache, btCollisionConfiguration* collisionConfiguration) | ||
|  | :m_dispatcher1(dispatcher), | ||
|  | m_broadphasePairCache(pairCache), | ||
|  | m_debugDrawer(0), | ||
|  | m_forceUpdateAllAabbs(true) | ||
|  | { | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | btCollisionWorld::~btCollisionWorld() | ||
|  | { | ||
|  | 
 | ||
|  | 	//clean up remaining objects
 | ||
|  | 	int i; | ||
|  | 	for (i=0;i<m_collisionObjects.size();i++) | ||
|  | 	{ | ||
|  | 		btCollisionObject* collisionObject= m_collisionObjects[i]; | ||
|  | 
 | ||
|  | 		btBroadphaseProxy* bp = collisionObject->getBroadphaseHandle(); | ||
|  | 		if (bp) | ||
|  | 		{ | ||
|  | 			//
 | ||
|  | 			// only clear the cached algorithms
 | ||
|  | 			//
 | ||
|  | 			getBroadphase()->getOverlappingPairCache()->cleanProxyFromPairs(bp,m_dispatcher1); | ||
|  | 			getBroadphase()->destroyProxy(bp,m_dispatcher1); | ||
|  | 			collisionObject->setBroadphaseHandle(0); | ||
|  | 		} | ||
|  | 	} | ||
|  | 
 | ||
|  | 
 | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | void	btCollisionWorld::addCollisionObject(btCollisionObject* collisionObject, int collisionFilterGroup, int collisionFilterMask) | ||
|  | { | ||
|  | 
 | ||
|  | 	btAssert(collisionObject); | ||
|  | 
 | ||
|  | 	//check that the object isn't already added
 | ||
|  | 	btAssert( m_collisionObjects.findLinearSearch(collisionObject)  == m_collisionObjects.size()); | ||
|  |     btAssert(collisionObject->getWorldArrayIndex() == -1);  // do not add the same object to more than one collision world
 | ||
|  | 
 | ||
|  |     collisionObject->setWorldArrayIndex(m_collisionObjects.size()); | ||
|  | 	m_collisionObjects.push_back(collisionObject); | ||
|  | 
 | ||
|  | 	//calculate new AABB
 | ||
|  | 	btTransform trans = collisionObject->getWorldTransform(); | ||
|  | 
 | ||
|  | 	btVector3	minAabb; | ||
|  | 	btVector3	maxAabb; | ||
|  | 	collisionObject->getCollisionShape()->getAabb(trans,minAabb,maxAabb); | ||
|  | 
 | ||
|  | 	int type = collisionObject->getCollisionShape()->getShapeType(); | ||
|  | 	collisionObject->setBroadphaseHandle( getBroadphase()->createProxy( | ||
|  | 		minAabb, | ||
|  | 		maxAabb, | ||
|  | 		type, | ||
|  | 		collisionObject, | ||
|  | 		collisionFilterGroup, | ||
|  | 		collisionFilterMask, | ||
|  | 		m_dispatcher1))	; | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | void	btCollisionWorld::updateSingleAabb(btCollisionObject* colObj) | ||
|  | { | ||
|  | 	btVector3 minAabb,maxAabb; | ||
|  | 	colObj->getCollisionShape()->getAabb(colObj->getWorldTransform(), minAabb,maxAabb); | ||
|  | 	//need to increase the aabb for contact thresholds
 | ||
|  | 	btVector3 contactThreshold(gContactBreakingThreshold,gContactBreakingThreshold,gContactBreakingThreshold); | ||
|  | 	minAabb -= contactThreshold; | ||
|  | 	maxAabb += contactThreshold; | ||
|  | 
 | ||
|  | 	if(getDispatchInfo().m_useContinuous && colObj->getInternalType()==btCollisionObject::CO_RIGID_BODY && !colObj->isStaticOrKinematicObject()) | ||
|  | 	{ | ||
|  | 		btVector3 minAabb2,maxAabb2; | ||
|  | 		colObj->getCollisionShape()->getAabb(colObj->getInterpolationWorldTransform(),minAabb2,maxAabb2); | ||
|  | 		minAabb2 -= contactThreshold; | ||
|  | 		maxAabb2 += contactThreshold; | ||
|  | 		minAabb.setMin(minAabb2); | ||
|  | 		maxAabb.setMax(maxAabb2); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	btBroadphaseInterface* bp = (btBroadphaseInterface*)m_broadphasePairCache; | ||
|  | 
 | ||
|  | 	//moving objects should be moderately sized, probably something wrong if not
 | ||
|  | 	if ( colObj->isStaticObject() || ((maxAabb-minAabb).length2() < btScalar(1e12))) | ||
|  | 	{ | ||
|  | 		bp->setAabb(colObj->getBroadphaseHandle(),minAabb,maxAabb, m_dispatcher1); | ||
|  | 	} else | ||
|  | 	{ | ||
|  | 		//something went wrong, investigate
 | ||
|  | 		//this assert is unwanted in 3D modelers (danger of loosing work)
 | ||
|  | 		colObj->setActivationState(DISABLE_SIMULATION); | ||
|  | 
 | ||
|  | 		static bool reportMe = true; | ||
|  | 		if (reportMe && m_debugDrawer) | ||
|  | 		{ | ||
|  | 			reportMe = false; | ||
|  | 			m_debugDrawer->reportErrorWarning("Overflow in AABB, object removed from simulation"); | ||
|  | 			m_debugDrawer->reportErrorWarning("If you can reproduce this, please email bugs@continuousphysics.com\n"); | ||
|  | 			m_debugDrawer->reportErrorWarning("Please include above information, your Platform, version of OS.\n"); | ||
|  | 			m_debugDrawer->reportErrorWarning("Thanks.\n"); | ||
|  | 		} | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | void	btCollisionWorld::updateAabbs() | ||
|  | { | ||
|  | 	BT_PROFILE("updateAabbs"); | ||
|  | 
 | ||
|  | 	btTransform predictedTrans; | ||
|  | 	for ( int i=0;i<m_collisionObjects.size();i++) | ||
|  | 	{ | ||
|  | 		btCollisionObject* colObj = m_collisionObjects[i]; | ||
|  |         btAssert(colObj->getWorldArrayIndex() == i); | ||
|  | 
 | ||
|  | 		//only update aabb of active objects
 | ||
|  | 		if (m_forceUpdateAllAabbs || colObj->isActive()) | ||
|  | 		{ | ||
|  | 			updateSingleAabb(colObj); | ||
|  | 		} | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | void	btCollisionWorld::computeOverlappingPairs() | ||
|  | { | ||
|  | 	BT_PROFILE("calculateOverlappingPairs"); | ||
|  | 	m_broadphasePairCache->calculateOverlappingPairs(m_dispatcher1); | ||
|  | } | ||
|  | 
 | ||
|  | void	btCollisionWorld::performDiscreteCollisionDetection() | ||
|  | { | ||
|  | 	BT_PROFILE("performDiscreteCollisionDetection"); | ||
|  | 
 | ||
|  | 	btDispatcherInfo& dispatchInfo = getDispatchInfo(); | ||
|  | 
 | ||
|  | 	updateAabbs(); | ||
|  | 
 | ||
|  | 	computeOverlappingPairs(); | ||
|  | 
 | ||
|  | 	btDispatcher* dispatcher = getDispatcher(); | ||
|  | 	{ | ||
|  | 		BT_PROFILE("dispatchAllCollisionPairs"); | ||
|  | 		if (dispatcher) | ||
|  | 			dispatcher->dispatchAllCollisionPairs(m_broadphasePairCache->getOverlappingPairCache(),dispatchInfo,m_dispatcher1); | ||
|  | 	} | ||
|  | 
 | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | void	btCollisionWorld::removeCollisionObject(btCollisionObject* collisionObject) | ||
|  | { | ||
|  | 
 | ||
|  | 
 | ||
|  | 	//bool removeFromBroadphase = false;
 | ||
|  | 
 | ||
|  | 	{ | ||
|  | 
 | ||
|  | 		btBroadphaseProxy* bp = collisionObject->getBroadphaseHandle(); | ||
|  | 		if (bp) | ||
|  | 		{ | ||
|  | 			//
 | ||
|  | 			// only clear the cached algorithms
 | ||
|  | 			//
 | ||
|  | 			getBroadphase()->getOverlappingPairCache()->cleanProxyFromPairs(bp,m_dispatcher1); | ||
|  | 			getBroadphase()->destroyProxy(bp,m_dispatcher1); | ||
|  | 			collisionObject->setBroadphaseHandle(0); | ||
|  | 		} | ||
|  | 	} | ||
|  | 
 | ||
|  | 
 | ||
|  |     int iObj = collisionObject->getWorldArrayIndex(); | ||
|  | //    btAssert(iObj >= 0 && iObj < m_collisionObjects.size()); // trying to remove an object that was never added or already removed previously?
 | ||
|  |     if (iObj >= 0 && iObj < m_collisionObjects.size()) | ||
|  |     { | ||
|  |         btAssert(collisionObject == m_collisionObjects[iObj]); | ||
|  |         m_collisionObjects.swap(iObj, m_collisionObjects.size()-1); | ||
|  |         m_collisionObjects.pop_back(); | ||
|  |         if (iObj < m_collisionObjects.size()) | ||
|  |         { | ||
|  |             m_collisionObjects[iObj]->setWorldArrayIndex(iObj); | ||
|  |         } | ||
|  |     } | ||
|  |     else | ||
|  |     { | ||
|  |         // slow linear search
 | ||
|  |         //swapremove
 | ||
|  |         m_collisionObjects.remove(collisionObject); | ||
|  |     } | ||
|  |     collisionObject->setWorldArrayIndex(-1); | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | void	btCollisionWorld::rayTestSingle(const btTransform& rayFromTrans,const btTransform& rayToTrans, | ||
|  | 										btCollisionObject* collisionObject, | ||
|  | 										const btCollisionShape* collisionShape, | ||
|  | 										const btTransform& colObjWorldTransform, | ||
|  | 										RayResultCallback& resultCallback) | ||
|  | { | ||
|  | 	btCollisionObjectWrapper colObWrap(0,collisionShape,collisionObject,colObjWorldTransform,-1,-1); | ||
|  | 	btCollisionWorld::rayTestSingleInternal(rayFromTrans,rayToTrans,&colObWrap,resultCallback); | ||
|  | } | ||
|  | 
 | ||
|  | void	btCollisionWorld::rayTestSingleInternal(const btTransform& rayFromTrans,const btTransform& rayToTrans, | ||
|  | 										const btCollisionObjectWrapper* collisionObjectWrap, | ||
|  | 										RayResultCallback& resultCallback) | ||
|  | { | ||
|  | 	btSphereShape pointShape(btScalar(0.0)); | ||
|  | 	pointShape.setMargin(0.f); | ||
|  | 	const btConvexShape* castShape = &pointShape; | ||
|  | 	const btCollisionShape* collisionShape = collisionObjectWrap->getCollisionShape(); | ||
|  | 	const btTransform& colObjWorldTransform = collisionObjectWrap->getWorldTransform(); | ||
|  | 
 | ||
|  | 	if (collisionShape->isConvex()) | ||
|  | 	{ | ||
|  | 		//		BT_PROFILE("rayTestConvex");
 | ||
|  | 		btConvexCast::CastResult castResult; | ||
|  | 		castResult.m_fraction = resultCallback.m_closestHitFraction; | ||
|  | 
 | ||
|  | 		btConvexShape* convexShape = (btConvexShape*) collisionShape; | ||
|  | 		btVoronoiSimplexSolver	simplexSolver; | ||
|  | 		btSubsimplexConvexCast subSimplexConvexCaster(castShape,convexShape,&simplexSolver); | ||
|  | 		 | ||
|  | 		btGjkConvexCast	gjkConvexCaster(castShape,convexShape,&simplexSolver); | ||
|  | 		 | ||
|  | 		//btContinuousConvexCollision convexCaster(castShape,convexShape,&simplexSolver,0);
 | ||
|  | 
 | ||
|  | 		btConvexCast* convexCasterPtr = 0; | ||
|  | 		//use kF_UseSubSimplexConvexCastRaytest by default
 | ||
|  | 		if (resultCallback.m_flags & btTriangleRaycastCallback::kF_UseGjkConvexCastRaytest) | ||
|  | 			convexCasterPtr = &gjkConvexCaster; | ||
|  | 		else | ||
|  | 			convexCasterPtr = &subSimplexConvexCaster; | ||
|  | 		 | ||
|  | 		btConvexCast& convexCaster = *convexCasterPtr; | ||
|  | 
 | ||
|  | 		if (convexCaster.calcTimeOfImpact(rayFromTrans,rayToTrans,colObjWorldTransform,colObjWorldTransform,castResult)) | ||
|  | 		{ | ||
|  | 			//add hit
 | ||
|  | 			if (castResult.m_normal.length2() > btScalar(0.0001)) | ||
|  | 			{ | ||
|  | 				if (castResult.m_fraction < resultCallback.m_closestHitFraction) | ||
|  | 				{ | ||
|  | 					//todo: figure out what this is about. When is rayFromTest.getBasis() not identity?
 | ||
|  | #ifdef USE_SUBSIMPLEX_CONVEX_CAST
 | ||
|  | 					//rotate normal into worldspace
 | ||
|  | 					castResult.m_normal = rayFromTrans.getBasis() * castResult.m_normal; | ||
|  | #endif //USE_SUBSIMPLEX_CONVEX_CAST
 | ||
|  | 
 | ||
|  | 					castResult.m_normal.normalize(); | ||
|  | 					btCollisionWorld::LocalRayResult localRayResult | ||
|  | 						( | ||
|  | 						collisionObjectWrap->getCollisionObject(), | ||
|  | 						0, | ||
|  | 						castResult.m_normal, | ||
|  | 						castResult.m_fraction | ||
|  | 						); | ||
|  | 
 | ||
|  | 					bool normalInWorldSpace = true; | ||
|  | 					resultCallback.addSingleResult(localRayResult, normalInWorldSpace); | ||
|  | 
 | ||
|  | 				} | ||
|  | 			} | ||
|  | 		} | ||
|  | 	} else { | ||
|  | 		if (collisionShape->isConcave()) | ||
|  | 		{ | ||
|  | 
 | ||
|  | 			//ConvexCast::CastResult
 | ||
|  | 				struct BridgeTriangleRaycastCallback : public btTriangleRaycastCallback | ||
|  | 				{ | ||
|  | 					btCollisionWorld::RayResultCallback* m_resultCallback; | ||
|  | 					const btCollisionObject*	m_collisionObject; | ||
|  | 					const btConcaveShape*	m_triangleMesh; | ||
|  | 
 | ||
|  | 					btTransform m_colObjWorldTransform; | ||
|  | 
 | ||
|  | 					BridgeTriangleRaycastCallback( const btVector3& from,const btVector3& to, | ||
|  | 					btCollisionWorld::RayResultCallback* resultCallback, const btCollisionObject* collisionObject,const btConcaveShape*	triangleMesh,const btTransform& colObjWorldTransform): | ||
|  | 						//@BP Mod
 | ||
|  | 						btTriangleRaycastCallback(from,to, resultCallback->m_flags), | ||
|  | 							m_resultCallback(resultCallback), | ||
|  | 							m_collisionObject(collisionObject), | ||
|  | 							m_triangleMesh(triangleMesh), | ||
|  | 							m_colObjWorldTransform(colObjWorldTransform) | ||
|  | 						{ | ||
|  | 						} | ||
|  | 
 | ||
|  | 
 | ||
|  | 					virtual btScalar reportHit(const btVector3& hitNormalLocal, btScalar hitFraction, int partId, int triangleIndex ) | ||
|  | 					{ | ||
|  | 						btCollisionWorld::LocalShapeInfo	shapeInfo; | ||
|  | 						shapeInfo.m_shapePart = partId; | ||
|  | 						shapeInfo.m_triangleIndex = triangleIndex; | ||
|  | 
 | ||
|  | 						btVector3 hitNormalWorld = m_colObjWorldTransform.getBasis() * hitNormalLocal; | ||
|  | 
 | ||
|  | 						btCollisionWorld::LocalRayResult rayResult | ||
|  | 							(m_collisionObject, | ||
|  | 							&shapeInfo, | ||
|  | 							hitNormalWorld, | ||
|  | 							hitFraction); | ||
|  | 
 | ||
|  | 						bool	normalInWorldSpace = true; | ||
|  | 						return m_resultCallback->addSingleResult(rayResult,normalInWorldSpace); | ||
|  | 					} | ||
|  | 
 | ||
|  | 				}; | ||
|  | 
 | ||
|  | 			btTransform worldTocollisionObject = colObjWorldTransform.inverse(); | ||
|  | 			btVector3 rayFromLocal = worldTocollisionObject * rayFromTrans.getOrigin(); | ||
|  | 			btVector3 rayToLocal = worldTocollisionObject * rayToTrans.getOrigin(); | ||
|  | 
 | ||
|  | 			//			BT_PROFILE("rayTestConcave");
 | ||
|  | 			if (collisionShape->getShapeType()==TRIANGLE_MESH_SHAPE_PROXYTYPE) | ||
|  | 			{ | ||
|  | 				///optimized version for btBvhTriangleMeshShape
 | ||
|  | 				btBvhTriangleMeshShape* triangleMesh = (btBvhTriangleMeshShape*)collisionShape; | ||
|  | 				 | ||
|  | 				BridgeTriangleRaycastCallback rcb(rayFromLocal,rayToLocal,&resultCallback,collisionObjectWrap->getCollisionObject(),triangleMesh,colObjWorldTransform); | ||
|  | 				rcb.m_hitFraction = resultCallback.m_closestHitFraction; | ||
|  | 				triangleMesh->performRaycast(&rcb,rayFromLocal,rayToLocal); | ||
|  | 			} | ||
|  | 			else | ||
|  | 			{ | ||
|  | 				//generic (slower) case
 | ||
|  | 				btConcaveShape* concaveShape = (btConcaveShape*)collisionShape; | ||
|  | 
 | ||
|  | 				btTransform worldTocollisionObject = colObjWorldTransform.inverse(); | ||
|  | 
 | ||
|  | 				btVector3 rayFromLocal = worldTocollisionObject * rayFromTrans.getOrigin(); | ||
|  | 				btVector3 rayToLocal = worldTocollisionObject * rayToTrans.getOrigin(); | ||
|  | 
 | ||
|  | 				//ConvexCast::CastResult
 | ||
|  | 
 | ||
|  | 				struct BridgeTriangleRaycastCallback : public btTriangleRaycastCallback | ||
|  | 				{ | ||
|  | 					btCollisionWorld::RayResultCallback* m_resultCallback; | ||
|  | 					const btCollisionObject*	m_collisionObject; | ||
|  | 					btConcaveShape*	m_triangleMesh; | ||
|  | 
 | ||
|  | 					btTransform m_colObjWorldTransform; | ||
|  | 
 | ||
|  | 					BridgeTriangleRaycastCallback( const btVector3& from,const btVector3& to, | ||
|  | 						btCollisionWorld::RayResultCallback* resultCallback, const btCollisionObject* collisionObject,btConcaveShape*	triangleMesh, const btTransform& colObjWorldTransform): | ||
|  | 					//@BP Mod
 | ||
|  | 					btTriangleRaycastCallback(from,to, resultCallback->m_flags), | ||
|  | 						m_resultCallback(resultCallback), | ||
|  | 						m_collisionObject(collisionObject), | ||
|  | 						m_triangleMesh(triangleMesh), | ||
|  | 						m_colObjWorldTransform(colObjWorldTransform) | ||
|  | 					{ | ||
|  | 					} | ||
|  | 
 | ||
|  | 
 | ||
|  | 					virtual btScalar reportHit(const btVector3& hitNormalLocal, btScalar hitFraction, int partId, int triangleIndex ) | ||
|  | 					{ | ||
|  | 						btCollisionWorld::LocalShapeInfo	shapeInfo; | ||
|  | 						shapeInfo.m_shapePart = partId; | ||
|  | 						shapeInfo.m_triangleIndex = triangleIndex; | ||
|  | 
 | ||
|  | 						btVector3 hitNormalWorld = m_colObjWorldTransform.getBasis() * hitNormalLocal; | ||
|  | 
 | ||
|  | 						btCollisionWorld::LocalRayResult rayResult | ||
|  | 							(m_collisionObject, | ||
|  | 							&shapeInfo, | ||
|  | 							hitNormalWorld, | ||
|  | 							hitFraction); | ||
|  | 
 | ||
|  | 						bool	normalInWorldSpace = true; | ||
|  | 						return m_resultCallback->addSingleResult(rayResult,normalInWorldSpace); | ||
|  | 					} | ||
|  | 
 | ||
|  | 				}; | ||
|  | 
 | ||
|  | 
 | ||
|  | 				BridgeTriangleRaycastCallback	rcb(rayFromLocal,rayToLocal,&resultCallback,collisionObjectWrap->getCollisionObject(),concaveShape, colObjWorldTransform); | ||
|  | 				rcb.m_hitFraction = resultCallback.m_closestHitFraction; | ||
|  | 
 | ||
|  | 				btVector3 rayAabbMinLocal = rayFromLocal; | ||
|  | 				rayAabbMinLocal.setMin(rayToLocal); | ||
|  | 				btVector3 rayAabbMaxLocal = rayFromLocal; | ||
|  | 				rayAabbMaxLocal.setMax(rayToLocal); | ||
|  | 
 | ||
|  | 				concaveShape->processAllTriangles(&rcb,rayAabbMinLocal,rayAabbMaxLocal); | ||
|  | 			} | ||
|  | 		} else { | ||
|  | 			//			BT_PROFILE("rayTestCompound");
 | ||
|  | 			if (collisionShape->isCompound()) | ||
|  | 			{ | ||
|  | 				struct LocalInfoAdder2 : public RayResultCallback | ||
|  | 				{ | ||
|  | 					RayResultCallback* m_userCallback; | ||
|  | 					int m_i; | ||
|  | 					 | ||
|  | 					LocalInfoAdder2 (int i, RayResultCallback *user) | ||
|  | 						: m_userCallback(user), m_i(i) | ||
|  | 					{  | ||
|  | 						m_closestHitFraction = m_userCallback->m_closestHitFraction; | ||
|  | 						m_flags = m_userCallback->m_flags; | ||
|  | 					} | ||
|  | 					virtual bool needsCollision(btBroadphaseProxy* p) const | ||
|  | 					{ | ||
|  | 						return m_userCallback->needsCollision(p); | ||
|  | 					} | ||
|  | 
 | ||
|  | 					virtual btScalar addSingleResult (btCollisionWorld::LocalRayResult &r, bool b) | ||
|  | 					{ | ||
|  | 						btCollisionWorld::LocalShapeInfo shapeInfo; | ||
|  | 						shapeInfo.m_shapePart = -1; | ||
|  | 						shapeInfo.m_triangleIndex = m_i; | ||
|  | 						if (r.m_localShapeInfo == NULL) | ||
|  | 							r.m_localShapeInfo = &shapeInfo; | ||
|  | 
 | ||
|  | 						const btScalar result = m_userCallback->addSingleResult(r, b); | ||
|  | 						m_closestHitFraction = m_userCallback->m_closestHitFraction; | ||
|  | 						return result; | ||
|  | 					} | ||
|  | 				}; | ||
|  | 				 | ||
|  | 				struct RayTester : btDbvt::ICollide | ||
|  | 				{ | ||
|  | 					const btCollisionObject* m_collisionObject; | ||
|  | 					const btCompoundShape* m_compoundShape; | ||
|  | 					const btTransform& m_colObjWorldTransform; | ||
|  | 					const btTransform& m_rayFromTrans; | ||
|  | 					const btTransform& m_rayToTrans; | ||
|  | 					RayResultCallback& m_resultCallback; | ||
|  | 					 | ||
|  | 					RayTester(const btCollisionObject* collisionObject, | ||
|  | 							const btCompoundShape* compoundShape, | ||
|  | 							const btTransform& colObjWorldTransform, | ||
|  | 							const btTransform& rayFromTrans, | ||
|  | 							const btTransform& rayToTrans, | ||
|  | 							RayResultCallback& resultCallback): | ||
|  | 						m_collisionObject(collisionObject), | ||
|  | 						m_compoundShape(compoundShape), | ||
|  | 						m_colObjWorldTransform(colObjWorldTransform), | ||
|  | 						m_rayFromTrans(rayFromTrans), | ||
|  | 						m_rayToTrans(rayToTrans), | ||
|  | 						m_resultCallback(resultCallback) | ||
|  | 					{ | ||
|  | 						 | ||
|  | 					} | ||
|  | 					 | ||
|  | 					void ProcessLeaf(int i) | ||
|  | 					{ | ||
|  | 						const btCollisionShape* childCollisionShape = m_compoundShape->getChildShape(i); | ||
|  | 						const btTransform& childTrans = m_compoundShape->getChildTransform(i); | ||
|  | 						btTransform childWorldTrans = m_colObjWorldTransform * childTrans; | ||
|  | 						 | ||
|  | 						btCollisionObjectWrapper tmpOb(0,childCollisionShape,m_collisionObject,childWorldTrans,-1,i); | ||
|  | 						// replace collision shape so that callback can determine the triangle
 | ||
|  | 
 | ||
|  | 						 | ||
|  | 
 | ||
|  | 						LocalInfoAdder2 my_cb(i, &m_resultCallback); | ||
|  | 
 | ||
|  | 						rayTestSingleInternal( | ||
|  | 							m_rayFromTrans, | ||
|  | 							m_rayToTrans, | ||
|  | 							&tmpOb, | ||
|  | 							my_cb); | ||
|  | 						 | ||
|  | 					} | ||
|  | 				 | ||
|  | 					void Process(const btDbvtNode* leaf) | ||
|  | 					{ | ||
|  | 						ProcessLeaf(leaf->dataAsInt); | ||
|  | 					} | ||
|  | 				}; | ||
|  | 				 | ||
|  | 				const btCompoundShape* compoundShape = static_cast<const btCompoundShape*>(collisionShape); | ||
|  | 				const btDbvt* dbvt = compoundShape->getDynamicAabbTree(); | ||
|  | 
 | ||
|  | 
 | ||
|  | 				RayTester rayCB( | ||
|  | 					collisionObjectWrap->getCollisionObject(), | ||
|  | 					compoundShape, | ||
|  | 					colObjWorldTransform, | ||
|  | 					rayFromTrans, | ||
|  | 					rayToTrans, | ||
|  | 					resultCallback); | ||
|  | #ifndef	DISABLE_DBVT_COMPOUNDSHAPE_RAYCAST_ACCELERATION
 | ||
|  | 				if (dbvt) | ||
|  | 				{ | ||
|  | 					btVector3 localRayFrom = colObjWorldTransform.inverseTimes(rayFromTrans).getOrigin(); | ||
|  | 					btVector3 localRayTo = colObjWorldTransform.inverseTimes(rayToTrans).getOrigin(); | ||
|  | 					btDbvt::rayTest(dbvt->m_root, localRayFrom , localRayTo, rayCB); | ||
|  | 				} | ||
|  | 				else | ||
|  | #endif //DISABLE_DBVT_COMPOUNDSHAPE_RAYCAST_ACCELERATION
 | ||
|  | 				{ | ||
|  | 					for (int i = 0, n = compoundShape->getNumChildShapes(); i < n; ++i) | ||
|  | 					{ | ||
|  | 						rayCB.ProcessLeaf(i); | ||
|  | 					}	 | ||
|  | 				} | ||
|  | 			} | ||
|  | 		} | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | void	btCollisionWorld::objectQuerySingle(const btConvexShape* castShape,const btTransform& convexFromTrans,const btTransform& convexToTrans, | ||
|  | 											btCollisionObject* collisionObject, | ||
|  | 											const btCollisionShape* collisionShape, | ||
|  | 											const btTransform& colObjWorldTransform, | ||
|  | 											ConvexResultCallback& resultCallback, btScalar allowedPenetration) | ||
|  | { | ||
|  | 	btCollisionObjectWrapper tmpOb(0,collisionShape,collisionObject,colObjWorldTransform,-1,-1); | ||
|  | 	btCollisionWorld::objectQuerySingleInternal(castShape,convexFromTrans,convexToTrans,&tmpOb,resultCallback,allowedPenetration); | ||
|  | } | ||
|  | 
 | ||
|  | void	btCollisionWorld::objectQuerySingleInternal(const btConvexShape* castShape,const btTransform& convexFromTrans,const btTransform& convexToTrans, | ||
|  | 											const btCollisionObjectWrapper* colObjWrap, | ||
|  | 											ConvexResultCallback& resultCallback, btScalar allowedPenetration) | ||
|  | { | ||
|  | 	const btCollisionShape* collisionShape = colObjWrap->getCollisionShape(); | ||
|  | 	const btTransform& colObjWorldTransform = colObjWrap->getWorldTransform(); | ||
|  | 
 | ||
|  | 	if (collisionShape->isConvex()) | ||
|  | 	{ | ||
|  | 		//BT_PROFILE("convexSweepConvex");
 | ||
|  | 		btConvexCast::CastResult castResult; | ||
|  | 		castResult.m_allowedPenetration = allowedPenetration; | ||
|  | 		castResult.m_fraction = resultCallback.m_closestHitFraction;//btScalar(1.);//??
 | ||
|  | 
 | ||
|  | 		btConvexShape* convexShape = (btConvexShape*) collisionShape; | ||
|  | 		btVoronoiSimplexSolver	simplexSolver; | ||
|  | 		btGjkEpaPenetrationDepthSolver	gjkEpaPenetrationSolver; | ||
|  | 
 | ||
|  | 		btContinuousConvexCollision convexCaster1(castShape,convexShape,&simplexSolver,&gjkEpaPenetrationSolver); | ||
|  | 		//btGjkConvexCast convexCaster2(castShape,convexShape,&simplexSolver);
 | ||
|  | 		//btSubsimplexConvexCast convexCaster3(castShape,convexShape,&simplexSolver);
 | ||
|  | 
 | ||
|  | 		btConvexCast* castPtr = &convexCaster1; | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 		if (castPtr->calcTimeOfImpact(convexFromTrans,convexToTrans,colObjWorldTransform,colObjWorldTransform,castResult)) | ||
|  | 		{ | ||
|  | 			//add hit
 | ||
|  | 			if (castResult.m_normal.length2() > btScalar(0.0001)) | ||
|  | 			{ | ||
|  | 				if (castResult.m_fraction < resultCallback.m_closestHitFraction) | ||
|  | 				{ | ||
|  | 					castResult.m_normal.normalize(); | ||
|  | 					btCollisionWorld::LocalConvexResult localConvexResult | ||
|  | 						( | ||
|  | 						colObjWrap->getCollisionObject(), | ||
|  | 						0, | ||
|  | 						castResult.m_normal, | ||
|  | 						castResult.m_hitPoint, | ||
|  | 						castResult.m_fraction | ||
|  | 						); | ||
|  | 
 | ||
|  | 					bool normalInWorldSpace = true; | ||
|  | 					resultCallback.addSingleResult(localConvexResult, normalInWorldSpace); | ||
|  | 
 | ||
|  | 				} | ||
|  | 			} | ||
|  | 		} | ||
|  | 	} else { | ||
|  | 		if (collisionShape->isConcave()) | ||
|  | 		{ | ||
|  | 			if (collisionShape->getShapeType()==TRIANGLE_MESH_SHAPE_PROXYTYPE) | ||
|  | 			{ | ||
|  | 				//BT_PROFILE("convexSweepbtBvhTriangleMesh");
 | ||
|  | 				btBvhTriangleMeshShape* triangleMesh = (btBvhTriangleMeshShape*)collisionShape; | ||
|  | 				btTransform worldTocollisionObject = colObjWorldTransform.inverse(); | ||
|  | 				btVector3 convexFromLocal = worldTocollisionObject * convexFromTrans.getOrigin(); | ||
|  | 				btVector3 convexToLocal = worldTocollisionObject * convexToTrans.getOrigin(); | ||
|  | 				// rotation of box in local mesh space = MeshRotation^-1 * ConvexToRotation
 | ||
|  | 				btTransform rotationXform = btTransform(worldTocollisionObject.getBasis() * convexToTrans.getBasis()); | ||
|  | 
 | ||
|  | 				//ConvexCast::CastResult
 | ||
|  | 				struct BridgeTriangleConvexcastCallback : public btTriangleConvexcastCallback | ||
|  | 				{ | ||
|  | 					btCollisionWorld::ConvexResultCallback* m_resultCallback; | ||
|  | 					const btCollisionObject*	m_collisionObject; | ||
|  | 					btTriangleMeshShape*	m_triangleMesh; | ||
|  | 
 | ||
|  | 					BridgeTriangleConvexcastCallback(const btConvexShape* castShape, const btTransform& from,const btTransform& to, | ||
|  | 						btCollisionWorld::ConvexResultCallback* resultCallback, const btCollisionObject* collisionObject,btTriangleMeshShape*	triangleMesh, const btTransform& triangleToWorld): | ||
|  | 					btTriangleConvexcastCallback(castShape, from,to, triangleToWorld, triangleMesh->getMargin()), | ||
|  | 						m_resultCallback(resultCallback), | ||
|  | 						m_collisionObject(collisionObject), | ||
|  | 						m_triangleMesh(triangleMesh) | ||
|  | 					{ | ||
|  | 					} | ||
|  | 
 | ||
|  | 
 | ||
|  | 					virtual btScalar reportHit(const btVector3& hitNormalLocal, const btVector3& hitPointLocal, btScalar hitFraction, int partId, int triangleIndex ) | ||
|  | 					{ | ||
|  | 						btCollisionWorld::LocalShapeInfo	shapeInfo; | ||
|  | 						shapeInfo.m_shapePart = partId; | ||
|  | 						shapeInfo.m_triangleIndex = triangleIndex; | ||
|  | 						if (hitFraction <= m_resultCallback->m_closestHitFraction) | ||
|  | 						{ | ||
|  | 
 | ||
|  | 							btCollisionWorld::LocalConvexResult convexResult | ||
|  | 								(m_collisionObject, | ||
|  | 								&shapeInfo, | ||
|  | 								hitNormalLocal, | ||
|  | 								hitPointLocal, | ||
|  | 								hitFraction); | ||
|  | 
 | ||
|  | 							bool	normalInWorldSpace = true; | ||
|  | 
 | ||
|  | 
 | ||
|  | 							return m_resultCallback->addSingleResult(convexResult,normalInWorldSpace); | ||
|  | 						} | ||
|  | 						return hitFraction; | ||
|  | 					} | ||
|  | 
 | ||
|  | 				}; | ||
|  | 
 | ||
|  | 				BridgeTriangleConvexcastCallback tccb(castShape, convexFromTrans,convexToTrans,&resultCallback,colObjWrap->getCollisionObject(),triangleMesh, colObjWorldTransform); | ||
|  | 				tccb.m_hitFraction = resultCallback.m_closestHitFraction; | ||
|  | 				tccb.m_allowedPenetration = allowedPenetration; | ||
|  | 				btVector3 boxMinLocal, boxMaxLocal; | ||
|  | 				castShape->getAabb(rotationXform, boxMinLocal, boxMaxLocal); | ||
|  | 				triangleMesh->performConvexcast(&tccb,convexFromLocal,convexToLocal,boxMinLocal, boxMaxLocal); | ||
|  | 			} else | ||
|  | 			{ | ||
|  | 				if (collisionShape->getShapeType()==STATIC_PLANE_PROXYTYPE) | ||
|  | 				{ | ||
|  | 					btConvexCast::CastResult castResult; | ||
|  | 					castResult.m_allowedPenetration = allowedPenetration; | ||
|  | 					castResult.m_fraction = resultCallback.m_closestHitFraction; | ||
|  | 					btStaticPlaneShape* planeShape = (btStaticPlaneShape*) collisionShape; | ||
|  | 					btContinuousConvexCollision convexCaster1(castShape,planeShape); | ||
|  | 					btConvexCast* castPtr = &convexCaster1; | ||
|  | 
 | ||
|  | 					if (castPtr->calcTimeOfImpact(convexFromTrans,convexToTrans,colObjWorldTransform,colObjWorldTransform,castResult)) | ||
|  | 					{ | ||
|  | 						//add hit
 | ||
|  | 						if (castResult.m_normal.length2() > btScalar(0.0001)) | ||
|  | 						{ | ||
|  | 							if (castResult.m_fraction < resultCallback.m_closestHitFraction) | ||
|  | 							{ | ||
|  | 								castResult.m_normal.normalize(); | ||
|  | 								btCollisionWorld::LocalConvexResult localConvexResult | ||
|  | 									( | ||
|  | 									colObjWrap->getCollisionObject(), | ||
|  | 									0, | ||
|  | 									castResult.m_normal, | ||
|  | 									castResult.m_hitPoint, | ||
|  | 									castResult.m_fraction | ||
|  | 									); | ||
|  | 
 | ||
|  | 								bool normalInWorldSpace = true; | ||
|  | 								resultCallback.addSingleResult(localConvexResult, normalInWorldSpace); | ||
|  | 							} | ||
|  | 						} | ||
|  | 					} | ||
|  | 
 | ||
|  | 				} else | ||
|  | 				{ | ||
|  | 					//BT_PROFILE("convexSweepConcave");
 | ||
|  | 					btConcaveShape* concaveShape = (btConcaveShape*)collisionShape; | ||
|  | 					btTransform worldTocollisionObject = colObjWorldTransform.inverse(); | ||
|  | 					btVector3 convexFromLocal = worldTocollisionObject * convexFromTrans.getOrigin(); | ||
|  | 					btVector3 convexToLocal = worldTocollisionObject * convexToTrans.getOrigin(); | ||
|  | 					// rotation of box in local mesh space = MeshRotation^-1 * ConvexToRotation
 | ||
|  | 					btTransform rotationXform = btTransform(worldTocollisionObject.getBasis() * convexToTrans.getBasis()); | ||
|  | 
 | ||
|  | 					//ConvexCast::CastResult
 | ||
|  | 					struct BridgeTriangleConvexcastCallback : public btTriangleConvexcastCallback | ||
|  | 					{ | ||
|  | 						btCollisionWorld::ConvexResultCallback* m_resultCallback; | ||
|  | 						const btCollisionObject*	m_collisionObject; | ||
|  | 						btConcaveShape*	m_triangleMesh; | ||
|  | 
 | ||
|  | 						BridgeTriangleConvexcastCallback(const btConvexShape* castShape, const btTransform& from,const btTransform& to, | ||
|  | 							btCollisionWorld::ConvexResultCallback* resultCallback, const btCollisionObject* collisionObject,btConcaveShape*	triangleMesh, const btTransform& triangleToWorld): | ||
|  | 						btTriangleConvexcastCallback(castShape, from,to, triangleToWorld, triangleMesh->getMargin()), | ||
|  | 							m_resultCallback(resultCallback), | ||
|  | 							m_collisionObject(collisionObject), | ||
|  | 							m_triangleMesh(triangleMesh) | ||
|  | 						{ | ||
|  | 						} | ||
|  | 
 | ||
|  | 
 | ||
|  | 						virtual btScalar reportHit(const btVector3& hitNormalLocal, const btVector3& hitPointLocal, btScalar hitFraction, int partId, int triangleIndex ) | ||
|  | 						{ | ||
|  | 							btCollisionWorld::LocalShapeInfo	shapeInfo; | ||
|  | 							shapeInfo.m_shapePart = partId; | ||
|  | 							shapeInfo.m_triangleIndex = triangleIndex; | ||
|  | 							if (hitFraction <= m_resultCallback->m_closestHitFraction) | ||
|  | 							{ | ||
|  | 
 | ||
|  | 								btCollisionWorld::LocalConvexResult convexResult | ||
|  | 									(m_collisionObject, | ||
|  | 									&shapeInfo, | ||
|  | 									hitNormalLocal, | ||
|  | 									hitPointLocal, | ||
|  | 									hitFraction); | ||
|  | 
 | ||
|  | 								bool	normalInWorldSpace = true; | ||
|  | 
 | ||
|  | 								return m_resultCallback->addSingleResult(convexResult,normalInWorldSpace); | ||
|  | 							} | ||
|  | 							return hitFraction; | ||
|  | 						} | ||
|  | 
 | ||
|  | 					}; | ||
|  | 
 | ||
|  | 					BridgeTriangleConvexcastCallback tccb(castShape, convexFromTrans,convexToTrans,&resultCallback,colObjWrap->getCollisionObject(),concaveShape, colObjWorldTransform); | ||
|  | 					tccb.m_hitFraction = resultCallback.m_closestHitFraction; | ||
|  | 					tccb.m_allowedPenetration = allowedPenetration; | ||
|  | 					btVector3 boxMinLocal, boxMaxLocal; | ||
|  | 					castShape->getAabb(rotationXform, boxMinLocal, boxMaxLocal); | ||
|  | 
 | ||
|  | 					btVector3 rayAabbMinLocal = convexFromLocal; | ||
|  | 					rayAabbMinLocal.setMin(convexToLocal); | ||
|  | 					btVector3 rayAabbMaxLocal = convexFromLocal; | ||
|  | 					rayAabbMaxLocal.setMax(convexToLocal); | ||
|  | 					rayAabbMinLocal += boxMinLocal; | ||
|  | 					rayAabbMaxLocal += boxMaxLocal; | ||
|  | 					concaveShape->processAllTriangles(&tccb,rayAabbMinLocal,rayAabbMaxLocal); | ||
|  | 				} | ||
|  | 			} | ||
|  | 		} else { | ||
|  | 			if (collisionShape->isCompound()) | ||
|  | 			{ | ||
|  | 				struct	btCompoundLeafCallback : btDbvt::ICollide | ||
|  | 				{ | ||
|  | 					btCompoundLeafCallback( | ||
|  | 										   const btCollisionObjectWrapper* colObjWrap, | ||
|  | 										   const btConvexShape* castShape, | ||
|  | 										   const btTransform& convexFromTrans, | ||
|  | 										   const btTransform& convexToTrans, | ||
|  | 										   btScalar allowedPenetration, | ||
|  | 										   const btCompoundShape* compoundShape, | ||
|  | 										   const btTransform& colObjWorldTransform, | ||
|  | 										   ConvexResultCallback& resultCallback) | ||
|  | 					:  | ||
|  | 					  m_colObjWrap(colObjWrap), | ||
|  | 						m_castShape(castShape), | ||
|  | 						m_convexFromTrans(convexFromTrans), | ||
|  | 						m_convexToTrans(convexToTrans), | ||
|  | 						m_allowedPenetration(allowedPenetration), | ||
|  | 						m_compoundShape(compoundShape), | ||
|  | 						m_colObjWorldTransform(colObjWorldTransform), | ||
|  | 						m_resultCallback(resultCallback) { | ||
|  | 					} | ||
|  | 
 | ||
|  | 				  const btCollisionObjectWrapper* m_colObjWrap; | ||
|  | 					const btConvexShape* m_castShape; | ||
|  | 					const btTransform& m_convexFromTrans; | ||
|  | 					const btTransform& m_convexToTrans; | ||
|  | 					btScalar m_allowedPenetration; | ||
|  | 					const btCompoundShape* m_compoundShape; | ||
|  | 					const btTransform& m_colObjWorldTransform; | ||
|  | 					ConvexResultCallback& m_resultCallback; | ||
|  | 
 | ||
|  | 				public: | ||
|  | 
 | ||
|  | 					void		ProcessChild(int index, const btTransform& childTrans, const btCollisionShape* childCollisionShape) | ||
|  | 					{ | ||
|  | 						btTransform childWorldTrans = m_colObjWorldTransform * childTrans; | ||
|  | 
 | ||
|  | 						struct	LocalInfoAdder : public ConvexResultCallback { | ||
|  | 							ConvexResultCallback* m_userCallback; | ||
|  | 							int m_i; | ||
|  | 
 | ||
|  | 							LocalInfoAdder(int i, ConvexResultCallback *user) | ||
|  | 								: m_userCallback(user), m_i(i) | ||
|  | 							{ | ||
|  | 								m_closestHitFraction = m_userCallback->m_closestHitFraction; | ||
|  | 							} | ||
|  | 							virtual bool needsCollision(btBroadphaseProxy* p) const | ||
|  | 							{ | ||
|  | 								return m_userCallback->needsCollision(p); | ||
|  | 							} | ||
|  | 							virtual btScalar addSingleResult(btCollisionWorld::LocalConvexResult&	r, bool b) | ||
|  | 							{ | ||
|  | 								btCollisionWorld::LocalShapeInfo	shapeInfo; | ||
|  | 								shapeInfo.m_shapePart = -1; | ||
|  | 								shapeInfo.m_triangleIndex = m_i; | ||
|  | 								if (r.m_localShapeInfo == NULL) | ||
|  | 									r.m_localShapeInfo = &shapeInfo; | ||
|  | 								const btScalar result = m_userCallback->addSingleResult(r, b); | ||
|  | 								m_closestHitFraction = m_userCallback->m_closestHitFraction; | ||
|  | 								return result; | ||
|  | 
 | ||
|  | 							} | ||
|  | 						}; | ||
|  | 
 | ||
|  | 						LocalInfoAdder my_cb(index, &m_resultCallback); | ||
|  | 
 | ||
|  | 						btCollisionObjectWrapper tmpObj(m_colObjWrap, childCollisionShape, m_colObjWrap->getCollisionObject(), childWorldTrans, -1, index); | ||
|  | 
 | ||
|  | 						objectQuerySingleInternal(m_castShape, m_convexFromTrans, m_convexToTrans, &tmpObj, my_cb, m_allowedPenetration); | ||
|  | 					} | ||
|  | 
 | ||
|  | 					void		Process(const btDbvtNode* leaf) | ||
|  | 					{ | ||
|  | 						// Processing leaf node
 | ||
|  | 						int index = leaf->dataAsInt; | ||
|  | 
 | ||
|  | 						btTransform childTrans = m_compoundShape->getChildTransform(index); | ||
|  | 						const btCollisionShape* childCollisionShape = m_compoundShape->getChildShape(index); | ||
|  | 
 | ||
|  | 						ProcessChild(index, childTrans, childCollisionShape); | ||
|  | 					} | ||
|  | 				}; | ||
|  | 
 | ||
|  | 				BT_PROFILE("convexSweepCompound"); | ||
|  | 				const btCompoundShape* compoundShape = static_cast<const btCompoundShape*>(collisionShape); | ||
|  | 
 | ||
|  | 				btVector3 fromLocalAabbMin, fromLocalAabbMax; | ||
|  | 				btVector3 toLocalAabbMin, toLocalAabbMax; | ||
|  | 
 | ||
|  | 				castShape->getAabb(colObjWorldTransform.inverse() * convexFromTrans, fromLocalAabbMin, fromLocalAabbMax); | ||
|  | 				castShape->getAabb(colObjWorldTransform.inverse() * convexToTrans, toLocalAabbMin, toLocalAabbMax); | ||
|  | 
 | ||
|  | 				fromLocalAabbMin.setMin(toLocalAabbMin); | ||
|  | 				fromLocalAabbMax.setMax(toLocalAabbMax); | ||
|  | 
 | ||
|  | 				btCompoundLeafCallback callback(colObjWrap, castShape, convexFromTrans, convexToTrans, | ||
|  | 					  allowedPenetration, compoundShape, colObjWorldTransform, resultCallback); | ||
|  | 
 | ||
|  | 				const btDbvt* tree = compoundShape->getDynamicAabbTree(); | ||
|  | 				if (tree) { | ||
|  | 					const ATTRIBUTE_ALIGNED16(btDbvtVolume)	bounds = btDbvtVolume::FromMM(fromLocalAabbMin, fromLocalAabbMax); | ||
|  | 					tree->collideTV(tree->m_root, bounds, callback); | ||
|  | 				} else { | ||
|  | 					int i; | ||
|  | 					for (i=0;i<compoundShape->getNumChildShapes();i++) | ||
|  | 					{ | ||
|  | 						const btCollisionShape* childCollisionShape = compoundShape->getChildShape(i); | ||
|  | 						btTransform childTrans = compoundShape->getChildTransform(i); | ||
|  | 						callback.ProcessChild(i, childTrans, childCollisionShape); | ||
|  | 					} | ||
|  | 				} | ||
|  | 			} | ||
|  | 		} | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | struct btSingleRayCallback : public btBroadphaseRayCallback | ||
|  | { | ||
|  | 
 | ||
|  | 	btVector3	m_rayFromWorld; | ||
|  | 	btVector3	m_rayToWorld; | ||
|  | 	btTransform	m_rayFromTrans; | ||
|  | 	btTransform	m_rayToTrans; | ||
|  | 	btVector3	m_hitNormal; | ||
|  | 
 | ||
|  | 	const btCollisionWorld*	m_world; | ||
|  | 	btCollisionWorld::RayResultCallback&	m_resultCallback; | ||
|  | 
 | ||
|  | 	btSingleRayCallback(const btVector3& rayFromWorld,const btVector3& rayToWorld,const btCollisionWorld* world,btCollisionWorld::RayResultCallback& resultCallback) | ||
|  | 		:m_rayFromWorld(rayFromWorld), | ||
|  | 		m_rayToWorld(rayToWorld), | ||
|  | 		m_world(world), | ||
|  | 		m_resultCallback(resultCallback) | ||
|  | 	{ | ||
|  | 		m_rayFromTrans.setIdentity(); | ||
|  | 		m_rayFromTrans.setOrigin(m_rayFromWorld); | ||
|  | 		m_rayToTrans.setIdentity(); | ||
|  | 		m_rayToTrans.setOrigin(m_rayToWorld); | ||
|  | 
 | ||
|  | 		btVector3 rayDir = (rayToWorld-rayFromWorld); | ||
|  | 
 | ||
|  | 		rayDir.normalize (); | ||
|  | 		///what about division by zero? --> just set rayDirection[i] to INF/BT_LARGE_FLOAT
 | ||
|  | 		m_rayDirectionInverse[0] = rayDir[0] == btScalar(0.0) ? btScalar(BT_LARGE_FLOAT) : btScalar(1.0) / rayDir[0]; | ||
|  | 		m_rayDirectionInverse[1] = rayDir[1] == btScalar(0.0) ? btScalar(BT_LARGE_FLOAT) : btScalar(1.0) / rayDir[1]; | ||
|  | 		m_rayDirectionInverse[2] = rayDir[2] == btScalar(0.0) ? btScalar(BT_LARGE_FLOAT) : btScalar(1.0) / rayDir[2]; | ||
|  | 		m_signs[0] = m_rayDirectionInverse[0] < 0.0; | ||
|  | 		m_signs[1] = m_rayDirectionInverse[1] < 0.0; | ||
|  | 		m_signs[2] = m_rayDirectionInverse[2] < 0.0; | ||
|  | 
 | ||
|  | 		m_lambda_max = rayDir.dot(m_rayToWorld-m_rayFromWorld); | ||
|  | 
 | ||
|  | 	} | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 	virtual bool	process(const btBroadphaseProxy* proxy) | ||
|  | 	{ | ||
|  | 		///terminate further ray tests, once the closestHitFraction reached zero
 | ||
|  | 		if (m_resultCallback.m_closestHitFraction == btScalar(0.f)) | ||
|  | 			return false; | ||
|  | 
 | ||
|  | 		btCollisionObject*	collisionObject = (btCollisionObject*)proxy->m_clientObject; | ||
|  | 
 | ||
|  | 		//only perform raycast if filterMask matches
 | ||
|  | 		if(m_resultCallback.needsCollision(collisionObject->getBroadphaseHandle()))  | ||
|  | 		{ | ||
|  | 			//RigidcollisionObject* collisionObject = ctrl->GetRigidcollisionObject();
 | ||
|  | 			//btVector3 collisionObjectAabbMin,collisionObjectAabbMax;
 | ||
|  | #if 0
 | ||
|  | #ifdef RECALCULATE_AABB
 | ||
|  | 			btVector3 collisionObjectAabbMin,collisionObjectAabbMax; | ||
|  | 			collisionObject->getCollisionShape()->getAabb(collisionObject->getWorldTransform(),collisionObjectAabbMin,collisionObjectAabbMax); | ||
|  | #else
 | ||
|  | 			//getBroadphase()->getAabb(collisionObject->getBroadphaseHandle(),collisionObjectAabbMin,collisionObjectAabbMax);
 | ||
|  | 			const btVector3& collisionObjectAabbMin = collisionObject->getBroadphaseHandle()->m_aabbMin; | ||
|  | 			const btVector3& collisionObjectAabbMax = collisionObject->getBroadphaseHandle()->m_aabbMax; | ||
|  | #endif
 | ||
|  | #endif
 | ||
|  | 			//btScalar hitLambda = m_resultCallback.m_closestHitFraction;
 | ||
|  | 			//culling already done by broadphase
 | ||
|  | 			//if (btRayAabb(m_rayFromWorld,m_rayToWorld,collisionObjectAabbMin,collisionObjectAabbMax,hitLambda,m_hitNormal))
 | ||
|  | 			{ | ||
|  | 				m_world->rayTestSingle(m_rayFromTrans,m_rayToTrans, | ||
|  | 					collisionObject, | ||
|  | 					collisionObject->getCollisionShape(), | ||
|  | 					collisionObject->getWorldTransform(), | ||
|  | 					m_resultCallback); | ||
|  | 			} | ||
|  | 		} | ||
|  | 		return true; | ||
|  | 	} | ||
|  | }; | ||
|  | 
 | ||
|  | void	btCollisionWorld::rayTest(const btVector3& rayFromWorld, const btVector3& rayToWorld, RayResultCallback& resultCallback) const | ||
|  | { | ||
|  | 	//BT_PROFILE("rayTest");
 | ||
|  | 	/// use the broadphase to accelerate the search for objects, based on their aabb
 | ||
|  | 	/// and for each object with ray-aabb overlap, perform an exact ray test
 | ||
|  | 	btSingleRayCallback rayCB(rayFromWorld,rayToWorld,this,resultCallback); | ||
|  | 
 | ||
|  | #ifndef USE_BRUTEFORCE_RAYBROADPHASE
 | ||
|  | 	m_broadphasePairCache->rayTest(rayFromWorld,rayToWorld,rayCB); | ||
|  | #else
 | ||
|  | 	for (int i=0;i<this->getNumCollisionObjects();i++) | ||
|  | 	{ | ||
|  | 		rayCB.process(m_collisionObjects[i]->getBroadphaseHandle()); | ||
|  | 	}	 | ||
|  | #endif //USE_BRUTEFORCE_RAYBROADPHASE
 | ||
|  | 
 | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | struct btSingleSweepCallback : public btBroadphaseRayCallback | ||
|  | { | ||
|  | 
 | ||
|  | 	btTransform	m_convexFromTrans; | ||
|  | 	btTransform	m_convexToTrans; | ||
|  | 	btVector3	m_hitNormal; | ||
|  | 	const btCollisionWorld*	m_world; | ||
|  | 	btCollisionWorld::ConvexResultCallback&	m_resultCallback; | ||
|  | 	btScalar	m_allowedCcdPenetration; | ||
|  | 	const btConvexShape* m_castShape; | ||
|  | 
 | ||
|  | 
 | ||
|  | 	btSingleSweepCallback(const btConvexShape* castShape, const btTransform& convexFromTrans,const btTransform& convexToTrans,const btCollisionWorld* world,btCollisionWorld::ConvexResultCallback& resultCallback,btScalar allowedPenetration) | ||
|  | 		:m_convexFromTrans(convexFromTrans), | ||
|  | 		m_convexToTrans(convexToTrans), | ||
|  | 		m_world(world), | ||
|  | 		m_resultCallback(resultCallback), | ||
|  | 		m_allowedCcdPenetration(allowedPenetration), | ||
|  | 		m_castShape(castShape) | ||
|  | 	{ | ||
|  | 		btVector3 unnormalizedRayDir = (m_convexToTrans.getOrigin()-m_convexFromTrans.getOrigin()); | ||
|  | 		btVector3 rayDir = unnormalizedRayDir.normalized(); | ||
|  | 		///what about division by zero? --> just set rayDirection[i] to INF/BT_LARGE_FLOAT
 | ||
|  | 		m_rayDirectionInverse[0] = rayDir[0] == btScalar(0.0) ? btScalar(BT_LARGE_FLOAT) : btScalar(1.0) / rayDir[0]; | ||
|  | 		m_rayDirectionInverse[1] = rayDir[1] == btScalar(0.0) ? btScalar(BT_LARGE_FLOAT) : btScalar(1.0) / rayDir[1]; | ||
|  | 		m_rayDirectionInverse[2] = rayDir[2] == btScalar(0.0) ? btScalar(BT_LARGE_FLOAT) : btScalar(1.0) / rayDir[2]; | ||
|  | 		m_signs[0] = m_rayDirectionInverse[0] < 0.0; | ||
|  | 		m_signs[1] = m_rayDirectionInverse[1] < 0.0; | ||
|  | 		m_signs[2] = m_rayDirectionInverse[2] < 0.0; | ||
|  | 
 | ||
|  | 		m_lambda_max = rayDir.dot(unnormalizedRayDir); | ||
|  | 
 | ||
|  | 	} | ||
|  | 
 | ||
|  | 	virtual bool	process(const btBroadphaseProxy* proxy) | ||
|  | 	{ | ||
|  | 		///terminate further convex sweep tests, once the closestHitFraction reached zero
 | ||
|  | 		if (m_resultCallback.m_closestHitFraction == btScalar(0.f)) | ||
|  | 			return false; | ||
|  | 
 | ||
|  | 		btCollisionObject*	collisionObject = (btCollisionObject*)proxy->m_clientObject; | ||
|  | 
 | ||
|  | 		//only perform raycast if filterMask matches
 | ||
|  | 		if(m_resultCallback.needsCollision(collisionObject->getBroadphaseHandle())) { | ||
|  | 			//RigidcollisionObject* collisionObject = ctrl->GetRigidcollisionObject();
 | ||
|  | 			m_world->objectQuerySingle(m_castShape, m_convexFromTrans,m_convexToTrans, | ||
|  | 				collisionObject, | ||
|  | 				collisionObject->getCollisionShape(), | ||
|  | 				collisionObject->getWorldTransform(), | ||
|  | 				m_resultCallback, | ||
|  | 				m_allowedCcdPenetration); | ||
|  | 		} | ||
|  | 
 | ||
|  | 		return true; | ||
|  | 	} | ||
|  | }; | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | void	btCollisionWorld::convexSweepTest(const btConvexShape* castShape, const btTransform& convexFromWorld, const btTransform& convexToWorld, ConvexResultCallback& resultCallback, btScalar allowedCcdPenetration) const | ||
|  | { | ||
|  | 
 | ||
|  | 	BT_PROFILE("convexSweepTest"); | ||
|  | 	/// use the broadphase to accelerate the search for objects, based on their aabb
 | ||
|  | 	/// and for each object with ray-aabb overlap, perform an exact ray test
 | ||
|  | 	/// unfortunately the implementation for rayTest and convexSweepTest duplicated, albeit practically identical
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 	btTransform	convexFromTrans,convexToTrans; | ||
|  | 	convexFromTrans = convexFromWorld; | ||
|  | 	convexToTrans = convexToWorld; | ||
|  | 	btVector3 castShapeAabbMin, castShapeAabbMax; | ||
|  | 	/* Compute AABB that encompasses angular movement */ | ||
|  | 	{ | ||
|  | 		btVector3 linVel, angVel; | ||
|  | 		btTransformUtil::calculateVelocity (convexFromTrans, convexToTrans, 1.0f, linVel, angVel); | ||
|  | 		btVector3 zeroLinVel; | ||
|  | 		zeroLinVel.setValue(0,0,0); | ||
|  | 		btTransform R; | ||
|  | 		R.setIdentity (); | ||
|  | 		R.setRotation (convexFromTrans.getRotation()); | ||
|  | 		castShape->calculateTemporalAabb (R, zeroLinVel, angVel, 1.0f, castShapeAabbMin, castShapeAabbMax); | ||
|  | 	} | ||
|  | 
 | ||
|  | #ifndef USE_BRUTEFORCE_RAYBROADPHASE
 | ||
|  | 
 | ||
|  | 	btSingleSweepCallback	convexCB(castShape,convexFromWorld,convexToWorld,this,resultCallback,allowedCcdPenetration); | ||
|  | 
 | ||
|  | 	m_broadphasePairCache->rayTest(convexFromTrans.getOrigin(),convexToTrans.getOrigin(),convexCB,castShapeAabbMin,castShapeAabbMax); | ||
|  | 
 | ||
|  | #else
 | ||
|  | 	/// go over all objects, and if the ray intersects their aabb + cast shape aabb,
 | ||
|  | 	// do a ray-shape query using convexCaster (CCD)
 | ||
|  | 	int i; | ||
|  | 	for (i=0;i<m_collisionObjects.size();i++) | ||
|  | 	{ | ||
|  | 		btCollisionObject*	collisionObject= m_collisionObjects[i]; | ||
|  | 		//only perform raycast if filterMask matches
 | ||
|  | 		if(resultCallback.needsCollision(collisionObject->getBroadphaseHandle())) { | ||
|  | 			//RigidcollisionObject* collisionObject = ctrl->GetRigidcollisionObject();
 | ||
|  | 			btVector3 collisionObjectAabbMin,collisionObjectAabbMax; | ||
|  | 			collisionObject->getCollisionShape()->getAabb(collisionObject->getWorldTransform(),collisionObjectAabbMin,collisionObjectAabbMax); | ||
|  | 			AabbExpand (collisionObjectAabbMin, collisionObjectAabbMax, castShapeAabbMin, castShapeAabbMax); | ||
|  | 			btScalar hitLambda = btScalar(1.); //could use resultCallback.m_closestHitFraction, but needs testing
 | ||
|  | 			btVector3 hitNormal; | ||
|  | 			if (btRayAabb(convexFromWorld.getOrigin(),convexToWorld.getOrigin(),collisionObjectAabbMin,collisionObjectAabbMax,hitLambda,hitNormal)) | ||
|  | 			{ | ||
|  | 				objectQuerySingle(castShape, convexFromTrans,convexToTrans, | ||
|  | 					collisionObject, | ||
|  | 					collisionObject->getCollisionShape(), | ||
|  | 					collisionObject->getWorldTransform(), | ||
|  | 					resultCallback, | ||
|  | 					allowedCcdPenetration); | ||
|  | 			} | ||
|  | 		} | ||
|  | 	} | ||
|  | #endif //USE_BRUTEFORCE_RAYBROADPHASE
 | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | struct btBridgedManifoldResult : public btManifoldResult | ||
|  | { | ||
|  | 
 | ||
|  | 	btCollisionWorld::ContactResultCallback&	m_resultCallback; | ||
|  | 
 | ||
|  | 	btBridgedManifoldResult( const btCollisionObjectWrapper* obj0Wrap,const btCollisionObjectWrapper* obj1Wrap,btCollisionWorld::ContactResultCallback& resultCallback ) | ||
|  | 		:btManifoldResult(obj0Wrap,obj1Wrap), | ||
|  | 		m_resultCallback(resultCallback) | ||
|  | 	{ | ||
|  | 	} | ||
|  | 
 | ||
|  | 	virtual void addContactPoint(const btVector3& normalOnBInWorld,const btVector3& pointInWorld,btScalar depth) | ||
|  | 	{ | ||
|  | 		bool isSwapped = m_manifoldPtr->getBody0() != m_body0Wrap->getCollisionObject(); | ||
|  | 		btVector3 pointA = pointInWorld + normalOnBInWorld * depth; | ||
|  | 		btVector3 localA; | ||
|  | 		btVector3 localB; | ||
|  | 		if (isSwapped) | ||
|  | 		{ | ||
|  | 			localA = m_body1Wrap->getCollisionObject()->getWorldTransform().invXform(pointA ); | ||
|  | 			localB = m_body0Wrap->getCollisionObject()->getWorldTransform().invXform(pointInWorld); | ||
|  | 		} else | ||
|  | 		{ | ||
|  | 			localA = m_body0Wrap->getCollisionObject()->getWorldTransform().invXform(pointA ); | ||
|  | 			localB = m_body1Wrap->getCollisionObject()->getWorldTransform().invXform(pointInWorld); | ||
|  | 		} | ||
|  | 		 | ||
|  | 		btManifoldPoint newPt(localA,localB,normalOnBInWorld,depth); | ||
|  | 		newPt.m_positionWorldOnA = pointA; | ||
|  | 		newPt.m_positionWorldOnB = pointInWorld; | ||
|  | 		 | ||
|  | 	   //BP mod, store contact triangles.
 | ||
|  | 		if (isSwapped) | ||
|  | 		{ | ||
|  | 			newPt.m_partId0 = m_partId1; | ||
|  | 			newPt.m_partId1 = m_partId0; | ||
|  | 			newPt.m_index0  = m_index1; | ||
|  | 			newPt.m_index1  = m_index0; | ||
|  | 		} else | ||
|  | 		{ | ||
|  | 			newPt.m_partId0 = m_partId0; | ||
|  | 			newPt.m_partId1 = m_partId1; | ||
|  | 			newPt.m_index0  = m_index0; | ||
|  | 			newPt.m_index1  = m_index1; | ||
|  | 		} | ||
|  | 
 | ||
|  | 		//experimental feature info, for per-triangle material etc.
 | ||
|  | 		const btCollisionObjectWrapper* obj0Wrap = isSwapped? m_body1Wrap : m_body0Wrap; | ||
|  | 		const btCollisionObjectWrapper* obj1Wrap = isSwapped? m_body0Wrap : m_body1Wrap; | ||
|  | 		m_resultCallback.addSingleResult(newPt,obj0Wrap,newPt.m_partId0,newPt.m_index0,obj1Wrap,newPt.m_partId1,newPt.m_index1); | ||
|  | 
 | ||
|  | 	} | ||
|  | 	 | ||
|  | }; | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | struct btSingleContactCallback : public btBroadphaseAabbCallback | ||
|  | { | ||
|  | 
 | ||
|  | 	btCollisionObject* m_collisionObject; | ||
|  | 	btCollisionWorld*	m_world; | ||
|  | 	btCollisionWorld::ContactResultCallback&	m_resultCallback; | ||
|  | 	 | ||
|  | 	 | ||
|  | 	btSingleContactCallback(btCollisionObject* collisionObject, btCollisionWorld* world,btCollisionWorld::ContactResultCallback& resultCallback) | ||
|  | 		:m_collisionObject(collisionObject), | ||
|  | 		m_world(world), | ||
|  | 		m_resultCallback(resultCallback) | ||
|  | 	{ | ||
|  | 	} | ||
|  | 
 | ||
|  | 	virtual bool	process(const btBroadphaseProxy* proxy) | ||
|  | 	{ | ||
|  | 		btCollisionObject*	collisionObject = (btCollisionObject*)proxy->m_clientObject; | ||
|  | 		if (collisionObject == m_collisionObject) | ||
|  | 			return true; | ||
|  | 
 | ||
|  | 		//only perform raycast if filterMask matches
 | ||
|  | 		if(m_resultCallback.needsCollision(collisionObject->getBroadphaseHandle()))  | ||
|  | 		{ | ||
|  | 			btCollisionObjectWrapper ob0(0,m_collisionObject->getCollisionShape(),m_collisionObject,m_collisionObject->getWorldTransform(),-1,-1); | ||
|  | 			btCollisionObjectWrapper ob1(0,collisionObject->getCollisionShape(),collisionObject,collisionObject->getWorldTransform(),-1,-1); | ||
|  | 
 | ||
|  | 			btCollisionAlgorithm* algorithm = m_world->getDispatcher()->findAlgorithm(&ob0,&ob1,0, BT_CLOSEST_POINT_ALGORITHMS); | ||
|  | 			if (algorithm) | ||
|  | 			{ | ||
|  | 				btBridgedManifoldResult contactPointResult(&ob0,&ob1, m_resultCallback); | ||
|  | 				//discrete collision detection query
 | ||
|  | 				 | ||
|  | 				algorithm->processCollision(&ob0,&ob1, m_world->getDispatchInfo(),&contactPointResult); | ||
|  | 
 | ||
|  | 				algorithm->~btCollisionAlgorithm(); | ||
|  | 				m_world->getDispatcher()->freeCollisionAlgorithm(algorithm); | ||
|  | 			} | ||
|  | 		} | ||
|  | 		return true; | ||
|  | 	} | ||
|  | }; | ||
|  | 
 | ||
|  | 
 | ||
|  | ///contactTest performs a discrete collision test against all objects in the btCollisionWorld, and calls the resultCallback.
 | ||
|  | ///it reports one or more contact points for every overlapping object (including the one with deepest penetration)
 | ||
|  | void	btCollisionWorld::contactTest( btCollisionObject* colObj, ContactResultCallback& resultCallback) | ||
|  | { | ||
|  | 	btVector3 aabbMin,aabbMax; | ||
|  | 	colObj->getCollisionShape()->getAabb(colObj->getWorldTransform(),aabbMin,aabbMax); | ||
|  | 	btSingleContactCallback	contactCB(colObj,this,resultCallback); | ||
|  | 	 | ||
|  | 	m_broadphasePairCache->aabbTest(aabbMin,aabbMax,contactCB); | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | ///contactTest performs a discrete collision test between two collision objects and calls the resultCallback if overlap if detected.
 | ||
|  | ///it reports one or more contact points (including the one with deepest penetration)
 | ||
|  | void	btCollisionWorld::contactPairTest(btCollisionObject* colObjA, btCollisionObject* colObjB, ContactResultCallback& resultCallback) | ||
|  | { | ||
|  | 	btCollisionObjectWrapper obA(0,colObjA->getCollisionShape(),colObjA,colObjA->getWorldTransform(),-1,-1); | ||
|  | 	btCollisionObjectWrapper obB(0,colObjB->getCollisionShape(),colObjB,colObjB->getWorldTransform(),-1,-1); | ||
|  | 
 | ||
|  | 	btCollisionAlgorithm* algorithm = getDispatcher()->findAlgorithm(&obA,&obB, 0, BT_CLOSEST_POINT_ALGORITHMS); | ||
|  | 	if (algorithm) | ||
|  | 	{ | ||
|  | 		btBridgedManifoldResult contactPointResult(&obA,&obB, resultCallback); | ||
|  | 		contactPointResult.m_closestPointDistanceThreshold = resultCallback.m_closestDistanceThreshold; | ||
|  | 		//discrete collision detection query
 | ||
|  | 		algorithm->processCollision(&obA,&obB, getDispatchInfo(),&contactPointResult); | ||
|  | 
 | ||
|  | 		algorithm->~btCollisionAlgorithm(); | ||
|  | 		getDispatcher()->freeCollisionAlgorithm(algorithm); | ||
|  | 	} | ||
|  | 
 | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | class DebugDrawcallback : public btTriangleCallback, public btInternalTriangleIndexCallback | ||
|  | { | ||
|  | 	btIDebugDraw*	m_debugDrawer; | ||
|  | 	btVector3	m_color; | ||
|  | 	btTransform	m_worldTrans; | ||
|  | 
 | ||
|  | public: | ||
|  | 
 | ||
|  | 	DebugDrawcallback(btIDebugDraw*	debugDrawer,const btTransform& worldTrans,const btVector3& color) : | ||
|  | 	  m_debugDrawer(debugDrawer), | ||
|  | 		  m_color(color), | ||
|  | 		  m_worldTrans(worldTrans) | ||
|  | 	  { | ||
|  | 	  } | ||
|  | 
 | ||
|  | 	  virtual void internalProcessTriangleIndex(btVector3* triangle,int partId,int  triangleIndex) | ||
|  | 	  { | ||
|  | 		  processTriangle(triangle,partId,triangleIndex); | ||
|  | 	  } | ||
|  | 
 | ||
|  | 	  virtual void processTriangle(btVector3* triangle,int partId, int triangleIndex) | ||
|  | 	  { | ||
|  | 		  (void)partId; | ||
|  | 		  (void)triangleIndex; | ||
|  | 
 | ||
|  | 		  btVector3 wv0,wv1,wv2; | ||
|  | 		  wv0 = m_worldTrans*triangle[0]; | ||
|  | 		  wv1 = m_worldTrans*triangle[1]; | ||
|  | 		  wv2 = m_worldTrans*triangle[2]; | ||
|  | 		  btVector3 center = (wv0+wv1+wv2)*btScalar(1./3.); | ||
|  |            | ||
|  |           if (m_debugDrawer->getDebugMode() & btIDebugDraw::DBG_DrawNormals ) | ||
|  |           { | ||
|  | 		    btVector3 normal = (wv1-wv0).cross(wv2-wv0); | ||
|  | 		    normal.normalize(); | ||
|  | 		    btVector3 normalColor(1,1,0); | ||
|  | 		    m_debugDrawer->drawLine(center,center+normal,normalColor); | ||
|  |           } | ||
|  | 		  m_debugDrawer->drawLine(wv0,wv1,m_color); | ||
|  | 		  m_debugDrawer->drawLine(wv1,wv2,m_color); | ||
|  | 		  m_debugDrawer->drawLine(wv2,wv0,m_color); | ||
|  | 	  } | ||
|  | }; | ||
|  | 
 | ||
|  | 
 | ||
|  | void btCollisionWorld::debugDrawObject(const btTransform& worldTransform, const btCollisionShape* shape, const btVector3& color) | ||
|  | { | ||
|  | 	// Draw a small simplex at the center of the object
 | ||
|  | 	if (getDebugDrawer() && getDebugDrawer()->getDebugMode() & btIDebugDraw::DBG_DrawFrames) | ||
|  | 	{ | ||
|  | 		getDebugDrawer()->drawTransform(worldTransform,.1); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	if (shape->getShapeType() == COMPOUND_SHAPE_PROXYTYPE) | ||
|  | 	{ | ||
|  | 		const btCompoundShape* compoundShape = static_cast<const btCompoundShape*>(shape); | ||
|  | 		for (int i=compoundShape->getNumChildShapes()-1;i>=0;i--) | ||
|  | 		{ | ||
|  | 			btTransform childTrans = compoundShape->getChildTransform(i); | ||
|  | 			const btCollisionShape* colShape = compoundShape->getChildShape(i); | ||
|  | 			debugDrawObject(worldTransform*childTrans,colShape,color); | ||
|  | 		} | ||
|  | 
 | ||
|  | 	} else | ||
|  | 	{ | ||
|  | 
 | ||
|  |         switch (shape->getShapeType()) | ||
|  |         { | ||
|  | 
 | ||
|  |         case BOX_SHAPE_PROXYTYPE: | ||
|  |             { | ||
|  |                 const btBoxShape* boxShape = static_cast<const btBoxShape*>(shape); | ||
|  |                 btVector3 halfExtents = boxShape->getHalfExtentsWithMargin(); | ||
|  |                 getDebugDrawer()->drawBox(-halfExtents,halfExtents,worldTransform,color); | ||
|  |                 break; | ||
|  |             } | ||
|  | 
 | ||
|  |         case SPHERE_SHAPE_PROXYTYPE: | ||
|  |             { | ||
|  |                 const btSphereShape* sphereShape = static_cast<const btSphereShape*>(shape); | ||
|  |                 btScalar radius = sphereShape->getMargin();//radius doesn't include the margin, so draw with margin
 | ||
|  | 
 | ||
|  |                 getDebugDrawer()->drawSphere(radius, worldTransform, color); | ||
|  |                 break; | ||
|  |             } | ||
|  |         case MULTI_SPHERE_SHAPE_PROXYTYPE: | ||
|  |             { | ||
|  |                 const btMultiSphereShape* multiSphereShape = static_cast<const btMultiSphereShape*>(shape); | ||
|  | 
 | ||
|  |                 btTransform childTransform; | ||
|  |                 childTransform.setIdentity(); | ||
|  | 
 | ||
|  |                 for (int i = multiSphereShape->getSphereCount()-1; i>=0;i--) | ||
|  |                 { | ||
|  |                     childTransform.setOrigin(multiSphereShape->getSpherePosition(i)); | ||
|  |                     getDebugDrawer()->drawSphere(multiSphereShape->getSphereRadius(i), worldTransform*childTransform, color); | ||
|  |                 } | ||
|  | 
 | ||
|  |                 break; | ||
|  |             } | ||
|  |         case CAPSULE_SHAPE_PROXYTYPE: | ||
|  |             { | ||
|  |                 const btCapsuleShape* capsuleShape = static_cast<const btCapsuleShape*>(shape); | ||
|  | 
 | ||
|  |                 btScalar radius = capsuleShape->getRadius(); | ||
|  |                 btScalar halfHeight = capsuleShape->getHalfHeight(); | ||
|  | 
 | ||
|  |                 int upAxis = capsuleShape->getUpAxis(); | ||
|  |                 getDebugDrawer()->drawCapsule(radius, halfHeight, upAxis, worldTransform, color); | ||
|  |                 break; | ||
|  |             } | ||
|  |         case CONE_SHAPE_PROXYTYPE: | ||
|  |             { | ||
|  |                 const btConeShape* coneShape = static_cast<const btConeShape*>(shape); | ||
|  |                 btScalar radius = coneShape->getRadius();//+coneShape->getMargin();
 | ||
|  |                 btScalar height = coneShape->getHeight();//+coneShape->getMargin();
 | ||
|  | 
 | ||
|  |                 int upAxis= coneShape->getConeUpIndex(); | ||
|  |                 getDebugDrawer()->drawCone(radius, height, upAxis, worldTransform, color); | ||
|  |                 break; | ||
|  | 
 | ||
|  |             } | ||
|  |         case CYLINDER_SHAPE_PROXYTYPE: | ||
|  |             { | ||
|  |                 const btCylinderShape* cylinder = static_cast<const btCylinderShape*>(shape); | ||
|  |                 int upAxis = cylinder->getUpAxis(); | ||
|  |                 btScalar radius = cylinder->getRadius(); | ||
|  |                 btScalar halfHeight = cylinder->getHalfExtentsWithMargin()[upAxis]; | ||
|  |                 getDebugDrawer()->drawCylinder(radius, halfHeight, upAxis, worldTransform, color); | ||
|  |                 break; | ||
|  |             } | ||
|  | 
 | ||
|  |         case STATIC_PLANE_PROXYTYPE: | ||
|  |             { | ||
|  |                 const btStaticPlaneShape* staticPlaneShape = static_cast<const btStaticPlaneShape*>(shape); | ||
|  |                 btScalar planeConst = staticPlaneShape->getPlaneConstant(); | ||
|  |                 const btVector3& planeNormal = staticPlaneShape->getPlaneNormal(); | ||
|  |                 getDebugDrawer()->drawPlane(planeNormal, planeConst,worldTransform, color); | ||
|  |                 break; | ||
|  | 
 | ||
|  |             } | ||
|  |         default: | ||
|  |             { | ||
|  | 
 | ||
|  |                 /// for polyhedral shapes
 | ||
|  |                 if (shape->isPolyhedral()) | ||
|  |                 { | ||
|  |                     btPolyhedralConvexShape* polyshape = (btPolyhedralConvexShape*) shape; | ||
|  |                      | ||
|  |                     int i; | ||
|  |                     if (polyshape->getConvexPolyhedron()) | ||
|  |                     { | ||
|  |                         const btConvexPolyhedron* poly = polyshape->getConvexPolyhedron(); | ||
|  |                         for (i=0;i<poly->m_faces.size();i++) | ||
|  |                         { | ||
|  |                             btVector3 centroid(0,0,0); | ||
|  |                             int numVerts = poly->m_faces[i].m_indices.size(); | ||
|  |                             if (numVerts) | ||
|  |                             { | ||
|  |                                 int lastV = poly->m_faces[i].m_indices[numVerts-1]; | ||
|  |                                 for (int v=0;v<poly->m_faces[i].m_indices.size();v++) | ||
|  |                                 { | ||
|  |                                     int curVert = poly->m_faces[i].m_indices[v]; | ||
|  |                                     centroid+=poly->m_vertices[curVert]; | ||
|  |                                     getDebugDrawer()->drawLine(worldTransform*poly->m_vertices[lastV],worldTransform*poly->m_vertices[curVert],color); | ||
|  |                                     lastV = curVert; | ||
|  |                                 } | ||
|  |                             } | ||
|  |                             centroid*= btScalar(1.f)/btScalar(numVerts); | ||
|  |                             if (getDebugDrawer()->getDebugMode() & btIDebugDraw::DBG_DrawNormals) | ||
|  |                             { | ||
|  |                                 btVector3 normalColor(1,1,0); | ||
|  |                                 btVector3 faceNormal(poly->m_faces[i].m_plane[0],poly->m_faces[i].m_plane[1],poly->m_faces[i].m_plane[2]); | ||
|  |                                 getDebugDrawer()->drawLine(worldTransform*centroid,worldTransform*(centroid+faceNormal),normalColor); | ||
|  |                             } | ||
|  |                              | ||
|  |                         } | ||
|  |                          | ||
|  |                          | ||
|  |                     } else | ||
|  |                     { | ||
|  |                         for (i=0;i<polyshape->getNumEdges();i++) | ||
|  |                         { | ||
|  |                             btVector3 a,b; | ||
|  |                             polyshape->getEdge(i,a,b); | ||
|  |                             btVector3 wa = worldTransform * a; | ||
|  |                             btVector3 wb = worldTransform * b; | ||
|  |                             getDebugDrawer()->drawLine(wa,wb,color); | ||
|  |                         } | ||
|  |                     } | ||
|  |                      | ||
|  |                      | ||
|  |                 } | ||
|  |                      | ||
|  |                 if (shape->isConcave()) | ||
|  |                 { | ||
|  |                     btConcaveShape* concaveMesh = (btConcaveShape*) shape; | ||
|  | 
 | ||
|  |                     ///@todo pass camera, for some culling? no -> we are not a graphics lib
 | ||
|  |                     btVector3 aabbMax(btScalar(BT_LARGE_FLOAT),btScalar(BT_LARGE_FLOAT),btScalar(BT_LARGE_FLOAT)); | ||
|  |                     btVector3 aabbMin(btScalar(-BT_LARGE_FLOAT),btScalar(-BT_LARGE_FLOAT),btScalar(-BT_LARGE_FLOAT)); | ||
|  | 
 | ||
|  |                     DebugDrawcallback drawCallback(getDebugDrawer(),worldTransform,color); | ||
|  |                     concaveMesh->processAllTriangles(&drawCallback,aabbMin,aabbMax); | ||
|  | 
 | ||
|  |                 } | ||
|  | 
 | ||
|  |                 if (shape->getShapeType() == CONVEX_TRIANGLEMESH_SHAPE_PROXYTYPE) | ||
|  |                 { | ||
|  |                     btConvexTriangleMeshShape* convexMesh = (btConvexTriangleMeshShape*) shape; | ||
|  |                     //todo: pass camera for some culling			
 | ||
|  |                     btVector3 aabbMax(btScalar(BT_LARGE_FLOAT),btScalar(BT_LARGE_FLOAT),btScalar(BT_LARGE_FLOAT)); | ||
|  |                     btVector3 aabbMin(btScalar(-BT_LARGE_FLOAT),btScalar(-BT_LARGE_FLOAT),btScalar(-BT_LARGE_FLOAT)); | ||
|  |                     //DebugDrawcallback drawCallback;
 | ||
|  |                     DebugDrawcallback drawCallback(getDebugDrawer(),worldTransform,color); | ||
|  |                     convexMesh->getMeshInterface()->InternalProcessAllTriangles(&drawCallback,aabbMin,aabbMax); | ||
|  |                 } | ||
|  | 
 | ||
|  | 
 | ||
|  |                  | ||
|  |             } | ||
|  |         | ||
|  | 		} | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | void	btCollisionWorld::debugDrawWorld() | ||
|  | { | ||
|  | 	if (getDebugDrawer()) | ||
|  | 	{ | ||
|  | 		getDebugDrawer()->clearLines(); | ||
|  | 
 | ||
|  | 		btIDebugDraw::DefaultColors defaultColors = getDebugDrawer()->getDefaultColors(); | ||
|  | 
 | ||
|  | 		if ( getDebugDrawer()->getDebugMode() & btIDebugDraw::DBG_DrawContactPoints) | ||
|  | 		{ | ||
|  | 		 | ||
|  | 
 | ||
|  | 			if (getDispatcher()) | ||
|  | 			{ | ||
|  | 				int numManifolds = getDispatcher()->getNumManifolds(); | ||
|  | 			 | ||
|  | 				for (int i=0;i<numManifolds;i++) | ||
|  | 				{ | ||
|  | 					btPersistentManifold* contactManifold = getDispatcher()->getManifoldByIndexInternal(i); | ||
|  | 					//btCollisionObject* obA = static_cast<btCollisionObject*>(contactManifold->getBody0());
 | ||
|  | 					//btCollisionObject* obB = static_cast<btCollisionObject*>(contactManifold->getBody1());
 | ||
|  | 
 | ||
|  | 					int numContacts = contactManifold->getNumContacts(); | ||
|  | 					for (int j=0;j<numContacts;j++) | ||
|  | 					{ | ||
|  | 						btManifoldPoint& cp = contactManifold->getContactPoint(j); | ||
|  | 						getDebugDrawer()->drawContactPoint(cp.m_positionWorldOnB,cp.m_normalWorldOnB,cp.getDistance(),cp.getLifeTime(),defaultColors.m_contactPoint); | ||
|  | 					} | ||
|  | 				} | ||
|  | 			} | ||
|  | 		} | ||
|  | 
 | ||
|  | 		if ((getDebugDrawer()->getDebugMode() & (btIDebugDraw::DBG_DrawWireframe | btIDebugDraw::DBG_DrawAabb))) | ||
|  | 		{ | ||
|  | 			int i; | ||
|  | 
 | ||
|  | 			for (  i=0;i<m_collisionObjects.size();i++) | ||
|  | 			{ | ||
|  | 				btCollisionObject* colObj = m_collisionObjects[i]; | ||
|  | 				if ((colObj->getCollisionFlags() & btCollisionObject::CF_DISABLE_VISUALIZE_OBJECT)==0) | ||
|  | 				{ | ||
|  | 					if (getDebugDrawer() && (getDebugDrawer()->getDebugMode() & btIDebugDraw::DBG_DrawWireframe)) | ||
|  | 					{ | ||
|  | 						btVector3 color(btScalar(0.4),btScalar(0.4),btScalar(0.4)); | ||
|  | 
 | ||
|  | 						switch(colObj->getActivationState()) | ||
|  | 						{ | ||
|  | 						case  ACTIVE_TAG: | ||
|  | 							color = defaultColors.m_activeObject; break; | ||
|  | 						case ISLAND_SLEEPING: | ||
|  | 							color =  defaultColors.m_deactivatedObject;break; | ||
|  | 						case WANTS_DEACTIVATION: | ||
|  | 							color = defaultColors.m_wantsDeactivationObject;break; | ||
|  | 						case DISABLE_DEACTIVATION: | ||
|  | 							color = defaultColors.m_disabledDeactivationObject;break; | ||
|  | 						case DISABLE_SIMULATION: | ||
|  | 							color = defaultColors.m_disabledSimulationObject;break; | ||
|  | 						default: | ||
|  | 							{ | ||
|  | 								color = btVector3(btScalar(.3),btScalar(0.3),btScalar(0.3)); | ||
|  | 							} | ||
|  | 						}; | ||
|  | 
 | ||
|  | 						colObj->getCustomDebugColor(color); | ||
|  | 
 | ||
|  | 						debugDrawObject(colObj->getWorldTransform(),colObj->getCollisionShape(),color); | ||
|  | 					} | ||
|  | 					if (m_debugDrawer && (m_debugDrawer->getDebugMode() & btIDebugDraw::DBG_DrawAabb)) | ||
|  | 					{ | ||
|  | 						btVector3 minAabb,maxAabb; | ||
|  | 						btVector3 colorvec = defaultColors.m_aabb; | ||
|  | 						colObj->getCollisionShape()->getAabb(colObj->getWorldTransform(), minAabb,maxAabb); | ||
|  | 						btVector3 contactThreshold(gContactBreakingThreshold,gContactBreakingThreshold,gContactBreakingThreshold); | ||
|  | 						minAabb -= contactThreshold; | ||
|  | 						maxAabb += contactThreshold; | ||
|  | 
 | ||
|  | 						btVector3 minAabb2,maxAabb2; | ||
|  | 
 | ||
|  | 						if(getDispatchInfo().m_useContinuous && colObj->getInternalType()==btCollisionObject::CO_RIGID_BODY && !colObj->isStaticOrKinematicObject()) | ||
|  | 						{ | ||
|  | 							colObj->getCollisionShape()->getAabb(colObj->getInterpolationWorldTransform(),minAabb2,maxAabb2); | ||
|  | 							minAabb2 -= contactThreshold; | ||
|  | 							maxAabb2 += contactThreshold; | ||
|  | 							minAabb.setMin(minAabb2); | ||
|  | 							maxAabb.setMax(maxAabb2); | ||
|  | 						} | ||
|  | 
 | ||
|  | 						m_debugDrawer->drawAabb(minAabb,maxAabb,colorvec); | ||
|  | 					} | ||
|  | 				} | ||
|  | 			} | ||
|  | 		} | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | void	btCollisionWorld::serializeCollisionObjects(btSerializer* serializer) | ||
|  | { | ||
|  | 	int i; | ||
|  | 
 | ||
|  | 	///keep track of shapes already serialized
 | ||
|  | 	btHashMap<btHashPtr,btCollisionShape*>	serializedShapes; | ||
|  | 
 | ||
|  | 	for (i=0;i<m_collisionObjects.size();i++) | ||
|  | 	{ | ||
|  | 		btCollisionObject* colObj = m_collisionObjects[i]; | ||
|  | 		btCollisionShape* shape = colObj->getCollisionShape(); | ||
|  | 
 | ||
|  | 		if (!serializedShapes.find(shape)) | ||
|  | 		{ | ||
|  | 			serializedShapes.insert(shape,shape); | ||
|  | 			shape->serializeSingleShape(serializer); | ||
|  | 		} | ||
|  | 	} | ||
|  | 
 | ||
|  | 	//serialize all collision objects
 | ||
|  | 	for (i=0;i<m_collisionObjects.size();i++) | ||
|  | 	{ | ||
|  | 		btCollisionObject* colObj = m_collisionObjects[i]; | ||
|  | 		if ((colObj->getInternalType() == btCollisionObject::CO_COLLISION_OBJECT) || (colObj->getInternalType() == btCollisionObject::CO_FEATHERSTONE_LINK)) | ||
|  | 		{ | ||
|  | 			colObj->serializeSingleObject(serializer); | ||
|  | 		} | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | void	btCollisionWorld::serialize(btSerializer* serializer) | ||
|  | { | ||
|  | 
 | ||
|  | 	serializer->startSerialization(); | ||
|  | 	 | ||
|  | 	serializeCollisionObjects(serializer); | ||
|  | 	 | ||
|  | 	serializer->finishSerialization(); | ||
|  | } | ||
|  | 
 |