• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 
2 /*
3 Bullet Continuous Collision Detection and Physics Library
4 Copyright (c) 2003-2006 Erwin Coumans  http://continuousphysics.com/Bullet/
5 
6 This software is provided 'as-is', without any express or implied warranty.
7 In no event will the authors be held liable for any damages arising from the use of this software.
8 Permission is granted to anyone to use this software for any purpose,
9 including commercial applications, and to alter it and redistribute it freely,
10 subject to the following restrictions:
11 
12 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.
13 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
14 3. This notice may not be removed or altered from any source distribution.
15 */
16 
17 
18 #include "LinearMath/btScalar.h"
19 #include "btSimulationIslandManager.h"
20 #include "BulletCollision/BroadphaseCollision/btDispatcher.h"
21 #include "BulletCollision/NarrowPhaseCollision/btPersistentManifold.h"
22 #include "BulletCollision/CollisionDispatch/btCollisionObject.h"
23 #include "BulletCollision/CollisionDispatch/btCollisionWorld.h"
24 
25 //#include <stdio.h>
26 #include "LinearMath/btQuickprof.h"
27 
btSimulationIslandManager()28 btSimulationIslandManager::btSimulationIslandManager():
29 m_splitIslands(true)
30 {
31 }
32 
~btSimulationIslandManager()33 btSimulationIslandManager::~btSimulationIslandManager()
34 {
35 }
36 
37 
initUnionFind(int n)38 void btSimulationIslandManager::initUnionFind(int n)
39 {
40 		m_unionFind.reset(n);
41 }
42 
43 
findUnions(btDispatcher *,btCollisionWorld * colWorld)44 void btSimulationIslandManager::findUnions(btDispatcher* /* dispatcher */,btCollisionWorld* colWorld)
45 {
46 
47 	{
48 		btOverlappingPairCache* pairCachePtr = colWorld->getPairCache();
49 		const int numOverlappingPairs = pairCachePtr->getNumOverlappingPairs();
50 		if (numOverlappingPairs)
51 		{
52 		btBroadphasePair* pairPtr = pairCachePtr->getOverlappingPairArrayPtr();
53 
54 		for (int i=0;i<numOverlappingPairs;i++)
55 		{
56 			const btBroadphasePair& collisionPair = pairPtr[i];
57 			btCollisionObject* colObj0 = (btCollisionObject*)collisionPair.m_pProxy0->m_clientObject;
58 			btCollisionObject* colObj1 = (btCollisionObject*)collisionPair.m_pProxy1->m_clientObject;
59 
60 			if (((colObj0) && ((colObj0)->mergesSimulationIslands())) &&
61 				((colObj1) && ((colObj1)->mergesSimulationIslands())))
62 			{
63 
64 				m_unionFind.unite((colObj0)->getIslandTag(),
65 					(colObj1)->getIslandTag());
66 			}
67 		}
68 		}
69 	}
70 }
71 
72 #ifdef STATIC_SIMULATION_ISLAND_OPTIMIZATION
updateActivationState(btCollisionWorld * colWorld,btDispatcher * dispatcher)73 void   btSimulationIslandManager::updateActivationState(btCollisionWorld* colWorld,btDispatcher* dispatcher)
74 {
75 
76 	// put the index into m_controllers into m_tag
77 	int index = 0;
78 	{
79 
80 		int i;
81 		for (i=0;i<colWorld->getCollisionObjectArray().size(); i++)
82 		{
83 			btCollisionObject*   collisionObject= colWorld->getCollisionObjectArray()[i];
84 			//Adding filtering here
85 			if (!collisionObject->isStaticOrKinematicObject())
86 			{
87 				collisionObject->setIslandTag(index++);
88 			}
89 			collisionObject->setCompanionId(-1);
90 			collisionObject->setHitFraction(btScalar(1.));
91 		}
92 	}
93 	// do the union find
94 
95 	initUnionFind( index );
96 
97 	findUnions(dispatcher,colWorld);
98 }
99 
storeIslandActivationState(btCollisionWorld * colWorld)100 void   btSimulationIslandManager::storeIslandActivationState(btCollisionWorld* colWorld)
101 {
102 	// put the islandId ('find' value) into m_tag
103 	{
104 		int index = 0;
105 		int i;
106 		for (i=0;i<colWorld->getCollisionObjectArray().size();i++)
107 		{
108 			btCollisionObject* collisionObject= colWorld->getCollisionObjectArray()[i];
109 			if (!collisionObject->isStaticOrKinematicObject())
110 			{
111 				collisionObject->setIslandTag( m_unionFind.find(index) );
112 				//Set the correct object offset in Collision Object Array
113 				m_unionFind.getElement(index).m_sz = i;
114 				collisionObject->setCompanionId(-1);
115 				index++;
116 			} else
117 			{
118 				collisionObject->setIslandTag(-1);
119 				collisionObject->setCompanionId(-2);
120 			}
121 		}
122 	}
123 }
124 
125 
126 #else //STATIC_SIMULATION_ISLAND_OPTIMIZATION
updateActivationState(btCollisionWorld * colWorld,btDispatcher * dispatcher)127 void	btSimulationIslandManager::updateActivationState(btCollisionWorld* colWorld,btDispatcher* dispatcher)
128 {
129 
130 	initUnionFind( int (colWorld->getCollisionObjectArray().size()));
131 
132 	// put the index into m_controllers into m_tag
133 	{
134 
135 		int index = 0;
136 		int i;
137 		for (i=0;i<colWorld->getCollisionObjectArray().size(); i++)
138 		{
139 			btCollisionObject*	collisionObject= colWorld->getCollisionObjectArray()[i];
140 			collisionObject->setIslandTag(index);
141 			collisionObject->setCompanionId(-1);
142 			collisionObject->setHitFraction(btScalar(1.));
143 			index++;
144 
145 		}
146 	}
147 	// do the union find
148 
149 	findUnions(dispatcher,colWorld);
150 }
151 
storeIslandActivationState(btCollisionWorld * colWorld)152 void	btSimulationIslandManager::storeIslandActivationState(btCollisionWorld* colWorld)
153 {
154 	// put the islandId ('find' value) into m_tag
155 	{
156 
157 
158 		int index = 0;
159 		int i;
160 		for (i=0;i<colWorld->getCollisionObjectArray().size();i++)
161 		{
162 			btCollisionObject* collisionObject= colWorld->getCollisionObjectArray()[i];
163 			if (!collisionObject->isStaticOrKinematicObject())
164 			{
165 				collisionObject->setIslandTag( m_unionFind.find(index) );
166 				collisionObject->setCompanionId(-1);
167 			} else
168 			{
169 				collisionObject->setIslandTag(-1);
170 				collisionObject->setCompanionId(-2);
171 			}
172 			index++;
173 		}
174 	}
175 }
176 
177 #endif //STATIC_SIMULATION_ISLAND_OPTIMIZATION
178 
getIslandId(const btPersistentManifold * lhs)179 inline	int	getIslandId(const btPersistentManifold* lhs)
180 {
181 	int islandId;
182 	const btCollisionObject* rcolObj0 = static_cast<const btCollisionObject*>(lhs->getBody0());
183 	const btCollisionObject* rcolObj1 = static_cast<const btCollisionObject*>(lhs->getBody1());
184 	islandId= rcolObj0->getIslandTag()>=0?rcolObj0->getIslandTag():rcolObj1->getIslandTag();
185 	return islandId;
186 
187 }
188 
189 
190 
191 /// function object that routes calls to operator<
192 class btPersistentManifoldSortPredicate
193 {
194 	public:
195 
operator ()(const btPersistentManifold * lhs,const btPersistentManifold * rhs) const196 		SIMD_FORCE_INLINE bool operator() ( const btPersistentManifold* lhs, const btPersistentManifold* rhs ) const
197 		{
198 			return getIslandId(lhs) < getIslandId(rhs);
199 		}
200 };
201 
202 
buildIslands(btDispatcher * dispatcher,btCollisionWorld * collisionWorld)203 void btSimulationIslandManager::buildIslands(btDispatcher* dispatcher,btCollisionWorld* collisionWorld)
204 {
205 
206 	BT_PROFILE("islandUnionFindAndQuickSort");
207 
208 	btCollisionObjectArray& collisionObjects = collisionWorld->getCollisionObjectArray();
209 
210 	m_islandmanifold.resize(0);
211 
212 	//we are going to sort the unionfind array, and store the element id in the size
213 	//afterwards, we clean unionfind, to make sure no-one uses it anymore
214 
215 	getUnionFind().sortIslands();
216 	int numElem = getUnionFind().getNumElements();
217 
218 	int endIslandIndex=1;
219 	int startIslandIndex;
220 
221 
222 	//update the sleeping state for bodies, if all are sleeping
223 	for ( startIslandIndex=0;startIslandIndex<numElem;startIslandIndex = endIslandIndex)
224 	{
225 		int islandId = getUnionFind().getElement(startIslandIndex).m_id;
226 		for (endIslandIndex = startIslandIndex+1;(endIslandIndex<numElem) && (getUnionFind().getElement(endIslandIndex).m_id == islandId);endIslandIndex++)
227 		{
228 		}
229 
230 		//int numSleeping = 0;
231 
232 		bool allSleeping = true;
233 
234 		int idx;
235 		for (idx=startIslandIndex;idx<endIslandIndex;idx++)
236 		{
237 			int i = getUnionFind().getElement(idx).m_sz;
238 
239 			btCollisionObject* colObj0 = collisionObjects[i];
240 			if ((colObj0->getIslandTag() != islandId) && (colObj0->getIslandTag() != -1))
241 			{
242 //				printf("error in island management\n");
243 			}
244 
245 			btAssert((colObj0->getIslandTag() == islandId) || (colObj0->getIslandTag() == -1));
246 			if (colObj0->getIslandTag() == islandId)
247 			{
248 				if (colObj0->getActivationState()== ACTIVE_TAG)
249 				{
250 					allSleeping = false;
251 				}
252 				if (colObj0->getActivationState()== DISABLE_DEACTIVATION)
253 				{
254 					allSleeping = false;
255 				}
256 			}
257 		}
258 
259 
260 		if (allSleeping)
261 		{
262 			int idx;
263 			for (idx=startIslandIndex;idx<endIslandIndex;idx++)
264 			{
265 				int i = getUnionFind().getElement(idx).m_sz;
266 				btCollisionObject* colObj0 = collisionObjects[i];
267 				if ((colObj0->getIslandTag() != islandId) && (colObj0->getIslandTag() != -1))
268 				{
269 //					printf("error in island management\n");
270 				}
271 
272 				btAssert((colObj0->getIslandTag() == islandId) || (colObj0->getIslandTag() == -1));
273 
274 				if (colObj0->getIslandTag() == islandId)
275 				{
276 					colObj0->setActivationState( ISLAND_SLEEPING );
277 				}
278 			}
279 		} else
280 		{
281 
282 			int idx;
283 			for (idx=startIslandIndex;idx<endIslandIndex;idx++)
284 			{
285 				int i = getUnionFind().getElement(idx).m_sz;
286 
287 				btCollisionObject* colObj0 = collisionObjects[i];
288 				if ((colObj0->getIslandTag() != islandId) && (colObj0->getIslandTag() != -1))
289 				{
290 //					printf("error in island management\n");
291 				}
292 
293 				btAssert((colObj0->getIslandTag() == islandId) || (colObj0->getIslandTag() == -1));
294 
295 				if (colObj0->getIslandTag() == islandId)
296 				{
297 					if ( colObj0->getActivationState() == ISLAND_SLEEPING)
298 					{
299 						colObj0->setActivationState( WANTS_DEACTIVATION);
300 						colObj0->setDeactivationTime(0.f);
301 					}
302 				}
303 			}
304 		}
305 	}
306 
307 
308 	int i;
309 	int maxNumManifolds = dispatcher->getNumManifolds();
310 
311 //#define SPLIT_ISLANDS 1
312 //#ifdef SPLIT_ISLANDS
313 
314 
315 //#endif //SPLIT_ISLANDS
316 
317 
318 	for (i=0;i<maxNumManifolds ;i++)
319 	{
320 		 btPersistentManifold* manifold = dispatcher->getManifoldByIndexInternal(i);
321 
322 		 const btCollisionObject* colObj0 = static_cast<const btCollisionObject*>(manifold->getBody0());
323 		 const btCollisionObject* colObj1 = static_cast<const btCollisionObject*>(manifold->getBody1());
324 
325 		 ///@todo: check sleeping conditions!
326 		 if (((colObj0) && colObj0->getActivationState() != ISLAND_SLEEPING) ||
327 			((colObj1) && colObj1->getActivationState() != ISLAND_SLEEPING))
328 		{
329 
330 			//kinematic objects don't merge islands, but wake up all connected objects
331 			if (colObj0->isKinematicObject() && colObj0->getActivationState() != ISLAND_SLEEPING)
332 			{
333 				if (colObj0->hasContactResponse())
334 					colObj1->activate();
335 			}
336 			if (colObj1->isKinematicObject() && colObj1->getActivationState() != ISLAND_SLEEPING)
337 			{
338 				if (colObj1->hasContactResponse())
339 					colObj0->activate();
340 			}
341 			if(m_splitIslands)
342 			{
343 				//filtering for response
344 				if (dispatcher->needsResponse(colObj0,colObj1))
345 					m_islandmanifold.push_back(manifold);
346 			}
347 		}
348 	}
349 }
350 
351 
352 
353 ///@todo: this is random access, it can be walked 'cache friendly'!
buildAndProcessIslands(btDispatcher * dispatcher,btCollisionWorld * collisionWorld,IslandCallback * callback)354 void btSimulationIslandManager::buildAndProcessIslands(btDispatcher* dispatcher,btCollisionWorld* collisionWorld, IslandCallback* callback)
355 {
356 	btCollisionObjectArray& collisionObjects = collisionWorld->getCollisionObjectArray();
357 
358 	buildIslands(dispatcher,collisionWorld);
359 
360 	int endIslandIndex=1;
361 	int startIslandIndex;
362 	int numElem = getUnionFind().getNumElements();
363 
364 	BT_PROFILE("processIslands");
365 
366 	if(!m_splitIslands)
367 	{
368 		btPersistentManifold** manifold = dispatcher->getInternalManifoldPointer();
369 		int maxNumManifolds = dispatcher->getNumManifolds();
370 		callback->processIsland(&collisionObjects[0],collisionObjects.size(),manifold,maxNumManifolds, -1);
371 	}
372 	else
373 	{
374 		// Sort manifolds, based on islands
375 		// Sort the vector using predicate and std::sort
376 		//std::sort(islandmanifold.begin(), islandmanifold.end(), btPersistentManifoldSortPredicate);
377 
378 		int numManifolds = int (m_islandmanifold.size());
379 
380 		//tried a radix sort, but quicksort/heapsort seems still faster
381 		//@todo rewrite island management
382 		m_islandmanifold.quickSort(btPersistentManifoldSortPredicate());
383 		//m_islandmanifold.heapSort(btPersistentManifoldSortPredicate());
384 
385 		//now process all active islands (sets of manifolds for now)
386 
387 		int startManifoldIndex = 0;
388 		int endManifoldIndex = 1;
389 
390 		//int islandId;
391 
392 
393 
394 	//	printf("Start Islands\n");
395 
396 		//traverse the simulation islands, and call the solver, unless all objects are sleeping/deactivated
397 		for ( startIslandIndex=0;startIslandIndex<numElem;startIslandIndex = endIslandIndex)
398 		{
399 			int islandId = getUnionFind().getElement(startIslandIndex).m_id;
400 
401 
402 			   bool islandSleeping = true;
403 
404 					for (endIslandIndex = startIslandIndex;(endIslandIndex<numElem) && (getUnionFind().getElement(endIslandIndex).m_id == islandId);endIslandIndex++)
405 					{
406 							int i = getUnionFind().getElement(endIslandIndex).m_sz;
407 							btCollisionObject* colObj0 = collisionObjects[i];
408 							m_islandBodies.push_back(colObj0);
409 							if (colObj0->isActive())
410 									islandSleeping = false;
411 					}
412 
413 
414 			//find the accompanying contact manifold for this islandId
415 			int numIslandManifolds = 0;
416 			btPersistentManifold** startManifold = 0;
417 
418 			if (startManifoldIndex<numManifolds)
419 			{
420 				int curIslandId = getIslandId(m_islandmanifold[startManifoldIndex]);
421 				if (curIslandId == islandId)
422 				{
423 					startManifold = &m_islandmanifold[startManifoldIndex];
424 
425 					for (endManifoldIndex = startManifoldIndex+1;(endManifoldIndex<numManifolds) && (islandId == getIslandId(m_islandmanifold[endManifoldIndex]));endManifoldIndex++)
426 					{
427 
428 					}
429 					/// Process the actual simulation, only if not sleeping/deactivated
430 					numIslandManifolds = endManifoldIndex-startManifoldIndex;
431 				}
432 
433 			}
434 
435 			if (!islandSleeping)
436 			{
437 				callback->processIsland(&m_islandBodies[0],m_islandBodies.size(),startManifold,numIslandManifolds, islandId);
438 	//			printf("Island callback of size:%d bodies, %d manifolds\n",islandBodies.size(),numIslandManifolds);
439 			}
440 
441 			if (numIslandManifolds)
442 			{
443 				startManifoldIndex = endManifoldIndex;
444 			}
445 
446 			m_islandBodies.resize(0);
447 		}
448 	} // else if(!splitIslands)
449 
450 }
451