forked from LeenkxTeam/LNXSDK
		
	
		
			
				
	
	
		
			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 //
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 |