123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419 |
- //-----------------------------------------------------------------------------
- // Copyright (c) 2012 GarageGames, LLC
- //
- // Permission is hereby granted, free of charge, to any person obtaining a copy
- // of this software and associated documentation files (the "Software"), to
- // deal in the Software without restriction, including without limitation the
- // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- // sell copies of the Software, and to permit persons to whom the Software is
- // furnished to do so, subject to the following conditions:
- //
- // The above copyright notice and this permission notice shall be included in
- // all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- // IN THE SOFTWARE.
- //-----------------------------------------------------------------------------
- #include "platform/platform.h"
- #include "T3D/physics/bullet/btBody.h"
- #include "T3D/physics/bullet/bt.h"
- #include "T3D/physics/bullet/btCasts.h"
- #include "T3D/physics/bullet/btWorld.h"
- #include "T3D/physics/bullet/btCollision.h"
- #include "math/mBox.h"
- #include "console/console.h"
- BtBody::BtBody() :
- mActor( NULL ),
- mWorld( NULL ),
- mMass( 0.0f ),
- mCompound( NULL ),
- mCenterOfMass( NULL ),
- mInvCenterOfMass( NULL ),
- mIsDynamic( false ),
- mIsEnabled( false )
- {
- }
- BtBody::~BtBody()
- {
- _releaseActor();
- }
- void BtBody::_releaseActor()
- {
- if ( mActor )
- {
- mWorld->getDynamicsWorld()->removeRigidBody( mActor );
- mActor->setUserPointer( NULL );
- SAFE_DELETE( mActor );
- }
- SAFE_DELETE( mCompound );
- SAFE_DELETE( mCenterOfMass );
- SAFE_DELETE( mInvCenterOfMass );
-
- mColShape = NULL;
- }
- bool BtBody::init( PhysicsCollision *shape,
- F32 mass,
- U32 bodyFlags,
- SceneObject *obj,
- PhysicsWorld *world )
- {
- AssertFatal( obj, "BtBody::init - Got a null scene object!" );
- AssertFatal( world, "BtBody::init - Got a null world!" );
- AssertFatal( dynamic_cast<BtWorld*>( world ), "BtBody::init - The world is the wrong type!" );
- AssertFatal( shape, "BtBody::init - Got a null collision shape!" );
- AssertFatal( dynamic_cast<BtCollision*>( shape ), "BtBody::init - The collision shape is the wrong type!" );
- AssertFatal( ((BtCollision*)shape)->getShape(), "BtBody::init - Got empty collision shape!" );
-
- // Cleanup any previous actor.
- _releaseActor();
- mWorld = (BtWorld*)world;
- mColShape = (BtCollision*)shape;
- btCollisionShape *btColShape = mColShape->getShape();
- MatrixF localXfm = mColShape->getLocalTransform();
- btVector3 localInertia( 0, 0, 0 );
- // If we have a mass then we're dynamic.
- mIsDynamic = mass > 0.0f;
- if ( mIsDynamic )
- {
- if ( btColShape->isCompound() )
- {
- btCompoundShape *btCompound = (btCompoundShape*)btColShape;
- btScalar *masses = new btScalar[ btCompound->getNumChildShapes() ];
- for ( U32 j=0; j < btCompound->getNumChildShapes(); j++ )
- masses[j] = mass / btCompound->getNumChildShapes();
- btVector3 principalInertia;
- btTransform principal;
- btCompound->calculatePrincipalAxisTransform( masses, principal, principalInertia );
- delete [] masses;
- // Create a new compound with the shifted children.
- btColShape = mCompound = new btCompoundShape();
- for ( U32 i=0; i < btCompound->getNumChildShapes(); i++ )
- {
- btTransform newChildTransform = principal.inverse() * btCompound->getChildTransform(i);
- mCompound->addChildShape( newChildTransform, btCompound->getChildShape(i) );
- }
- localXfm = btCast<MatrixF>( principal );
- }
- // Note... this looks like we're changing the shape, but
- // we're not. All this does is ask the shape to calculate the
- // local inertia vector from the mass... the shape doesn't change.
- btColShape->calculateLocalInertia( mass, localInertia );
- }
- // If we have a local transform then we need to
- // store it and the inverse to offset the center
- // of mass from the graphics origin.
- if ( !localXfm.isIdentity() )
- {
- mCenterOfMass = new MatrixF( localXfm );
- mInvCenterOfMass = new MatrixF( *mCenterOfMass );
- mInvCenterOfMass->inverse();
- }
- mMass = mass;
- mActor = new btRigidBody( mass, NULL, btColShape, localInertia );
-
- int btFlags = mActor->getCollisionFlags();
- if ( bodyFlags & BF_TRIGGER )
- btFlags |= btCollisionObject::CF_NO_CONTACT_RESPONSE;
- if ( bodyFlags & BF_KINEMATIC )
- {
- btFlags &= ~btCollisionObject::CF_STATIC_OBJECT;
- btFlags |= btCollisionObject::CF_KINEMATIC_OBJECT;
- }
- mActor->setCollisionFlags( btFlags );
- mWorld->getDynamicsWorld()->addRigidBody( mActor );
- mIsEnabled = true;
- mUserData.setObject( obj );
- mUserData.setBody( this );
- mActor->setUserPointer( &mUserData );
- return true;
- }
- void BtBody::setMaterial( F32 restitution,
- F32 friction,
- F32 staticFriction )
- {
- AssertFatal( mActor, "BtBody::setMaterial - The actor is null!" );
- mActor->setRestitution( restitution );
- // TODO: Weird.. Bullet doesn't have seperate dynamic
- // and static friction.
- //
- // Either add it and submit it as an official patch
- // or hack it via contact reporting or something
- // like that.
- mActor->setFriction( friction );
- // Wake it up... it may need to move.
- mActor->activate();
- }
- void BtBody::setSleepThreshold( F32 linear, F32 angular )
- {
- AssertFatal( mActor, "BtBody::setSleepThreshold - The actor is null!" );
- mActor->setSleepingThresholds( linear, angular );
- }
- void BtBody::setDamping( F32 linear, F32 angular )
- {
- AssertFatal( mActor, "BtBody::setDamping - The actor is null!" );
- mActor->setDamping( linear, angular );
- }
- void BtBody::getState( PhysicsState *outState )
- {
- AssertFatal( isDynamic(), "BtBody::getState - This call is only for dynamics!" );
- // TODO: Fix this to do what we intended... to return
- // false so that the caller can early out of the state
- // hasn't changed since the last tick.
- MatrixF trans;
- if ( mInvCenterOfMass )
- trans.mul( btCast<MatrixF>( mActor->getCenterOfMassTransform() ), *mInvCenterOfMass );
- else
- trans = btCast<MatrixF>( mActor->getCenterOfMassTransform() );
- outState->position = trans.getPosition();
- outState->orientation.set( trans );
- outState->linVelocity = btCast<Point3F>( mActor->getLinearVelocity() );
- outState->angVelocity = btCast<Point3F>( mActor->getAngularVelocity() );
- outState->sleeping = !mActor->isActive();
- // Bullet doesn't keep the momentum... recalc it.
- outState->momentum = ( 1.0f / mActor->getInvMass() ) * outState->linVelocity;
- }
- Point3F BtBody::getCMassPosition() const
- {
- AssertFatal( mActor, "BtBody::getCMassPosition - The actor is null!" );
- return btCast<Point3F>( mActor->getCenterOfMassTransform().getOrigin() );
- }
- void BtBody::setLinVelocity( const Point3F &vel )
- {
- AssertFatal( mActor, "BtBody::setLinVelocity - The actor is null!" );
- AssertFatal( isDynamic(), "BtBody::setLinVelocity - This call is only for dynamics!" );
- mActor->setLinearVelocity( btCast<btVector3>( vel ) );
- }
- void BtBody::setAngVelocity( const Point3F &vel )
- {
- AssertFatal( mActor, "BtBody::setAngVelocity - The actor is null!" );
- AssertFatal( isDynamic(), "BtBody::setAngVelocity - This call is only for dynamics!" );
- mActor->setAngularVelocity( btCast<btVector3>( vel ) );
- }
- Point3F BtBody::getLinVelocity() const
- {
- AssertFatal( mActor, "BtBody::getLinVelocity - The actor is null!" );
- AssertFatal( isDynamic(), "BtBody::getLinVelocity - This call is only for dynamics!" );
- return btCast<Point3F>( mActor->getLinearVelocity() );
- }
- Point3F BtBody::getAngVelocity() const
- {
- AssertFatal( mActor, "BtBody::getAngVelocity - The actor is null!" );
- AssertFatal( isDynamic(), "BtBody::getAngVelocity - This call is only for dynamics!" );
- return btCast<Point3F>( mActor->getAngularVelocity() );
- }
- void BtBody::setSleeping( bool sleeping )
- {
- AssertFatal( mActor, "BtBody::setSleeping - The actor is null!" );
- AssertFatal( isDynamic(), "BtBody::setSleeping - This call is only for dynamics!" );
- if ( sleeping )
- {
- //mActor->setCollisionFlags( mActor->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT );
- mActor->setActivationState( WANTS_DEACTIVATION );
- mActor->setDeactivationTime( 0.0f );
- }
- else
- {
- //mActor->setCollisionFlags( mActor->getCollisionFlags() & ~btCollisionObject::CF_KINEMATIC_OBJECT );
- mActor->activate();
- }
- }
- PhysicsWorld* BtBody::getWorld()
- {
- return mWorld;
- }
- PhysicsCollision* BtBody::getColShape()
- {
- return mColShape;
- }
- MatrixF& BtBody::getTransform( MatrixF *outMatrix )
- {
- AssertFatal( mActor, "BtBody::getTransform - The actor is null!" );
- if ( mInvCenterOfMass )
- outMatrix->mul( *mInvCenterOfMass, btCast<MatrixF>( mActor->getCenterOfMassTransform() ) );
- else
- *outMatrix = btCast<MatrixF>( mActor->getCenterOfMassTransform() );
- return *outMatrix;
- }
- void BtBody::setTransform( const MatrixF &transform )
- {
- AssertFatal( mActor, "BtBody::setTransform - The actor is null!" );
- if ( mCenterOfMass )
- {
- MatrixF xfm;
- xfm.mul( transform, *mCenterOfMass );
- mActor->setCenterOfMassTransform( btCast<btTransform>( xfm ) );
- }
- else
- mActor->setCenterOfMassTransform( btCast<btTransform>( transform ) );
- // If its dynamic we have more to do.
- if ( isDynamic() )
- {
- // Clear any velocity and forces... this is a warp.
- mActor->clearForces();
- mActor->setLinearVelocity( btVector3( 0, 0, 0 ) );
- mActor->setAngularVelocity( btVector3( 0, 0, 0 ) );
- mActor->activate();
- }
- }
- void BtBody::applyCorrection( const MatrixF &transform )
- {
- AssertFatal( mActor, "BtBody::applyCorrection - The actor is null!" );
- AssertFatal( isDynamic(), "BtBody::applyCorrection - This call is only for dynamics!" );
- if ( mCenterOfMass )
- {
- MatrixF xfm;
- xfm.mul( transform, *mCenterOfMass );
- mActor->setCenterOfMassTransform( btCast<btTransform>( xfm ) );
- }
- else
- mActor->setCenterOfMassTransform( btCast<btTransform>( transform ) );
- }
- void BtBody::applyImpulse( const Point3F &origin, const Point3F &force )
- {
- AssertFatal( mActor, "BtBody::applyImpulse - The actor is null!" );
- AssertFatal( isDynamic(), "BtBody::applyImpulse - This call is only for dynamics!" );
- // Convert the world position to local
- MatrixF trans = btCast<MatrixF>( mActor->getCenterOfMassTransform() );
- trans.inverse();
- Point3F localOrigin( origin );
- trans.mulP( localOrigin );
- if ( mCenterOfMass )
- {
- Point3F relOrigin( localOrigin );
- mCenterOfMass->mulP( relOrigin );
- Point3F relForce( force );
- mCenterOfMass->mulV( relForce );
- mActor->applyImpulse( btCast<btVector3>( relForce ), btCast<btVector3>( relOrigin ) );
- }
- else
- mActor->applyImpulse( btCast<btVector3>( force ), btCast<btVector3>( localOrigin ) );
- if ( !mActor->isActive() )
- mActor->activate();
- }
- void BtBody::applyTorque(const Point3F &torque)
- {
- AssertFatal(mActor, "BtBody::applyTorque - The actor is null!");
- AssertFatal(isDynamic(), "BtBody::applyTorque - This call is only for dynamics!");
- mActor->applyTorque( btCast<btVector3>(torque) );
- if (!mActor->isActive())
- mActor->activate();
- }
- Box3F BtBody::getWorldBounds()
- {
- btVector3 min, max;
- mActor->getAabb( min, max );
- Box3F bounds( btCast<Point3F>( min ), btCast<Point3F>( max ) );
- return bounds;
- }
- void BtBody::setSimulationEnabled( bool enabled )
- {
- if ( mIsEnabled == enabled )
- return;
- if ( !enabled )
- mWorld->getDynamicsWorld()->removeRigidBody( mActor );
- else
- mWorld->getDynamicsWorld()->addRigidBody( mActor );
- mIsEnabled = enabled;
- }
- void BtBody::findContact(SceneObject **contactObject,
- VectorF *contactNormal,
- Vector<SceneObject*> *outOverlapObjects) const
- {
- }
- void BtBody::moveKinematicTo(const MatrixF &transform)
- {
- AssertFatal(mActor, "BtBody::moveKinematicTo - The actor is null!");
- U32 bodyflags = mActor->getCollisionFlags();
- const bool isKinematic = bodyflags & BF_KINEMATIC;
- if (!isKinematic)
- {
- Con::errorf("BtBody::moveKinematicTo is only for kinematic bodies.");
- return;
- }
- if (mCenterOfMass)
- {
- MatrixF xfm;
- xfm.mul(transform, *mCenterOfMass);
- mActor->setCenterOfMassTransform(btCast<btTransform>(xfm));
- }
- else
- mActor->setCenterOfMassTransform(btCast<btTransform>(transform));
- }
|