btBody.cpp

Engine/source/T3D/physics/bullet/btBody.cpp

More...

Detailed Description

  1
  2//-----------------------------------------------------------------------------
  3// Copyright (c) 2012 GarageGames, LLC
  4//
  5// Permission is hereby granted, free of charge, to any person obtaining a copy
  6// of this software and associated documentation files (the "Software"), to
  7// deal in the Software without restriction, including without limitation the
  8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  9// sell copies of the Software, and to permit persons to whom the Software is
 10// furnished to do so, subject to the following conditions:
 11//
 12// The above copyright notice and this permission notice shall be included in
 13// all copies or substantial portions of the Software.
 14//
 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 21// IN THE SOFTWARE.
 22//-----------------------------------------------------------------------------
 23
 24#include "platform/platform.h"
 25#include "T3D/physics/bullet/btBody.h"
 26
 27#include "T3D/physics/bullet/bt.h"
 28#include "T3D/physics/bullet/btCasts.h"
 29#include "T3D/physics/bullet/btWorld.h"
 30#include "T3D/physics/bullet/btCollision.h"
 31#include "math/mBox.h"
 32#include "console/console.h"
 33
 34
 35BtBody::BtBody() :
 36   mActor( NULL ),
 37   mWorld( NULL ),
 38   mMass( 0.0f ),
 39   mCompound( NULL ),
 40   mCenterOfMass( NULL ),
 41   mInvCenterOfMass( NULL ),
 42   mIsDynamic( false ),
 43   mIsEnabled( false )
 44{
 45}
 46
 47BtBody::~BtBody()
 48{
 49   _releaseActor();
 50}
 51
 52void BtBody::_releaseActor()
 53{
 54   if ( mActor )
 55   {
 56      mWorld->getDynamicsWorld()->removeRigidBody( mActor );
 57      mActor->setUserPointer( NULL );
 58      SAFE_DELETE( mActor );
 59   }
 60
 61   SAFE_DELETE( mCompound );
 62   SAFE_DELETE( mCenterOfMass );
 63   SAFE_DELETE( mInvCenterOfMass );
 64   
 65   mColShape = NULL;
 66}
 67
 68bool BtBody::init(   PhysicsCollision *shape, 
 69                        F32 mass,
 70                        U32 bodyFlags,
 71                        SceneObject *obj, 
 72                        PhysicsWorld *world )
 73{
 74   AssertFatal( obj, "BtBody::init - Got a null scene object!" );
 75   AssertFatal( world, "BtBody::init - Got a null world!" );
 76   AssertFatal( dynamic_cast<BtWorld*>( world ), "BtBody::init - The world is the wrong type!" );
 77   AssertFatal( shape, "BtBody::init - Got a null collision shape!" );
 78   AssertFatal( dynamic_cast<BtCollision*>( shape ), "BtBody::init - The collision shape is the wrong type!" );
 79   AssertFatal( ((BtCollision*)shape)->getShape(), "BtBody::init - Got empty collision shape!" );
 80    
 81   // Cleanup any previous actor.
 82   _releaseActor();
 83
 84   mWorld = (BtWorld*)world;
 85
 86   mColShape = (BtCollision*)shape;
 87   btCollisionShape *btColShape = mColShape->getShape();
 88   MatrixF localXfm = mColShape->getLocalTransform();
 89   btVector3 localInertia( 0, 0, 0 );   
 90
 91   // If we have a mass then we're dynamic.
 92   mIsDynamic = mass > 0.0f;
 93   if ( mIsDynamic )
 94   {
 95      if ( btColShape->isCompound() )
 96      {
 97         btCompoundShape *btCompound = (btCompoundShape*)btColShape;
 98
 99         btScalar *masses = new btScalar[ btCompound->getNumChildShapes() ];
100         for ( U32 j=0; j < btCompound->getNumChildShapes(); j++ )
101            masses[j] = mass / btCompound->getNumChildShapes();
102
103         btVector3 principalInertia;
104         btTransform principal;
105         btCompound->calculatePrincipalAxisTransform( masses, principal, principalInertia );
106         delete [] masses;
107
108         // Create a new compound with the shifted children.
109         btColShape = mCompound = new btCompoundShape();
110         for ( U32 i=0; i < btCompound->getNumChildShapes(); i++ )
111         {
112            btTransform newChildTransform = principal.inverse() * btCompound->getChildTransform(i);
113            mCompound->addChildShape( newChildTransform, btCompound->getChildShape(i) );
114         }
115
116         localXfm = btCast<MatrixF>( principal );
117      }
118
119      // Note... this looks like we're changing the shape, but 
120      // we're not.  All this does is ask the shape to calculate the
121      // local inertia vector from the mass... the shape doesn't change.
122      btColShape->calculateLocalInertia( mass, localInertia );
123   }
124
125   // If we have a local transform then we need to
126   // store it and the inverse to offset the center
127   // of mass from the graphics origin.
128   if ( !localXfm.isIdentity() )
129   {
130      mCenterOfMass = new MatrixF( localXfm );
131      mInvCenterOfMass = new MatrixF( *mCenterOfMass );
132      mInvCenterOfMass->inverse();
133   }
134
135   mMass = mass;
136   mActor = new btRigidBody( mass, NULL, btColShape, localInertia );
137   
138   int btFlags = mActor->getCollisionFlags();
139
140   if ( bodyFlags & BF_TRIGGER )
141      btFlags |= btCollisionObject::CF_NO_CONTACT_RESPONSE;
142   if ( bodyFlags & BF_KINEMATIC )
143   {
144      btFlags &= ~btCollisionObject::CF_STATIC_OBJECT;
145      btFlags |= btCollisionObject::CF_KINEMATIC_OBJECT;
146   }
147
148   mActor->setCollisionFlags( btFlags );
149
150   mWorld->getDynamicsWorld()->addRigidBody( mActor );
151   mIsEnabled = true;
152
153   mUserData.setObject( obj );
154   mUserData.setBody( this );
155   mActor->setUserPointer( &mUserData );
156
157   return true;
158}
159
160void BtBody::setMaterial(  F32 restitution,
161                           F32 friction, 
162                           F32 staticFriction )
163{
164   AssertFatal( mActor, "BtBody::setMaterial - The actor is null!" );
165
166   mActor->setRestitution( restitution );
167
168   // TODO: Weird.. Bullet doesn't have seperate dynamic 
169   // and static friction.
170   //
171   // Either add it and submit it as an official patch
172   // or hack it via contact reporting or something
173   // like that.
174
175   mActor->setFriction( friction );
176
177   // Wake it up... it may need to move.
178   mActor->activate();
179}
180
181void BtBody::setSleepThreshold( F32 linear, F32 angular )
182{
183   AssertFatal( mActor, "BtBody::setSleepThreshold - The actor is null!" );
184   mActor->setSleepingThresholds( linear, angular );
185}
186
187void BtBody::setDamping( F32 linear, F32 angular )
188{
189   AssertFatal( mActor, "BtBody::setDamping - The actor is null!" );
190   mActor->setDamping( linear, angular );
191}
192
193void BtBody::getState( PhysicsState *outState )
194{
195   AssertFatal( isDynamic(), "BtBody::getState - This call is only for dynamics!" );
196
197   // TODO: Fix this to do what we intended... to return
198   // false so that the caller can early out of the state
199   // hasn't changed since the last tick.
200
201   MatrixF trans;
202   if ( mInvCenterOfMass )
203      trans.mul( btCast<MatrixF>( mActor->getCenterOfMassTransform() ), *mInvCenterOfMass );
204   else
205      trans = btCast<MatrixF>( mActor->getCenterOfMassTransform() );
206
207   outState->position = trans.getPosition();
208   outState->orientation.set( trans );
209   outState->linVelocity = btCast<Point3F>( mActor->getLinearVelocity() ); 
210   outState->angVelocity = btCast<Point3F>( mActor->getAngularVelocity() ); 
211   outState->sleeping = !mActor->isActive();
212
213   // Bullet doesn't keep the momentum... recalc it.
214   outState->momentum = ( 1.0f / mActor->getInvMass() ) * outState->linVelocity;
215}
216
217Point3F BtBody::getCMassPosition() const
218{
219   AssertFatal( mActor, "BtBody::getCMassPosition - The actor is null!" );
220   return btCast<Point3F>( mActor->getCenterOfMassTransform().getOrigin() );
221}
222
223void BtBody::setLinVelocity( const Point3F &vel )
224{
225   AssertFatal( mActor, "BtBody::setLinVelocity - The actor is null!" );
226   AssertFatal( isDynamic(), "BtBody::setLinVelocity - This call is only for dynamics!" );
227
228   mActor->setLinearVelocity( btCast<btVector3>( vel ) );
229}
230
231void BtBody::setAngVelocity( const Point3F &vel )
232{
233   AssertFatal( mActor, "BtBody::setAngVelocity - The actor is null!" );
234   AssertFatal( isDynamic(), "BtBody::setAngVelocity - This call is only for dynamics!" );
235
236   mActor->setAngularVelocity( btCast<btVector3>( vel ) );
237}
238
239Point3F BtBody::getLinVelocity() const
240{
241   AssertFatal( mActor, "BtBody::getLinVelocity - The actor is null!" );
242   AssertFatal( isDynamic(), "BtBody::getLinVelocity - This call is only for dynamics!" );
243
244   return btCast<Point3F>( mActor->getLinearVelocity() );
245}
246
247Point3F BtBody::getAngVelocity() const
248{
249   AssertFatal( mActor, "BtBody::getAngVelocity - The actor is null!" );
250   AssertFatal( isDynamic(), "BtBody::getAngVelocity - This call is only for dynamics!" );
251
252   return btCast<Point3F>( mActor->getAngularVelocity() );
253}
254
255void BtBody::setSleeping( bool sleeping )
256{
257   AssertFatal( mActor, "BtBody::setSleeping - The actor is null!" );
258   AssertFatal( isDynamic(), "BtBody::setSleeping - This call is only for dynamics!" );
259
260   if ( sleeping )
261   {
262      //mActor->setCollisionFlags( mActor->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT );
263      mActor->setActivationState( WANTS_DEACTIVATION );
264      mActor->setDeactivationTime( 0.0f );
265   }
266   else
267   {
268      //mActor->setCollisionFlags( mActor->getCollisionFlags() & ~btCollisionObject::CF_KINEMATIC_OBJECT );
269      mActor->activate();
270   }
271}
272
273PhysicsWorld* BtBody::getWorld() 
274{
275   return mWorld; 
276}
277
278PhysicsCollision* BtBody::getColShape() 
279{
280   return mColShape;
281}
282
283MatrixF& BtBody::getTransform( MatrixF *outMatrix )
284{
285   AssertFatal( mActor, "BtBody::getTransform - The actor is null!" );
286
287   if ( mInvCenterOfMass )
288      outMatrix->mul( *mInvCenterOfMass, btCast<MatrixF>( mActor->getCenterOfMassTransform() ) );
289   else
290      *outMatrix = btCast<MatrixF>( mActor->getCenterOfMassTransform() );
291
292   return *outMatrix;
293}
294
295void BtBody::setTransform( const MatrixF &transform )
296{
297   AssertFatal( mActor, "BtBody::setTransform - The actor is null!" );
298
299   if ( mCenterOfMass )
300   {
301      MatrixF xfm;
302      xfm.mul( transform, *mCenterOfMass );
303      mActor->setCenterOfMassTransform( btCast<btTransform>( xfm ) ); 
304   }
305   else
306      mActor->setCenterOfMassTransform( btCast<btTransform>( transform ) ); 
307
308   // If its dynamic we have more to do.
309   if ( isDynamic() )
310   {
311      // Clear any velocity and forces... this is a warp.
312      mActor->clearForces();
313      mActor->setLinearVelocity( btVector3( 0, 0, 0 ) );
314      mActor->setAngularVelocity( btVector3( 0, 0, 0 ) );
315      mActor->activate();
316   }
317}
318
319void BtBody::applyCorrection( const MatrixF &transform )
320{
321   AssertFatal( mActor, "BtBody::applyCorrection - The actor is null!" );
322   AssertFatal( isDynamic(), "BtBody::applyCorrection - This call is only for dynamics!" );
323
324   if ( mCenterOfMass )
325   {
326      MatrixF xfm;
327      xfm.mul( transform, *mCenterOfMass );
328      mActor->setCenterOfMassTransform( btCast<btTransform>( xfm ) ); 
329   }
330   else
331      mActor->setCenterOfMassTransform( btCast<btTransform>( transform ) ); 
332}
333
334void BtBody::applyImpulse( const Point3F &origin, const Point3F &force )
335{
336   AssertFatal( mActor, "BtBody::applyImpulse - The actor is null!" );
337   AssertFatal( isDynamic(), "BtBody::applyImpulse - This call is only for dynamics!" );
338
339   // Convert the world position to local
340   MatrixF trans = btCast<MatrixF>( mActor->getCenterOfMassTransform() );
341   trans.inverse();
342   Point3F localOrigin( origin );
343   trans.mulP( localOrigin );
344
345   if ( mCenterOfMass )
346   {
347      Point3F relOrigin( localOrigin );
348      mCenterOfMass->mulP( relOrigin );
349      Point3F relForce( force );
350      mCenterOfMass->mulV( relForce );
351      mActor->applyImpulse( btCast<btVector3>( relForce ), btCast<btVector3>( relOrigin ) );
352   }
353   else
354      mActor->applyImpulse( btCast<btVector3>( force ), btCast<btVector3>( localOrigin ) );
355
356   if ( !mActor->isActive() )
357      mActor->activate();
358}
359
360void BtBody::applyTorque( const Point3F &torque )
361{
362   AssertFatal(mActor, "BtBody::applyTorque - The actor is null!");
363   AssertFatal(isDynamic(), "BtBody::applyTorque - This call is only for dynamics!");
364
365   mActor->applyTorque( btCast<btVector3>(torque) );
366
367   if (!mActor->isActive())
368      mActor->activate();
369}
370
371void BtBody::applyForce( const Point3F &force )
372{
373   AssertFatal(mActor, "BtBody::applyForce - The actor is null!");
374   AssertFatal(isDynamic(), "BtBody::applyForce - This call is only for dynamics!");
375
376   if (mCenterOfMass)
377   {
378      Point3F relForce(force);
379      mCenterOfMass->mulV(relForce);
380      mActor->applyCentralForce(btCast<btVector3>(relForce));
381   }
382   else
383      mActor->applyCentralForce(btCast<btVector3>(force));
384
385   if (!mActor->isActive())
386      mActor->activate();
387}
388
389Box3F BtBody::getWorldBounds()
390{   
391   btVector3 min, max;
392   mActor->getAabb( min, max );
393
394   Box3F bounds( btCast<Point3F>( min ), btCast<Point3F>( max ) );
395
396   return bounds;
397}
398
399void BtBody::setSimulationEnabled( bool enabled )
400{
401   if ( mIsEnabled == enabled )
402      return;
403
404   if ( !enabled )
405      mWorld->getDynamicsWorld()->removeRigidBody( mActor );
406   else
407      mWorld->getDynamicsWorld()->addRigidBody( mActor );
408
409   mIsEnabled = enabled;
410}
411
412void BtBody::findContact(SceneObject **contactObject,
413   VectorF *contactNormal,
414   Vector<SceneObject*> *outOverlapObjects) const
415{
416}
417
418void BtBody::moveKinematicTo(const MatrixF &transform)
419{
420   AssertFatal(mActor, "BtBody::moveKinematicTo - The actor is null!");
421
422   U32 bodyflags = mActor->getCollisionFlags();
423   const bool isKinematic = bodyflags & BF_KINEMATIC;
424   if (!isKinematic)
425   {
426      Con::errorf("BtBody::moveKinematicTo is only for kinematic bodies.");
427      return;
428   }
429
430   if (mCenterOfMass)
431   {
432      MatrixF xfm;
433      xfm.mul(transform, *mCenterOfMass);
434      mActor->setCenterOfMassTransform(btCast<btTransform>(xfm));
435   }
436   else
437      mActor->setCenterOfMassTransform(btCast<btTransform>(transform));
438}
439