1/*
2Bullet Continuous Collision Detection and Physics Library
3Copyright (c) 2003-2006 Erwin Coumans  http://continuousphysics.com/Bullet/
4
5This software is provided 'as-is', without any express or implied warranty.
6In no event will the authors be held liable for any damages arising from the use of this software.
7Permission is granted to anyone to use this software for any purpose,
8including commercial applications, and to alter it and redistribute it freely,
9subject to the following restrictions:
10
111. 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.
122. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
133. This notice may not be removed or altered from any source distribution.
14*/
15
16#ifndef BT_PERSISTENT_MANIFOLD_H
17#define BT_PERSISTENT_MANIFOLD_H
18
19
20#include "LinearMath/btVector3.h"
21#include "LinearMath/btTransform.h"
22#include "btManifoldPoint.h"
23class btCollisionObject;
24#include "LinearMath/btAlignedAllocator.h"
25
26struct btCollisionResult;
27
28///maximum contact breaking and merging threshold
29extern btScalar gContactBreakingThreshold;
30
31#ifndef SWIG
32class btPersistentManifold;
33
34typedef bool (*ContactDestroyedCallback)(void* userPersistentData);
35typedef bool (*ContactProcessedCallback)(btManifoldPoint& cp,void* body0,void* body1);
36typedef void(*ContactStartedCallback)(btPersistentManifold* const &manifold);
37typedef void(*ContactEndedCallback)(btPersistentManifold* const &manifold);
38extern ContactDestroyedCallback	gContactDestroyedCallback;
39extern ContactProcessedCallback gContactProcessedCallback;
40extern ContactStartedCallback gContactStartedCallback;
41extern ContactEndedCallback gContactEndedCallback;
42#endif //SWIG
43
44//the enum starts at 1024 to avoid type conflicts with btTypedConstraint
45enum btContactManifoldTypes
46{
47	MIN_CONTACT_MANIFOLD_TYPE = 1024,
48	BT_PERSISTENT_MANIFOLD_TYPE
49};
50
51#define MANIFOLD_CACHE_SIZE 4
52
53///btPersistentManifold is a contact point cache, it stays persistent as long as objects are overlapping in the broadphase.
54///Those contact points are created by the collision narrow phase.
55///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.
56///updates/refreshes old contact points, and throw them away if necessary (distance becomes too large)
57///reduces the cache to 4 points, when more then 4 points are added, using following rules:
58///the contact point with deepest penetration is always kept, and it tries to maximuze the area covered by the points
59///note that some pairs of objects might have more then one contact manifold.
60
61
62ATTRIBUTE_ALIGNED128( class) btPersistentManifold : public btTypedObject
63//ATTRIBUTE_ALIGNED16( class) btPersistentManifold : public btTypedObject
64{
65
66	btManifoldPoint m_pointCache[MANIFOLD_CACHE_SIZE];
67
68	/// this two body pointers can point to the physics rigidbody class.
69	const btCollisionObject* m_body0;
70	const btCollisionObject* m_body1;
71
72	int	m_cachedPoints;
73
74	btScalar	m_contactBreakingThreshold;
75	btScalar	m_contactProcessingThreshold;
76
77
78	/// sort cached points so most isolated points come first
79	int	sortCachedPoints(const btManifoldPoint& pt);
80
81	int		findContactPoint(const btManifoldPoint* unUsed, int numUnused,const btManifoldPoint& pt);
82
83public:
84
85	BT_DECLARE_ALIGNED_ALLOCATOR();
86
87	int	m_companionIdA;
88	int	m_companionIdB;
89
90	int m_index1a;
91
92	btPersistentManifold();
93
94	btPersistentManifold(const btCollisionObject* body0,const btCollisionObject* body1,int , btScalar contactBreakingThreshold,btScalar contactProcessingThreshold)
95		: btTypedObject(BT_PERSISTENT_MANIFOLD_TYPE),
96	m_body0(body0),m_body1(body1),m_cachedPoints(0),
97		m_contactBreakingThreshold(contactBreakingThreshold),
98		m_contactProcessingThreshold(contactProcessingThreshold)
99	{
100	}
101
102	SIMD_FORCE_INLINE const btCollisionObject* getBody0() const { return m_body0;}
103	SIMD_FORCE_INLINE const btCollisionObject* getBody1() const { return m_body1;}
104
105	void	setBodies(const btCollisionObject* body0,const btCollisionObject* body1)
106	{
107		m_body0 = body0;
108		m_body1 = body1;
109	}
110
111	void clearUserCache(btManifoldPoint& pt);
112
113#ifdef DEBUG_PERSISTENCY
114	void	DebugPersistency();
115#endif //
116
117	SIMD_FORCE_INLINE int	getNumContacts() const { return m_cachedPoints;}
118	/// the setNumContacts API is usually not used, except when you gather/fill all contacts manually
119	void setNumContacts(int cachedPoints)
120	{
121		m_cachedPoints = cachedPoints;
122	}
123
124
125	SIMD_FORCE_INLINE const btManifoldPoint& getContactPoint(int index) const
126	{
127		btAssert(index < m_cachedPoints);
128		return m_pointCache[index];
129	}
130
131	SIMD_FORCE_INLINE btManifoldPoint& getContactPoint(int index)
132	{
133		btAssert(index < m_cachedPoints);
134		return m_pointCache[index];
135	}
136
137	///@todo: get this margin from the current physics / collision environment
138	btScalar	getContactBreakingThreshold() const;
139
140	btScalar	getContactProcessingThreshold() const
141	{
142		return m_contactProcessingThreshold;
143	}
144
145	void setContactBreakingThreshold(btScalar contactBreakingThreshold)
146	{
147		m_contactBreakingThreshold = contactBreakingThreshold;
148	}
149
150	void setContactProcessingThreshold(btScalar	contactProcessingThreshold)
151	{
152		m_contactProcessingThreshold = contactProcessingThreshold;
153	}
154
155
156
157
158	int getCacheEntry(const btManifoldPoint& newPoint) const;
159
160	int addManifoldPoint( const btManifoldPoint& newPoint, bool isPredictive=false);
161
162	void removeContactPoint (int index)
163	{
164		clearUserCache(m_pointCache[index]);
165
166		int lastUsedIndex = getNumContacts() - 1;
167//		m_pointCache[index] = m_pointCache[lastUsedIndex];
168		if(index != lastUsedIndex)
169		{
170			m_pointCache[index] = m_pointCache[lastUsedIndex];
171			//get rid of duplicated userPersistentData pointer
172			m_pointCache[lastUsedIndex].m_userPersistentData = 0;
173			m_pointCache[lastUsedIndex].m_appliedImpulse = 0.f;
174			m_pointCache[lastUsedIndex].m_lateralFrictionInitialized = false;
175			m_pointCache[lastUsedIndex].m_appliedImpulseLateral1 = 0.f;
176			m_pointCache[lastUsedIndex].m_appliedImpulseLateral2 = 0.f;
177			m_pointCache[lastUsedIndex].m_lifeTime = 0;
178		}
179
180		btAssert(m_pointCache[lastUsedIndex].m_userPersistentData==0);
181		m_cachedPoints--;
182
183		if (gContactEndedCallback && m_cachedPoints == 0)
184		{
185			gContactEndedCallback(this);
186		}
187	}
188	void replaceContactPoint(const btManifoldPoint& newPoint,int insertIndex)
189	{
190		btAssert(validContactDistance(newPoint));
191
192#define MAINTAIN_PERSISTENCY 1
193#ifdef MAINTAIN_PERSISTENCY
194		int	lifeTime = m_pointCache[insertIndex].getLifeTime();
195		btScalar	appliedImpulse = m_pointCache[insertIndex].m_appliedImpulse;
196		btScalar	appliedLateralImpulse1 = m_pointCache[insertIndex].m_appliedImpulseLateral1;
197		btScalar	appliedLateralImpulse2 = m_pointCache[insertIndex].m_appliedImpulseLateral2;
198//		bool isLateralFrictionInitialized = m_pointCache[insertIndex].m_lateralFrictionInitialized;
199
200
201
202		btAssert(lifeTime>=0);
203		void* cache = m_pointCache[insertIndex].m_userPersistentData;
204
205		m_pointCache[insertIndex] = newPoint;
206
207		m_pointCache[insertIndex].m_userPersistentData = cache;
208		m_pointCache[insertIndex].m_appliedImpulse = appliedImpulse;
209		m_pointCache[insertIndex].m_appliedImpulseLateral1 = appliedLateralImpulse1;
210		m_pointCache[insertIndex].m_appliedImpulseLateral2 = appliedLateralImpulse2;
211
212		m_pointCache[insertIndex].m_appliedImpulse =  appliedImpulse;
213		m_pointCache[insertIndex].m_appliedImpulseLateral1 = appliedLateralImpulse1;
214		m_pointCache[insertIndex].m_appliedImpulseLateral2 = appliedLateralImpulse2;
215
216
217		m_pointCache[insertIndex].m_lifeTime = lifeTime;
218#else
219		clearUserCache(m_pointCache[insertIndex]);
220		m_pointCache[insertIndex] = newPoint;
221
222#endif
223	}
224
225
226	bool validContactDistance(const btManifoldPoint& pt) const
227	{
228		return pt.m_distance1 <= getContactBreakingThreshold();
229	}
230	/// calculated new worldspace coordinates and depth, and reject points that exceed the collision margin
231	void	refreshContactPoints(  const btTransform& trA,const btTransform& trB);
232
233
234	SIMD_FORCE_INLINE	void	clearManifold()
235	{
236		int i;
237		for (i=0;i<m_cachedPoints;i++)
238		{
239			clearUserCache(m_pointCache[i]);
240		}
241
242		if (gContactEndedCallback && m_cachedPoints)
243		{
244			gContactEndedCallback(this);
245		}
246		m_cachedPoints = 0;
247	}
248
249
250
251}
252;
253
254
255
256
257
258#endif //BT_PERSISTENT_MANIFOLD_H
259