vrsode/src/PhysicsManager.cpp

Go to the documentation of this file.
00001 
00002 #include "random_utils/LogManager.h"
00003 #include "random_utils/ThreadSafeCanvas.h"
00004 
00005 #include "PhysicsManager.h"
00006 #include "PhysicsBody.h"
00007 
00008 namespace vrsode
00009 {
00010 
00011 PhysicsManager* PhysicsManager::m_instance = 0;
00012 bool PhysicsManager::m_keepRunning = true;
00013 double PhysicsManager::m_stepSize = 0.02;
00014 double PhysicsManager::m_stepTime = 0.004;
00015 unsigned int PhysicsManager::m_updateResolution = 1;
00016 bool PhysicsManager::m_runningMultiThreaded = false;
00017 SDL_Thread* PhysicsManager::m_thread = 0;
00018 
00019 const unsigned int g_initialCollisionCategory = 0xFFFF0000;
00020 const unsigned int g_initialCollisionPartnerCategories = 0xFFFF0000;
00021 
00022 static void
00023 NearCallback(void* p_data, dGeomID p_geomOne, dGeomID p_geomTwo);
00024 
00025 PhysicsManager::PhysicsManager()
00026 {
00027     m_initialised           = false;
00028     m_performanceAutoAdjust = false;
00029     m_maxCollisionContacts  = 16;
00030     init();
00031 }
00032 
00033 PhysicsManager::~PhysicsManager()
00034 {
00035     if(m_initialised)
00036         release();
00037 }
00038 
00039 void
00040 PhysicsManager::registerCollisionBody(VRS::SO<CollisionBody> p_object)
00041 {
00042     m_collisionBodies.push_back(p_object);
00043 
00044     p_object->setCollisionCategory(g_initialCollisionCategory);
00045     p_object->setCollisionPartnerCategories(
00046             g_initialCollisionPartnerCategories);
00047 }
00048 
00049 void
00050 PhysicsManager::registerPhysicsBody(VRS::SO<PhysicsBody> p_object)
00051 {
00052     m_physicsBodies.push_back(p_object);
00053 
00054     p_object->setCollisionCategory(g_initialCollisionCategory);
00055     p_object->setCollisionPartnerCategories(
00056             g_initialCollisionPartnerCategories);
00057 }
00058 
00059 void
00060 PhysicsManager::unregisterCollisionBody(VRS::SO<CollisionBody> p_object)
00061 {
00062     std::vector<VRS::SO<CollisionBody> >::iterator it;
00063     it = findCollisionBody(p_object);
00064 
00065     if(it != m_collisionBodies.end())
00066         m_collisionBodies.erase(it);
00067 
00068     if(p_object->geomId())
00069         dSpaceRemove(spaceId(), p_object->geomId());
00070 }
00071 
00072 void
00073 PhysicsManager::unregisterPhysicsBody(VRS::SO<PhysicsBody> p_object)
00074 {
00075     std::vector<VRS::SO<PhysicsBody> >::iterator it;
00076     it = findPhysicsBody(p_object);
00077 
00078     if(it != m_physicsBodies.end())
00079         m_physicsBodies.erase(it);
00080 
00081     if(p_object->geomId())
00082         dSpaceRemove(spaceId(), p_object->geomId());
00083 }
00084 
00085 const bool
00086 PhysicsManager::isInitialised() const
00087 {
00088     return m_initialised;
00089 }
00090 
00091 const dSpaceID
00092 PhysicsManager::spaceId() const
00093 {
00094     return m_spaceId;
00095 }
00096 
00097 const dWorldID
00098 PhysicsManager::worldId() const
00099 {
00100     return m_worldId;
00101 }
00102 
00103 const unsigned int
00104 PhysicsManager::maxCollisionContacts() const
00105 {
00106     return m_maxCollisionContacts;
00107 }
00108 
00109 void
00110 PhysicsManager::setMaxCollisionContacts(unsigned int p_maxCollisionContacts)
00111 {
00112     m_maxCollisionContacts = p_maxCollisionContacts;
00113 }
00114 
00115 const dJointGroupID
00116 PhysicsManager::collisionContactGroupId() const
00117 {
00118     return m_collisionContactGroupId;
00119 }
00120 
00121 const std::vector<VRS::SO<PhysicsBody> >&
00122 PhysicsManager::physicsBodies() const
00123 {
00124     return m_physicsBodies;
00125 }
00126 
00127 const std::vector<VRS::SO<CollisionBody> >&
00128 PhysicsManager::collisionBodies() const
00129 {
00130     return m_collisionBodies;
00131 }
00132 
00133 unsigned int
00134 PhysicsManager::physicsBodyCount() const
00135 {
00136     return m_physicsBodies.size();
00137 }
00138 
00139 unsigned int
00140 PhysicsManager::collisionBodyCount() const
00141 {
00142     return m_collisionBodies.size();
00143 }
00144 
00145 void
00146 PhysicsManager::init()
00147 {
00148     m_worldId = dWorldCreate();
00149     m_spaceId = dHashSpaceCreate(0);
00150 //     m_spaceId = dSimpleSpaceCreate(0);
00151     m_collisionContactGroupId = dJointGroupCreate(0);
00152 
00153     // TODO: change those values via accessor function
00154 //     dWorldSetERP(m_worldId, 0.2);
00155     dWorldSetERP(m_worldId, 0.9);
00156     dWorldSetCFM(m_worldId, 0.0001);
00157     dWorldSetGravity(m_worldId, 0.0, -9.81, 0.0);
00158     dWorldSetAutoDisableFlag(m_worldId, true);
00159     dWorldSetAutoDisableLinearThreshold(m_worldId, 0.01);
00160     dWorldSetAutoDisableAngularThreshold(m_worldId, 0.01);
00161     dWorldSetAutoDisableSteps(m_worldId, 10);
00162     dWorldSetAutoDisableTime(m_worldId, 0);
00163     dWorldSetContactMaxCorrectingVel(m_worldId, dInfinity);
00164     dWorldSetContactSurfaceLayer(m_worldId, 0.001);
00165 
00166     m_initialised   = true;
00167 }
00168 
00169 void
00170 PhysicsManager::tick(double p_stepSize)
00171 {
00172     if(!isInitialised())
00173         return;
00174     {
00175         std::vector<VRS::SO<CollisionBody> >::iterator it;
00176         for(it = m_collisionBodies.begin(); it != m_collisionBodies.end(); it++)
00177             (*it)->update();
00178     }
00179 
00180     {
00181         std::vector<VRS::SO<PhysicsBody> >::iterator it;
00182         for(it = m_physicsBodies.begin(); it != m_physicsBodies.end(); it++)
00183             (*it)->update();
00184     }
00185 
00186     dSpaceCollide(m_spaceId, 0, &NearCallback);
00187     dWorldStep(m_worldId, p_stepSize);
00188     dJointGroupEmpty(m_collisionContactGroupId);
00189 }
00190 
00191 void
00192 PhysicsManager::update()
00193 {
00194     lock();
00195     tick(stepSize() / (double)updateResolution());
00196     unlock();
00197 }
00198 
00199 void
00200 PhysicsManager::update(double p_stepSize)
00201 {
00202     for(unsigned int i = 0; i < updateResolution(); i++)
00203         tick(p_stepSize / (double)updateResolution());
00204     
00205     applyTransformations();
00206 }
00207 
00208 void
00209 PhysicsManager::release()
00210 {
00211     if(!isInitialised())
00212         return;
00213 
00214     dJointGroupEmpty(m_collisionContactGroupId);
00215     dJointGroupDestroy(m_collisionContactGroupId);
00216     dWorldDestroy(m_worldId);
00217     dSpaceDestroy(m_spaceId);
00218     dCloseODE();
00219 
00220     m_initialised = false;
00221 }
00222 
00223 void
00224 PhysicsManager::applyTransformations()
00225 {
00226     std::vector<VRS::SO<PhysicsBody> >::iterator it;
00227     for(it = m_physicsBodies.begin(); it != m_physicsBodies.end(); it++)
00228         (*it)->syncTransformationsToVRS();
00229 }
00230 
00231 std::vector<VRS::SO<PhysicsBody> >::iterator
00232 PhysicsManager::findPhysicsBody(VRS::SO<PhysicsBody> p_physicsBody)
00233 {
00234     std::vector<VRS::SO<PhysicsBody> >::iterator it;
00235 
00236     for(it = m_physicsBodies.begin(); it != m_physicsBodies.end(); it++)
00237         if(*it == p_physicsBody)
00238             return it;
00239 
00240     return m_physicsBodies.end();
00241 }
00242 
00243 std::vector<VRS::SO<CollisionBody> >::iterator
00244 PhysicsManager::findCollisionBody(VRS::SO<CollisionBody> p_collisionBody)
00245 {
00246     std::vector<VRS::SO<CollisionBody> >::iterator it;
00247 
00248     for(it = m_collisionBodies.begin(); it != m_collisionBodies.end(); it++)
00249         if(*it == p_collisionBody)
00250             return it;
00251 
00252     return m_collisionBodies.end();
00253 }
00254 
00255 void
00256 PhysicsManager::setDebugNodesGlobal(bool p_debugNodes)
00257 {
00258     std::vector<VRS::SO<PhysicsBody> >::iterator it1;
00259     std::vector<VRS::SO<CollisionBody> >::iterator it2;
00260 
00261     for(it1 = m_physicsBodies.begin(); it1 != m_physicsBodies.end(); it1++)
00262         (*it1)->setDebugNode(p_debugNodes);
00263     for(it2 = m_collisionBodies.begin(); it2 != m_collisionBodies.end(); it2++)
00264         (*it2)->setDebugNode(p_debugNodes);
00265 }
00266 
00267 static void
00268 NearCallback(void* p_data, dGeomID p_geomOne, dGeomID p_geomTwo)
00269 {
00270     unsigned int maxContacts = PhysicsManager::get()->maxCollisionContacts();
00271 
00272     if(dGeomGetBody(p_geomOne) && dGeomGetBody(p_geomTwo))
00273         if(dAreConnected(dGeomGetBody(p_geomOne), dGeomGetBody(p_geomTwo)))
00274             return;
00275 
00276     if (dGeomIsSpace(p_geomOne) || dGeomIsSpace(p_geomTwo))
00277     {
00278         dSpaceCollide2(p_geomOne, p_geomTwo, p_data, &NearCallback);
00279 
00280         if(dGeomIsSpace(p_geomOne))
00281             dSpaceCollide((dSpaceID)p_geomOne, p_data, &NearCallback);
00282 
00283         if(dGeomIsSpace(p_geomTwo))
00284             dSpaceCollide((dSpaceID)p_geomTwo, p_data, &NearCallback);
00285 
00286         return;
00287     }
00288 
00289     VRS::SO<CollisionBody> bodyOne = (CollisionBody*)dGeomGetData(p_geomOne);
00290     VRS::SO<CollisionBody> bodyTwo = (CollisionBody*)dGeomGetData(p_geomTwo);
00291     VRS::SO<Surface> surfaceOne = bodyOne ? bodyOne->surface() : 0;
00292     VRS::SO<Surface> surfaceTwo = bodyTwo ? bodyTwo->surface() : 0;
00293 
00294     // check collision categories
00295     unsigned long bodyOneCategory = bodyOne->collisionCategory();
00296     unsigned long bodyOnePartners = bodyOne->collisionPartnerCategories();
00297     unsigned long bodyTwoCategory = bodyTwo->collisionCategory();
00298     unsigned long bodyTwoPartners = bodyTwo->collisionPartnerCategories();
00299 
00300     // collide if both want to collide
00301     if((bodyOneCategory&bodyTwoPartners) && (bodyTwoCategory&bodyOnePartners))
00302     {
00303         dContact     contacts[maxContacts];
00304         unsigned int numberOfContacts =
00305                 dCollide(p_geomOne, p_geomTwo, maxContacts,
00306                 &(contacts[0].geom), sizeof(dContact));
00307 
00308         for (unsigned int i = 0; i < numberOfContacts; i++)
00309         {
00310             contacts[i].surface.mode =
00311                     dContactSoftERP | dContactSoftCFM | dContactBounce |
00312                     dContactApprox1 | dContactSlip1   | dContactSlip2;
00313 
00314             // if we do not have surface information, use default values
00315             if(!surfaceOne || !surfaceTwo)
00316             {
00317                 rErr("no surface, using hardcoded default values...");
00318                 contacts[i].surface.slip1       = 0.1;
00319                 contacts[i].surface.slip2       = 0.1;
00320                 contacts[i].surface.mu          = dInfinity;
00321                 contacts[i].surface.bounce      = 0.0;
00322                 contacts[i].surface.bounce_vel  = dInfinity;
00323                 contacts[i].surface.soft_erp    = 0.99;
00324                 contacts[i].surface.soft_cfm    = 0.02;
00325             }
00326             // if we have surfaces and no ghost, set values
00327             else if(!surfaceOne->ghostMode() && !surfaceTwo->ghostMode())
00328             {
00329                 // the bigger slip value is the one we are using
00330                 contacts[i].surface.slip1 =
00331                         fmax(surfaceOne->slip1(), surfaceTwo->slip1());
00332 
00333                 // the bigger slip value is the one we are using
00334                 contacts[i].surface.slip2 =
00335                         fmax(surfaceOne->slip2(), surfaceTwo->slip2());
00336 
00337                 // the bigger slip value is the one we are using
00338                 contacts[i].surface.mu =
00339                         fmax(surfaceOne->mu(), surfaceTwo->mu());
00340 
00341                 // the bigger bounce value will be used
00342                 contacts[i].surface.bounce =
00343                         fmax(surfaceOne->bounce(), surfaceTwo->bounce());
00344 
00345                 // the smaller bounce velocity will be used
00346                 contacts[i].surface.bounce =
00347                         fmin(surfaceOne->bounceVelocity(),
00348                             surfaceTwo->bounceVelocity());
00349 
00350                 // use average erp value
00351                 contacts[i].surface.soft_erp =
00352                         (surfaceOne->softErp() + surfaceTwo->softErp()) / 2.0;
00353 
00354                 // use average cfm value
00355                 contacts[i].surface.soft_cfm =
00356                         surfaceOne->softCfm() + surfaceTwo->softCfm() / 2.0;
00357             }
00358 
00359             // if we have no ghosts, create contact joint
00360             if(!surfaceOne->ghostMode() && !surfaceTwo->ghostMode())
00361             {
00362                 dJointID contact = dJointCreateContact(
00363                         PhysicsManager::get()->worldId(),
00364                         PhysicsManager::get()->collisionContactGroupId(),
00365                         &contacts[i]);
00366 
00367                 dJointAttach(contact, dGeomGetBody(contacts[i].geom.g1),
00368                         dGeomGetBody(contacts[i].geom.g2));
00369             }
00370         }
00371 
00372         // inform collision partners
00373         if(bodyOne && bodyTwo)
00374         {
00375             bodyOne->handleCollision(bodyTwo);
00376             bodyTwo->handleCollision(bodyOne);
00377         }
00378     }
00379 }
00380 
00381 void
00382 PhysicsManager::setStepSize(double p_value)
00383 {
00384     m_stepSize = p_value;
00385 }
00386 
00387 double
00388 PhysicsManager::stepSize()
00389 {
00390     return m_stepSize;
00391 }
00392 
00393 void
00394 PhysicsManager::setStepTime(double p_value)
00395 {
00396     m_stepTime = p_value;
00397 }
00398 
00399 double
00400 PhysicsManager::stepTime()
00401 {
00402     return m_stepTime;
00403 }
00404 
00405 bool
00406 PhysicsManager::keepRunning()
00407 {
00408     return m_keepRunning;
00409 }
00410 
00411 void
00412 PhysicsManager::stop()
00413 {
00414     m_keepRunning = false;
00415 }
00416 
00417 int
00418 PhysicsManager::updateWorker(void* p_data)
00419 {
00420     // never waste a void* :P
00421     PhysicsManager* physicsManager = (PhysicsManager*)p_data;
00422 
00423     const int performanceAdjustmentThreshold = 25;
00424     int performanceMeter = 0;
00425     double timeTemp;
00426     double updateTime;
00427 
00428     while(physicsManager->keepRunning())
00429     {
00430         timeTemp = physicsManager->currentTime();
00431         for(unsigned int i = 0; i < m_updateResolution; i++)
00432             physicsManager->update();
00433 
00434         if(m_runningMultiThreaded)
00435             random_utils::ThreadSafeCanvas::get()->sleep();
00436 
00437         physicsManager->applyTransformations();
00438 
00439         if(m_runningMultiThreaded)
00440             random_utils::ThreadSafeCanvas::get()->wakeUp();
00441 
00442         updateTime = physicsManager->currentTime() - timeTemp;
00443 
00444         if(physicsManager->performanceAutoAdjust())
00445         {
00446             // if we needed too much time for the update
00447             if(updateTime > physicsManager->stepTime())
00448                 performanceMeter--;
00449 
00450             // if we needed less than one fifth of the time for the update
00451             if((updateTime * 5.0) < physicsManager->stepTime())
00452                 performanceMeter++;
00453 
00454             // if the performance was good several times
00455             if(performanceMeter > performanceAdjustmentThreshold)
00456             {
00457                 // reset the performance meter
00458                 performanceMeter = 0;
00459 
00460                 // update the update resolution
00461                 physicsManager->setUpdateResolution(
00462                         (physicsManager->updateResolution()) + 1);
00463 
00464                 std::cout << "+++ " << "increasing update resolution, now: "
00465                         << physicsManager->updateResolution() << std::endl;
00466             }
00467 
00468             // if the performance was bad several times
00469             if(performanceMeter < -performanceAdjustmentThreshold)
00470             {
00471                 // reset the performance meter
00472                 performanceMeter = 0;
00473 
00474                 // update the update resolution
00475                 if(physicsManager->updateResolution() > 1)
00476                 {
00477                     physicsManager->setUpdateResolution(
00478                             (physicsManager->updateResolution()) - 1);
00479                     std::cout << "--- " << "decreasing update resolution, now: "
00480                             << physicsManager->updateResolution() << std::endl;
00481                 }
00482                 else
00483                     std::cout << "!!! BAD PERFORMANCE !!!" << std::endl
00484                             << "no more real time performance tweaking possible"
00485                             << std::endl;
00486 
00487             }
00488         }
00489         else if(physicsManager->stepTime() - updateTime > 0)
00490             SDL_Delay((unsigned long)((physicsManager->stepTime() -
00491                     updateTime) * 1000.0));
00492     }
00493 
00494     return 0;
00495 }
00496 
00497 double
00498 PhysicsManager::currentTime()
00499 {
00500     return SDL_GetTicks() / 1000.0;
00501 }
00502 
00503 void
00504 PhysicsManager::setPerformanceAutoAdjust(bool p_value)
00505 {
00506     m_performanceAutoAdjust = p_value;
00507 }
00508 
00509 void
00510 PhysicsManager::setUpdateSpeed(double p_updateSpeed)
00511 {
00512     double currentSpeed = updateSpeed();
00513 
00514     m_stepSize *= (p_updateSpeed / currentSpeed);
00515 }
00516 
00517 double
00518 PhysicsManager::updateSpeed()
00519 {
00520     return m_stepSize / m_stepTime;
00521 }
00522 
00523 void
00524 PhysicsManager::setUpdateResolution(unsigned int p_updateResolution)
00525 {
00526     m_updateResolution = p_updateResolution;
00527 }
00528 
00529 unsigned int
00530 PhysicsManager::updateResolution()
00531 {
00532     return m_updateResolution;
00533 }
00534 
00535 bool
00536 PhysicsManager::performanceAutoAdjust()
00537 {
00538     return m_performanceAutoAdjust;
00539 }
00540 
00541 bool
00542 PhysicsManager::runningMultiThreaded()
00543 {
00544     return m_runningMultiThreaded;
00545 }
00546 
00547 std::string
00548 PhysicsManager::odeVersionString()
00549 {
00550     return std::string(PACKAGE_STRING);
00551 }
00552 
00553 }

Generated on Fri May 11 21:01:58 2007 for Random Racer by  doxygen 1.5.1