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
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
00026
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 )
00055 return false;
00056
00057 if ( m_oSpace == 0 )
00058 return false;
00059
00061 unsigned iNumPieces = pINI.GetValueI( sShapeName, "NumPieces" );
00062
00063
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
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
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" );
00102 float fDensity = pINI.GetValueF( sShapeName, sPieceName + "Density", 0 );
00103
00104 if ( bVisible )
00105 {
00106 switch ( iPieceType )
00107 {
00108 case 0:
00109 {
00110 MercuryShape * s = new MercuryShape;
00111 s->SetName( sPieceName + sShapeName );
00112 s->Init();
00113
00114 s->MakeSphere( pINI.GetValueI( sShapeName, sPieceName + "Stacks", 24 ),
00115 pINI.GetValueI( sShapeName, sPieceName + "Slices", 48 ) );
00116
00117
00118 s->LoadImage( THEME.GetPathToGraphic( sFileName ) );
00119
00120
00121 float fRadius = pINI.GetValueF( sShapeName, sPieceName + "Radius", 1 );
00122 s->SetScale( MercuryPoint( fRadius, fRadius, fRadius ) );
00123
00124
00125 m_vMercuryShapes[i] = s;
00126 break;
00127 }
00128 case 1:
00129 {
00130
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
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:
00158 {
00159
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
00176 if ( m_vMercuryShapes[i] )
00177 {
00178
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
00187 AddObject( m_vMercuryShapes[i] );
00188 }
00189 }
00190
00191 if ( bUsesODE )
00192 {
00193 dGeomID cg = 0;
00194 switch ( iPieceType )
00195 {
00196 case 0:
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:
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:
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:
00238 {
00239
00240
00241
00242
00243
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
00249 MercuryModel * s = (MercuryModel*)(void*)m_vMercuryShapes[i];
00250
00251
00252 m_vTrimeshes[i] = new InternalTrimesh;
00253 InternalTrimesh * c = m_vTrimeshes[i];
00254 MercuryMesh* mesh = s->GetMesh(0);
00255
00256 unsigned int j;
00257
00258
00259
00260
00261
00262
00263
00264 c->m_iIndexCount = mesh->NumIndices();
00265
00266 c->m_iVertexCount = mesh->NumVertices();
00267
00268
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
00286 c->m_oTriData = dGeomTriMeshDataCreate();
00287
00288
00289 dGeomTriMeshDataBuildSimple( c->m_oTriData,
00290 (float*)c->m_aVerts,c->m_iVertexCount,
00291 c->m_aIndices, c->m_iIndexCount );
00292
00293
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
00312
00313
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
00333
00334
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
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
00361
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 );
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 );
00384 }
00385
00386 return true;
00387 }
00388
00389 void MercuryODEObjectLoadable::Update( const float dTime )
00390 {
00391
00392
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
00425 m_oWorld = dWorldCreate();
00426 m_oSpace = dHashSpaceCreate (0);
00427
00428
00429 m_oGround = dCreatePlane( m_oSpace, 0, 0, 1, 0 );
00430
00431
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
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
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
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
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
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
00550 void nearCallback (void *data, dGeomID o1, dGeomID o2)
00551 {
00552 dBodyID b1,b2;
00553 b1 = dGeomGetBody(o1);
00554 b2 = dGeomGetBody(o2);
00555
00556 if (b1 && b2 && dAreConnectedExcluding (b1,b2,dJointTypeContact)) return;
00557
00558 MercuryODEWorld * inthis =(MercuryODEWorld*) data;
00559 dContact contact[16];
00560
00561
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
00571 int numcol;
00572 if ( (numcol = dCollide (o1,o2,16,&contact[0].geom,sizeof(dContact))))
00573 {
00574
00575 for ( i = 0; i < numcol; i++ )
00576 {
00577
00578 MercuryODEObject * m1 = (MercuryODEObject*)dGeomGetData( o1 );
00579 MercuryODEObject * m2 = (MercuryODEObject*)dGeomGetData( o2 );
00580
00581 if ( m1 && m2 )
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
00602 dSpaceCollide( m_oSpace, this, &nearCallback );
00603
00604
00605
00606 dWorldQuickStep( m_oWorld, Clamp(fDeltaTime,0.0f,0.2f) );
00607
00608
00609 dJointGroupEmpty (m_oJointGroup);
00610 }
00611
00612
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
00633
00634
00635
00636
00637
00638
00639
00640
00641
00642
00643
00644
00645
00646
00647
00648
00649
00650
00651
00652
00653
00654
00655
00656
00657