Blender  V2.59
btSimulationIslandManager.cpp
Go to the documentation of this file.
00001 
00002 /*
00003 Bullet Continuous Collision Detection and Physics Library
00004 Copyright (c) 2003-2006 Erwin Coumans  http://continuousphysics.com/Bullet/
00005 
00006 This software is provided 'as-is', without any express or implied warranty.
00007 In no event will the authors be held liable for any damages arising from the use of this software.
00008 Permission is granted to anyone to use this software for any purpose, 
00009 including commercial applications, and to alter it and redistribute it freely, 
00010 subject to the following restrictions:
00011 
00012 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.
00013 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
00014 3. This notice may not be removed or altered from any source distribution.
00015 */
00016 
00017 
00018 #include "LinearMath/btScalar.h"
00019 #include "btSimulationIslandManager.h"
00020 #include "BulletCollision/BroadphaseCollision/btDispatcher.h"
00021 #include "BulletCollision/NarrowPhaseCollision/btPersistentManifold.h"
00022 #include "BulletCollision/CollisionDispatch/btCollisionObject.h"
00023 #include "BulletCollision/CollisionDispatch/btCollisionWorld.h"
00024 
00025 //#include <stdio.h>
00026 #include "LinearMath/btQuickprof.h"
00027 
00028 btSimulationIslandManager::btSimulationIslandManager():
00029 m_splitIslands(true)
00030 {
00031 }
00032 
00033 btSimulationIslandManager::~btSimulationIslandManager()
00034 {
00035 }
00036 
00037 
00038 void btSimulationIslandManager::initUnionFind(int n)
00039 {
00040                 m_unionFind.reset(n);
00041 }
00042                 
00043 
00044 void btSimulationIslandManager::findUnions(btDispatcher* /* dispatcher */,btCollisionWorld* colWorld)
00045 {
00046         
00047         {
00048                 btOverlappingPairCache* pairCachePtr = colWorld->getPairCache();
00049                 const int numOverlappingPairs = pairCachePtr->getNumOverlappingPairs();
00050                 btBroadphasePair* pairPtr = pairCachePtr->getOverlappingPairArrayPtr();
00051                 
00052                 for (int i=0;i<numOverlappingPairs;i++)
00053                 {
00054                         const btBroadphasePair& collisionPair = pairPtr[i];
00055                         btCollisionObject* colObj0 = (btCollisionObject*)collisionPair.m_pProxy0->m_clientObject;
00056                         btCollisionObject* colObj1 = (btCollisionObject*)collisionPair.m_pProxy1->m_clientObject;
00057 
00058                         if (((colObj0) && ((colObj0)->mergesSimulationIslands())) &&
00059                                 ((colObj1) && ((colObj1)->mergesSimulationIslands())))
00060                         {
00061 
00062                                 m_unionFind.unite((colObj0)->getIslandTag(),
00063                                         (colObj1)->getIslandTag());
00064                         }
00065                 }
00066         }
00067 }
00068 
00069 #ifdef STATIC_SIMULATION_ISLAND_OPTIMIZATION
00070 void   btSimulationIslandManager::updateActivationState(btCollisionWorld* colWorld,btDispatcher* dispatcher)
00071 {
00072 
00073         // put the index into m_controllers into m_tag   
00074         int index = 0;
00075         {
00076 
00077                 int i;
00078                 for (i=0;i<colWorld->getCollisionObjectArray().size(); i++)
00079                 {
00080                         btCollisionObject*   collisionObject= colWorld->getCollisionObjectArray()[i];
00081                         //Adding filtering here
00082                         if (!collisionObject->isStaticOrKinematicObject())
00083                         {
00084                                 collisionObject->setIslandTag(index++);
00085                         }
00086                         collisionObject->setCompanionId(-1);
00087                         collisionObject->setHitFraction(btScalar(1.));
00088                 }
00089         }
00090         // do the union find
00091 
00092         initUnionFind( index );
00093 
00094         findUnions(dispatcher,colWorld);
00095 }
00096 
00097 void   btSimulationIslandManager::storeIslandActivationState(btCollisionWorld* colWorld)
00098 {
00099         // put the islandId ('find' value) into m_tag   
00100         {
00101                 int index = 0;
00102                 int i;
00103                 for (i=0;i<colWorld->getCollisionObjectArray().size();i++)
00104                 {
00105                         btCollisionObject* collisionObject= colWorld->getCollisionObjectArray()[i];
00106                         if (!collisionObject->isStaticOrKinematicObject())
00107                         {
00108                                 collisionObject->setIslandTag( m_unionFind.find(index) );
00109                                 //Set the correct object offset in Collision Object Array
00110                                 m_unionFind.getElement(index).m_sz = i;
00111                                 collisionObject->setCompanionId(-1);
00112                                 index++;
00113                         } else
00114                         {
00115                                 collisionObject->setIslandTag(-1);
00116                                 collisionObject->setCompanionId(-2);
00117                         }
00118                 }
00119         }
00120 }
00121 
00122 
00123 #else //STATIC_SIMULATION_ISLAND_OPTIMIZATION
00124 void    btSimulationIslandManager::updateActivationState(btCollisionWorld* colWorld,btDispatcher* dispatcher)
00125 {
00126 
00127         initUnionFind( int (colWorld->getCollisionObjectArray().size()));
00128 
00129         // put the index into m_controllers into m_tag  
00130         {
00131 
00132                 int index = 0;
00133                 int i;
00134                 for (i=0;i<colWorld->getCollisionObjectArray().size(); i++)
00135                 {
00136                         btCollisionObject*      collisionObject= colWorld->getCollisionObjectArray()[i];
00137                         collisionObject->setIslandTag(index);
00138                         collisionObject->setCompanionId(-1);
00139                         collisionObject->setHitFraction(btScalar(1.));
00140                         index++;
00141 
00142                 }
00143         }
00144         // do the union find
00145 
00146         findUnions(dispatcher,colWorld);
00147 }
00148 
00149 void    btSimulationIslandManager::storeIslandActivationState(btCollisionWorld* colWorld)
00150 {
00151         // put the islandId ('find' value) into m_tag   
00152         {
00153 
00154 
00155                 int index = 0;
00156                 int i;
00157                 for (i=0;i<colWorld->getCollisionObjectArray().size();i++)
00158                 {
00159                         btCollisionObject* collisionObject= colWorld->getCollisionObjectArray()[i];
00160                         if (!collisionObject->isStaticOrKinematicObject())
00161                         {
00162                                 collisionObject->setIslandTag( m_unionFind.find(index) );
00163                                 collisionObject->setCompanionId(-1);
00164                         } else
00165                         {
00166                                 collisionObject->setIslandTag(-1);
00167                                 collisionObject->setCompanionId(-2);
00168                         }
00169                         index++;
00170                 }
00171         }
00172 }
00173 
00174 #endif //STATIC_SIMULATION_ISLAND_OPTIMIZATION
00175 
00176 inline  int     getIslandId(const btPersistentManifold* lhs)
00177 {
00178         int islandId;
00179         const btCollisionObject* rcolObj0 = static_cast<const btCollisionObject*>(lhs->getBody0());
00180         const btCollisionObject* rcolObj1 = static_cast<const btCollisionObject*>(lhs->getBody1());
00181         islandId= rcolObj0->getIslandTag()>=0?rcolObj0->getIslandTag():rcolObj1->getIslandTag();
00182         return islandId;
00183 
00184 }
00185 
00186 
00187 
00189 class btPersistentManifoldSortPredicate
00190 {
00191         public:
00192 
00193                 SIMD_FORCE_INLINE bool operator() ( const btPersistentManifold* lhs, const btPersistentManifold* rhs )
00194                 {
00195                         return getIslandId(lhs) < getIslandId(rhs);
00196                 }
00197 };
00198 
00199 
00200 void btSimulationIslandManager::buildIslands(btDispatcher* dispatcher,btCollisionWorld* collisionWorld)
00201 {
00202 
00203         BT_PROFILE("islandUnionFindAndQuickSort");
00204         
00205         btCollisionObjectArray& collisionObjects = collisionWorld->getCollisionObjectArray();
00206 
00207         m_islandmanifold.resize(0);
00208 
00209         //we are going to sort the unionfind array, and store the element id in the size
00210         //afterwards, we clean unionfind, to make sure no-one uses it anymore
00211         
00212         getUnionFind().sortIslands();
00213         int numElem = getUnionFind().getNumElements();
00214 
00215         int endIslandIndex=1;
00216         int startIslandIndex;
00217 
00218 
00219         //update the sleeping state for bodies, if all are sleeping
00220         for ( startIslandIndex=0;startIslandIndex<numElem;startIslandIndex = endIslandIndex)
00221         {
00222                 int islandId = getUnionFind().getElement(startIslandIndex).m_id;
00223                 for (endIslandIndex = startIslandIndex+1;(endIslandIndex<numElem) && (getUnionFind().getElement(endIslandIndex).m_id == islandId);endIslandIndex++)
00224                 {
00225                 }
00226 
00227                 //int numSleeping = 0;
00228 
00229                 bool allSleeping = true;
00230 
00231                 int idx;
00232                 for (idx=startIslandIndex;idx<endIslandIndex;idx++)
00233                 {
00234                         int i = getUnionFind().getElement(idx).m_sz;
00235 
00236                         btCollisionObject* colObj0 = collisionObjects[i];
00237                         if ((colObj0->getIslandTag() != islandId) && (colObj0->getIslandTag() != -1))
00238                         {
00239 //                              printf("error in island management\n");
00240                         }
00241 
00242                         btAssert((colObj0->getIslandTag() == islandId) || (colObj0->getIslandTag() == -1));
00243                         if (colObj0->getIslandTag() == islandId)
00244                         {
00245                                 if (colObj0->getActivationState()== ACTIVE_TAG)
00246                                 {
00247                                         allSleeping = false;
00248                                 }
00249                                 if (colObj0->getActivationState()== DISABLE_DEACTIVATION)
00250                                 {
00251                                         allSleeping = false;
00252                                 }
00253                         }
00254                 }
00255                         
00256 
00257                 if (allSleeping)
00258                 {
00259                         int idx;
00260                         for (idx=startIslandIndex;idx<endIslandIndex;idx++)
00261                         {
00262                                 int i = getUnionFind().getElement(idx).m_sz;
00263                                 btCollisionObject* colObj0 = collisionObjects[i];
00264                                 if ((colObj0->getIslandTag() != islandId) && (colObj0->getIslandTag() != -1))
00265                                 {
00266 //                                      printf("error in island management\n");
00267                                 }
00268 
00269                                 btAssert((colObj0->getIslandTag() == islandId) || (colObj0->getIslandTag() == -1));
00270 
00271                                 if (colObj0->getIslandTag() == islandId)
00272                                 {
00273                                         colObj0->setActivationState( ISLAND_SLEEPING );
00274                                 }
00275                         }
00276                 } else
00277                 {
00278 
00279                         int idx;
00280                         for (idx=startIslandIndex;idx<endIslandIndex;idx++)
00281                         {
00282                                 int i = getUnionFind().getElement(idx).m_sz;
00283 
00284                                 btCollisionObject* colObj0 = collisionObjects[i];
00285                                 if ((colObj0->getIslandTag() != islandId) && (colObj0->getIslandTag() != -1))
00286                                 {
00287 //                                      printf("error in island management\n");
00288                                 }
00289 
00290                                 btAssert((colObj0->getIslandTag() == islandId) || (colObj0->getIslandTag() == -1));
00291 
00292                                 if (colObj0->getIslandTag() == islandId)
00293                                 {
00294                                         if ( colObj0->getActivationState() == ISLAND_SLEEPING)
00295                                         {
00296                                                 colObj0->setActivationState( WANTS_DEACTIVATION);
00297                                                 colObj0->setDeactivationTime(0.f);
00298                                         }
00299                                 }
00300                         }
00301                 }
00302         }
00303 
00304         
00305         int i;
00306         int maxNumManifolds = dispatcher->getNumManifolds();
00307 
00308 //#define SPLIT_ISLANDS 1
00309 //#ifdef SPLIT_ISLANDS
00310 
00311         
00312 //#endif //SPLIT_ISLANDS
00313 
00314         
00315         for (i=0;i<maxNumManifolds ;i++)
00316         {
00317                  btPersistentManifold* manifold = dispatcher->getManifoldByIndexInternal(i);
00318                  
00319                  btCollisionObject* colObj0 = static_cast<btCollisionObject*>(manifold->getBody0());
00320                  btCollisionObject* colObj1 = static_cast<btCollisionObject*>(manifold->getBody1());
00321                 
00323                  if (((colObj0) && colObj0->getActivationState() != ISLAND_SLEEPING) ||
00324                         ((colObj1) && colObj1->getActivationState() != ISLAND_SLEEPING))
00325                 {
00326                 
00327                         //kinematic objects don't merge islands, but wake up all connected objects
00328                         if (colObj0->isKinematicObject() && colObj0->getActivationState() != ISLAND_SLEEPING)
00329                         {
00330                                 colObj1->activate();
00331                         }
00332                         if (colObj1->isKinematicObject() && colObj1->getActivationState() != ISLAND_SLEEPING)
00333                         {
00334                                 colObj0->activate();
00335                         }
00336                         if(m_splitIslands)
00337                         { 
00338                                 //filtering for response
00339                                 if (dispatcher->needsResponse(colObj0,colObj1))
00340                                         m_islandmanifold.push_back(manifold);
00341                         }
00342                 }
00343         }
00344 }
00345 
00346 
00347 
00349 void btSimulationIslandManager::buildAndProcessIslands(btDispatcher* dispatcher,btCollisionWorld* collisionWorld, IslandCallback* callback)
00350 {
00351         btCollisionObjectArray& collisionObjects = collisionWorld->getCollisionObjectArray();
00352 
00353         buildIslands(dispatcher,collisionWorld);
00354 
00355         int endIslandIndex=1;
00356         int startIslandIndex;
00357         int numElem = getUnionFind().getNumElements();
00358 
00359         BT_PROFILE("processIslands");
00360 
00361         if(!m_splitIslands)
00362         {
00363                 btPersistentManifold** manifold = dispatcher->getInternalManifoldPointer();
00364                 int maxNumManifolds = dispatcher->getNumManifolds();
00365                 callback->ProcessIsland(&collisionObjects[0],collisionObjects.size(),manifold,maxNumManifolds, -1);
00366         }
00367         else
00368         {
00369                 // Sort manifolds, based on islands
00370                 // Sort the vector using predicate and std::sort
00371                 //std::sort(islandmanifold.begin(), islandmanifold.end(), btPersistentManifoldSortPredicate);
00372 
00373                 int numManifolds = int (m_islandmanifold.size());
00374 
00375                 //we should do radix sort, it it much faster (O(n) instead of O (n log2(n))
00376                 m_islandmanifold.quickSort(btPersistentManifoldSortPredicate());
00377 
00378                 //now process all active islands (sets of manifolds for now)
00379 
00380                 int startManifoldIndex = 0;
00381                 int endManifoldIndex = 1;
00382 
00383                 //int islandId;
00384 
00385                 
00386 
00387         //      printf("Start Islands\n");
00388 
00389                 //traverse the simulation islands, and call the solver, unless all objects are sleeping/deactivated
00390                 for ( startIslandIndex=0;startIslandIndex<numElem;startIslandIndex = endIslandIndex)
00391                 {
00392                         int islandId = getUnionFind().getElement(startIslandIndex).m_id;
00393 
00394 
00395                            bool islandSleeping = true;
00396                         
00397                                         for (endIslandIndex = startIslandIndex;(endIslandIndex<numElem) && (getUnionFind().getElement(endIslandIndex).m_id == islandId);endIslandIndex++)
00398                                         {
00399                                                         int i = getUnionFind().getElement(endIslandIndex).m_sz;
00400                                                         btCollisionObject* colObj0 = collisionObjects[i];
00401                                                         m_islandBodies.push_back(colObj0);
00402                                                         if (colObj0->isActive())
00403                                                                         islandSleeping = false;
00404                                         }
00405                         
00406 
00407                         //find the accompanying contact manifold for this islandId
00408                         int numIslandManifolds = 0;
00409                         btPersistentManifold** startManifold = 0;
00410 
00411                         if (startManifoldIndex<numManifolds)
00412                         {
00413                                 int curIslandId = getIslandId(m_islandmanifold[startManifoldIndex]);
00414                                 if (curIslandId == islandId)
00415                                 {
00416                                         startManifold = &m_islandmanifold[startManifoldIndex];
00417                                 
00418                                         for (endManifoldIndex = startManifoldIndex+1;(endManifoldIndex<numManifolds) && (islandId == getIslandId(m_islandmanifold[endManifoldIndex]));endManifoldIndex++)
00419                                         {
00420 
00421                                         }
00423                                         numIslandManifolds = endManifoldIndex-startManifoldIndex;
00424                                 }
00425 
00426                         }
00427 
00428                         if (!islandSleeping)
00429                         {
00430                                 callback->ProcessIsland(&m_islandBodies[0],m_islandBodies.size(),startManifold,numIslandManifolds, islandId);
00431         //                      printf("Island callback of size:%d bodies, %d manifolds\n",islandBodies.size(),numIslandManifolds);
00432                         }
00433                         
00434                         if (numIslandManifolds)
00435                         {
00436                                 startManifoldIndex = endManifoldIndex;
00437                         }
00438 
00439                         m_islandBodies.resize(0);
00440                 }
00441         } // else if(!splitIslands) 
00442 
00443 }