mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-07-13 23:54:35 +00:00
Engine directory for ticket #1
This commit is contained in:
parent
352279af7a
commit
7dbfe6994d
3795 changed files with 1363358 additions and 0 deletions
44
Engine/source/T3D/physics/bullet/bt.h
Normal file
44
Engine/source/T3D/physics/bullet/bt.h
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _BULLET_H_
|
||||
#define _BULLET_H_
|
||||
|
||||
// NOTE: We set these defines which bullet needs here.
|
||||
#ifdef TORQUE_OS_WIN32
|
||||
#define WIN32
|
||||
#endif
|
||||
|
||||
// NOTE: All the Bullet includes we use should be here and
|
||||
// nowhere else.... beware!
|
||||
|
||||
#include <btBulletDynamicsCommon.h>
|
||||
#include <BulletCollision/CollisionDispatch/btGhostObject.h>
|
||||
#include <BulletCollision/CollisionShapes/btHeightfieldTerrainShape.h>
|
||||
|
||||
#include <BulletMultiThreaded/PlatformDefinitions.h>
|
||||
#include <BulletMultiThreaded/SpuGatheringCollisionDispatcher.h>
|
||||
#include <BulletMultiThreaded/Win32ThreadSupport.h>
|
||||
#include <BulletMultiThreaded/SpuNarrowPhaseCollisionTask/SpuGatheringCollisionTask.h>
|
||||
|
||||
|
||||
#endif // _BULLET_H_
|
||||
374
Engine/source/T3D/physics/bullet/btBody.cpp
Normal file
374
Engine/source/T3D/physics/bullet/btBody.cpp
Normal file
|
|
@ -0,0 +1,374 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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!" );
|
||||
|
||||
if ( mCenterOfMass )
|
||||
{
|
||||
Point3F relOrigin( origin );
|
||||
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>( origin ) );
|
||||
|
||||
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;
|
||||
}
|
||||
116
Engine/source/T3D/physics/bullet/btBody.h
Normal file
116
Engine/source/T3D/physics/bullet/btBody.h
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _T3D_PHYSICS_BTBODY_H_
|
||||
#define _T3D_PHYSICS_BTBODY_H_
|
||||
|
||||
#ifndef _T3D_PHYSICS_PHYSICSBODY_H_
|
||||
#include "T3D/physics/physicsBody.h"
|
||||
#endif
|
||||
#ifndef _REFBASE_H_
|
||||
#include "core/util/refBase.h"
|
||||
#endif
|
||||
#ifndef _MMATRIX_H_
|
||||
#include "math/mMatrix.h"
|
||||
#endif
|
||||
|
||||
class BtWorld;
|
||||
class btRigidBody;
|
||||
class btCompoundShape;
|
||||
class BtCollision;
|
||||
|
||||
|
||||
class BtBody : public PhysicsBody
|
||||
{
|
||||
protected:
|
||||
|
||||
/// The physics world we are in.
|
||||
BtWorld *mWorld;
|
||||
|
||||
/// The physics actor.
|
||||
btRigidBody *mActor;
|
||||
|
||||
/// The collision representation.
|
||||
StrongRefPtr<BtCollision> mColShape;
|
||||
|
||||
/// Our local compound if we had to adjust
|
||||
/// the mass center on a dynamic.
|
||||
btCompoundShape *mCompound;
|
||||
|
||||
///
|
||||
F32 mMass;
|
||||
|
||||
///
|
||||
bool mIsDynamic;
|
||||
|
||||
/// Is the body participating in the physics simulation.
|
||||
bool mIsEnabled;
|
||||
|
||||
/// The center of mass offset used if the graphical
|
||||
/// transform is not at the mass center.
|
||||
MatrixF *mCenterOfMass;
|
||||
|
||||
/// The inverse center of mass offset.
|
||||
MatrixF *mInvCenterOfMass;
|
||||
|
||||
///
|
||||
void _releaseActor();
|
||||
|
||||
public:
|
||||
|
||||
BtBody();
|
||||
virtual ~BtBody();
|
||||
|
||||
// PhysicsObject
|
||||
virtual PhysicsWorld* getWorld();
|
||||
virtual void setTransform( const MatrixF &xfm );
|
||||
virtual MatrixF& getTransform( MatrixF *outMatrix );
|
||||
virtual Box3F getWorldBounds();
|
||||
virtual void setSimulationEnabled( bool enabled );
|
||||
virtual bool isSimulationEnabled() { return mIsEnabled; }
|
||||
|
||||
// PhysicsBody
|
||||
virtual bool init( PhysicsCollision *shape,
|
||||
F32 mass,
|
||||
U32 bodyFlags,
|
||||
SceneObject *obj,
|
||||
PhysicsWorld *world );
|
||||
virtual bool isDynamic() const { return mIsDynamic; }
|
||||
virtual PhysicsCollision* getColShape();
|
||||
virtual void setSleepThreshold( F32 linear, F32 angular );
|
||||
virtual void setDamping( F32 linear, F32 angular );
|
||||
virtual void getState( PhysicsState *outState );
|
||||
virtual F32 getMass() const { return mMass; }
|
||||
virtual Point3F getCMassPosition() const;
|
||||
virtual void setLinVelocity( const Point3F &vel );
|
||||
virtual void setAngVelocity( const Point3F &vel );
|
||||
virtual Point3F getLinVelocity() const;
|
||||
virtual Point3F getAngVelocity() const;
|
||||
virtual void setSleeping( bool sleeping );
|
||||
virtual void setMaterial( F32 restitution,
|
||||
F32 friction,
|
||||
F32 staticFriction );
|
||||
virtual void applyCorrection( const MatrixF &xfm );
|
||||
virtual void applyImpulse( const Point3F &origin, const Point3F &force );
|
||||
};
|
||||
|
||||
#endif // _T3D_PHYSICS_BTBODY_H_
|
||||
102
Engine/source/T3D/physics/bullet/btCasts.h
Normal file
102
Engine/source/T3D/physics/bullet/btCasts.h
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _BULLET_CASTS_H_
|
||||
#define _BULLET_CASTS_H_
|
||||
|
||||
#ifndef _BULLET_H_
|
||||
#include "T3D/physics/bullet/bt.h"
|
||||
#endif
|
||||
#ifndef _MMATRIX_H_
|
||||
#include "math/mMatrix.h"
|
||||
#endif
|
||||
#ifndef _MPOINT3_H_
|
||||
#include "math/mPoint3.h"
|
||||
#endif
|
||||
#ifndef _MQUAT_H_
|
||||
#include "math/mQuat.h"
|
||||
#endif
|
||||
|
||||
template <class T, class F> inline T btCast( const F &from );
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
template<>
|
||||
inline Point3F btCast( const btVector3 &vec )
|
||||
{
|
||||
return Point3F( vec.x(), vec.y(), vec.z() );
|
||||
}
|
||||
|
||||
template<>
|
||||
inline btVector3 btCast( const Point3F &point )
|
||||
{
|
||||
return btVector3( point.x, point.y, point.z );
|
||||
}
|
||||
|
||||
template<>
|
||||
inline QuatF btCast( const btQuaternion &quat )
|
||||
{
|
||||
/// The Torque quat has the opposite winding order.
|
||||
return QuatF( -quat.x(), -quat.y(), -quat.z(), quat.w() );
|
||||
}
|
||||
|
||||
template<>
|
||||
inline btQuaternion btCast( const QuatF &quat )
|
||||
{
|
||||
/// The Torque quat has the opposite winding order.
|
||||
return btQuaternion( -quat.x, -quat.y, -quat.z, quat.w );
|
||||
}
|
||||
|
||||
template<>
|
||||
inline btTransform btCast( const MatrixF &xfm )
|
||||
{
|
||||
btTransform out;
|
||||
out.getBasis().setValue( xfm[0], xfm[1], xfm[2],
|
||||
xfm[4], xfm[5], xfm[6],
|
||||
xfm[8], xfm[9], xfm[10] );
|
||||
out.getOrigin().setValue( xfm[3], xfm[7], xfm[11] );
|
||||
return out;
|
||||
}
|
||||
|
||||
template<>
|
||||
inline MatrixF btCast( const btTransform &xfm )
|
||||
{
|
||||
MatrixF out;
|
||||
|
||||
// Set the rotation.
|
||||
out.setRow( 0, btCast<Point3F>( xfm.getBasis()[0] ) );
|
||||
out.setRow( 1, btCast<Point3F>( xfm.getBasis()[1] ) );
|
||||
out.setRow( 2, btCast<Point3F>( xfm.getBasis()[2] ) );
|
||||
|
||||
// The position.
|
||||
out[3] = xfm.getOrigin().x();
|
||||
out[7] = xfm.getOrigin().y();
|
||||
out[11] = xfm.getOrigin().z();
|
||||
|
||||
// Clear out the rest.
|
||||
out[12] = out[13] = out[14] = 0.0f;
|
||||
out[15] = 1.0f;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
#endif // _BULLET_CASTS_H_
|
||||
205
Engine/source/T3D/physics/bullet/btCollision.cpp
Normal file
205
Engine/source/T3D/physics/bullet/btCollision.cpp
Normal file
|
|
@ -0,0 +1,205 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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/btCollision.h"
|
||||
|
||||
#include "math/mPoint3.h"
|
||||
#include "math/mMatrix.h"
|
||||
#include "T3D/physics/bullet/bt.h"
|
||||
#include "T3D/physics/bullet/btCasts.h"
|
||||
|
||||
|
||||
BtCollision::BtCollision()
|
||||
: mCompound( NULL ),
|
||||
mLocalXfm( true )
|
||||
{
|
||||
}
|
||||
|
||||
BtCollision::~BtCollision()
|
||||
{
|
||||
SAFE_DELETE( mCompound );
|
||||
|
||||
for ( U32 i=0; i < mShapes.size(); i++ )
|
||||
delete mShapes[i];
|
||||
|
||||
for ( U32 i=0; i < mMeshInterfaces.size(); i++ )
|
||||
delete mMeshInterfaces[i];
|
||||
}
|
||||
|
||||
btCollisionShape* BtCollision::getShape()
|
||||
{
|
||||
if ( mCompound )
|
||||
return mCompound;
|
||||
|
||||
if ( mShapes.empty() )
|
||||
return NULL;
|
||||
|
||||
return mShapes.first();
|
||||
}
|
||||
|
||||
void BtCollision::_addShape( btCollisionShape *shape, const MatrixF &localXfm )
|
||||
{
|
||||
AssertFatal( !shape->isCompound(), "BtCollision::_addShape - Shape should not be a compound!" );
|
||||
|
||||
// Stick the shape into the array to delete later. Remember
|
||||
// that the compound shape doesn't delete its children.
|
||||
mShapes.push_back( shape );
|
||||
|
||||
// If this is the first shape then just store the
|
||||
// local transform and we're done.
|
||||
if ( mShapes.size() == 1 )
|
||||
{
|
||||
mLocalXfm = localXfm;
|
||||
return;
|
||||
}
|
||||
|
||||
// We use a compound to store the shapes with their
|
||||
// local transforms... so create it if we haven't already.
|
||||
if ( !mCompound )
|
||||
{
|
||||
mCompound = new btCompoundShape();
|
||||
|
||||
// There should only be one shape now... add it and
|
||||
// clear the local transform.
|
||||
mCompound->addChildShape( btCast<btTransform>( mLocalXfm ), mShapes.first() );
|
||||
mLocalXfm = MatrixF::Identity;
|
||||
}
|
||||
|
||||
// Add the new shape to the compound.
|
||||
mCompound->addChildShape( btCast<btTransform>( localXfm ), shape );
|
||||
}
|
||||
|
||||
void BtCollision::addPlane( const PlaneF &plane )
|
||||
{
|
||||
// NOTE: Torque uses a negative D... thats why we flip it here.
|
||||
btStaticPlaneShape *shape = new btStaticPlaneShape( btVector3( plane.x, plane.y, plane.z ), -plane.d );
|
||||
_addShape( shape, MatrixF::Identity );
|
||||
}
|
||||
|
||||
void BtCollision::addBox( const Point3F &halfWidth,
|
||||
const MatrixF &localXfm )
|
||||
{
|
||||
btBoxShape *shape = new btBoxShape( btVector3( halfWidth.x, halfWidth.y, halfWidth.z ) );
|
||||
shape->setMargin( 0.01f );
|
||||
_addShape( shape, localXfm );
|
||||
}
|
||||
|
||||
void BtCollision::addSphere( const F32 radius,
|
||||
const MatrixF &localXfm )
|
||||
{
|
||||
btSphereShape *shape = new btSphereShape( radius );
|
||||
shape->setMargin( 0.01f );
|
||||
_addShape( shape, localXfm );
|
||||
}
|
||||
|
||||
void BtCollision::addCapsule( F32 radius,
|
||||
F32 height,
|
||||
const MatrixF &localXfm )
|
||||
{
|
||||
btCapsuleShape *shape = new btCapsuleShape( radius, height );
|
||||
shape->setMargin( 0.01f );
|
||||
_addShape( shape, localXfm );
|
||||
}
|
||||
|
||||
bool BtCollision::addConvex( const Point3F *points,
|
||||
U32 count,
|
||||
const MatrixF &localXfm )
|
||||
{
|
||||
btConvexHullShape *shape = new btConvexHullShape( (btScalar*)points, count, sizeof( Point3F ) );
|
||||
shape->setMargin( 0.01f );
|
||||
_addShape( shape, localXfm );
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BtCollision::addTriangleMesh( const Point3F *vert,
|
||||
U32 vertCount,
|
||||
const U32 *index,
|
||||
U32 triCount,
|
||||
const MatrixF &localXfm )
|
||||
{
|
||||
// Setup the interface for loading the triangles.
|
||||
btTriangleMesh *meshInterface = new btTriangleMesh( true, false );
|
||||
for ( ; triCount-- ; )
|
||||
{
|
||||
meshInterface->addTriangle( btCast<btVector3>( vert[ *( index + 0 ) ] ),
|
||||
btCast<btVector3>( vert[ *( index + 1 ) ] ),
|
||||
btCast<btVector3>( vert[ *( index + 2 ) ] ),
|
||||
false );
|
||||
|
||||
index += 3;
|
||||
}
|
||||
mMeshInterfaces.push_back( meshInterface );
|
||||
|
||||
btBvhTriangleMeshShape *shape = new btBvhTriangleMeshShape( meshInterface, true, true );
|
||||
shape->setMargin( 0.01f );
|
||||
_addShape( shape, localXfm );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BtCollision::addHeightfield( const U16 *heights,
|
||||
const bool *holes, // TODO: Bullet height fields do not support holes
|
||||
U32 blockSize,
|
||||
F32 metersPerSample,
|
||||
const MatrixF &localXfm )
|
||||
{
|
||||
// We pass the absolute maximum and minimum of a U16 height
|
||||
// field and not the actual min and max. This helps with
|
||||
// placement.
|
||||
const F32 heightScale = 0.03125f;
|
||||
const F32 minHeight = 0;
|
||||
const F32 maxHeight = 65535 * heightScale;
|
||||
|
||||
btHeightfieldTerrainShape *shape = new btHeightfieldTerrainShape( blockSize, blockSize,
|
||||
(void*)heights,
|
||||
heightScale,
|
||||
minHeight, maxHeight,
|
||||
2, // Z up!
|
||||
PHY_SHORT,
|
||||
false );
|
||||
shape->setMargin( 0.01f );
|
||||
shape->setLocalScaling( btVector3( metersPerSample, metersPerSample, 1.0f ) );
|
||||
shape->setUseDiamondSubdivision( true );
|
||||
|
||||
// The local axis of the heightfield is the exact center of
|
||||
// its bounds defined as...
|
||||
//
|
||||
// ( blockSize * samplesPerMeter, blockSize * samplesPerMeter, maxHeight ) / 2.0f
|
||||
//
|
||||
// So we create a local transform to move it to the min point
|
||||
// of the bounds so it matched Torque terrain.
|
||||
Point3F offset( (F32)blockSize * metersPerSample / 2.0f,
|
||||
(F32)blockSize * metersPerSample / 2.0f,
|
||||
maxHeight / 2.0f );
|
||||
|
||||
// And also bump it by half a sample square size.
|
||||
offset.x -= metersPerSample / 2.0f;
|
||||
offset.y -= metersPerSample / 2.0f;
|
||||
|
||||
MatrixF offsetXfm( true );
|
||||
offsetXfm.setPosition( offset );
|
||||
|
||||
_addShape( shape, offsetXfm );
|
||||
|
||||
return true;
|
||||
}
|
||||
98
Engine/source/T3D/physics/bullet/btCollision.h
Normal file
98
Engine/source/T3D/physics/bullet/btCollision.h
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _T3D_PHYSICS_BTCOLLISION_H_
|
||||
#define _T3D_PHYSICS_BTCOLLISION_H_
|
||||
|
||||
#ifndef _T3D_PHYSICS_PHYSICSCOLLISION_H_
|
||||
#include "T3D/physics/physicsCollision.h"
|
||||
#endif
|
||||
#ifndef _MMATRIX_H_
|
||||
#include "math/mMatrix.h"
|
||||
#endif
|
||||
#ifndef _TVECTOR_H_
|
||||
#include "core/util/tVector.h"
|
||||
#endif
|
||||
|
||||
class btCollisionShape;
|
||||
class btCompoundShape;
|
||||
class btTriangleMesh;
|
||||
|
||||
|
||||
class BtCollision : public PhysicsCollision
|
||||
{
|
||||
protected:
|
||||
|
||||
/// The compound if we have more than one collision shape.
|
||||
btCompoundShape *mCompound;
|
||||
|
||||
/// The concrete collision shapes.
|
||||
Vector<btCollisionShape*> mShapes;
|
||||
|
||||
/// The local transform for the collision shape
|
||||
/// or identity if this is a compound.
|
||||
MatrixF mLocalXfm;
|
||||
|
||||
/// If we have any triangle mesh collision shapes then
|
||||
/// we need to store the mesh data.
|
||||
Vector<btTriangleMesh*> mMeshInterfaces;
|
||||
|
||||
/// Helper for adding shapes.
|
||||
void _addShape( btCollisionShape *shape, const MatrixF &localXfm );
|
||||
|
||||
public:
|
||||
|
||||
BtCollision();
|
||||
virtual ~BtCollision();
|
||||
|
||||
/// Return the Bullet collision shape.
|
||||
btCollisionShape* getShape();
|
||||
|
||||
// The local transform used to offset the collsion
|
||||
// to its correct graphics position.
|
||||
const MatrixF& getLocalTransform() const { return mLocalXfm; }
|
||||
|
||||
// PhysicsCollision
|
||||
virtual void addPlane( const PlaneF &plane );
|
||||
virtual void addBox( const Point3F &halfWidth,
|
||||
const MatrixF &localXfm );
|
||||
virtual void addSphere( F32 radius,
|
||||
const MatrixF &localXfm );
|
||||
virtual void addCapsule( F32 radius,
|
||||
F32 height,
|
||||
const MatrixF &localXfm );
|
||||
virtual bool addConvex( const Point3F *points,
|
||||
U32 count,
|
||||
const MatrixF &localXfm );
|
||||
virtual bool addTriangleMesh( const Point3F *vert,
|
||||
U32 vertCount,
|
||||
const U32 *index,
|
||||
U32 triCount,
|
||||
const MatrixF &localXfm );
|
||||
virtual bool addHeightfield( const U16 *heights,
|
||||
const bool *holes,
|
||||
U32 blockSize,
|
||||
F32 metersPerSample,
|
||||
const MatrixF &localXfm );
|
||||
};
|
||||
|
||||
#endif // _T3D_PHYSICS_BTCOLLISION_H_
|
||||
85
Engine/source/T3D/physics/bullet/btDebugDraw.cpp
Normal file
85
Engine/source/T3D/physics/bullet/btDebugDraw.cpp
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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/btDebugDraw.h"
|
||||
|
||||
#include "T3D/physics/bullet/btCasts.h"
|
||||
#include "gfx/gfxDevice.h"
|
||||
#include "math/util/frustum.h"
|
||||
#include "gfx/primBuilder.h"
|
||||
|
||||
|
||||
void BtDebugDraw::drawLine( const btVector3 &fromBt, const btVector3 &toBt, const btVector3 &color )
|
||||
{
|
||||
Point3F from = btCast<Point3F>( fromBt );
|
||||
Point3F to = btCast<Point3F>( toBt );
|
||||
|
||||
// Cull first if we have a frustum.
|
||||
//F32 distSquared = ( mCuller->getPosition() - from ).lenSquared();
|
||||
//if ( mCuller && distSquared > ( 150 * 150 ) ) //!mCuller->clipSegment( from, to ) )
|
||||
//return;
|
||||
|
||||
// Do we need to flush the builder?
|
||||
if ( mVertexCount + 2 >= 1000 )
|
||||
flush();
|
||||
|
||||
// Are we starting a new primitive?
|
||||
if ( mVertexCount == 0 )
|
||||
PrimBuild::begin( GFXLineList, 1000 );
|
||||
|
||||
PrimBuild::color3f( color.x(), color.y(), color.z() );
|
||||
PrimBuild::vertex3f( from.x, from.y, from.z );
|
||||
PrimBuild::vertex3f( to.x, to.y, to.z );
|
||||
|
||||
mVertexCount += 2;
|
||||
}
|
||||
|
||||
void BtDebugDraw::drawTriangle( const btVector3 &v0,
|
||||
const btVector3 &v1,
|
||||
const btVector3 &v2,
|
||||
const btVector3 &color,
|
||||
btScalar /*alpha*/ )
|
||||
{
|
||||
drawLine(v0,v1,color);
|
||||
drawLine(v1,v2,color);
|
||||
drawLine(v2,v0,color);
|
||||
}
|
||||
|
||||
void BtDebugDraw::drawContactPoint( const btVector3 &pointOnB,
|
||||
const btVector3 &normalOnB,
|
||||
btScalar distance,
|
||||
int lifeTime, const
|
||||
btVector3 &color )
|
||||
{
|
||||
drawLine( pointOnB, pointOnB+normalOnB*distance, color );
|
||||
}
|
||||
|
||||
void BtDebugDraw::flush()
|
||||
{
|
||||
// Do we have verts to render?
|
||||
if ( mVertexCount == 0 )
|
||||
return;
|
||||
|
||||
PrimBuild::end();
|
||||
mVertexCount = 0;
|
||||
}
|
||||
70
Engine/source/T3D/physics/bullet/btDebugDraw.h
Normal file
70
Engine/source/T3D/physics/bullet/btDebugDraw.h
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _T3D_PHYSICS_BTDEBUGDRAW_H_
|
||||
#define _T3D_PHYSICS_BTDEBUGDRAW_H_
|
||||
|
||||
#ifndef _BULLET_H_
|
||||
#include "T3D/physics/bullet/bt.h"
|
||||
#endif
|
||||
|
||||
class Frustum;
|
||||
|
||||
|
||||
class BtDebugDraw : public btIDebugDraw
|
||||
{
|
||||
protected:
|
||||
|
||||
/// The number of verts we've used in rendering.
|
||||
U32 mVertexCount;
|
||||
|
||||
/// The frustum to use for culling or NULL.
|
||||
const Frustum *mCuller;
|
||||
|
||||
public:
|
||||
|
||||
BtDebugDraw()
|
||||
: mVertexCount( 0 ),
|
||||
mCuller( NULL )
|
||||
{
|
||||
}
|
||||
|
||||
/// Sets the culler which we use to cull out primitives
|
||||
/// that are completely offscreen.
|
||||
void setCuller( const Frustum *culler ) { mCuller = culler; }
|
||||
|
||||
/// Call this after debug drawing to submit any
|
||||
/// remaining primitives for rendering.
|
||||
void flush();
|
||||
|
||||
// btIDebugDraw
|
||||
virtual void drawLine( const btVector3 &from, const btVector3 &to, const btVector3 &color );
|
||||
virtual void drawTriangle(const btVector3& v0,const btVector3& v1,const btVector3& v2,const btVector3& color, btScalar /*alpha*/);
|
||||
virtual void drawContactPoint( const btVector3 &PointOnB, const btVector3 &normalOnB, btScalar distance, int lifeTime, const btVector3 &color );
|
||||
virtual void reportErrorWarning( const char *warningString ) {}
|
||||
virtual void draw3dText( const btVector3 &location, const char *textString ) {}
|
||||
virtual void setDebugMode( int debugMode ) {}
|
||||
virtual int getDebugMode() const { return DBG_DrawWireframe; }
|
||||
};
|
||||
|
||||
|
||||
#endif // _T3D_PHYSICS_BTDEBUGDRAW_H_
|
||||
513
Engine/source/T3D/physics/bullet/btPlayer.cpp
Normal file
513
Engine/source/T3D/physics/bullet/btPlayer.cpp
Normal file
|
|
@ -0,0 +1,513 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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/btPlayer.h"
|
||||
|
||||
#include "T3D/physics/physicsPlugin.h"
|
||||
#include "T3D/physics/bullet/btWorld.h"
|
||||
#include "T3D/physics/bullet/btCasts.h"
|
||||
#include "collision/collision.h"
|
||||
|
||||
BtPlayer::BtPlayer()
|
||||
: PhysicsPlayer(),
|
||||
mWorld( NULL ),
|
||||
mObject( NULL ),
|
||||
mGhostObject( NULL ),
|
||||
mColShape( NULL ),
|
||||
mOriginOffset( 0.0f )
|
||||
{
|
||||
}
|
||||
|
||||
BtPlayer::~BtPlayer()
|
||||
{
|
||||
_releaseController();
|
||||
}
|
||||
|
||||
void BtPlayer::_releaseController()
|
||||
{
|
||||
if ( !mGhostObject )
|
||||
return;
|
||||
|
||||
mWorld->getDynamicsWorld()->removeCollisionObject( mGhostObject );
|
||||
|
||||
SAFE_DELETE( mGhostObject );
|
||||
SAFE_DELETE( mColShape );
|
||||
}
|
||||
|
||||
void BtPlayer::init( const char *type,
|
||||
const Point3F &size,
|
||||
F32 runSurfaceCos,
|
||||
F32 stepHeight,
|
||||
SceneObject *obj,
|
||||
PhysicsWorld *world )
|
||||
{
|
||||
AssertFatal( obj, "BtPlayer::init - Got a null scene object!" );
|
||||
AssertFatal( world, "BtPlayer::init - Got a null world!" );
|
||||
AssertFatal( dynamic_cast<BtWorld*>( world ), "BtPlayer::init - The world is the wrong type!" );
|
||||
|
||||
// Cleanup any previous controller.
|
||||
_releaseController();
|
||||
|
||||
mObject = obj;
|
||||
mWorld = (BtWorld*)world;
|
||||
|
||||
mStepHeight = stepHeight;
|
||||
|
||||
//if ( dStricmp( type, "Capsule" ) == 0 )
|
||||
{
|
||||
F32 radius = getMax( size.x, size.y ) * 0.5f;
|
||||
F32 height = size.z - ( radius * 2.0f );
|
||||
mColShape = new btCapsuleShapeZ( radius, height );
|
||||
mColShape->setMargin( 0.05f );
|
||||
mOriginOffset = ( height * 0.5 ) + radius;
|
||||
}
|
||||
//else
|
||||
{
|
||||
//mColShape = new btBoxShape( btVector3( 0.5f, 0.5f, 1.0f ) );
|
||||
//mOriginOffset = 1.0f;
|
||||
}
|
||||
|
||||
mGhostObject = new btPairCachingGhostObject();
|
||||
mGhostObject->setCollisionShape( mColShape );
|
||||
mGhostObject->setCollisionFlags( btCollisionObject::CF_CHARACTER_OBJECT );
|
||||
mWorld->getDynamicsWorld()->addCollisionObject( mGhostObject,
|
||||
btBroadphaseProxy::CharacterFilter,
|
||||
btBroadphaseProxy::StaticFilter | btBroadphaseProxy::DefaultFilter );
|
||||
|
||||
mUserData.setObject( obj );
|
||||
mGhostObject->setUserPointer( &mUserData );
|
||||
}
|
||||
|
||||
Point3F BtPlayer::move( const VectorF &disp, CollisionList &outCol )
|
||||
{
|
||||
AssertFatal( mGhostObject, "BtPlayer::move - The controller is null!" );
|
||||
|
||||
// First recover from any penetrations from the previous tick.
|
||||
U32 numPenetrationLoops = 0;
|
||||
bool touchingContact = false;
|
||||
while ( _recoverFromPenetration() )
|
||||
{
|
||||
numPenetrationLoops++;
|
||||
touchingContact = true;
|
||||
if ( numPenetrationLoops > 4 )
|
||||
break;
|
||||
}
|
||||
|
||||
btTransform newTrans = mGhostObject->getWorldTransform();
|
||||
btVector3 newPos = newTrans.getOrigin();
|
||||
|
||||
// The move consists of 3 steps... the up step, the forward
|
||||
// step, and the down step.
|
||||
|
||||
btVector3 forwardSweep( disp.x, disp.y, 0.0f );
|
||||
const bool hasForwardSweep = forwardSweep.length2() > 0.0f;
|
||||
F32 upSweep = 0.0f;
|
||||
F32 downSweep = 0.0f;
|
||||
if ( disp[2] < 0.0f )
|
||||
downSweep = disp[2];
|
||||
else
|
||||
upSweep = disp[2];
|
||||
|
||||
// Only do auto stepping if the character is moving forward.
|
||||
F32 stepOffset = mStepHeight;
|
||||
if ( hasForwardSweep )
|
||||
upSweep += stepOffset;
|
||||
|
||||
// First we do the up step which includes the passed in
|
||||
// upward displacement as well as the auto stepping.
|
||||
if ( upSweep > 0.0f &&
|
||||
_sweep( &newPos, btVector3( 0.0f, 0.0f, upSweep ), NULL ) )
|
||||
{
|
||||
// Keep track of how far we actually swept to make sure
|
||||
// we do not remove too much in the down sweep.
|
||||
F32 delta = newPos[2] - newTrans.getOrigin()[2];
|
||||
if ( delta < stepOffset )
|
||||
stepOffset = delta;
|
||||
}
|
||||
|
||||
// Now do the forward step.
|
||||
_stepForward( &newPos, forwardSweep, &outCol );
|
||||
|
||||
// Now remove what remains of our auto step
|
||||
// from the down sweep.
|
||||
if ( hasForwardSweep )
|
||||
downSweep -= stepOffset;
|
||||
|
||||
// Do the downward sweep.
|
||||
if ( downSweep < 0.0f )
|
||||
_sweep( &newPos, btVector3( 0.0f, 0.0f, downSweep ), &outCol );
|
||||
|
||||
// Finally update the ghost with its new position.
|
||||
newTrans.setOrigin( newPos );
|
||||
mGhostObject->setWorldTransform( newTrans );
|
||||
|
||||
// Return the current position of the ghost.
|
||||
newPos[2] -= mOriginOffset;
|
||||
return btCast<Point3F>( newPos );
|
||||
}
|
||||
|
||||
bool BtPlayer::_recoverFromPenetration()
|
||||
{
|
||||
bool penetration = false;
|
||||
|
||||
btDynamicsWorld *collWorld = mWorld->getDynamicsWorld();
|
||||
|
||||
collWorld->getDispatcher()->dispatchAllCollisionPairs( mGhostObject->getOverlappingPairCache(),
|
||||
collWorld->getDispatchInfo(),
|
||||
collWorld->getDispatcher() );
|
||||
|
||||
btVector3 currPos = mGhostObject->getWorldTransform().getOrigin();
|
||||
btScalar maxPen = 0.0f;
|
||||
btManifoldArray manifoldArray;
|
||||
|
||||
for ( U32 i = 0; i < mGhostObject->getOverlappingPairCache()->getNumOverlappingPairs(); i++ )
|
||||
{
|
||||
btBroadphasePair *collisionPair = &mGhostObject->getOverlappingPairCache()->getOverlappingPairArray()[i];
|
||||
|
||||
if ( ((btCollisionObject*)collisionPair->m_pProxy0->m_clientObject)->getCollisionFlags() & btCollisionObject::CF_NO_CONTACT_RESPONSE ||
|
||||
((btCollisionObject*)collisionPair->m_pProxy1->m_clientObject)->getCollisionFlags() & btCollisionObject::CF_NO_CONTACT_RESPONSE )
|
||||
continue;
|
||||
|
||||
manifoldArray.resize(0);
|
||||
if (collisionPair->m_algorithm)
|
||||
collisionPair->m_algorithm->getAllContactManifolds(manifoldArray);
|
||||
|
||||
for ( U32 j=0; j < manifoldArray.size(); j++ )
|
||||
{
|
||||
btPersistentManifold* manifold = manifoldArray[j];
|
||||
btScalar directionSign = manifold->getBody0() == mGhostObject ? -1.0f : 1.0f;
|
||||
|
||||
for ( U32 p=0; p < manifold->getNumContacts(); p++ )
|
||||
{
|
||||
const btManifoldPoint&pt = manifold->getContactPoint(p);
|
||||
|
||||
if ( pt.getDistance() < -mColShape->getMargin() )
|
||||
{
|
||||
if ( pt.getDistance() < maxPen )
|
||||
{
|
||||
maxPen = pt.getDistance();
|
||||
//m_touchingNormal = pt.m_normalWorldOnB * directionSign;//??
|
||||
}
|
||||
|
||||
currPos += pt.m_normalWorldOnB * directionSign * pt.getDistance(); // * 0.25f;
|
||||
penetration = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
//printf("touching %f\n", pt.getDistance());
|
||||
}
|
||||
}
|
||||
|
||||
//manifold->clearManifold();
|
||||
}
|
||||
}
|
||||
|
||||
// Update the ghost transform.
|
||||
btTransform newTrans = mGhostObject->getWorldTransform();
|
||||
newTrans.setOrigin( currPos );
|
||||
mGhostObject->setWorldTransform( newTrans );
|
||||
|
||||
return penetration;
|
||||
}
|
||||
|
||||
|
||||
class BtPlayerSweepCallback : public btCollisionWorld::ClosestConvexResultCallback
|
||||
{
|
||||
typedef btCollisionWorld::ClosestConvexResultCallback Parent;
|
||||
|
||||
public:
|
||||
|
||||
BtPlayerSweepCallback( btCollisionObject *me, const btVector3 &moveVec )
|
||||
: Parent( btVector3(0.0, 0.0, 0.0), btVector3(0.0, 0.0, 0.0) ),
|
||||
mMe( me ),
|
||||
mMoveVec( moveVec )
|
||||
{
|
||||
}
|
||||
|
||||
virtual bool needsCollision(btBroadphaseProxy* proxy0) const
|
||||
{
|
||||
if ( proxy0->m_clientObject == mMe )
|
||||
return false;
|
||||
|
||||
return Parent::needsCollision( proxy0 );
|
||||
}
|
||||
|
||||
virtual btScalar addSingleResult( btCollisionWorld::LocalConvexResult &convexResult,
|
||||
bool normalInWorldSpace )
|
||||
{
|
||||
// NOTE: I shouldn't have to do any of this, but Bullet
|
||||
// has some weird bugs.
|
||||
//
|
||||
// For one the plane type will return hits on a Z up surface
|
||||
// for sweeps that have no Z sweep component.
|
||||
//
|
||||
// Second the normal returned here is sometimes backwards
|
||||
// to the sweep direction... no clue why.
|
||||
//
|
||||
F32 dotN = mMoveVec.dot( convexResult.m_hitNormalLocal );
|
||||
if ( mFabs( dotN ) < 0.1f )
|
||||
return 1.0f;
|
||||
|
||||
if ( convexResult.m_hitCollisionObject->getCollisionFlags() & btCollisionObject::CF_NO_CONTACT_RESPONSE )
|
||||
return 1.0f;
|
||||
|
||||
return Parent::addSingleResult( convexResult, normalInWorldSpace );
|
||||
}
|
||||
|
||||
protected:
|
||||
btVector3 mMoveVec;
|
||||
btCollisionObject *mMe;
|
||||
};
|
||||
|
||||
bool BtPlayer::_sweep( btVector3 *inOutCurrPos, const btVector3 &disp, CollisionList *outCol )
|
||||
{
|
||||
btTransform start( btTransform::getIdentity() );
|
||||
start.setOrigin ( *inOutCurrPos );
|
||||
|
||||
btTransform end( btTransform::getIdentity() );
|
||||
end.setOrigin ( *inOutCurrPos + disp );
|
||||
|
||||
BtPlayerSweepCallback callback( mGhostObject, disp.normalized() );
|
||||
callback.m_collisionFilterGroup = mGhostObject->getBroadphaseHandle()->m_collisionFilterGroup;
|
||||
callback.m_collisionFilterMask = mGhostObject->getBroadphaseHandle()->m_collisionFilterMask;
|
||||
|
||||
mGhostObject->convexSweepTest( mColShape, start, end, callback, 0.0f );
|
||||
|
||||
inOutCurrPos->setInterpolate3( start.getOrigin(), end.getOrigin(), callback.m_closestHitFraction );
|
||||
if ( callback.hasHit() )
|
||||
{
|
||||
if ( outCol )
|
||||
{
|
||||
Collision& col = outCol->increment();
|
||||
dMemset( &col, 0, sizeof( col ) );
|
||||
|
||||
col.normal = btCast<Point3F>( callback.m_hitNormalWorld );
|
||||
col.object = PhysicsUserData::getObject( callback.m_hitCollisionObject->getUserPointer() );
|
||||
|
||||
if (disp.z() < 0.0f)
|
||||
{
|
||||
// We're sweeping down as part of the stepping routine. In this
|
||||
// case we want to have the collision normal only point in the opposite direction.
|
||||
// i.e. up If we include the sideways part of the normal then the Player class
|
||||
// velocity calculations using this normal will affect the player's forwards
|
||||
// momentum. This is especially noticable on stairs as the rounded bottom of
|
||||
// the capsule slides up the corner of a stair.
|
||||
col.normal.set(0.0f, 0.0f, 1.0f);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void BtPlayer::_stepForward( btVector3 *inOutCurrPos, const btVector3 &displacement, CollisionList *outCol )
|
||||
{
|
||||
btTransform start( btTransform::getIdentity() );
|
||||
btTransform end( btTransform::getIdentity() );
|
||||
F32 fraction = 1.0f;
|
||||
S32 maxIter = 10;
|
||||
btVector3 disp = displacement;
|
||||
|
||||
while ( fraction > 0.01f && maxIter-- > 0 )
|
||||
{
|
||||
// Setup the sweep start and end transforms.
|
||||
start.setOrigin( *inOutCurrPos );
|
||||
end.setOrigin( *inOutCurrPos + disp );
|
||||
|
||||
BtPlayerSweepCallback callback( mGhostObject, disp.length2() > 0.0f ? disp.normalized() : disp );
|
||||
callback.m_collisionFilterGroup = mGhostObject->getBroadphaseHandle()->m_collisionFilterGroup;
|
||||
callback.m_collisionFilterMask = mGhostObject->getBroadphaseHandle()->m_collisionFilterMask;
|
||||
|
||||
mGhostObject->convexSweepTest( mColShape, start, end, callback, 0.0f );
|
||||
|
||||
// Subtract from the travel fraction.
|
||||
fraction -= callback.m_closestHitFraction;
|
||||
|
||||
// Did we get a hit?
|
||||
if ( callback.hasHit() )
|
||||
{
|
||||
/*
|
||||
// Get the real hit normal... Bullet returns the 'seperating normal' and not
|
||||
// the normal of the hit object.
|
||||
btTransform rayStart( btTransform::getIdentity() );
|
||||
rayStart.setOrigin( callback.m_hitPointWorld + callback.m_hitNormalWorld );
|
||||
btTransform rayEnd( btTransform::getIdentity() );
|
||||
rayEnd.setOrigin( callback.m_hitPointWorld - callback.m_hitNormalWorld );
|
||||
|
||||
btCollisionWorld::ClosestRayResultCallback rayHit( rayStart.getOrigin(), rayEnd.getOrigin() );
|
||||
mWorld->getDynamicsWorld()->rayTestSingle( rayStart,
|
||||
rayEnd,
|
||||
callback.m_hitCollisionObject,
|
||||
callback.m_hitCollisionObject->getCollisionShape(),
|
||||
callback.m_hitCollisionObject->getWorldTransform(),
|
||||
rayHit );
|
||||
|
||||
if ( !rayHit.hasHit() )
|
||||
break;
|
||||
*/
|
||||
|
||||
Collision& col = outCol->increment();
|
||||
dMemset( &col, 0, sizeof( col ) );
|
||||
|
||||
col.normal = btCast<Point3F>( callback.m_hitNormalWorld );
|
||||
col.object = PhysicsUserData::getObject( callback.m_hitCollisionObject->getUserPointer() );
|
||||
|
||||
// If the collision direction is sideways then modify the collision normal
|
||||
// to remove any z component. This takes care of any sideways collisions
|
||||
// with the round bottom of the capsule when it comes to the Player class
|
||||
// velocity calculations. We want all sideways collisions to be treated
|
||||
// as if they hit the side of a cylinder.
|
||||
if (col.normal.z > 0.0f)
|
||||
{
|
||||
// This will only remove the z component of the collision normal
|
||||
// for the bottom of the character controller, which would hit during
|
||||
// a step. We'll leave the top hemisphere of the character's capsule
|
||||
// alone as bumping one's head is an entirely different story. This
|
||||
// helps with low doorways.
|
||||
col.normal.z = 0.0f;
|
||||
col.normal.normalizeSafe();
|
||||
}
|
||||
|
||||
// Interpolate to the new position.
|
||||
inOutCurrPos->setInterpolate3( start.getOrigin(), end.getOrigin(), callback.m_closestHitFraction );
|
||||
|
||||
// Subtract out the displacement along the collision normal.
|
||||
F32 bd = -disp.dot( callback.m_hitNormalWorld );
|
||||
btVector3 dv = callback.m_hitNormalWorld * bd;
|
||||
disp += dv;
|
||||
}
|
||||
else
|
||||
{
|
||||
// we moved whole way
|
||||
*inOutCurrPos = end.getOrigin();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BtPlayer::findContact( SceneObject **contactObject,
|
||||
VectorF *contactNormal,
|
||||
Vector<SceneObject*> *outOverlapObjects ) const
|
||||
{
|
||||
AssertFatal( mGhostObject, "BtPlayer::findContact - The controller is null!" );
|
||||
|
||||
VectorF normal;
|
||||
F32 maxDot = -1.0f;
|
||||
|
||||
// Go thru the contact points... get the first contact.
|
||||
btHashedOverlappingPairCache *pairCache = mGhostObject->getOverlappingPairCache();
|
||||
btBroadphasePairArray& pairArray = pairCache->getOverlappingPairArray();
|
||||
U32 numPairs = pairArray.size();
|
||||
btManifoldArray manifoldArray;
|
||||
|
||||
for ( U32 i=0; i < numPairs; i++ )
|
||||
{
|
||||
const btBroadphasePair &pair = pairArray[i];
|
||||
|
||||
btBroadphasePair *collisionPair = pairCache->findPair( pair.m_pProxy0, pair.m_pProxy1 );
|
||||
if ( !collisionPair || !collisionPair->m_algorithm )
|
||||
continue;
|
||||
|
||||
btCollisionObject *other = (btCollisionObject*)pair.m_pProxy0->m_clientObject;
|
||||
if ( other == mGhostObject )
|
||||
other = (btCollisionObject*)pair.m_pProxy1->m_clientObject;
|
||||
|
||||
AssertFatal( !outOverlapObjects->contains( PhysicsUserData::getObject( other->getUserPointer() ) ),
|
||||
"Got multiple pairs of the same object!" );
|
||||
outOverlapObjects->push_back( PhysicsUserData::getObject( other->getUserPointer() ) );
|
||||
|
||||
if ( other->getCollisionFlags() & btCollisionObject::CF_NO_CONTACT_RESPONSE )
|
||||
continue;
|
||||
|
||||
manifoldArray.clear();
|
||||
collisionPair->m_algorithm->getAllContactManifolds( manifoldArray );
|
||||
|
||||
for ( U32 j=0; j < manifoldArray.size(); j++ )
|
||||
{
|
||||
btPersistentManifold *manifold = manifoldArray[j];
|
||||
btScalar directionSign = manifold->getBody0() == mGhostObject ? 1.0f : -1.0f;
|
||||
|
||||
for ( U32 p=0; p < manifold->getNumContacts(); p++ )
|
||||
{
|
||||
const btManifoldPoint &pt = manifold->getContactPoint(p);
|
||||
|
||||
// Test the normal... is it the most vertical one we got?
|
||||
normal = btCast<Point3F>( pt.m_normalWorldOnB * directionSign );
|
||||
F32 dot = mDot( normal, VectorF( 0, 0, 1 ) );
|
||||
if ( dot > maxDot )
|
||||
{
|
||||
maxDot = dot;
|
||||
|
||||
btCollisionObject *colObject = (btCollisionObject*)collisionPair->m_pProxy0->m_clientObject;
|
||||
*contactObject = PhysicsUserData::getObject( colObject->getUserPointer() );
|
||||
*contactNormal = normal;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BtPlayer::enableCollision()
|
||||
{
|
||||
AssertFatal( mGhostObject, "BtPlayer::enableCollision - The controller is null!" );
|
||||
|
||||
//mController->setCollision( true );
|
||||
}
|
||||
|
||||
void BtPlayer::disableCollision()
|
||||
{
|
||||
AssertFatal( mGhostObject, "BtPlayer::disableCollision - The controller is null!" );
|
||||
|
||||
//mController->setCollision( false );
|
||||
}
|
||||
|
||||
PhysicsWorld* BtPlayer::getWorld()
|
||||
{
|
||||
return mWorld;
|
||||
}
|
||||
|
||||
void BtPlayer::setTransform( const MatrixF &transform )
|
||||
{
|
||||
AssertFatal( mGhostObject, "BtPlayer::setTransform - The ghost object is null!" );
|
||||
|
||||
btTransform xfm = btCast<btTransform>( transform );
|
||||
xfm.getOrigin()[2] += mOriginOffset;
|
||||
|
||||
mGhostObject->setWorldTransform( xfm );
|
||||
}
|
||||
|
||||
MatrixF& BtPlayer::getTransform( MatrixF *outMatrix )
|
||||
{
|
||||
AssertFatal( mGhostObject, "BtPlayer::getTransform - The ghost object is null!" );
|
||||
|
||||
*outMatrix = btCast<MatrixF>( mGhostObject->getWorldTransform() );
|
||||
*outMatrix[11] -= mOriginOffset;
|
||||
|
||||
return *outMatrix;
|
||||
}
|
||||
|
||||
void BtPlayer::setScale( const Point3F &scale )
|
||||
{
|
||||
}
|
||||
104
Engine/source/T3D/physics/bullet/btPlayer.h
Normal file
104
Engine/source/T3D/physics/bullet/btPlayer.h
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _BTPLAYER_H
|
||||
#define _BTPLAYER_H
|
||||
|
||||
#ifndef _T3D_PHYSICS_PHYSICSPLAYER_H_
|
||||
#include "T3D/physics/physicsPlayer.h"
|
||||
#endif
|
||||
|
||||
|
||||
class BtWorld;
|
||||
//class btKinematicCharacterController;
|
||||
class btPairCachingGhostObject;
|
||||
class btConvexShape;
|
||||
class btVector3;
|
||||
|
||||
|
||||
class BtPlayer : public PhysicsPlayer
|
||||
{
|
||||
protected:
|
||||
|
||||
//F32 mSkinWidth;
|
||||
|
||||
BtWorld *mWorld;
|
||||
|
||||
SceneObject *mObject;
|
||||
|
||||
///
|
||||
//btKinematicCharacterController *mController;
|
||||
|
||||
///
|
||||
btPairCachingGhostObject *mGhostObject;
|
||||
|
||||
///
|
||||
btConvexShape *mColShape;
|
||||
|
||||
///
|
||||
F32 mOriginOffset;
|
||||
|
||||
///
|
||||
F32 mStepHeight;
|
||||
///
|
||||
void _releaseController();
|
||||
|
||||
///
|
||||
bool _recoverFromPenetration();
|
||||
|
||||
///
|
||||
bool _sweep( btVector3 *inOutCurrPos, const btVector3 &disp, CollisionList *outCol );
|
||||
|
||||
///
|
||||
void _stepForward( btVector3 *inOutCurrPos, const btVector3 &displacement, CollisionList *outCol );
|
||||
|
||||
public:
|
||||
|
||||
BtPlayer();
|
||||
virtual ~BtPlayer();
|
||||
|
||||
// PhysicsObject
|
||||
virtual PhysicsWorld* getWorld();
|
||||
virtual void setTransform( const MatrixF &transform );
|
||||
virtual MatrixF& getTransform( MatrixF *outMatrix );
|
||||
virtual void setScale( const Point3F &scale );
|
||||
virtual Box3F getWorldBounds() { return Box3F::Invalid; }
|
||||
virtual void setSimulationEnabled( bool enabled ) {}
|
||||
virtual bool isSimulationEnabled() { return true; }
|
||||
|
||||
// PhysicsPlayer
|
||||
virtual void init( const char *type,
|
||||
const Point3F &size,
|
||||
F32 runSurfaceCos,
|
||||
F32 stepHeight,
|
||||
SceneObject *obj,
|
||||
PhysicsWorld *world );
|
||||
virtual Point3F move( const VectorF &displacement, CollisionList &outCol );
|
||||
virtual void findContact( SceneObject **contactObject, VectorF *contactNormal, Vector<SceneObject*> *outOverlapObjects ) const;
|
||||
virtual bool testSpacials( const Point3F &nPos, const Point3F &nSize ) const { return true; }
|
||||
virtual void setSpacials( const Point3F &nPos, const Point3F &nSize ) {}
|
||||
virtual void enableCollision();
|
||||
virtual void disableCollision();
|
||||
};
|
||||
|
||||
|
||||
#endif // _BTPLAYER_H
|
||||
218
Engine/source/T3D/physics/bullet/btPlugin.cpp
Normal file
218
Engine/source/T3D/physics/bullet/btPlugin.cpp
Normal file
|
|
@ -0,0 +1,218 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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/btPlugin.h"
|
||||
|
||||
#include "T3D/physics/physicsShape.h"
|
||||
#include "T3D/physics/bullet/btWorld.h"
|
||||
#include "T3D/physics/bullet/btBody.h"
|
||||
#include "T3D/physics/bullet/btPlayer.h"
|
||||
#include "T3D/physics/bullet/btCollision.h"
|
||||
#include "T3D/gameBase/gameProcess.h"
|
||||
#include "core/util/tNamedFactory.h"
|
||||
|
||||
|
||||
AFTER_MODULE_INIT( Sim )
|
||||
{
|
||||
NamedFactory<PhysicsPlugin>::add( "Bullet", &BtPlugin::create );
|
||||
|
||||
#if defined(TORQUE_OS_MAC)
|
||||
NamedFactory<PhysicsPlugin>::add( "default", &BtPlugin::create );
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
PhysicsPlugin* BtPlugin::create()
|
||||
{
|
||||
return new BtPlugin();
|
||||
}
|
||||
|
||||
BtPlugin::BtPlugin()
|
||||
{
|
||||
}
|
||||
|
||||
BtPlugin::~BtPlugin()
|
||||
{
|
||||
}
|
||||
|
||||
void BtPlugin::destroyPlugin()
|
||||
{
|
||||
// Cleanup any worlds that are still kicking.
|
||||
Map<StringNoCase, PhysicsWorld*>::Iterator iter = mPhysicsWorldLookup.begin();
|
||||
for ( ; iter != mPhysicsWorldLookup.end(); iter++ )
|
||||
{
|
||||
iter->value->destroyWorld();
|
||||
delete iter->value;
|
||||
}
|
||||
mPhysicsWorldLookup.clear();
|
||||
|
||||
delete this;
|
||||
}
|
||||
|
||||
void BtPlugin::reset()
|
||||
{
|
||||
// First delete all the cleanup objects.
|
||||
if ( getPhysicsCleanup() )
|
||||
getPhysicsCleanup()->deleteAllObjects();
|
||||
|
||||
getPhysicsResetSignal().trigger( PhysicsResetEvent_Restore );
|
||||
|
||||
// Now let each world reset itself.
|
||||
Map<StringNoCase, PhysicsWorld*>::Iterator iter = mPhysicsWorldLookup.begin();
|
||||
for ( ; iter != mPhysicsWorldLookup.end(); iter++ )
|
||||
iter->value->reset();
|
||||
}
|
||||
|
||||
PhysicsCollision* BtPlugin::createCollision()
|
||||
{
|
||||
return new BtCollision();
|
||||
}
|
||||
|
||||
PhysicsBody* BtPlugin::createBody()
|
||||
{
|
||||
return new BtBody();
|
||||
}
|
||||
|
||||
PhysicsPlayer* BtPlugin::createPlayer()
|
||||
{
|
||||
return new BtPlayer();
|
||||
}
|
||||
|
||||
bool BtPlugin::isSimulationEnabled() const
|
||||
{
|
||||
bool ret = false;
|
||||
BtWorld *world = static_cast<BtWorld*>( getWorld( smClientWorldName ) );
|
||||
if ( world )
|
||||
{
|
||||
ret = world->getEnabled();
|
||||
return ret;
|
||||
}
|
||||
|
||||
world = static_cast<BtWorld*>( getWorld( smServerWorldName ) );
|
||||
if ( world )
|
||||
{
|
||||
ret = world->getEnabled();
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void BtPlugin::enableSimulation( const String &worldName, bool enable )
|
||||
{
|
||||
BtWorld *world = static_cast<BtWorld*>( getWorld( worldName ) );
|
||||
if ( world )
|
||||
world->setEnabled( enable );
|
||||
}
|
||||
|
||||
void BtPlugin::setTimeScale( const F32 timeScale )
|
||||
{
|
||||
// Grab both the client and
|
||||
// server worlds and set their time
|
||||
// scales to the passed value.
|
||||
BtWorld *world = static_cast<BtWorld*>( getWorld( smClientWorldName ) );
|
||||
if ( world )
|
||||
world->setEditorTimeScale( timeScale );
|
||||
|
||||
world = static_cast<BtWorld*>( getWorld( smServerWorldName ) );
|
||||
if ( world )
|
||||
world->setEditorTimeScale( timeScale );
|
||||
}
|
||||
|
||||
const F32 BtPlugin::getTimeScale() const
|
||||
{
|
||||
// Grab both the client and
|
||||
// server worlds and call
|
||||
// setEnabled( true ) on them.
|
||||
BtWorld *world = static_cast<BtWorld*>( getWorld( smClientWorldName ) );
|
||||
if ( !world )
|
||||
{
|
||||
world = static_cast<BtWorld*>( getWorld( smServerWorldName ) );
|
||||
if ( !world )
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
return world->getEditorTimeScale();
|
||||
}
|
||||
|
||||
bool BtPlugin::createWorld( const String &worldName )
|
||||
{
|
||||
Map<StringNoCase, PhysicsWorld*>::Iterator iter = mPhysicsWorldLookup.find( worldName );
|
||||
PhysicsWorld *world = NULL;
|
||||
|
||||
iter != mPhysicsWorldLookup.end() ? world = (*iter).value : world = NULL;
|
||||
|
||||
if ( world )
|
||||
{
|
||||
Con::errorf( "BtPlugin::createWorld - %s world already exists!", worldName.c_str() );
|
||||
return false;
|
||||
}
|
||||
|
||||
world = new BtWorld();
|
||||
|
||||
if ( worldName.equal( smClientWorldName, String::NoCase ) )
|
||||
world->initWorld( false, ClientProcessList::get() );
|
||||
else
|
||||
world->initWorld( true, ServerProcessList::get() );
|
||||
|
||||
mPhysicsWorldLookup.insert( worldName, world );
|
||||
|
||||
return world != NULL;
|
||||
}
|
||||
|
||||
void BtPlugin::destroyWorld( const String &worldName )
|
||||
{
|
||||
Map<StringNoCase, PhysicsWorld*>::Iterator iter = mPhysicsWorldLookup.find( worldName );
|
||||
if ( iter == mPhysicsWorldLookup.end() )
|
||||
return;
|
||||
|
||||
PhysicsWorld *world = (*iter).value;
|
||||
world->destroyWorld();
|
||||
delete world;
|
||||
|
||||
mPhysicsWorldLookup.erase( iter );
|
||||
}
|
||||
|
||||
PhysicsWorld* BtPlugin::getWorld( const String &worldName ) const
|
||||
{
|
||||
if ( mPhysicsWorldLookup.isEmpty() )
|
||||
return NULL;
|
||||
|
||||
Map<StringNoCase, PhysicsWorld*>::ConstIterator iter = mPhysicsWorldLookup.find( worldName );
|
||||
|
||||
return iter != mPhysicsWorldLookup.end() ? (*iter).value : NULL;
|
||||
}
|
||||
|
||||
PhysicsWorld* BtPlugin::getWorld() const
|
||||
{
|
||||
if ( mPhysicsWorldLookup.size() == 0 )
|
||||
return NULL;
|
||||
|
||||
Map<StringNoCase, PhysicsWorld*>::ConstIterator iter = mPhysicsWorldLookup.begin();
|
||||
return iter->value;
|
||||
}
|
||||
|
||||
U32 BtPlugin::getWorldCount() const
|
||||
{
|
||||
return mPhysicsWorldLookup.size();
|
||||
}
|
||||
58
Engine/source/T3D/physics/bullet/btPlugin.h
Normal file
58
Engine/source/T3D/physics/bullet/btPlugin.h
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _T3D_PHYSICS_BTPLUGIN_H_
|
||||
#define _T3D_PHYSICS_BTPLUGIN_H_
|
||||
|
||||
#ifndef _T3D_PHYSICS_PHYSICSPLUGIN_H_
|
||||
#include "T3D/physics/physicsPlugin.h"
|
||||
#endif
|
||||
|
||||
|
||||
class BtPlugin : public PhysicsPlugin
|
||||
{
|
||||
public:
|
||||
|
||||
BtPlugin();
|
||||
~BtPlugin();
|
||||
|
||||
/// Create function for factory.
|
||||
static PhysicsPlugin* create();
|
||||
|
||||
// PhysicsPlugin
|
||||
virtual void destroyPlugin();
|
||||
virtual void reset();
|
||||
virtual PhysicsCollision* createCollision();
|
||||
virtual PhysicsBody* createBody();
|
||||
virtual PhysicsPlayer* createPlayer();
|
||||
virtual bool isSimulationEnabled() const;
|
||||
virtual void enableSimulation( const String &worldName, bool enable );
|
||||
virtual void setTimeScale( const F32 timeScale );
|
||||
virtual const F32 getTimeScale() const;
|
||||
virtual bool createWorld( const String &worldName );
|
||||
virtual void destroyWorld( const String &worldName );
|
||||
virtual PhysicsWorld* getWorld( const String &worldName ) const;
|
||||
virtual PhysicsWorld* getWorld() const;
|
||||
virtual U32 getWorldCount() const;
|
||||
};
|
||||
|
||||
#endif // _T3D_PHYSICS_PXPLUGIN_H_
|
||||
377
Engine/source/T3D/physics/bullet/btWorld.cpp
Normal file
377
Engine/source/T3D/physics/bullet/btWorld.cpp
Normal file
|
|
@ -0,0 +1,377 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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/btWorld.h"
|
||||
|
||||
#include "T3D/physics/bullet/btPlugin.h"
|
||||
#include "T3D/physics/bullet/btCasts.h"
|
||||
#include "T3D/physics/physicsUserData.h"
|
||||
#include "core/stream/bitStream.h"
|
||||
#include "platform/profiler.h"
|
||||
#include "sim/netConnection.h"
|
||||
#include "console/console.h"
|
||||
#include "console/consoleTypes.h"
|
||||
#include "scene/sceneRenderState.h"
|
||||
#include "T3D/gameBase/gameProcess.h"
|
||||
|
||||
|
||||
BtWorld::BtWorld() :
|
||||
mProcessList( NULL ),
|
||||
mIsSimulating( false ),
|
||||
mErrorReport( false ),
|
||||
mTickCount( 0 ),
|
||||
mIsEnabled( false ),
|
||||
mEditorTimeScale( 1.0f ),
|
||||
mDynamicsWorld( NULL ),
|
||||
mThreadSupportCollision( NULL )
|
||||
{
|
||||
}
|
||||
|
||||
BtWorld::~BtWorld()
|
||||
{
|
||||
}
|
||||
|
||||
bool BtWorld::initWorld( bool isServer, ProcessList *processList )
|
||||
{
|
||||
// Collision configuration contains default setup for memory, collision setup.
|
||||
mCollisionConfiguration = new btDefaultCollisionConfiguration();
|
||||
|
||||
// TODO: There is something wrong with multithreading
|
||||
// and compound convex shapes... so disable it for now.
|
||||
static const U32 smMaxThreads = 1;
|
||||
|
||||
// Different initialization with threading enabled.
|
||||
if ( smMaxThreads > 1 )
|
||||
{
|
||||
|
||||
// TODO: ifdef assumes smMaxThread is always one at this point. MACOSX support to be decided
|
||||
#ifdef WIN32
|
||||
mThreadSupportCollision = new Win32ThreadSupport(
|
||||
Win32ThreadSupport::Win32ThreadConstructionInfo( isServer ? "bt_servercol" : "bt_clientcol",
|
||||
processCollisionTask,
|
||||
createCollisionLocalStoreMemory,
|
||||
smMaxThreads ) );
|
||||
|
||||
mDispatcher = new SpuGatheringCollisionDispatcher( mThreadSupportCollision,
|
||||
smMaxThreads,
|
||||
mCollisionConfiguration );
|
||||
#endif // WIN32
|
||||
}
|
||||
else
|
||||
{
|
||||
mThreadSupportCollision = NULL;
|
||||
mDispatcher = new btCollisionDispatcher( mCollisionConfiguration );
|
||||
}
|
||||
|
||||
btVector3 worldMin( -2000, -2000, -1000 );
|
||||
btVector3 worldMax( 2000, 2000, 1000 );
|
||||
btAxisSweep3 *sweepBP = new btAxisSweep3( worldMin, worldMax );
|
||||
mBroadphase = sweepBP;
|
||||
sweepBP->getOverlappingPairCache()->setInternalGhostPairCallback( new btGhostPairCallback() );
|
||||
|
||||
// The default constraint solver. For parallel processing you can use a different solver (see Extras/BulletMultiThreaded).
|
||||
mSolver = new btSequentialImpulseConstraintSolver;
|
||||
|
||||
mDynamicsWorld = new btDiscreteDynamicsWorld( mDispatcher, mBroadphase, mSolver, mCollisionConfiguration );
|
||||
if ( !mDynamicsWorld )
|
||||
{
|
||||
Con::errorf( "BtWorld - %s failed to create dynamics world!", isServer ? "Server" : "Client" );
|
||||
return false;
|
||||
}
|
||||
|
||||
// Removing the randomization in the solver is required
|
||||
// to make the simulation deterministic.
|
||||
mDynamicsWorld->getSolverInfo().m_solverMode &= ~SOLVER_RANDMIZE_ORDER;
|
||||
|
||||
mDynamicsWorld->setGravity( btCast<btVector3>( mGravity ) );
|
||||
|
||||
AssertFatal( processList, "BtWorld::init() - We need a process list to create the world!" );
|
||||
mProcessList = processList;
|
||||
mProcessList->preTickSignal().notify( this, &BtWorld::getPhysicsResults );
|
||||
mProcessList->postTickSignal().notify( this, &BtWorld::tickPhysics, 1000.0f );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void BtWorld::_destroy()
|
||||
{
|
||||
// Release the tick processing signals.
|
||||
if ( mProcessList )
|
||||
{
|
||||
mProcessList->preTickSignal().remove( this, &BtWorld::getPhysicsResults );
|
||||
mProcessList->postTickSignal().remove( this, &BtWorld::tickPhysics );
|
||||
mProcessList = NULL;
|
||||
}
|
||||
|
||||
// TODO: Release any remaining
|
||||
// orphaned rigid bodies here.
|
||||
|
||||
SAFE_DELETE( mDynamicsWorld );
|
||||
SAFE_DELETE( mSolver );
|
||||
SAFE_DELETE( mBroadphase );
|
||||
SAFE_DELETE( mDispatcher );
|
||||
SAFE_DELETE( mThreadSupportCollision );
|
||||
SAFE_DELETE( mCollisionConfiguration );
|
||||
}
|
||||
|
||||
void BtWorld::tickPhysics( U32 elapsedMs )
|
||||
{
|
||||
if ( !mDynamicsWorld || !mIsEnabled )
|
||||
return;
|
||||
|
||||
// Did we forget to call getPhysicsResults somewhere?
|
||||
AssertFatal( !mIsSimulating, "PhysXWorld::tickPhysics() - Already simulating!" );
|
||||
|
||||
// The elapsed time should be non-zero and
|
||||
// a multiple of TickMs!
|
||||
AssertFatal( elapsedMs != 0 &&
|
||||
( elapsedMs % TickMs ) == 0 , "PhysXWorld::tickPhysics() - Got bad elapsed time!" );
|
||||
|
||||
PROFILE_SCOPE(BtWorld_TickPhysics);
|
||||
|
||||
// Convert it to seconds.
|
||||
const F32 elapsedSec = (F32)elapsedMs * 0.001f;
|
||||
|
||||
// Simulate... it is recommended to always use Bullet's default fixed timestep/
|
||||
mDynamicsWorld->stepSimulation( elapsedSec * mEditorTimeScale );
|
||||
|
||||
mIsSimulating = true;
|
||||
|
||||
//Con::printf( "%s BtWorld::tickPhysics!", this == smClientWorld ? "Client" : "Server" );
|
||||
}
|
||||
|
||||
void BtWorld::getPhysicsResults()
|
||||
{
|
||||
if ( !mDynamicsWorld || !mIsSimulating )
|
||||
return;
|
||||
|
||||
PROFILE_SCOPE(BtWorld_GetPhysicsResults);
|
||||
|
||||
// Get results from scene.
|
||||
// mScene->fetchResults( NX_RIGID_BODY_FINISHED, true );
|
||||
mIsSimulating = false;
|
||||
mTickCount++;
|
||||
}
|
||||
|
||||
void BtWorld::setEnabled( bool enabled )
|
||||
{
|
||||
mIsEnabled = enabled;
|
||||
|
||||
if ( !mIsEnabled )
|
||||
getPhysicsResults();
|
||||
}
|
||||
|
||||
void BtWorld::destroyWorld()
|
||||
{
|
||||
_destroy();
|
||||
}
|
||||
|
||||
bool BtWorld::castRay( const Point3F &startPnt, const Point3F &endPnt, RayInfo *ri, const Point3F &impulse )
|
||||
{
|
||||
btCollisionWorld::ClosestRayResultCallback result( btCast<btVector3>( startPnt ), btCast<btVector3>( endPnt ) );
|
||||
mDynamicsWorld->rayTest( btCast<btVector3>( startPnt ), btCast<btVector3>( endPnt ), result );
|
||||
|
||||
if ( !result.hasHit() || !result.m_collisionObject )
|
||||
return false;
|
||||
|
||||
if ( ri )
|
||||
{
|
||||
ri->object = PhysicsUserData::getObject( result.m_collisionObject->getUserPointer() );
|
||||
|
||||
// If we were passed a RayInfo, we can only return true signifying a collision
|
||||
// if we hit an object that actually has a torque object associated with it.
|
||||
//
|
||||
// In some ways this could be considered an error, either a physx object
|
||||
// has raycast-collision enabled that shouldn't or someone did not set
|
||||
// an object in this actor's userData.
|
||||
//
|
||||
if ( ri->object == NULL )
|
||||
return false;
|
||||
|
||||
ri->distance = ( endPnt - startPnt ).len() * result.m_closestHitFraction;
|
||||
ri->normal = btCast<Point3F>( result.m_hitNormalWorld );
|
||||
ri->point = btCast<Point3F>( result.m_hitPointWorld );
|
||||
ri->t = result.m_closestHitFraction;
|
||||
}
|
||||
|
||||
/*
|
||||
if ( impulse.isZero() ||
|
||||
!actor.isDynamic() ||
|
||||
actor.readBodyFlag( NX_BF_KINEMATIC ) )
|
||||
return true;
|
||||
|
||||
NxVec3 force = pxCast<NxVec3>( impulse );//worldRay.dir * forceAmt;
|
||||
actor.addForceAtPos( force, hitInfo.worldImpact, NX_IMPULSE );
|
||||
*/
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
PhysicsBody* BtWorld::castRay( const Point3F &start, const Point3F &end, U32 bodyTypes )
|
||||
{
|
||||
btVector3 startPt = btCast<btVector3>( start );
|
||||
btVector3 endPt = btCast<btVector3>( end );
|
||||
|
||||
btCollisionWorld::ClosestRayResultCallback result( startPt, endPt );
|
||||
mDynamicsWorld->rayTest( startPt, endPt, result );
|
||||
|
||||
if ( !result.hasHit() || !result.m_collisionObject )
|
||||
return NULL;
|
||||
|
||||
PhysicsUserData *userData = PhysicsUserData::cast( result.m_collisionObject->getUserPointer() );
|
||||
if ( !userData )
|
||||
return NULL;
|
||||
|
||||
return userData->getBody();
|
||||
}
|
||||
|
||||
void BtWorld::explosion( const Point3F &pos, F32 radius, F32 forceMagnitude )
|
||||
{
|
||||
/*
|
||||
// Find Actors at the position within the radius
|
||||
// and apply force to them.
|
||||
|
||||
NxVec3 nxPos = pxCast<NxVec3>( pos );
|
||||
NxShape **shapes = (NxShape**)NxAlloca(10*sizeof(NxShape*));
|
||||
NxSphere worldSphere( nxPos, radius );
|
||||
|
||||
NxU32 numHits = mScene->overlapSphereShapes( worldSphere, NX_ALL_SHAPES, 10, shapes, NULL );
|
||||
|
||||
for ( NxU32 i = 0; i < numHits; i++ )
|
||||
{
|
||||
NxActor &actor = shapes[i]->getActor();
|
||||
|
||||
bool dynamic = actor.isDynamic();
|
||||
|
||||
if ( !dynamic )
|
||||
continue;
|
||||
|
||||
bool kinematic = actor.readBodyFlag( NX_BF_KINEMATIC );
|
||||
|
||||
if ( kinematic )
|
||||
continue;
|
||||
|
||||
NxVec3 force = actor.getGlobalPosition() - nxPos;
|
||||
force.normalize();
|
||||
force *= forceMagnitude;
|
||||
|
||||
actor.addForceAtPos( force, nxPos, NX_IMPULSE, true );
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
void BtWorld::onDebugDraw( const SceneRenderState *state )
|
||||
{
|
||||
mDebugDraw.setCuller( &state->getFrustum() );
|
||||
|
||||
mDynamicsWorld->setDebugDrawer( &mDebugDraw );
|
||||
mDynamicsWorld->debugDrawWorld();
|
||||
mDynamicsWorld->setDebugDrawer( NULL );
|
||||
|
||||
mDebugDraw.flush();
|
||||
}
|
||||
|
||||
void BtWorld::reset()
|
||||
{
|
||||
if ( !mDynamicsWorld )
|
||||
return;
|
||||
|
||||
///create a copy of the array, not a reference!
|
||||
btCollisionObjectArray copyArray = mDynamicsWorld->getCollisionObjectArray();
|
||||
|
||||
S32 numObjects = mDynamicsWorld->getNumCollisionObjects();
|
||||
for ( S32 i=0; i < numObjects; i++ )
|
||||
{
|
||||
btCollisionObject* colObj = copyArray[i];
|
||||
btRigidBody* body = btRigidBody::upcast(colObj);
|
||||
|
||||
if (body)
|
||||
{
|
||||
if (body->getMotionState())
|
||||
{
|
||||
//btDefaultMotionState* myMotionState = (btDefaultMotionState*)body->getMotionState();
|
||||
//myMotionState->m_graphicsWorldTrans = myMotionState->m_startWorldTrans;
|
||||
//body->setCenterOfMassTransform( myMotionState->m_graphicsWorldTrans );
|
||||
//colObj->setInterpolationWorldTransform( myMotionState->m_startWorldTrans );
|
||||
colObj->forceActivationState(ACTIVE_TAG);
|
||||
colObj->activate();
|
||||
colObj->setDeactivationTime(0);
|
||||
//colObj->setActivationState(WANTS_DEACTIVATION);
|
||||
}
|
||||
|
||||
//removed cached contact points (this is not necessary if all objects have been removed from the dynamics world)
|
||||
//m_dynamicsWorld->getBroadphase()->getOverlappingPairCache()->cleanProxyFromPairs(colObj->getBroadphaseHandle(),getDynamicsWorld()->getDispatcher());
|
||||
|
||||
btRigidBody* body = btRigidBody::upcast(colObj);
|
||||
if (body && !body->isStaticObject())
|
||||
{
|
||||
btRigidBody::upcast(colObj)->setLinearVelocity(btVector3(0,0,0));
|
||||
btRigidBody::upcast(colObj)->setAngularVelocity(btVector3(0,0,0));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// reset some internal cached data in the broadphase
|
||||
mDynamicsWorld->getBroadphase()->resetPool( mDynamicsWorld->getDispatcher() );
|
||||
mDynamicsWorld->getConstraintSolver()->reset();
|
||||
}
|
||||
|
||||
/*
|
||||
ConsoleFunction( castForceRay, const char*, 4, 4, "( Point3F startPnt, Point3F endPnt, VectorF impulseVec )" )
|
||||
{
|
||||
PhysicsWorld *world = PHYSICSPLUGIN->getWorld( "server" );
|
||||
if ( !world )
|
||||
return NULL;
|
||||
|
||||
char *returnBuffer = Con::getReturnBuffer(256);
|
||||
|
||||
Point3F impulse;
|
||||
Point3F startPnt, endPnt;
|
||||
dSscanf( argv[1], "%f %f %f", &startPnt.x, &startPnt.y, &startPnt.z );
|
||||
dSscanf( argv[2], "%f %f %f", &endPnt.x, &endPnt.y, &endPnt.z );
|
||||
dSscanf( argv[3], "%f %f %f", &impulse.x, &impulse.y, &impulse.z );
|
||||
|
||||
Point3F hitPoint;
|
||||
|
||||
RayInfo rinfo;
|
||||
|
||||
bool hit = world->castRay( startPnt, endPnt, &rinfo, impulse );
|
||||
|
||||
DebugDrawer *ddraw = DebugDrawer::get();
|
||||
if ( ddraw )
|
||||
{
|
||||
ddraw->drawLine( startPnt, endPnt, hit ? ColorF::RED : ColorF::GREEN );
|
||||
ddraw->setLastTTL( 3000 );
|
||||
}
|
||||
|
||||
if ( hit )
|
||||
{
|
||||
dSprintf(returnBuffer, 256, "%g %g %g",
|
||||
rinfo.point.x, rinfo.point.y, rinfo.point.z );
|
||||
return returnBuffer;
|
||||
}
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
*/
|
||||
100
Engine/source/T3D/physics/bullet/btWorld.h
Normal file
100
Engine/source/T3D/physics/bullet/btWorld.h
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _BTWORLD_H_
|
||||
#define _BTWORLD_H_
|
||||
|
||||
#ifndef _T3D_PHYSICS_PHYSICSWORLD_H_
|
||||
#include "T3D/physics/physicsWorld.h"
|
||||
#endif
|
||||
#ifndef _T3D_PHYSICS_BTDEBUGDRAW_H_
|
||||
#include "T3D/physics/bullet/btDebugDraw.h"
|
||||
#endif
|
||||
#ifndef _BULLET_H_
|
||||
#include "T3D/physics/bullet/bt.h"
|
||||
#endif
|
||||
#ifndef _TVECTOR_H_
|
||||
#include "core/util/tVector.h"
|
||||
#endif
|
||||
|
||||
class ProcessList;
|
||||
class btThreadSupportInterface;
|
||||
class PhysicsBody;
|
||||
|
||||
|
||||
class BtWorld : public PhysicsWorld
|
||||
{
|
||||
protected:
|
||||
|
||||
BtDebugDraw mDebugDraw;
|
||||
|
||||
F32 mEditorTimeScale;
|
||||
|
||||
btDynamicsWorld *mDynamicsWorld;
|
||||
btBroadphaseInterface *mBroadphase;
|
||||
btCollisionDispatcher *mDispatcher;
|
||||
btConstraintSolver *mSolver;
|
||||
btDefaultCollisionConfiguration *mCollisionConfiguration;
|
||||
btThreadSupportInterface *mThreadSupportCollision;
|
||||
|
||||
bool mErrorReport;
|
||||
|
||||
bool mIsEnabled;
|
||||
|
||||
bool mIsSimulating;
|
||||
|
||||
U32 mTickCount;
|
||||
|
||||
ProcessList *mProcessList;
|
||||
|
||||
void _destroy();
|
||||
|
||||
public:
|
||||
|
||||
BtWorld();
|
||||
virtual ~BtWorld();
|
||||
|
||||
// PhysicWorld
|
||||
virtual bool initWorld( bool isServer, ProcessList *processList );
|
||||
virtual void destroyWorld();
|
||||
virtual bool castRay( const Point3F &startPnt, const Point3F &endPnt, RayInfo *ri, const Point3F &impulse );
|
||||
virtual PhysicsBody* castRay( const Point3F &start, const Point3F &end, U32 bodyTypes );
|
||||
virtual void explosion( const Point3F &pos, F32 radius, F32 forceMagnitude );
|
||||
virtual void onDebugDraw( const SceneRenderState *state );
|
||||
virtual void reset();
|
||||
virtual bool isEnabled() const { return mIsEnabled; }
|
||||
|
||||
btDynamicsWorld* getDynamicsWorld() const { return mDynamicsWorld; }
|
||||
|
||||
void tickPhysics( U32 elapsedMs );
|
||||
void getPhysicsResults();
|
||||
bool isWritable() const { return !mIsSimulating; }
|
||||
|
||||
void setEnabled( bool enabled );
|
||||
bool getEnabled() const { return mIsEnabled; }
|
||||
|
||||
void setEditorTimeScale( F32 timeScale ) { mEditorTimeScale = timeScale; }
|
||||
const F32 getEditorTimeScale() const { return mEditorTimeScale; }
|
||||
|
||||
};
|
||||
|
||||
#endif // _BTWORLD_H_
|
||||
Loading…
Add table
Add a link
Reference in a new issue