2 Bullet Continuous Collision Detection and Physics Library
3 Copyright (c) 2003-2013 Erwin Coumans http://bulletphysics.org
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:
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.
16 #include "b3OverlappingPairCache.h"
18 //#include "b3Dispatcher.h"
19 //#include "b3CollisionAlgorithm.h"
20 #include "Bullet3Geometry/b3AabbUtil.h"
24 int b3g_overlappingPairs = 0;
25 int b3g_removePairs = 0;
26 int b3g_addedPairs = 0;
27 int b3g_findPairs = 0;
29 b3HashedOverlappingPairCache::b3HashedOverlappingPairCache() : m_overlapFilterCallback(0)
30 //, m_blockedForChanges(false)
32 int initialAllocatedSize = 2;
33 m_overlappingPairArray.reserve(initialAllocatedSize);
37 b3HashedOverlappingPairCache::~b3HashedOverlappingPairCache()
41 void b3HashedOverlappingPairCache::cleanOverlappingPair(b3BroadphasePair& pair, b3Dispatcher* dispatcher)
43 /* if (pair.m_algorithm)
46 pair.m_algorithm->~b3CollisionAlgorithm();
47 dispatcher->freeCollisionAlgorithm(pair.m_algorithm);
54 void b3HashedOverlappingPairCache::cleanProxyFromPairs(int proxy, b3Dispatcher* dispatcher)
56 class CleanPairCallback : public b3OverlapCallback
59 b3OverlappingPairCache* m_pairCache;
60 b3Dispatcher* m_dispatcher;
63 CleanPairCallback(int cleanProxy, b3OverlappingPairCache* pairCache, b3Dispatcher* dispatcher)
64 : m_cleanProxy(cleanProxy),
65 m_pairCache(pairCache),
66 m_dispatcher(dispatcher)
69 virtual bool processOverlap(b3BroadphasePair& pair)
71 if ((pair.x == m_cleanProxy) ||
72 (pair.y == m_cleanProxy))
74 m_pairCache->cleanOverlappingPair(pair, m_dispatcher);
80 CleanPairCallback cleanPairs(proxy, this, dispatcher);
82 processAllOverlappingPairs(&cleanPairs, dispatcher);
85 void b3HashedOverlappingPairCache::removeOverlappingPairsContainingProxy(int proxy, b3Dispatcher* dispatcher)
87 class RemovePairCallback : public b3OverlapCallback
92 RemovePairCallback(int obsoleteProxy)
93 : m_obsoleteProxy(obsoleteProxy)
96 virtual bool processOverlap(b3BroadphasePair& pair)
98 return ((pair.x == m_obsoleteProxy) ||
99 (pair.y == m_obsoleteProxy));
103 RemovePairCallback removeCallback(proxy);
105 processAllOverlappingPairs(&removeCallback, dispatcher);
108 b3BroadphasePair* b3HashedOverlappingPairCache::findPair(int proxy0, int proxy1)
112 b3Swap(proxy0, proxy1);
113 int proxyId1 = proxy0;
114 int proxyId2 = proxy1;
116 /*if (proxyId1 > proxyId2)
117 b3Swap(proxyId1, proxyId2);*/
119 int hash = static_cast<int>(getHash(static_cast<unsigned int>(proxyId1), static_cast<unsigned int>(proxyId2)) & (m_overlappingPairArray.capacity() - 1));
121 if (hash >= m_hashTable.size())
126 int index = m_hashTable[hash];
127 while (index != B3_NULL_PAIR && equalsPair(m_overlappingPairArray[index], proxyId1, proxyId2) == false)
129 index = m_next[index];
132 if (index == B3_NULL_PAIR)
137 b3Assert(index < m_overlappingPairArray.size());
139 return &m_overlappingPairArray[index];
144 void b3HashedOverlappingPairCache::growTables()
146 int newCapacity = m_overlappingPairArray.capacity();
148 if (m_hashTable.size() < newCapacity)
150 //grow hashtable and next table
151 int curHashtableSize = m_hashTable.size();
153 m_hashTable.resize(newCapacity);
154 m_next.resize(newCapacity);
158 for (i = 0; i < newCapacity; ++i)
160 m_hashTable[i] = B3_NULL_PAIR;
162 for (i = 0; i < newCapacity; ++i)
164 m_next[i] = B3_NULL_PAIR;
167 for (i = 0; i < curHashtableSize; i++)
169 const b3BroadphasePair& pair = m_overlappingPairArray[i];
170 int proxyId1 = pair.x;
171 int proxyId2 = pair.y;
172 /*if (proxyId1 > proxyId2)
173 b3Swap(proxyId1, proxyId2);*/
174 int hashValue = static_cast<int>(getHash(static_cast<unsigned int>(proxyId1), static_cast<unsigned int>(proxyId2)) & (m_overlappingPairArray.capacity() - 1)); // New hash value with new mask
175 m_next[i] = m_hashTable[hashValue];
176 m_hashTable[hashValue] = i;
181 b3BroadphasePair* b3HashedOverlappingPairCache::internalAddPair(int proxy0, int proxy1)
184 b3Swap(proxy0, proxy1);
185 int proxyId1 = proxy0;
186 int proxyId2 = proxy1;
188 /*if (proxyId1 > proxyId2)
189 b3Swap(proxyId1, proxyId2);*/
191 int hash = static_cast<int>(getHash(static_cast<unsigned int>(proxyId1), static_cast<unsigned int>(proxyId2)) & (m_overlappingPairArray.capacity() - 1)); // New hash value with new mask
193 b3BroadphasePair* pair = internalFindPair(proxy0, proxy1, hash);
198 /*for(int i=0;i<m_overlappingPairArray.size();++i)
200 if( (m_overlappingPairArray[i].m_pProxy0==proxy0)&&
201 (m_overlappingPairArray[i].m_pProxy1==proxy1))
203 printf("Adding duplicated %u<>%u\r\n",proxyId1,proxyId2);
204 internalFindPair(proxy0, proxy1, hash);
207 int count = m_overlappingPairArray.size();
208 int oldCapacity = m_overlappingPairArray.capacity();
209 pair = &m_overlappingPairArray.expandNonInitializing();
211 //this is where we add an actual pair, so also call the 'ghost'
212 // if (m_ghostPairCallback)
213 // m_ghostPairCallback->addOverlappingPair(proxy0,proxy1);
215 int newCapacity = m_overlappingPairArray.capacity();
217 if (oldCapacity < newCapacity)
220 //hash with new capacity
221 hash = static_cast<int>(getHash(static_cast<unsigned int>(proxyId1), static_cast<unsigned int>(proxyId2)) & (m_overlappingPairArray.capacity() - 1));
224 *pair = b3MakeBroadphasePair(proxy0, proxy1);
226 // pair->m_pProxy0 = proxy0;
227 // pair->m_pProxy1 = proxy1;
228 //pair->m_algorithm = 0;
229 //pair->m_internalTmpValue = 0;
231 m_next[count] = m_hashTable[hash];
232 m_hashTable[hash] = count;
237 void* b3HashedOverlappingPairCache::removeOverlappingPair(int proxy0, int proxy1, b3Dispatcher* dispatcher)
241 b3Swap(proxy0, proxy1);
242 int proxyId1 = proxy0;
243 int proxyId2 = proxy1;
245 /*if (proxyId1 > proxyId2)
246 b3Swap(proxyId1, proxyId2);*/
248 int hash = static_cast<int>(getHash(static_cast<unsigned int>(proxyId1), static_cast<unsigned int>(proxyId2)) & (m_overlappingPairArray.capacity() - 1));
250 b3BroadphasePair* pair = internalFindPair(proxy0, proxy1, hash);
256 cleanOverlappingPair(*pair, dispatcher);
258 int pairIndex = int(pair - &m_overlappingPairArray[0]);
259 b3Assert(pairIndex < m_overlappingPairArray.size());
261 // Remove the pair from the hash table.
262 int index = m_hashTable[hash];
263 b3Assert(index != B3_NULL_PAIR);
265 int previous = B3_NULL_PAIR;
266 while (index != pairIndex)
269 index = m_next[index];
272 if (previous != B3_NULL_PAIR)
274 b3Assert(m_next[previous] == pairIndex);
275 m_next[previous] = m_next[pairIndex];
279 m_hashTable[hash] = m_next[pairIndex];
282 // We now move the last pair into spot of the
283 // pair being removed. We need to fix the hash
284 // table indices to support the move.
286 int lastPairIndex = m_overlappingPairArray.size() - 1;
288 //if (m_ghostPairCallback)
289 // m_ghostPairCallback->removeOverlappingPair(proxy0, proxy1,dispatcher);
291 // If the removed pair is the last pair, we are done.
292 if (lastPairIndex == pairIndex)
294 m_overlappingPairArray.pop_back();
298 // Remove the last pair from the hash table.
299 const b3BroadphasePair* last = &m_overlappingPairArray[lastPairIndex];
300 /* missing swap here too, Nat. */
301 int lastHash = static_cast<int>(getHash(static_cast<unsigned int>(last->x), static_cast<unsigned int>(last->y)) & (m_overlappingPairArray.capacity() - 1));
303 index = m_hashTable[lastHash];
304 b3Assert(index != B3_NULL_PAIR);
306 previous = B3_NULL_PAIR;
307 while (index != lastPairIndex)
310 index = m_next[index];
313 if (previous != B3_NULL_PAIR)
315 b3Assert(m_next[previous] == lastPairIndex);
316 m_next[previous] = m_next[lastPairIndex];
320 m_hashTable[lastHash] = m_next[lastPairIndex];
323 // Copy the last pair into the remove pair's spot.
324 m_overlappingPairArray[pairIndex] = m_overlappingPairArray[lastPairIndex];
326 // Insert the last pair into the hash table
327 m_next[pairIndex] = m_hashTable[lastHash];
328 m_hashTable[lastHash] = pairIndex;
330 m_overlappingPairArray.pop_back();
336 void b3HashedOverlappingPairCache::processAllOverlappingPairs(b3OverlapCallback* callback, b3Dispatcher* dispatcher)
340 // printf("m_overlappingPairArray.size()=%d\n",m_overlappingPairArray.size());
341 for (i = 0; i < m_overlappingPairArray.size();)
343 b3BroadphasePair* pair = &m_overlappingPairArray[i];
344 if (callback->processOverlap(*pair))
346 removeOverlappingPair(pair->x, pair->y, dispatcher);
348 b3g_overlappingPairs--;
357 void b3HashedOverlappingPairCache::sortOverlappingPairs(b3Dispatcher* dispatcher)
359 ///need to keep hashmap in sync with pair address, so rebuild all
360 b3BroadphasePairArray tmpPairs;
362 for (i = 0; i < m_overlappingPairArray.size(); i++)
364 tmpPairs.push_back(m_overlappingPairArray[i]);
367 for (i = 0; i < tmpPairs.size(); i++)
369 removeOverlappingPair(tmpPairs[i].x, tmpPairs[i].y, dispatcher);
372 for (i = 0; i < m_next.size(); i++)
374 m_next[i] = B3_NULL_PAIR;
377 tmpPairs.quickSort(b3BroadphasePairSortPredicate());
379 for (i = 0; i < tmpPairs.size(); i++)
381 addOverlappingPair(tmpPairs[i].x, tmpPairs[i].y);
385 void* b3SortedOverlappingPairCache::removeOverlappingPair(int proxy0, int proxy1, b3Dispatcher* dispatcher)
387 if (!hasDeferredRemoval())
389 b3BroadphasePair findPair = b3MakeBroadphasePair(proxy0, proxy1);
391 int findIndex = m_overlappingPairArray.findLinearSearch(findPair);
392 if (findIndex < m_overlappingPairArray.size())
394 b3g_overlappingPairs--;
395 b3BroadphasePair& pair = m_overlappingPairArray[findIndex];
397 cleanOverlappingPair(pair, dispatcher);
398 //if (m_ghostPairCallback)
399 // m_ghostPairCallback->removeOverlappingPair(proxy0, proxy1,dispatcher);
401 m_overlappingPairArray.swap(findIndex, m_overlappingPairArray.capacity() - 1);
402 m_overlappingPairArray.pop_back();
410 b3BroadphasePair* b3SortedOverlappingPairCache::addOverlappingPair(int proxy0, int proxy1)
412 //don't add overlap with own
413 b3Assert(proxy0 != proxy1);
415 if (!needsBroadphaseCollision(proxy0, proxy1))
418 b3BroadphasePair* pair = &m_overlappingPairArray.expandNonInitializing();
419 *pair = b3MakeBroadphasePair(proxy0, proxy1);
421 b3g_overlappingPairs++;
424 // if (m_ghostPairCallback)
425 // m_ghostPairCallback->addOverlappingPair(proxy0, proxy1);
429 ///this findPair becomes really slow. Either sort the list to speedup the query, or
430 ///use a different solution. It is mainly used for Removing overlapping pairs. Removal could be delayed.
431 ///we could keep a linked list in each proxy, and store pair in one of the proxies (with lowest memory address)
432 ///Also we can use a 2D bitmap, which can be useful for a future GPU implementation
433 b3BroadphasePair* b3SortedOverlappingPairCache::findPair(int proxy0, int proxy1)
435 if (!needsBroadphaseCollision(proxy0, proxy1))
438 b3BroadphasePair tmpPair = b3MakeBroadphasePair(proxy0, proxy1);
439 int findIndex = m_overlappingPairArray.findLinearSearch(tmpPair);
441 if (findIndex < m_overlappingPairArray.size())
443 //b3Assert(it != m_overlappingPairSet.end());
444 b3BroadphasePair* pair = &m_overlappingPairArray[findIndex];
452 void b3SortedOverlappingPairCache::processAllOverlappingPairs(b3OverlapCallback* callback, b3Dispatcher* dispatcher)
456 for (i = 0; i < m_overlappingPairArray.size();)
458 b3BroadphasePair* pair = &m_overlappingPairArray[i];
459 if (callback->processOverlap(*pair))
461 cleanOverlappingPair(*pair, dispatcher);
464 m_overlappingPairArray.swap(i, m_overlappingPairArray.size() - 1);
465 m_overlappingPairArray.pop_back();
466 b3g_overlappingPairs--;
475 b3SortedOverlappingPairCache::b3SortedOverlappingPairCache() : m_blockedForChanges(false),
476 m_hasDeferredRemoval(true),
477 m_overlapFilterCallback(0)
480 int initialAllocatedSize = 2;
481 m_overlappingPairArray.reserve(initialAllocatedSize);
484 b3SortedOverlappingPairCache::~b3SortedOverlappingPairCache()
488 void b3SortedOverlappingPairCache::cleanOverlappingPair(b3BroadphasePair& pair, b3Dispatcher* dispatcher)
490 /* if (pair.m_algorithm)
493 pair.m_algorithm->~b3CollisionAlgorithm();
494 dispatcher->freeCollisionAlgorithm(pair.m_algorithm);
502 void b3SortedOverlappingPairCache::cleanProxyFromPairs(int proxy, b3Dispatcher* dispatcher)
504 class CleanPairCallback : public b3OverlapCallback
507 b3OverlappingPairCache* m_pairCache;
508 b3Dispatcher* m_dispatcher;
511 CleanPairCallback(int cleanProxy, b3OverlappingPairCache* pairCache, b3Dispatcher* dispatcher)
512 : m_cleanProxy(cleanProxy),
513 m_pairCache(pairCache),
514 m_dispatcher(dispatcher)
517 virtual bool processOverlap(b3BroadphasePair& pair)
519 if ((pair.x == m_cleanProxy) ||
520 (pair.y == m_cleanProxy))
522 m_pairCache->cleanOverlappingPair(pair, m_dispatcher);
528 CleanPairCallback cleanPairs(proxy, this, dispatcher);
530 processAllOverlappingPairs(&cleanPairs, dispatcher);
533 void b3SortedOverlappingPairCache::removeOverlappingPairsContainingProxy(int proxy, b3Dispatcher* dispatcher)
535 class RemovePairCallback : public b3OverlapCallback
540 RemovePairCallback(int obsoleteProxy)
541 : m_obsoleteProxy(obsoleteProxy)
544 virtual bool processOverlap(b3BroadphasePair& pair)
546 return ((pair.x == m_obsoleteProxy) ||
547 (pair.y == m_obsoleteProxy));
551 RemovePairCallback removeCallback(proxy);
553 processAllOverlappingPairs(&removeCallback, dispatcher);
556 void b3SortedOverlappingPairCache::sortOverlappingPairs(b3Dispatcher* dispatcher)
558 //should already be sorted