309 lines
		
	
	
		
			8.8 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
		
		
			
		
	
	
			309 lines
		
	
	
		
			8.8 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 "btPersistentManifold.h"
 | ||
|  | #include "LinearMath/btTransform.h"
 | ||
|  | 
 | ||
|  | 
 | ||
|  | btScalar					gContactBreakingThreshold = btScalar(0.02); | ||
|  | ContactDestroyedCallback	gContactDestroyedCallback = 0; | ||
|  | ContactProcessedCallback	gContactProcessedCallback = 0; | ||
|  | ContactStartedCallback		gContactStartedCallback = 0; | ||
|  | ContactEndedCallback		gContactEndedCallback = 0; | ||
|  | ///gContactCalcArea3Points will approximate the convex hull area using 3 points
 | ||
|  | ///when setting it to false, it will use 4 points to compute the area: it is more accurate but slower
 | ||
|  | bool						gContactCalcArea3Points = true; | ||
|  | 
 | ||
|  | 
 | ||
|  | btPersistentManifold::btPersistentManifold() | ||
|  | :btTypedObject(BT_PERSISTENT_MANIFOLD_TYPE), | ||
|  | m_body0(0), | ||
|  | m_body1(0), | ||
|  | m_cachedPoints (0), | ||
|  | m_index1a(0) | ||
|  | { | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | #ifdef DEBUG_PERSISTENCY
 | ||
|  | #include <stdio.h>
 | ||
|  | void	btPersistentManifold::DebugPersistency() | ||
|  | { | ||
|  | 	int i; | ||
|  | 	printf("DebugPersistency : numPoints %d\n",m_cachedPoints); | ||
|  | 	for (i=0;i<m_cachedPoints;i++) | ||
|  | 	{ | ||
|  | 		printf("m_pointCache[%d].m_userPersistentData = %x\n",i,m_pointCache[i].m_userPersistentData); | ||
|  | 	} | ||
|  | } | ||
|  | #endif //DEBUG_PERSISTENCY
 | ||
|  | 
 | ||
|  | void btPersistentManifold::clearUserCache(btManifoldPoint& pt) | ||
|  | { | ||
|  | 
 | ||
|  | 	void* oldPtr = pt.m_userPersistentData; | ||
|  | 	if (oldPtr) | ||
|  | 	{ | ||
|  | #ifdef DEBUG_PERSISTENCY
 | ||
|  | 		int i; | ||
|  | 		int occurance = 0; | ||
|  | 		for (i=0;i<m_cachedPoints;i++) | ||
|  | 		{ | ||
|  | 			if (m_pointCache[i].m_userPersistentData == oldPtr) | ||
|  | 			{ | ||
|  | 				occurance++; | ||
|  | 				if (occurance>1) | ||
|  | 					printf("error in clearUserCache\n"); | ||
|  | 			} | ||
|  | 		} | ||
|  | 		btAssert(occurance<=0); | ||
|  | #endif //DEBUG_PERSISTENCY
 | ||
|  | 
 | ||
|  | 		if (pt.m_userPersistentData && gContactDestroyedCallback) | ||
|  | 		{ | ||
|  | 			(*gContactDestroyedCallback)(pt.m_userPersistentData); | ||
|  | 			pt.m_userPersistentData = 0; | ||
|  | 		} | ||
|  | 		 | ||
|  | #ifdef DEBUG_PERSISTENCY
 | ||
|  | 		DebugPersistency(); | ||
|  | #endif
 | ||
|  | 	} | ||
|  | 
 | ||
|  | 	 | ||
|  | } | ||
|  | 
 | ||
|  | static inline btScalar calcArea4Points(const btVector3 &p0,const btVector3 &p1,const btVector3 &p2,const btVector3 &p3) | ||
|  | { | ||
|  | 	// It calculates possible 3 area constructed from random 4 points and returns the biggest one.
 | ||
|  | 
 | ||
|  | 	btVector3 a[3],b[3]; | ||
|  | 	a[0] = p0 - p1; | ||
|  | 	a[1] = p0 - p2; | ||
|  | 	a[2] = p0 - p3; | ||
|  | 	b[0] = p2 - p3; | ||
|  | 	b[1] = p1 - p3; | ||
|  | 	b[2] = p1 - p2; | ||
|  | 
 | ||
|  | 	//todo: Following 3 cross production can be easily optimized by SIMD.
 | ||
|  | 	btVector3 tmp0 = a[0].cross(b[0]); | ||
|  | 	btVector3 tmp1 = a[1].cross(b[1]); | ||
|  | 	btVector3 tmp2 = a[2].cross(b[2]); | ||
|  | 
 | ||
|  | 	return btMax(btMax(tmp0.length2(),tmp1.length2()),tmp2.length2()); | ||
|  | } | ||
|  | 
 | ||
|  | int btPersistentManifold::sortCachedPoints(const btManifoldPoint& pt)  | ||
|  | { | ||
|  | 		//calculate 4 possible cases areas, and take biggest area
 | ||
|  | 		//also need to keep 'deepest'
 | ||
|  | 		 | ||
|  | 		int maxPenetrationIndex = -1; | ||
|  | #define KEEP_DEEPEST_POINT 1
 | ||
|  | #ifdef KEEP_DEEPEST_POINT
 | ||
|  | 		btScalar maxPenetration = pt.getDistance(); | ||
|  | 		for (int i=0;i<4;i++) | ||
|  | 		{ | ||
|  | 			if (m_pointCache[i].getDistance() < maxPenetration) | ||
|  | 			{ | ||
|  | 				maxPenetrationIndex = i; | ||
|  | 				maxPenetration = m_pointCache[i].getDistance(); | ||
|  | 			} | ||
|  | 		} | ||
|  | #endif //KEEP_DEEPEST_POINT
 | ||
|  | 		 | ||
|  | 		btScalar res0(btScalar(0.)),res1(btScalar(0.)),res2(btScalar(0.)),res3(btScalar(0.)); | ||
|  | 
 | ||
|  | 	if (gContactCalcArea3Points) | ||
|  | 	{ | ||
|  | 		if (maxPenetrationIndex != 0) | ||
|  | 		{ | ||
|  | 			btVector3 a0 = pt.m_localPointA-m_pointCache[1].m_localPointA; | ||
|  | 			btVector3 b0 = m_pointCache[3].m_localPointA-m_pointCache[2].m_localPointA; | ||
|  | 			btVector3 cross = a0.cross(b0); | ||
|  | 			res0 = cross.length2(); | ||
|  | 		} | ||
|  | 		if (maxPenetrationIndex != 1) | ||
|  | 		{ | ||
|  | 			btVector3 a1 = pt.m_localPointA-m_pointCache[0].m_localPointA; | ||
|  | 			btVector3 b1 = m_pointCache[3].m_localPointA-m_pointCache[2].m_localPointA; | ||
|  | 			btVector3 cross = a1.cross(b1); | ||
|  | 			res1 = cross.length2(); | ||
|  | 		} | ||
|  | 
 | ||
|  | 		if (maxPenetrationIndex != 2) | ||
|  | 		{ | ||
|  | 			btVector3 a2 = pt.m_localPointA-m_pointCache[0].m_localPointA; | ||
|  | 			btVector3 b2 = m_pointCache[3].m_localPointA-m_pointCache[1].m_localPointA; | ||
|  | 			btVector3 cross = a2.cross(b2); | ||
|  | 			res2 = cross.length2(); | ||
|  | 		} | ||
|  | 
 | ||
|  | 		if (maxPenetrationIndex != 3) | ||
|  | 		{ | ||
|  | 			btVector3 a3 = pt.m_localPointA-m_pointCache[0].m_localPointA; | ||
|  | 			btVector3 b3 = m_pointCache[2].m_localPointA-m_pointCache[1].m_localPointA; | ||
|  | 			btVector3 cross = a3.cross(b3); | ||
|  | 			res3 = cross.length2(); | ||
|  | 		} | ||
|  | 	}  | ||
|  | 	else | ||
|  | 	{ | ||
|  | 		if(maxPenetrationIndex != 0) { | ||
|  | 			res0 = calcArea4Points(pt.m_localPointA,m_pointCache[1].m_localPointA,m_pointCache[2].m_localPointA,m_pointCache[3].m_localPointA); | ||
|  | 		} | ||
|  | 
 | ||
|  | 		if(maxPenetrationIndex != 1) { | ||
|  | 			res1 = calcArea4Points(pt.m_localPointA,m_pointCache[0].m_localPointA,m_pointCache[2].m_localPointA,m_pointCache[3].m_localPointA); | ||
|  | 		} | ||
|  | 
 | ||
|  | 		if(maxPenetrationIndex != 2) { | ||
|  | 			res2 = calcArea4Points(pt.m_localPointA,m_pointCache[0].m_localPointA,m_pointCache[1].m_localPointA,m_pointCache[3].m_localPointA); | ||
|  | 		} | ||
|  | 
 | ||
|  | 		if(maxPenetrationIndex != 3) { | ||
|  | 			res3 = calcArea4Points(pt.m_localPointA,m_pointCache[0].m_localPointA,m_pointCache[1].m_localPointA,m_pointCache[2].m_localPointA); | ||
|  | 		} | ||
|  | 	} | ||
|  | 	btVector4 maxvec(res0,res1,res2,res3); | ||
|  | 	int biggestarea = maxvec.closestAxis4(); | ||
|  | 	return biggestarea; | ||
|  | 	 | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | int btPersistentManifold::getCacheEntry(const btManifoldPoint& newPoint) const | ||
|  | { | ||
|  | 	btScalar shortestDist =  getContactBreakingThreshold() * getContactBreakingThreshold(); | ||
|  | 	int size = getNumContacts(); | ||
|  | 	int nearestPoint = -1; | ||
|  | 	for( int i = 0; i < size; i++ ) | ||
|  | 	{ | ||
|  | 		const btManifoldPoint &mp = m_pointCache[i]; | ||
|  | 
 | ||
|  | 		btVector3 diffA =  mp.m_localPointA- newPoint.m_localPointA; | ||
|  | 		const btScalar distToManiPoint = diffA.dot(diffA); | ||
|  | 		if( distToManiPoint < shortestDist ) | ||
|  | 		{ | ||
|  | 			shortestDist = distToManiPoint; | ||
|  | 			nearestPoint = i; | ||
|  | 		} | ||
|  | 	} | ||
|  | 	return nearestPoint; | ||
|  | } | ||
|  | 
 | ||
|  | int btPersistentManifold::addManifoldPoint(const btManifoldPoint& newPoint, bool isPredictive) | ||
|  | { | ||
|  | 	if (!isPredictive) | ||
|  | 	{ | ||
|  | 		btAssert(validContactDistance(newPoint)); | ||
|  | 	} | ||
|  | 	 | ||
|  | 	int insertIndex = getNumContacts(); | ||
|  | 	if (insertIndex == MANIFOLD_CACHE_SIZE) | ||
|  | 	{ | ||
|  | #if MANIFOLD_CACHE_SIZE >= 4
 | ||
|  | 		//sort cache so best points come first, based on area
 | ||
|  | 		insertIndex = sortCachedPoints(newPoint); | ||
|  | #else
 | ||
|  | 		insertIndex = 0; | ||
|  | #endif
 | ||
|  | 		clearUserCache(m_pointCache[insertIndex]); | ||
|  | 		 | ||
|  | 	} else | ||
|  | 	{ | ||
|  | 		m_cachedPoints++; | ||
|  | 
 | ||
|  | 		 | ||
|  | 	} | ||
|  | 	if (insertIndex<0) | ||
|  | 		insertIndex=0; | ||
|  | 
 | ||
|  | 	btAssert(m_pointCache[insertIndex].m_userPersistentData==0); | ||
|  | 	m_pointCache[insertIndex] = newPoint; | ||
|  | 	return insertIndex; | ||
|  | } | ||
|  | 
 | ||
|  | btScalar	btPersistentManifold::getContactBreakingThreshold() const | ||
|  | { | ||
|  | 	return m_contactBreakingThreshold; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | void btPersistentManifold::refreshContactPoints(const btTransform& trA,const btTransform& trB) | ||
|  | { | ||
|  | 	int i; | ||
|  | #ifdef DEBUG_PERSISTENCY
 | ||
|  | 	printf("refreshContactPoints posA = (%f,%f,%f) posB = (%f,%f,%f)\n", | ||
|  | 		trA.getOrigin().getX(), | ||
|  | 		trA.getOrigin().getY(), | ||
|  | 		trA.getOrigin().getZ(), | ||
|  | 		trB.getOrigin().getX(), | ||
|  | 		trB.getOrigin().getY(), | ||
|  | 		trB.getOrigin().getZ()); | ||
|  | #endif //DEBUG_PERSISTENCY
 | ||
|  | 	/// first refresh worldspace positions and distance
 | ||
|  | 	for (i=getNumContacts()-1;i>=0;i--) | ||
|  | 	{ | ||
|  | 		btManifoldPoint &manifoldPoint = m_pointCache[i]; | ||
|  | 		manifoldPoint.m_positionWorldOnA = trA( manifoldPoint.m_localPointA ); | ||
|  | 		manifoldPoint.m_positionWorldOnB = trB( manifoldPoint.m_localPointB ); | ||
|  | 		manifoldPoint.m_distance1 = (manifoldPoint.m_positionWorldOnA -  manifoldPoint.m_positionWorldOnB).dot(manifoldPoint.m_normalWorldOnB); | ||
|  | 		manifoldPoint.m_lifeTime++; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	/// then 
 | ||
|  | 	btScalar distance2d; | ||
|  | 	btVector3 projectedDifference,projectedPoint; | ||
|  | 	for (i=getNumContacts()-1;i>=0;i--) | ||
|  | 	{ | ||
|  | 		 | ||
|  | 		btManifoldPoint &manifoldPoint = m_pointCache[i]; | ||
|  | 		//contact becomes invalid when signed distance exceeds margin (projected on contactnormal direction)
 | ||
|  | 		if (!validContactDistance(manifoldPoint)) | ||
|  | 		{ | ||
|  | 			removeContactPoint(i); | ||
|  | 		} else | ||
|  | 		{ | ||
|  |             //todo: friction anchor may require the contact to be around a bit longer
 | ||
|  | 			//contact also becomes invalid when relative movement orthogonal to normal exceeds margin
 | ||
|  | 			projectedPoint = manifoldPoint.m_positionWorldOnA - manifoldPoint.m_normalWorldOnB * manifoldPoint.m_distance1; | ||
|  | 			projectedDifference = manifoldPoint.m_positionWorldOnB - projectedPoint; | ||
|  | 			distance2d = projectedDifference.dot(projectedDifference); | ||
|  | 			if (distance2d  > getContactBreakingThreshold()*getContactBreakingThreshold() ) | ||
|  | 			{ | ||
|  | 				removeContactPoint(i); | ||
|  | 			} else | ||
|  | 			{ | ||
|  | 				//contact point processed callback
 | ||
|  | 				if (gContactProcessedCallback) | ||
|  | 					(*gContactProcessedCallback)(manifoldPoint,(void*)m_body0,(void*)m_body1); | ||
|  | 			} | ||
|  | 		} | ||
|  | 	} | ||
|  | #ifdef DEBUG_PERSISTENCY
 | ||
|  | 	DebugPersistency(); | ||
|  | #endif //
 | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 |