MercuryODE.cpp

Go to the documentation of this file.
00001 #include "global.h"
00002 #include "MercuryODE.h"
00003 #include "MercuryUtil.h"
00004 #include "MercuryShapes.h"
00005 #include "MercuryLoadableModel.h"
00006 #include "MercuryLog.h"
00007 #include "MercuryTheme.h"
00008 #include "MercuryPoly.h"
00009 
00010 //#ifdef WIN32
00011 #if defined(WIN32) && !defined(__GNUC__)
00012 #pragma comment(lib, "ode.lib")
00013 #endif
00014 
00015 MercuryODEObject::MercuryODEObject()
00016 {
00017     m_oAccumulatedMass.mass = 0;
00018     m_oBody = 0;
00019     m_oSpace = 0;
00020     m_wasActive = true;
00021 }
00022 
00023 MercuryODEObject::~MercuryODEObject()
00024 {
00025 //  if ( m_oBody )
00026 //      dBodyDestroy( m_oBody );
00027 }
00028 
00029 CLASS_FUNCTION_VOID_NOARGS( MercuryODEObject, RemoveODE );
00030 void MercuryODEObject::RemoveODE()
00031 {
00032         dBodyDestroy( m_oBody );
00033 }
00034 
00035 
00036 REGISTER_ODE_OBJECT_CLASS( MercuryODEObjectLoadable );
00037 
00038 MercuryODEObjectLoadable::~MercuryODEObjectLoadable( )
00039 {
00040     unsigned i;
00041     for ( i = 0; i < m_vMercuryShapes.size(); i++ )
00042         SAFE_DELETE( m_vMercuryShapes[i] );
00043 
00044     for ( i = 0; i < m_vTrimeshes.size(); i++ )
00045         SAFE_DELETE( m_vTrimeshes[i] );
00046 }
00047 
00048 bool MercuryODEObjectLoadable::LoadFromINI( MercuryINI & pINI, 
00049         const MString & sShapeName, const dWorldID & oWorld )
00050 {
00051     unsigned int i;
00052     m_oParentWorld = oWorld;
00053 
00054     if ( m_vMercuryShapes.size() > 0 )      //We cannot double-load objects
00055         return false;
00056 
00057     if ( m_oSpace == 0 )                    //We must have our object space set up for us.
00058         return false;
00059 
00061     unsigned iNumPieces = pINI.GetValueI( sShapeName, "NumPieces" );
00062 
00063     //Pre-resize the trimesh and shape's arrays
00064     m_vMercuryShapes.resize( iNumPieces );
00065     m_vTrimeshes.resize( iNumPieces );
00066 
00067     for( i = 0; i < m_vMercuryShapes.size(); i++ )
00068     {
00069         m_vTrimeshes[i] = NULL;
00070         m_vMercuryShapes[i] = NULL;
00071     }
00072 
00073     if ( m_bBodied )
00074     {
00075         m_oBody = dBodyCreate ( oWorld );
00076         m_oAccumulatedMass.setZero();
00077         m_oAccumulatedMass.c[0] = 0;
00078         m_oAccumulatedMass.c[1] = 0;
00079         m_oAccumulatedMass.c[2] = 0;
00080 
00081     }
00082 
00083     //Pre Rotation Matrix
00084     dQuaternion q1,q2,q3,q4,qSum;
00085     dMatrix3 PRERtx;
00086     dQFromAxisAndAngle (q1, 1, 0, 0, m_pPreRotation.x / 57.2958f );
00087     dQFromAxisAndAngle (q2, 0, 1, 0, m_pPreRotation.y / 57.2958f );
00088     dQMultiply0( q4, q1, q2 );
00089     dQFromAxisAndAngle (q3, 0, 0, 1, m_pPreRotation.z / 57.2958f );
00090     dQMultiply0( qSum, q4, q3 );
00091     dQtoR ( qSum, PRERtx);
00092 
00093     //Now, see if we have one or more geoms to deal with.
00094     for ( i = 0; i < iNumPieces; i++ )
00095     {
00096         MString sPieceName = ssprintf( "Piece%d", i+1 );
00097         
00098         unsigned    iPieceType  = pINI.GetValueI( sShapeName, sPieceName + "Type", 0 );
00099         bool        bUsesODE    = pINI.GetValueB( sShapeName, sPieceName + "UsesODE", true );
00100         bool        bVisible    = pINI.GetValueB( sShapeName, sPieceName + "Visible", true );
00101         MString     sFileName   = pINI.GetValueS( sShapeName, sPieceName + "Filename" );    //Optional
00102         float       fDensity    = pINI.GetValueF( sShapeName, sPieceName + "Density", 0 );
00103 
00104         if ( bVisible )
00105         {
00106             switch ( iPieceType )
00107             {
00108             case 0:     //Sphere
00109                 {
00110                 MercuryShape * s = new MercuryShape;
00111                 s->SetName( sPieceName + sShapeName );
00112                 s->Init();
00113                 //Make a sphere with stacks/slices based on the INI file
00114                 s->MakeSphere(  pINI.GetValueI( sShapeName, sPieceName + "Stacks", 24 ),
00115                                 pINI.GetValueI( sShapeName, sPieceName + "Slices", 48 ) );
00116                 
00117                 //Load the PNG file based on the theme
00118                 s->LoadImage( THEME.GetPathToGraphic( sFileName ) );
00119 
00120                 //Set all other information for the sphere here
00121                 float fRadius = pINI.GetValueF( sShapeName, sPieceName + "Radius", 1 );
00122                 s->SetScale( MercuryPoint( fRadius, fRadius, fRadius ) );
00123 
00124                 //Put our sphere in the vector of objects so it gets deleted in the end.
00125                 m_vMercuryShapes[i] = s;
00126                 break;
00127                 }
00128             case 1:     //Cylinder
00129                 {
00130                     //For info, refer to sphere
00131                 MercuryShape * s = new MercuryShape;
00132                 s->SetName( sPieceName + sShapeName );
00133                 s->Init();
00134                 s->MakeCylinder(pINI.GetValueI( sShapeName, sPieceName + "Stacks", 24 ),
00135                                 pINI.GetValueI( sShapeName, sPieceName + "Slices", 48 ) );
00136                 s->LoadImage( THEME.GetPathToGraphic( sFileName ) );
00137                 float fRadius = pINI.GetValueF( sShapeName, sPieceName + "Radius", 1 );
00138                 float fLength = pINI.GetValueF( sShapeName, sPieceName + "Length", 1 );
00139                 s->SetScale( MercuryPoint( fRadius, fRadius, fLength ) );
00140                 m_vMercuryShapes[i] = s;
00141                 break;
00142                 }
00143             case 2:
00144                 {
00145                     //For info, refer to sphere
00146                 MercuryShape * s = new MercuryShape;
00147                 s->SetName( sPieceName + sShapeName );
00148                 s->Init();
00149                 s->MakeBox( );
00150                 s->LoadImage( THEME.GetPathToGraphic( sFileName ) );
00151                 s->SetScaleX( pINI.GetValueF( sShapeName, sPieceName + "LengthX", 1 ) );
00152                 s->SetScaleY( pINI.GetValueF( sShapeName, sPieceName + "LengthY", 1 ) );
00153                 s->SetScaleZ( pINI.GetValueF( sShapeName, sPieceName + "LengthZ", 1 ) );
00154                 m_vMercuryShapes[i] = s;
00155                 break;
00156                 }
00157             case 3: //Model
00158                 {
00159                 //Refer to sphere
00160                 MercuryModel* s = new MercuryLoadableModel();
00161                 s->SetName( sPieceName + sShapeName );
00162                 s->Init();
00163                 s->Load( THEME.GetPathToModel( sFileName ) );
00164                 s->SetScaleX( pINI.GetValueF( sShapeName, sPieceName + "LengthX", 1 ) );
00165                 s->SetScaleY( pINI.GetValueF( sShapeName, sPieceName + "LengthY", 1 ) );
00166                 s->SetScaleZ( pINI.GetValueF( sShapeName, sPieceName + "LengthZ", 1 ) );
00167                 m_vMercuryShapes[i] = s;
00168                 break;
00169                 }
00170             default:
00171                 LOG.Warn( ssprintf( "Unknown piece type '%d' in shape: %s", iPieceType, sShapeName.c_str() ) );
00172                 break;
00173             };
00174             
00175             //if we loaded the object, continue here.
00176             if ( m_vMercuryShapes[i] )
00177             {
00178                 //Set all other information for the file.
00179                 m_vMercuryShapes[i]->SetX( pINI.GetValueF( sShapeName, sPieceName + "X" ) );
00180                 m_vMercuryShapes[i]->SetY( pINI.GetValueF( sShapeName, sPieceName + "Y" ) );
00181                 m_vMercuryShapes[i]->SetZ( pINI.GetValueF( sShapeName, sPieceName + "Z" ) );
00182                 m_vMercuryShapes[i]->SetRotX( pINI.GetValueF( sShapeName, sPieceName + "RotX" ) );
00183                 m_vMercuryShapes[i]->SetRotY( pINI.GetValueF( sShapeName, sPieceName + "RotY" ) );
00184                 m_vMercuryShapes[i]->SetRotZ( pINI.GetValueF( sShapeName, sPieceName + "RotZ" ) );
00185 
00186                 //Add the object, so MercuryFrame/MercuryObject will handle it for us
00187                 AddObject( m_vMercuryShapes[i] );
00188             }
00189         }
00190 
00191         if ( bUsesODE )
00192         {
00193             dGeomID cg = 0;
00194             switch ( iPieceType )
00195             {
00196             case 0:     //Sphere
00197                 cg = dCreateSphere( 0, pINI.GetValueF( sShapeName, sPieceName + "Radius", 1 ) );
00198                 if ( fDensity > 0 )
00199                 {
00200                     dMass pTempSph;
00201                     pTempSph.setSphere( fDensity,
00202                         pINI.GetValueF( sShapeName, sPieceName + "Radius", 1 ) );
00203                     pTempSph.c[0] = pINI.GetValueF( sShapeName, sPieceName + "X" );
00204                     pTempSph.c[1] = pINI.GetValueF( sShapeName, sPieceName + "Y" );
00205                     pTempSph.c[2] = pINI.GetValueF( sShapeName, sPieceName + "Z" );
00206                     m_oAccumulatedMass.add( &pTempSph );
00207                 }
00208                 break;
00209             case 1:     //Cylinder
00210                 cg = dCreateCCylinder( 0, 
00211                     pINI.GetValueF( sShapeName, sPieceName + "Radius", 1 ),
00212                     pINI.GetValueF( sShapeName, sPieceName + "Length", 1 ) );
00213                 if ( fDensity > 0 )
00214                 {
00215                     dMass pTempCyl;
00216                     pTempCyl.setCappedCylinder( fDensity, 1, 
00217                         pINI.GetValueF( sShapeName, sPieceName + "Radius", 1 ),
00218                         pINI.GetValueF( sShapeName, sPieceName + "Length", 1 )/2 );
00219                     m_oAccumulatedMass.add( &pTempCyl );
00220                 }
00221                 break;
00222             case 2:     //Box
00223                 cg = dCreateBox ( 0, 
00224                     pINI.GetValueF( sShapeName, sPieceName + "LengthX", 1 ),
00225                     pINI.GetValueF( sShapeName, sPieceName + "LengthY", 1 ),
00226                     pINI.GetValueF( sShapeName, sPieceName + "LengthZ", 1 ) );
00227                 if ( fDensity > 0 )
00228                 {
00229                     dMass pTempBox;
00230                     pTempBox.setBox( fDensity,
00231                         pINI.GetValueF( sShapeName, sPieceName + "LengthX", 1 ),
00232                         pINI.GetValueF( sShapeName, sPieceName + "LengthY", 1 ),
00233                         pINI.GetValueF( sShapeName, sPieceName + "LengthZ", 1 ) );
00234                     m_oAccumulatedMass.add( &pTempBox );
00235                 }
00236                 break;
00237             case 3:     //Model
00238                 {
00239                 //Note about use of variables:
00240                 //  s: original MercuryModel
00241                 //  c: this triangle's InternalTrimesh
00242                 //  j,k,l,m,n: counter objects (for loops)
00243                 //  p: the poly we are using for work
00244 
00245                 MercuryPoint pResize( pINI.GetValueF( sShapeName, sPieceName + "LengthX", 1 ),
00246                     pINI.GetValueF( sShapeName, sPieceName + "LengthY", 1 ),
00247                     pINI.GetValueF( sShapeName, sPieceName + "LengthZ", 1 ) );
00248                 //Get the corresponding model.  We know it's a model.
00249                 MercuryModel * s = (MercuryModel*)(void*)m_vMercuryShapes[i];
00250 
00251                 //Make a new internatl trimesh here and cache it to be c
00252                 m_vTrimeshes[i] = new InternalTrimesh;
00253                 InternalTrimesh * c = m_vTrimeshes[i];
00254                 MercuryMesh* mesh = s->GetMesh(0);
00255 
00256                 unsigned int j;
00257 //              bool bBackfaces = pINI.GetValueB( sShapeName, 
00258 //                  sPieceName + "PhysicsBackfaces", 0 );
00259 
00260                 //Since we're not rewhelding the verticies,
00261                 //we know we have 3*number of poly's indexes 
00262                 //potentially *2 if we are doing backfaces
00263                 //and 3*number of poly's verts.
00264                 c->m_iIndexCount =  mesh->NumIndices(); //*(bBackfaces+1);//Backfaces are useless and broken now.
00265 //              c->m_iVertexCount = G->NumVertices();
00266                 c->m_iVertexCount = mesh->NumVertices();
00267 
00268                 //allocate space for our indices and verticies
00269                 c->m_aIndices = new int[mesh->NumIndices()];
00270                 c->m_aVerts = new dVector3[mesh->NumVertices()];
00271 
00272                 for( j = 0; j < mesh->NumIndices(); j++ )
00273                 {
00274                     int index = mesh->GetIndicesPtr()[j];
00275                     c->m_aIndices[j] = index;
00276                 }
00277 
00278                 for( j = 0; j < mesh->NumVertices(); j++ )
00279                 {
00280                     c->m_aVerts[j][0] = mesh->GetVerticePtr()[j].GetX() * pResize.x;
00281                     c->m_aVerts[j][1] = mesh->GetVerticePtr()[j].GetY() * pResize.y;
00282                     c->m_aVerts[j][2] = mesh->GetVerticePtr()[j].GetZ() * pResize.z;
00283                 }
00284                 
00285                 //Create the trimesh data
00286                 c->m_oTriData = dGeomTriMeshDataCreate();
00287     
00288                 //Build the geom
00289                 dGeomTriMeshDataBuildSimple( c->m_oTriData,
00290                     (float*)c->m_aVerts,c->m_iVertexCount,
00291                     c->m_aIndices, c->m_iIndexCount );
00292                 
00293                 //Actually create the ODE object
00294                 cg = dCreateTriMesh( 0, c->m_oTriData, 0, 0, 0 );
00295                 }
00296                 if ( fDensity > 0 )
00297                 {
00298                     dMass pTempSph;
00299                     pTempSph.setSphere( fDensity,
00300                         pINI.GetValueF( sShapeName, sPieceName + "Radius", 1 ) );
00301                     m_oAccumulatedMass.add( &pTempSph );
00302                 }
00303                 break;
00304             default:
00305                 LOG.Warn( ssprintf( "Unknown piece type '%d' in shape: %s", iPieceType, sShapeName.c_str() ) );
00306                 break;
00307             }
00308 
00309             if ( cg )
00310             {
00311                 //If we have a GeomID (loading was successful)
00312                 //set it's rotation and position according to what
00313                 //it's piece info is, independent to it's body's center.
00314                 dQuaternion q1,q2,q3,q4,qSum;
00315                 dMatrix3 Rtx;
00316                 dQFromAxisAndAngle (q1, 1, 0, 0, pINI.GetValueF( sShapeName, sPieceName + "RotX" ) / 57.2958f );
00317                 dQFromAxisAndAngle (q2, 0, 1, 0, pINI.GetValueF( sShapeName, sPieceName + "RotY" ) / 57.2958f );
00318                 dQMultiply0( q4, q1, q2 );
00319                 dQFromAxisAndAngle (q3, 0, 0, 1, pINI.GetValueF( sShapeName, sPieceName + "RotZ" ) / 57.2958f );
00320                 dQMultiply0( qSum, q4, q3 );
00321 
00322                 dQtoR ( qSum, Rtx);
00323 
00324                 dGeomSetRotation( cg, Rtx );
00325 
00326 
00327                 dGeomSetPosition( cg, 
00328                     pINI.GetValueF( sShapeName, sPieceName + "X" ),
00329                     pINI.GetValueF( sShapeName, sPieceName + "Y" ),
00330                     pINI.GetValueF( sShapeName, sPieceName + "Z" ) );
00331 
00332                 //Make a transform so the movement we made before
00333                 //will be independent from space.  Put this transform
00334                 //in the world space.
00335                 dGeomID Tran = dCreateGeomTransform( m_oSpace );
00336 
00337                 dGeomSetData( Tran, this );
00338 
00339                 dGeomTransformSetCleanup( Tran, 1 );
00340                 dGeomTransformSetGeom( Tran, cg );
00341                 m_vAllGeoms.push_back( cg );
00342                 m_vAllTransforms.push_back( Tran );
00343                 if ( m_bBodied )
00344                 {
00345                     //If it's bodied, set the body.
00346                     dGeomSetBody( Tran, m_oBody );
00347                 }
00348                 else
00349                 {
00350                     dGeomSetRotation( Tran, PRERtx );
00351                     dGeomSetPosition( Tran, 
00352                         m_pPrePosition.x,
00353                         m_pPrePosition.y,
00354                         m_pPrePosition.z );
00355                 }
00356             }
00357         }
00358     }
00359 
00360     //If it's bodied, then set the outer rotation and such
00361     //based on what was sent in beforehand
00362     if ( m_bBodied )
00363     {
00364         dBodySetMass( m_oBody, &m_oAccumulatedMass );
00365         dBodySetPosition( m_oBody, 
00366             m_pPrePosition.x,
00367             m_pPrePosition.y,
00368             m_pPrePosition.z );
00369         dBodySetRotation( m_oBody, PRERtx );
00370     } else
00371         SetRot( m_pPreRotation );
00372 
00373     MString sParameterList = pINI.GetValueS( sShapeName, "Properties" );
00374     while ( sParameterList.size() > 0 )
00375     {
00376         int i = BytesUntil( sParameterList.c_str(), ",", 0, sParameterList.length(), 1 );   //Find next comma
00377         if ( i == (int)sParameterList.size() )
00378         {
00379             SetParameter( sParameterList, PSElement( pINI.GetValueS( sShapeName, sParameterList ) ) );
00380             break;
00381         }
00382         SetParameter( sParameterList.substr( 0, i ), PSElement( pINI.GetValueS( sShapeName, sParameterList.substr( 0, i ) ) ) );
00383         sParameterList = sParameterList.substr( i+1 );                  //and change the remaining parameters
00384     }
00385 
00386     return true;
00387 }
00388 
00389 void MercuryODEObjectLoadable::Update( const float dTime )
00390 {
00391     //If the object is bodied, then we will
00392     //have to update it's MercuryObject's info (location & position)
00393     if ( m_bBodied && m_wasActive )
00394     {
00395         const float * sz1 = dBodyGetPosition ( m_oBody );
00396 
00397         SetX( sz1[0] );
00398         SetY( sz1[1] );
00399         SetZ( sz1[2] );
00400 
00401         SetRotationMode( RM_QUATERNION );
00402         SetRotationQuaternion( (float*)dBodyGetQuaternion(m_oBody) );
00403     }
00404     MercuryODEObject::Update( dTime );
00405 }
00406 
00407 CLASS_FUNCTION_VOID_NOARGS( MercuryODEObjectLoadable, RemoveODE );
00408 void MercuryODEObjectLoadable::RemoveODE()
00409 {
00410     unsigned i;
00411     MercuryODEObject::RemoveODE();
00412     for( i = 0; i < m_vAllTransforms.size(); i++ )
00413         dGeomDestroy( m_vAllTransforms[i] );
00414 }
00415 
00416 MercuryODEWorld::MercuryODEWorld( )
00417 {
00418 }
00419 
00420 void MercuryODEWorld::Init()
00421 {
00422     MercuryObject::Init();
00423 
00424     //Make the world
00425     m_oWorld = dWorldCreate();
00426     m_oSpace = dHashSpaceCreate (0);
00427 
00428     //Make the plane
00429     m_oGround = dCreatePlane( m_oSpace, 0, 0, 1, 0 );
00430 
00431     //Make the joint group (for collisions)
00432     m_oJointGroup = dJointGroupCreate(0);
00433 
00434     dWorldSetAutoDisableFlag(m_oWorld, true);
00435     dWorldSetAutoDisableLinearThreshold (m_oWorld, 0.1f);
00436     dWorldSetAutoDisableAngularThreshold (m_oWorld, 0.1f);
00437 }
00438 
00439 MercuryODEWorld::~MercuryODEWorld()
00440 {
00441     //Kill all underlings first, then destroy the spaces, this way, when they delete themselves, we won't have an issue.
00442 
00443     FOREACH_Object(m_objects, i)
00444     if ( i->bAutoDelete )
00445         SAFE_DELETE(i->pObject);
00446 
00447     dSpaceDestroy ( m_oSpace );
00448     dWorldDestroy ( m_oWorld );
00449 }
00450 
00451 bool MercuryODEWorld::LoadFromINI( MercuryINI & pINI, const MString & sWorldName )
00452 {
00453     //Set this the world's name
00454     SetName( sWorldName );
00455 
00456     unsigned NumElements = pINI.GetValueI( sWorldName, "NumElements" );
00457     SetGravity( -pINI.GetValueF( sWorldName, "Gravity", 32 ) );
00458 
00459     for ( unsigned i = 0; i < NumElements; i++ )
00460     {
00461         MString sInName = pINI.GetValueS( sWorldName, ssprintf( "Piece%d", i+1 ) );
00462         if ( sInName.length() == 0 )
00463         {
00464             LOG.Warn( ssprintf( "Cannot load object #%d in world.", i + 1 ) );
00465             continue;
00466         }
00467 
00468         MString sName = pINI.GetValueS( sWorldName, ssprintf( "Piece%dName", i+1 ), sInName );
00469         MString sClass = pINI.GetValueS( sWorldName, ssprintf( "Piece%dClass", i+1 ), "MercuryODEObjectLoadable" );
00470 
00471         if ( ToMakeODEs->find( sClass ) == ToMakeODEs->end() )
00472         {
00473             LOG.Warn( ssprintf( "Could not find class name %s on object #%d", sName.c_str(), i+1) );
00474             continue;
00475         }
00476 
00477         MercuryODEObjectLoadable * c = (*ToMakeODEs)[sClass]( sName );
00478         //Set up all info and send it in to the ODEObjectLoadable before it is loaded
00479         c->m_pWorld = this;
00480         c->m_bBodied = pINI.GetValueB( sWorldName, ssprintf( "Piece%dBodied", i + 1 ) );
00481         c->m_oSpace = m_oSpace;
00482 
00483         c->m_pPrePosition = MercuryPoint( 
00484                 pINI.GetValueF( sWorldName, ssprintf( "Piece%dX", i + 1 ) ),
00485                 pINI.GetValueF( sWorldName, ssprintf( "Piece%dY", i + 1 ) ),
00486                 pINI.GetValueF( sWorldName, ssprintf( "Piece%dZ", i + 1 ) ) );
00487         
00488         c->m_pPreRotation = MercuryPoint( 
00489                 pINI.GetValueF( sWorldName, ssprintf( "Piece%dRotX", i + 1 ) ),
00490                 pINI.GetValueF( sWorldName, ssprintf( "Piece%dRotY", i + 1 ) ),
00491                 pINI.GetValueF( sWorldName, ssprintf( "Piece%dRotZ", i + 1) ) );
00492 
00493         //Actually load the object
00494         c->m_oWorldSpace = m_oSpace;
00495         c->SetName( sWorldName + sInName );
00496         c->Init();
00497         c->LoadFromINI( pINI, sInName, m_oWorld );
00498 
00499         m_mObjects[sName] = c;
00500 
00501         c->SetPosition( c->m_pPrePosition );
00502         AddObject( c, true );
00503     }
00504     return true;
00505 }
00506 MercuryODEObject * MercuryODEWorld::GenAndAddToWorld( MercuryINI & pINI,
00507     const MString & sItemName, const MString & sItemType, const MString & sClass,
00508     bool bBodied, const MercuryPoint & pInitialPosition )
00509 {
00510     MercuryODEObjectLoadable * c = (*ToMakeODEs)[sClass]( sItemName );
00511     c->m_bBodied = bBodied;
00512     c->m_oSpace = m_oSpace;
00513     c->m_pPrePosition = pInitialPosition;
00514     c->m_pPreRotation = gpZero;
00515 
00516     //Actually load the object
00517     c->m_oWorldSpace = m_oSpace;
00518     c->SetName( sItemName );
00519     c->Init();
00520     c->LoadFromINI( pINI, sItemType, m_oWorld );
00521     m_mObjects[sItemName] = c;
00522     c->SetPosition( c->m_pPrePosition );
00523     AddObject( c, true );
00524     return c;
00525 }
00526 
00528 void MercuryODEWorld::AddToWorld( MercuryODEObject * toAdd )
00529 {
00530     m_mObjects[toAdd->GetName()] = toAdd;
00531     AddObject( toAdd );
00532 }
00533 
00534 bool MercuryODEWorld::RemoveObject( MercuryObject * object, bool bAllowDelete )
00535 {
00536     if ( bAllowDelete )
00537     {
00538         PStack ret;
00539         PStack args;
00540 
00541         object->Command( ret, "RemoveODE", args );
00542         MercuryObject::RemoveObject( object, bAllowDelete );
00543         return true;
00544     }   
00545     return MercuryObject::RemoveObject( object, bAllowDelete );
00546 }
00547 
00548 /**************CONTACT STUFF************************************************/
00550 void nearCallback (void *data, dGeomID o1, dGeomID o2)
00551 {
00552     dBodyID b1,b2;
00553     b1 = dGeomGetBody(o1);
00554     b2 = dGeomGetBody(o2);
00555     //If we don't actually have a collision, then break out
00556     if (b1 && b2 && dAreConnectedExcluding (b1,b2,dJointTypeContact)) return;
00557 
00558     MercuryODEWorld * inthis =(MercuryODEWorld*) data;
00559     dContact contact[16];
00560 
00561     //Initialize all of our contacts
00562     int i;
00563     for ( i = 0; i <16; i++ )
00564     {
00565         contact[i].surface.mode = 0;
00566         contact[i].surface.mu = 5000;
00567         contact[i].surface.bounce = 0;
00568     }
00569 
00570     //Do the object actually collide?
00571     int numcol;
00572     if ( (numcol = dCollide (o1,o2,16,&contact[0].geom,sizeof(dContact)))) 
00573     {
00574         //Process the collisions
00575         for ( i = 0; i < numcol; i++ )
00576         {
00577             //Make sure we should collide
00578             MercuryODEObject * m1 = (MercuryODEObject*)dGeomGetData( o1 );
00579             MercuryODEObject * m2 = (MercuryODEObject*)dGeomGetData( o2 );
00580 
00581             if ( m1 && m2 )     //If shouldn't collide, bail out.
00582                 if ( ( !m1->Collide( m2, contact[i], inthis ) ) || ( !m2->Collide( m1, contact[i], inthis ) ) )
00583                     continue;
00584 
00585             dJointID c = dJointCreateContact (inthis->m_oWorld,
00586                 inthis->m_oJointGroup, &contact[i]);
00587             dJointAttach (c,b1,b2);
00588         }
00589     }
00590 }
00591 
00592 
00593 void MercuryODEWorld::Update( const float fDeltaTime )
00594 {
00595     if ( fDeltaTime != 0 )
00596     {
00597         for( MDequeIterator<ParentHoldPair> child = m_objects.begin(); child != m_objects.end(); ++child )
00598             ((MercuryODEObject*)child->pObject)->PreCycleUpdate( fDeltaTime );
00599 
00600 
00601         //Do the collisions
00602         dSpaceCollide( m_oSpace, this, &nearCallback );
00603 
00604         //Step the world (quickstep is better at not crashing)
00605         //dWorldStep( m_oWorld, Clamp(fDeltaTime, 0.0f, 0.2f) );
00606         dWorldQuickStep( m_oWorld, Clamp(fDeltaTime,0.0f,0.2f) );
00607 
00608         //Empty all collisions and joints
00609         dJointGroupEmpty (m_oJointGroup);
00610     }
00611 
00612     //Run the update on the world
00613     MercuryObject::Update( fDeltaTime );
00614 }
00615 
00616 void MercuryODEWorld::SetGravity( const float fGravity )
00617 {
00618     dWorldSetGravity( m_oWorld, 0, 0, fGravity );
00619 }
00620 
00621 std::map< MString, NewODEObjectFunction >  *ToMakeODEs = NULL;
00622 
00623 void RegisterODEType( const MString& sClassName, NewODEObjectFunction pfn )
00624 {
00625     if ( !ToMakeODEs )
00626         ToMakeODEs = new std::map< MString, NewODEObjectFunction >;
00627 
00628     (*ToMakeODEs)[sClassName] = pfn;
00629 }
00630 
00631 /* 
00632  * Copyright (c) 2005-2006, Charles Lohr
00633  * All rights reserved.
00634  *
00635  * Redistribution and use in source and binary forms, with or
00636  * without modification, are permitted provided that the following
00637  * conditions are met:
00638  *  -   Redistributions of source code must retain the above
00639  *      copyright notice, this list of conditions and the following disclaimer.
00640  *  -   Redistributions in binary form must reproduce the above copyright
00641  *      notice, this list of conditions and the following disclaimer in
00642  *      the documentation and/or other materials provided with the distribution.
00643  *  -   Neither the name of the Mercury Engine nor the names of its
00644  *      contributors may be used to endorse or promote products derived from
00645  *      this software without specific prior written permission.
00646  *
00647  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00648  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00649  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00650  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
00651  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00652  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
00653  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00654  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
00655  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
00656  * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00657  */

Hosted by SourceForge.net Logo