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
17
18 #include "btCollisionDispatcher.h"
19
20
21 #include "BulletCollision/BroadphaseCollision/btCollisionAlgorithm.h"
22
23 #include "BulletCollision/CollisionShapes/btCollisionShape.h"
24 #include "BulletCollision/CollisionDispatch/btCollisionObject.h"
25 #include "BulletCollision/BroadphaseCollision/btOverlappingPairCache.h"
26 #include "LinearMath/btPoolAllocator.h"
27 #include "BulletCollision/CollisionDispatch/btCollisionConfiguration.h"
28
29 //int gNumManifold = 0;
30
31 #ifdef BT_DEBUG
32 #include <stdio.h>
33 #endif
34
35
btCollisionDispatcher(btCollisionConfiguration * collisionConfiguration)36 btCollisionDispatcher::btCollisionDispatcher (btCollisionConfiguration* collisionConfiguration):
37 m_dispatcherFlags(btCollisionDispatcher::CD_USE_RELATIVE_CONTACT_BREAKING_THRESHOLD),
38 m_collisionConfiguration(collisionConfiguration)
39 {
40 int i;
41
42 setNearCallback(defaultNearCallback);
43
44 m_collisionAlgorithmPoolAllocator = collisionConfiguration->getCollisionAlgorithmPool();
45
46 m_persistentManifoldPoolAllocator = collisionConfiguration->getPersistentManifoldPool();
47
48 for (i=0;i<MAX_BROADPHASE_COLLISION_TYPES;i++)
49 {
50 for (int j=0;j<MAX_BROADPHASE_COLLISION_TYPES;j++)
51 {
52 m_doubleDispatch[i][j] = m_collisionConfiguration->getCollisionAlgorithmCreateFunc(i,j);
53 btAssert(m_doubleDispatch[i][j]);
54 }
55 }
56
57
58 }
59
60
registerCollisionCreateFunc(int proxyType0,int proxyType1,btCollisionAlgorithmCreateFunc * createFunc)61 void btCollisionDispatcher::registerCollisionCreateFunc(int proxyType0, int proxyType1, btCollisionAlgorithmCreateFunc *createFunc)
62 {
63 m_doubleDispatch[proxyType0][proxyType1] = createFunc;
64 }
65
~btCollisionDispatcher()66 btCollisionDispatcher::~btCollisionDispatcher()
67 {
68 }
69
getNewManifold(void * b0,void * b1)70 btPersistentManifold* btCollisionDispatcher::getNewManifold(void* b0,void* b1)
71 {
72 //gNumManifold++;
73
74 //btAssert(gNumManifold < 65535);
75
76
77 btCollisionObject* body0 = (btCollisionObject*)b0;
78 btCollisionObject* body1 = (btCollisionObject*)b1;
79
80 //optional relative contact breaking threshold, turned on by default (use setDispatcherFlags to switch off feature for improved performance)
81
82 btScalar contactBreakingThreshold = (m_dispatcherFlags & btCollisionDispatcher::CD_USE_RELATIVE_CONTACT_BREAKING_THRESHOLD) ?
83 btMin(body0->getCollisionShape()->getContactBreakingThreshold(gContactBreakingThreshold) , body1->getCollisionShape()->getContactBreakingThreshold(gContactBreakingThreshold))
84 : gContactBreakingThreshold ;
85
86 btScalar contactProcessingThreshold = btMin(body0->getContactProcessingThreshold(),body1->getContactProcessingThreshold());
87
88 void* mem = 0;
89
90 if (m_persistentManifoldPoolAllocator->getFreeCount())
91 {
92 mem = m_persistentManifoldPoolAllocator->allocate(sizeof(btPersistentManifold));
93 } else
94 {
95 //we got a pool memory overflow, by default we fallback to dynamically allocate memory. If we require a contiguous contact pool then assert.
96 if ((m_dispatcherFlags&CD_DISABLE_CONTACTPOOL_DYNAMIC_ALLOCATION)==0)
97 {
98 mem = btAlignedAlloc(sizeof(btPersistentManifold),16);
99 } else
100 {
101 btAssert(0);
102 //make sure to increase the m_defaultMaxPersistentManifoldPoolSize in the btDefaultCollisionConstructionInfo/btDefaultCollisionConfiguration
103 return 0;
104 }
105 }
106 btPersistentManifold* manifold = new(mem) btPersistentManifold (body0,body1,0,contactBreakingThreshold,contactProcessingThreshold);
107 manifold->m_index1a = m_manifoldsPtr.size();
108 m_manifoldsPtr.push_back(manifold);
109
110 return manifold;
111 }
112
clearManifold(btPersistentManifold * manifold)113 void btCollisionDispatcher::clearManifold(btPersistentManifold* manifold)
114 {
115 manifold->clearManifold();
116 }
117
118
releaseManifold(btPersistentManifold * manifold)119 void btCollisionDispatcher::releaseManifold(btPersistentManifold* manifold)
120 {
121
122 //gNumManifold--;
123
124 //printf("releaseManifold: gNumManifold %d\n",gNumManifold);
125 clearManifold(manifold);
126
127 int findIndex = manifold->m_index1a;
128 btAssert(findIndex < m_manifoldsPtr.size());
129 m_manifoldsPtr.swap(findIndex,m_manifoldsPtr.size()-1);
130 m_manifoldsPtr[findIndex]->m_index1a = findIndex;
131 m_manifoldsPtr.pop_back();
132
133 manifold->~btPersistentManifold();
134 if (m_persistentManifoldPoolAllocator->validPtr(manifold))
135 {
136 m_persistentManifoldPoolAllocator->freeMemory(manifold);
137 } else
138 {
139 btAlignedFree(manifold);
140 }
141
142 }
143
144
145
findAlgorithm(btCollisionObject * body0,btCollisionObject * body1,btPersistentManifold * sharedManifold)146 btCollisionAlgorithm* btCollisionDispatcher::findAlgorithm(btCollisionObject* body0,btCollisionObject* body1,btPersistentManifold* sharedManifold)
147 {
148
149 btCollisionAlgorithmConstructionInfo ci;
150
151 ci.m_dispatcher1 = this;
152 ci.m_manifold = sharedManifold;
153 btCollisionAlgorithm* algo = m_doubleDispatch[body0->getCollisionShape()->getShapeType()][body1->getCollisionShape()->getShapeType()]->CreateCollisionAlgorithm(ci,body0,body1);
154
155 return algo;
156 }
157
158
159
160
needsResponse(btCollisionObject * body0,btCollisionObject * body1)161 bool btCollisionDispatcher::needsResponse(btCollisionObject* body0,btCollisionObject* body1)
162 {
163 //here you can do filtering
164 bool hasResponse =
165 (body0->hasContactResponse() && body1->hasContactResponse());
166 //no response between two static/kinematic bodies:
167 hasResponse = hasResponse &&
168 ((!body0->isStaticOrKinematicObject()) ||(! body1->isStaticOrKinematicObject()));
169 return hasResponse;
170 }
171
needsCollision(btCollisionObject * body0,btCollisionObject * body1)172 bool btCollisionDispatcher::needsCollision(btCollisionObject* body0,btCollisionObject* body1)
173 {
174 btAssert(body0);
175 btAssert(body1);
176
177 bool needsCollision = true;
178
179 #ifdef BT_DEBUG
180 if (!(m_dispatcherFlags & btCollisionDispatcher::CD_STATIC_STATIC_REPORTED))
181 {
182 //broadphase filtering already deals with this
183 if (body0->isStaticOrKinematicObject() && body1->isStaticOrKinematicObject())
184 {
185 m_dispatcherFlags |= btCollisionDispatcher::CD_STATIC_STATIC_REPORTED;
186 printf("warning btCollisionDispatcher::needsCollision: static-static collision!\n");
187 }
188 }
189 #endif //BT_DEBUG
190
191 if ((!body0->isActive()) && (!body1->isActive()))
192 needsCollision = false;
193 else if (!body0->checkCollideWith(body1))
194 needsCollision = false;
195
196 return needsCollision ;
197
198 }
199
200
201
202 ///interface for iterating all overlapping collision pairs, no matter how those pairs are stored (array, set, map etc)
203 ///this is useful for the collision dispatcher.
204 class btCollisionPairCallback : public btOverlapCallback
205 {
206 const btDispatcherInfo& m_dispatchInfo;
207 btCollisionDispatcher* m_dispatcher;
208
209 public:
210
btCollisionPairCallback(const btDispatcherInfo & dispatchInfo,btCollisionDispatcher * dispatcher)211 btCollisionPairCallback(const btDispatcherInfo& dispatchInfo,btCollisionDispatcher* dispatcher)
212 :m_dispatchInfo(dispatchInfo),
213 m_dispatcher(dispatcher)
214 {
215 }
216
217 /*btCollisionPairCallback& operator=(btCollisionPairCallback& other)
218 {
219 m_dispatchInfo = other.m_dispatchInfo;
220 m_dispatcher = other.m_dispatcher;
221 return *this;
222 }
223 */
224
225
~btCollisionPairCallback()226 virtual ~btCollisionPairCallback() {}
227
228
processOverlap(btBroadphasePair & pair)229 virtual bool processOverlap(btBroadphasePair& pair)
230 {
231 (*m_dispatcher->getNearCallback())(pair,*m_dispatcher,m_dispatchInfo);
232
233 return false;
234 }
235 };
236
237
238
dispatchAllCollisionPairs(btOverlappingPairCache * pairCache,const btDispatcherInfo & dispatchInfo,btDispatcher * dispatcher)239 void btCollisionDispatcher::dispatchAllCollisionPairs(btOverlappingPairCache* pairCache,const btDispatcherInfo& dispatchInfo,btDispatcher* dispatcher)
240 {
241 //m_blockedForChanges = true;
242
243 btCollisionPairCallback collisionCallback(dispatchInfo,this);
244
245 pairCache->processAllOverlappingPairs(&collisionCallback,dispatcher);
246
247 //m_blockedForChanges = false;
248
249 }
250
251
252
253
254 //by default, Bullet will use this near callback
defaultNearCallback(btBroadphasePair & collisionPair,btCollisionDispatcher & dispatcher,const btDispatcherInfo & dispatchInfo)255 void btCollisionDispatcher::defaultNearCallback(btBroadphasePair& collisionPair, btCollisionDispatcher& dispatcher, const btDispatcherInfo& dispatchInfo)
256 {
257 btCollisionObject* colObj0 = (btCollisionObject*)collisionPair.m_pProxy0->m_clientObject;
258 btCollisionObject* colObj1 = (btCollisionObject*)collisionPair.m_pProxy1->m_clientObject;
259
260 if (dispatcher.needsCollision(colObj0,colObj1))
261 {
262 //dispatcher will keep algorithms persistent in the collision pair
263 if (!collisionPair.m_algorithm)
264 {
265 collisionPair.m_algorithm = dispatcher.findAlgorithm(colObj0,colObj1);
266 }
267
268 if (collisionPair.m_algorithm)
269 {
270 btManifoldResult contactPointResult(colObj0,colObj1);
271
272 if (dispatchInfo.m_dispatchFunc == btDispatcherInfo::DISPATCH_DISCRETE)
273 {
274 //discrete collision detection query
275 collisionPair.m_algorithm->processCollision(colObj0,colObj1,dispatchInfo,&contactPointResult);
276 } else
277 {
278 //continuous collision detection query, time of impact (toi)
279 btScalar toi = collisionPair.m_algorithm->calculateTimeOfImpact(colObj0,colObj1,dispatchInfo,&contactPointResult);
280 if (dispatchInfo.m_timeOfImpact > toi)
281 dispatchInfo.m_timeOfImpact = toi;
282
283 }
284 }
285 }
286
287 }
288
289
allocateCollisionAlgorithm(int size)290 void* btCollisionDispatcher::allocateCollisionAlgorithm(int size)
291 {
292 if (m_collisionAlgorithmPoolAllocator->getFreeCount())
293 {
294 return m_collisionAlgorithmPoolAllocator->allocate(size);
295 }
296
297 //warn user for overflow?
298 return btAlignedAlloc(static_cast<size_t>(size), 16);
299 }
300
freeCollisionAlgorithm(void * ptr)301 void btCollisionDispatcher::freeCollisionAlgorithm(void* ptr)
302 {
303 if (m_collisionAlgorithmPoolAllocator->validPtr(ptr))
304 {
305 m_collisionAlgorithmPoolAllocator->freeMemory(ptr);
306 } else
307 {
308 btAlignedFree(ptr);
309 }
310 }
311