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