269 lines
		
	
	
		
			8.8 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			269 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.
 | 
						|
*/
 | 
						|
 | 
						|
#ifndef BT_PERSISTENT_MANIFOLD_H
 | 
						|
#define BT_PERSISTENT_MANIFOLD_H
 | 
						|
 | 
						|
 | 
						|
#include "LinearMath/btVector3.h"
 | 
						|
#include "LinearMath/btTransform.h"
 | 
						|
#include "btManifoldPoint.h"
 | 
						|
class btCollisionObject;
 | 
						|
#include "LinearMath/btAlignedAllocator.h"
 | 
						|
 | 
						|
struct btCollisionResult;
 | 
						|
 | 
						|
///maximum contact breaking and merging threshold
 | 
						|
extern btScalar gContactBreakingThreshold;
 | 
						|
 | 
						|
#ifndef SWIG
 | 
						|
class btPersistentManifold;
 | 
						|
 | 
						|
typedef bool (*ContactDestroyedCallback)(void* userPersistentData);
 | 
						|
typedef bool (*ContactProcessedCallback)(btManifoldPoint& cp,void* body0,void* body1);
 | 
						|
typedef void (*ContactStartedCallback)(btPersistentManifold* const &manifold);
 | 
						|
typedef void (*ContactEndedCallback)(btPersistentManifold* const &manifold);
 | 
						|
extern ContactDestroyedCallback	gContactDestroyedCallback;
 | 
						|
extern ContactProcessedCallback gContactProcessedCallback;
 | 
						|
extern ContactStartedCallback gContactStartedCallback;
 | 
						|
extern ContactEndedCallback gContactEndedCallback;
 | 
						|
#endif //SWIG
 | 
						|
 | 
						|
//the enum starts at 1024 to avoid type conflicts with btTypedConstraint
 | 
						|
enum btContactManifoldTypes
 | 
						|
{
 | 
						|
	MIN_CONTACT_MANIFOLD_TYPE = 1024,
 | 
						|
	BT_PERSISTENT_MANIFOLD_TYPE
 | 
						|
};
 | 
						|
 | 
						|
#define MANIFOLD_CACHE_SIZE 4
 | 
						|
 | 
						|
///btPersistentManifold is a contact point cache, it stays persistent as long as objects are overlapping in the broadphase.
 | 
						|
///Those contact points are created by the collision narrow phase.
 | 
						|
///The cache can be empty, or hold 1,2,3 or 4 points. Some collision algorithms (GJK) might only add one point at a time.
 | 
						|
///updates/refreshes old contact points, and throw them away if necessary (distance becomes too large)
 | 
						|
///reduces the cache to 4 points, when more then 4 points are added, using following rules:
 | 
						|
///the contact point with deepest penetration is always kept, and it tries to maximuze the area covered by the points
 | 
						|
///note that some pairs of objects might have more then one contact manifold.
 | 
						|
 | 
						|
 | 
						|
//ATTRIBUTE_ALIGNED128( class) btPersistentManifold : public btTypedObject
 | 
						|
ATTRIBUTE_ALIGNED16( class) btPersistentManifold : public btTypedObject
 | 
						|
{
 | 
						|
 | 
						|
	btManifoldPoint m_pointCache[MANIFOLD_CACHE_SIZE];
 | 
						|
 | 
						|
	/// this two body pointers can point to the physics rigidbody class.
 | 
						|
	const btCollisionObject* m_body0;
 | 
						|
	const btCollisionObject* m_body1;
 | 
						|
 | 
						|
	int	m_cachedPoints;
 | 
						|
 | 
						|
	btScalar	m_contactBreakingThreshold;
 | 
						|
	btScalar	m_contactProcessingThreshold;
 | 
						|
 | 
						|
	
 | 
						|
	/// sort cached points so most isolated points come first
 | 
						|
	int	sortCachedPoints(const btManifoldPoint& pt);
 | 
						|
 | 
						|
	int		findContactPoint(const btManifoldPoint* unUsed, int numUnused,const btManifoldPoint& pt);
 | 
						|
 | 
						|
public:
 | 
						|
 | 
						|
	BT_DECLARE_ALIGNED_ALLOCATOR();
 | 
						|
 | 
						|
	int	m_companionIdA;
 | 
						|
	int	m_companionIdB;
 | 
						|
 | 
						|
	int m_index1a;
 | 
						|
 | 
						|
	btPersistentManifold();
 | 
						|
 | 
						|
	btPersistentManifold(const btCollisionObject* body0,const btCollisionObject* body1,int , btScalar contactBreakingThreshold,btScalar contactProcessingThreshold)
 | 
						|
		: btTypedObject(BT_PERSISTENT_MANIFOLD_TYPE),
 | 
						|
	m_body0(body0),m_body1(body1),m_cachedPoints(0),
 | 
						|
		m_contactBreakingThreshold(contactBreakingThreshold),
 | 
						|
		m_contactProcessingThreshold(contactProcessingThreshold)
 | 
						|
	{
 | 
						|
	}
 | 
						|
 | 
						|
	SIMD_FORCE_INLINE const btCollisionObject* getBody0() const { return m_body0;}
 | 
						|
	SIMD_FORCE_INLINE const btCollisionObject* getBody1() const { return m_body1;}
 | 
						|
 | 
						|
	void	setBodies(const btCollisionObject* body0,const btCollisionObject* body1)
 | 
						|
	{
 | 
						|
		m_body0 = body0;
 | 
						|
		m_body1 = body1;
 | 
						|
	}
 | 
						|
 | 
						|
	void clearUserCache(btManifoldPoint& pt);
 | 
						|
 | 
						|
#ifdef DEBUG_PERSISTENCY
 | 
						|
	void	DebugPersistency();
 | 
						|
#endif //
 | 
						|
	
 | 
						|
	SIMD_FORCE_INLINE int	getNumContacts() const { return m_cachedPoints;}
 | 
						|
	/// the setNumContacts API is usually not used, except when you gather/fill all contacts manually
 | 
						|
	void setNumContacts(int cachedPoints)
 | 
						|
	{
 | 
						|
		m_cachedPoints = cachedPoints;
 | 
						|
	}
 | 
						|
 | 
						|
 | 
						|
	SIMD_FORCE_INLINE const btManifoldPoint& getContactPoint(int index) const
 | 
						|
	{
 | 
						|
		btAssert(index < m_cachedPoints);
 | 
						|
		return m_pointCache[index];
 | 
						|
	}
 | 
						|
 | 
						|
	SIMD_FORCE_INLINE btManifoldPoint& getContactPoint(int index)
 | 
						|
	{
 | 
						|
		btAssert(index < m_cachedPoints);
 | 
						|
		return m_pointCache[index];
 | 
						|
	}
 | 
						|
 | 
						|
	///@todo: get this margin from the current physics / collision environment
 | 
						|
	btScalar	getContactBreakingThreshold() const;
 | 
						|
 | 
						|
	btScalar	getContactProcessingThreshold() const
 | 
						|
	{
 | 
						|
		return m_contactProcessingThreshold;
 | 
						|
	}
 | 
						|
	
 | 
						|
	void setContactBreakingThreshold(btScalar contactBreakingThreshold)
 | 
						|
	{
 | 
						|
		m_contactBreakingThreshold = contactBreakingThreshold;
 | 
						|
	}
 | 
						|
 | 
						|
	void setContactProcessingThreshold(btScalar	contactProcessingThreshold)
 | 
						|
	{
 | 
						|
		m_contactProcessingThreshold = contactProcessingThreshold;
 | 
						|
	}
 | 
						|
	
 | 
						|
	
 | 
						|
 | 
						|
 | 
						|
	int getCacheEntry(const btManifoldPoint& newPoint) const;
 | 
						|
 | 
						|
	int addManifoldPoint( const btManifoldPoint& newPoint, bool isPredictive=false);
 | 
						|
 | 
						|
	void removeContactPoint (int index)
 | 
						|
	{
 | 
						|
		clearUserCache(m_pointCache[index]);
 | 
						|
 | 
						|
		int lastUsedIndex = getNumContacts() - 1;
 | 
						|
//		m_pointCache[index] = m_pointCache[lastUsedIndex];
 | 
						|
		if(index != lastUsedIndex) 
 | 
						|
		{
 | 
						|
			m_pointCache[index] = m_pointCache[lastUsedIndex]; 
 | 
						|
			//get rid of duplicated userPersistentData pointer
 | 
						|
			m_pointCache[lastUsedIndex].m_userPersistentData = 0;
 | 
						|
			m_pointCache[lastUsedIndex].m_appliedImpulse = 0.f;
 | 
						|
			m_pointCache[lastUsedIndex].m_contactPointFlags = 0;
 | 
						|
			m_pointCache[lastUsedIndex].m_appliedImpulseLateral1 = 0.f;
 | 
						|
			m_pointCache[lastUsedIndex].m_appliedImpulseLateral2 = 0.f;
 | 
						|
			m_pointCache[lastUsedIndex].m_lifeTime = 0;
 | 
						|
		}
 | 
						|
 | 
						|
		btAssert(m_pointCache[lastUsedIndex].m_userPersistentData==0);
 | 
						|
		m_cachedPoints--;
 | 
						|
 | 
						|
		if (gContactEndedCallback && m_cachedPoints == 0)
 | 
						|
		{
 | 
						|
			gContactEndedCallback(this);
 | 
						|
		}
 | 
						|
	}
 | 
						|
	void replaceContactPoint(const btManifoldPoint& newPoint, int insertIndex)
 | 
						|
	{
 | 
						|
		btAssert(validContactDistance(newPoint));
 | 
						|
 | 
						|
#define MAINTAIN_PERSISTENCY 1
 | 
						|
#ifdef MAINTAIN_PERSISTENCY
 | 
						|
		int lifeTime = m_pointCache[insertIndex].getLifeTime();
 | 
						|
		btScalar appliedImpulse = m_pointCache[insertIndex].m_appliedImpulse;
 | 
						|
		btScalar appliedLateralImpulse1 = m_pointCache[insertIndex].m_appliedImpulseLateral1;
 | 
						|
		btScalar appliedLateralImpulse2 = m_pointCache[insertIndex].m_appliedImpulseLateral2;
 | 
						|
 | 
						|
		bool replacePoint = true;
 | 
						|
		///we keep existing contact points for friction anchors
 | 
						|
		///if the friction force is within the Coulomb friction cone
 | 
						|
		if (newPoint.m_contactPointFlags & BT_CONTACT_FLAG_FRICTION_ANCHOR)
 | 
						|
		{
 | 
						|
			//   printf("appliedImpulse=%f\n", appliedImpulse);
 | 
						|
			//   printf("appliedLateralImpulse1=%f\n", appliedLateralImpulse1);
 | 
						|
			//   printf("appliedLateralImpulse2=%f\n", appliedLateralImpulse2);
 | 
						|
			//   printf("mu = %f\n", m_pointCache[insertIndex].m_combinedFriction);
 | 
						|
			btScalar mu = m_pointCache[insertIndex].m_combinedFriction;
 | 
						|
			btScalar eps = 0;  //we could allow to enlarge or shrink the tolerance to check against the friction cone a bit, say 1e-7
 | 
						|
			btScalar a = appliedLateralImpulse1 * appliedLateralImpulse1 + appliedLateralImpulse2 * appliedLateralImpulse2;
 | 
						|
			btScalar b = eps + mu * appliedImpulse;
 | 
						|
			b = b * b;
 | 
						|
			replacePoint = (a) > (b);
 | 
						|
		}
 | 
						|
 | 
						|
		if (replacePoint)
 | 
						|
		{
 | 
						|
			btAssert(lifeTime >= 0);
 | 
						|
			void* cache = m_pointCache[insertIndex].m_userPersistentData;
 | 
						|
 | 
						|
			m_pointCache[insertIndex] = newPoint;
 | 
						|
			m_pointCache[insertIndex].m_userPersistentData = cache;
 | 
						|
			m_pointCache[insertIndex].m_appliedImpulse = appliedImpulse;
 | 
						|
			m_pointCache[insertIndex].m_appliedImpulseLateral1 = appliedLateralImpulse1;
 | 
						|
			m_pointCache[insertIndex].m_appliedImpulseLateral2 = appliedLateralImpulse2;
 | 
						|
		}
 | 
						|
 | 
						|
		m_pointCache[insertIndex].m_lifeTime = lifeTime;
 | 
						|
#else
 | 
						|
		clearUserCache(m_pointCache[insertIndex]);
 | 
						|
		m_pointCache[insertIndex] = newPoint;
 | 
						|
 | 
						|
#endif
 | 
						|
	}
 | 
						|
 | 
						|
	bool validContactDistance(const btManifoldPoint& pt) const
 | 
						|
	{
 | 
						|
		return pt.m_distance1 <= getContactBreakingThreshold();
 | 
						|
	}
 | 
						|
	/// calculated new worldspace coordinates and depth, and reject points that exceed the collision margin
 | 
						|
	void	refreshContactPoints(  const btTransform& trA,const btTransform& trB);
 | 
						|
 | 
						|
	
 | 
						|
	SIMD_FORCE_INLINE	void	clearManifold()
 | 
						|
	{
 | 
						|
		int i;
 | 
						|
		for (i=0;i<m_cachedPoints;i++)
 | 
						|
		{
 | 
						|
			clearUserCache(m_pointCache[i]);
 | 
						|
		}
 | 
						|
 | 
						|
		if (gContactEndedCallback && m_cachedPoints)
 | 
						|
		{
 | 
						|
			gContactEndedCallback(this);
 | 
						|
		}
 | 
						|
		m_cachedPoints = 0;
 | 
						|
	}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
}
 | 
						|
;
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
#endif //BT_PERSISTENT_MANIFOLD_H
 |