mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-04-25 06:15:36 +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_
|
||||
24
Engine/source/T3D/physics/physicsBody.cpp
Normal file
24
Engine/source/T3D/physics/physicsBody.cpp
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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/physicsBody.h"
|
||||
119
Engine/source/T3D/physics/physicsBody.h
Normal file
119
Engine/source/T3D/physics/physicsBody.h
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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_PHYSICSBODY_H_
|
||||
#define _T3D_PHYSICS_PHYSICSBODY_H_
|
||||
|
||||
#ifndef _T3D_PHYSICSCOMMON_H_
|
||||
#include "T3D/physics/physicsCommon.h"
|
||||
#endif
|
||||
#ifndef _T3D_PHYSICS_PHYSICSOBJECT_H_
|
||||
#include "T3D/physics/physicsObject.h"
|
||||
#endif
|
||||
|
||||
class PhysicsCollision;
|
||||
class SceneObject;
|
||||
|
||||
|
||||
/// Simple physics object that represents a single rigid body.
|
||||
class PhysicsBody : public PhysicsObject
|
||||
{
|
||||
public:
|
||||
|
||||
virtual ~PhysicsBody() {}
|
||||
|
||||
enum
|
||||
{
|
||||
/// Marks the body as a trigger object which is only used
|
||||
/// to get collision events and not get collision response.
|
||||
BF_TRIGGER = BIT( 0 ),
|
||||
|
||||
/// The body is kinematic and assumed to be moved by
|
||||
/// the game code via transforms.
|
||||
BF_KINEMATIC = BIT( 1 ),
|
||||
|
||||
/// The body responds to contacts but does not push forces into others.
|
||||
BF_DEBRIS = BIT( 2 )
|
||||
};
|
||||
|
||||
/// Initialize the body with a collision shape
|
||||
/// and basic physics properties.
|
||||
virtual bool init( PhysicsCollision *shape,
|
||||
F32 mass,
|
||||
U32 bodyFlags,
|
||||
SceneObject *obj,
|
||||
PhysicsWorld *world ) = 0;
|
||||
|
||||
/// Returns true if the object is a dynamic rigid body
|
||||
/// animated by the physics simulation.
|
||||
///
|
||||
/// Kinematics are not considered to be dynamic.
|
||||
///
|
||||
virtual bool isDynamic() const = 0;
|
||||
|
||||
/// Returns the collision shape used to create the body.
|
||||
virtual PhysicsCollision* getColShape() = 0;
|
||||
|
||||
///
|
||||
virtual void setSleepThreshold( F32 linear, F32 angular ) = 0;
|
||||
|
||||
///
|
||||
virtual void setDamping( F32 linear, F32 angular ) = 0;
|
||||
|
||||
///
|
||||
virtual void getState( PhysicsState *outState ) = 0;
|
||||
|
||||
///
|
||||
virtual F32 getMass() const = 0;
|
||||
|
||||
///
|
||||
virtual Point3F getCMassPosition() const = 0;
|
||||
|
||||
///
|
||||
virtual void setLinVelocity( const Point3F &vel ) = 0;
|
||||
|
||||
///
|
||||
virtual void setAngVelocity( const Point3F &vel ) = 0;
|
||||
|
||||
///
|
||||
virtual Point3F getLinVelocity() const = 0;
|
||||
|
||||
///
|
||||
virtual Point3F getAngVelocity() const = 0;
|
||||
|
||||
///
|
||||
virtual void setSleeping( bool sleeping ) = 0;
|
||||
|
||||
///
|
||||
virtual void setMaterial( F32 restitution,
|
||||
F32 friction,
|
||||
F32 staticFriction ) = 0;
|
||||
|
||||
///
|
||||
virtual void applyCorrection( const MatrixF &xfm ) = 0;
|
||||
|
||||
///
|
||||
virtual void applyImpulse( const Point3F &origin, const Point3F &force ) = 0;
|
||||
};
|
||||
|
||||
|
||||
#endif // _T3D_PHYSICS_PHYSICSBODY_H_
|
||||
87
Engine/source/T3D/physics/physicsCollision.h
Normal file
87
Engine/source/T3D/physics/physicsCollision.h
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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_PHYSICSCOLLISION_H_
|
||||
#define _T3D_PHYSICS_PHYSICSCOLLISION_H_
|
||||
|
||||
#ifndef _REFBASE_H_
|
||||
#include "core/util/refBase.h"
|
||||
#endif
|
||||
|
||||
class Point3F;
|
||||
class MatrixF;
|
||||
class PlaneF;
|
||||
|
||||
|
||||
/// The shared collision representation for a instance of a
|
||||
/// static or dynamic physics body.
|
||||
///
|
||||
/// Note that making very big convex primitives can cause bad
|
||||
/// queries and collisions in some physics providers.
|
||||
///
|
||||
/// @see PhysicsBody
|
||||
///
|
||||
class PhysicsCollision : public StrongRefBase
|
||||
{
|
||||
public:
|
||||
|
||||
/// Add an infinite plane to the collision shape.
|
||||
///
|
||||
/// This shape is assumed to be static in some physics
|
||||
/// providers and will at times be faked with a large box.
|
||||
///
|
||||
virtual void addPlane( const PlaneF &plane ) = 0;
|
||||
|
||||
/// Add a box to the collision shape.
|
||||
virtual void addBox( const Point3F &halfWidth,
|
||||
const MatrixF &localXfm ) = 0;
|
||||
|
||||
/// Add a sphere to the collision shape.
|
||||
virtual void addSphere( F32 radius,
|
||||
const MatrixF &localXfm ) = 0;
|
||||
|
||||
/// Add a Y axis capsule to the collision shape.
|
||||
virtual void addCapsule( F32 radius,
|
||||
F32 height,
|
||||
const MatrixF &localXfm ) = 0;
|
||||
|
||||
/// Add a point cloud convex hull to the collision shape.
|
||||
virtual bool addConvex( const Point3F *points,
|
||||
U32 count,
|
||||
const MatrixF &localXfm ) = 0;
|
||||
|
||||
/// Add a triangle mesh to the collision shape.
|
||||
virtual bool addTriangleMesh( const Point3F *vert,
|
||||
U32 vertCount,
|
||||
const U32 *index,
|
||||
U32 triCount,
|
||||
const MatrixF &localXfm ) = 0;
|
||||
|
||||
/// Add a heightfield to the collision shape.
|
||||
virtual bool addHeightfield( const U16 *heights,
|
||||
const bool *holes,
|
||||
U32 blockSize,
|
||||
F32 metersPerSample,
|
||||
const MatrixF &localXfm ) = 0;
|
||||
};
|
||||
|
||||
#endif // _T3D_PHYSICS_PHYSICSCOLLISION_H_
|
||||
141
Engine/source/T3D/physics/physicsCommon.h
Normal file
141
Engine/source/T3D/physics/physicsCommon.h
Normal file
|
|
@ -0,0 +1,141 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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_PHYSICSCOMMON_H_
|
||||
#define _T3D_PHYSICSCOMMON_H_
|
||||
|
||||
#ifndef _MPOINT3_H_
|
||||
#include "math/mPoint3.h"
|
||||
#endif
|
||||
#ifndef _MQUAT_H_
|
||||
#include "math/mQuat.h"
|
||||
#endif
|
||||
#ifndef _MMATRIX_H_
|
||||
#include "math/mMatrix.h"
|
||||
#endif
|
||||
#ifndef _REFBASE_H_
|
||||
#include "core/util/refBase.h"
|
||||
#endif
|
||||
|
||||
|
||||
/// Helper structure which defines the state of a single physics body.
|
||||
struct PhysicsState
|
||||
{
|
||||
/// Constructor.
|
||||
PhysicsState()
|
||||
: position( Point3F::Zero ),
|
||||
momentum( Point3F::Zero ),
|
||||
orientation( QuatF::Identity ),
|
||||
angularMomentum( Point3F::Zero ),
|
||||
linVelocity( Point3F::Zero ),
|
||||
angVelocity( Point3F::Zero ),
|
||||
sleeping( false )
|
||||
{
|
||||
}
|
||||
|
||||
/// The primary physics state.
|
||||
// @{
|
||||
|
||||
/// The position of the body.
|
||||
Point3F position;
|
||||
|
||||
/// The momentum in kilogram meters per second.
|
||||
Point3F momentum;
|
||||
|
||||
/// The orientation of the body.
|
||||
QuatF orientation;
|
||||
|
||||
/// The angular momentum.
|
||||
Point3F angularMomentum;
|
||||
|
||||
/// Is true if the shape is asleep.
|
||||
bool sleeping;
|
||||
|
||||
// @}
|
||||
|
||||
/// The secondary physics state derived from the primary state.
|
||||
/// @{
|
||||
|
||||
/// The linear velocity derived from the momentum.
|
||||
Point3F linVelocity;
|
||||
|
||||
///
|
||||
Point3F angVelocity;
|
||||
|
||||
/*
|
||||
Vector velocity; ///< velocity in meters per second (calculated from momentum).
|
||||
Quaternion spin; ///< quaternion rate of change in orientation.
|
||||
Vector angularVelocity; ///< angular velocity (calculated from angularMomentum).
|
||||
Matrix bodyToWorld; ///< body to world coordinates matrix.
|
||||
Matrix worldToBody; ///< world to body coordinates matrix.
|
||||
*/
|
||||
|
||||
/// @}
|
||||
|
||||
|
||||
/// Interpolates between two physics states leaving the
|
||||
/// result in this physics state.
|
||||
inline PhysicsState& interpolate( const PhysicsState &a, const PhysicsState &b, F32 t )
|
||||
{
|
||||
F32 inverseT = 1.0f - t;
|
||||
position = a.position*inverseT + b.position*t;
|
||||
momentum = a.momentum*inverseT + b.momentum*t;
|
||||
orientation.interpolate( a.orientation, b.orientation, t );
|
||||
angularMomentum = a.angularMomentum*inverseT + b.angularMomentum*t;
|
||||
|
||||
// Recalculate the velocities
|
||||
//linVelocity =
|
||||
//angVelocity
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Helper builds the transform from the state.
|
||||
inline MatrixF getTransform() const
|
||||
{
|
||||
MatrixF xfm;
|
||||
orientation.setMatrix( &xfm );
|
||||
xfm.setPosition( position );
|
||||
return xfm;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
/// The event type passed to the physics reset signal.
|
||||
/// @see PhysicsPlugin::getPhysicsResetSignal().
|
||||
enum PhysicsResetEvent
|
||||
{
|
||||
PhysicsResetEvent_Store,
|
||||
PhysicsResetEvent_Restore
|
||||
};
|
||||
|
||||
/// The signal for system wide physics events.
|
||||
/// @see PhysicsPlugin
|
||||
typedef Signal<void(PhysicsResetEvent reset)> PhysicsResetSignal;
|
||||
|
||||
class PhysicsCollision;
|
||||
|
||||
/// A strong reference to a physics collision shape.
|
||||
typedef StrongRefPtr<PhysicsCollision> PhysicsCollisionRef;
|
||||
|
||||
#endif // _T3D_PHYSICSCOMMON_H_
|
||||
716
Engine/source/T3D/physics/physicsDebris.cpp
Normal file
716
Engine/source/T3D/physics/physicsDebris.cpp
Normal file
|
|
@ -0,0 +1,716 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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/physicsDebris.h"
|
||||
|
||||
#include "core/stream/bitStream.h"
|
||||
#include "math/mathUtils.h"
|
||||
#include "console/consoleTypes.h"
|
||||
#include "console/consoleObject.h"
|
||||
#include "sim/netConnection.h"
|
||||
#include "scene/sceneRenderState.h"
|
||||
#include "scene/sceneManager.h"
|
||||
#include "ts/tsShapeInstance.h"
|
||||
#include "T3D/gameBase/gameProcess.h"
|
||||
#include "core/resourceManager.h"
|
||||
#include "gfx/gfxTransformSaver.h"
|
||||
#include "lighting/lightQuery.h"
|
||||
#include "T3D/physics/physicsBody.h"
|
||||
#include "T3D/physics/physicsCollision.h"
|
||||
#include "T3D/physics/physicsWorld.h"
|
||||
#include "collision/concretePolyList.h"
|
||||
#include "T3D/physics/physicsPlugin.h"
|
||||
#include "math/mathUtils.h"
|
||||
#include "gui/worldEditor/worldEditor.h"
|
||||
#include "T3D/containerQuery.h"
|
||||
|
||||
|
||||
F32 PhysicsDebris::smLifetimeScale = 1.0f;
|
||||
|
||||
|
||||
IMPLEMENT_CO_DATABLOCK_V1( PhysicsDebrisData );
|
||||
|
||||
ConsoleDocClass( PhysicsDebrisData,
|
||||
|
||||
"@brief Defines the properties of a PhysicsDebris object.\n\n"
|
||||
"@see PhysicsDebris.\n"
|
||||
"@ingroup Physics"
|
||||
);
|
||||
|
||||
PhysicsDebrisData::PhysicsDebrisData()
|
||||
: mass( 1.0f ),
|
||||
dynamicFriction( 0.0f ),
|
||||
staticFriction( 0.0f ),
|
||||
restitution( 0.0f ),
|
||||
linearDamping( 0.0f ),
|
||||
angularDamping( 0.0f ),
|
||||
linearSleepThreshold( 1.0f ),
|
||||
angularSleepThreshold( 1.0f ),
|
||||
waterDampingScale( 1.0f ),
|
||||
buoyancyDensity( 0.0f ),
|
||||
castShadows( true )
|
||||
{
|
||||
lifetime = 5.0f;
|
||||
lifetimeVariance = 0.0f;
|
||||
shapeName = NULL;
|
||||
}
|
||||
|
||||
bool PhysicsDebrisData::onAdd()
|
||||
{
|
||||
if(!Parent::onAdd())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PhysicsDebrisData::preload( bool server, String &errorStr )
|
||||
{
|
||||
if ( Parent::preload( server, errorStr ) == false )
|
||||
return false;
|
||||
|
||||
if ( server ) return true;
|
||||
|
||||
if ( shapeName && shapeName[0] != '\0' && !bool(shape) )
|
||||
{
|
||||
shape = ResourceManager::get().load( shapeName );
|
||||
if ( bool(shape) == false )
|
||||
{
|
||||
errorStr = String::ToString( "PhysicsDebrisData::load: Couldn't load shape \"%s\"", shapeName );
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Create a dummy shape to force the generation of shaders and materials
|
||||
// during the level load and not during gameplay.
|
||||
TSShapeInstance *pDummy = new TSShapeInstance( shape, !server );
|
||||
delete pDummy;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void PhysicsDebrisData::initPersistFields()
|
||||
{
|
||||
addGroup( "Display" );
|
||||
|
||||
addField( "shapeFile", TypeShapeFilename, Offset( shapeName, PhysicsDebrisData ),
|
||||
"@brief Path to the .DAE or .DTS file to use for this shape.\n\n"
|
||||
"Compatable with Live-Asset Reloading.");
|
||||
|
||||
addField( "castShadows", TypeBool, Offset( castShadows, PhysicsDebrisData ),
|
||||
"@brief Determines if the shape's shadow should be cast onto the environment.\n\n" );
|
||||
|
||||
endGroup( "Display" );
|
||||
|
||||
addGroup( "Physical Properties" );
|
||||
|
||||
addField("lifetime", TypeF32, Offset( lifetime, PhysicsDebrisData ),
|
||||
"@brief Base time, in seconds, that debris persists after time of creation.\n\n"
|
||||
"@note A %PhysicsDebris' lifetime multiplied by it's $pref::PhysicsDebris::lifetimeScale "
|
||||
"must be equal to or greater than 1.0.\n\n");
|
||||
|
||||
addField("lifetimeVariance", TypeF32, Offset( lifetimeVariance, PhysicsDebrisData ),
|
||||
"@brief Range of variation randomly applied to lifetime when debris is created.\n\n"
|
||||
"Represents the maximum amount of seconds that will be added or subtracted to a shape's base lifetime. "
|
||||
"A value of 0 will apply the same lifetime to each shape created.\n\n");
|
||||
|
||||
addField( "mass", TypeF32, Offset( mass, PhysicsDebrisData ),
|
||||
"@brief Value representing the mass of the shape.\n\n"
|
||||
"A shape's mass influences the magnitude of any force applied to it. "
|
||||
"@note All PhysicsDebris objects are dynamic.");
|
||||
|
||||
addField( "friction", TypeF32, Offset( dynamicFriction, PhysicsDebrisData ),
|
||||
"@brief Coefficient of kinetic %friction to be applied to the shape.\n\n"
|
||||
"Kinetic %friction reduces the velocity of a moving object while it is in contact with a surface. "
|
||||
"A larger coefficient will result in a larger reduction in velocity. "
|
||||
"A shape's friction should be smaller than it's staticFriction, but greater than 0.\n\n"
|
||||
"@note This value is only applied while an object is in motion. For an object starting at rest, see PhysicsDebrisData::staticFriction");
|
||||
|
||||
addField( "staticFriction", TypeF32, Offset( staticFriction, PhysicsDebrisData ),
|
||||
"@brief Coefficient of static %friction to be applied to the shape.\n\n"
|
||||
"Static %friction determines the force needed to start moving an at-rest object in contact with a surface. "
|
||||
"If the force applied onto shape cannot overcome the force of static %friction, the shape will remain at rest. "
|
||||
"A higher coefficient will require a larger force to start motion. "
|
||||
"This value should be both greater than 0 and the PhysicsDebrisData::friction.\n\n"
|
||||
"@note This value is only applied while an object is at rest. For an object in motion, see PhysicsDebrisData::friction");
|
||||
|
||||
addField( "restitution", TypeF32, Offset( restitution, PhysicsDebrisData ),
|
||||
"@brief Bounce coeffecient applied to the shape in response to a collision.\n\n"
|
||||
"Restitution is a ratio of a shape's velocity before and after a collision. "
|
||||
"A value of 0 will zero out a shape's post-collision velocity, making it stop on contact. "
|
||||
"Larger values will remove less velocity after a collision, making it \'bounce\' with greater force. "
|
||||
"Normal %restitution values range between 0 and 1.0."
|
||||
"@note Values near or equaling 1.0 are likely to cause undesirable results in the physics simulation."
|
||||
" Because of this, it is reccomended to avoid values close to 1.0");
|
||||
|
||||
addField( "linearDamping", TypeF32, Offset( linearDamping, PhysicsDebrisData ),
|
||||
"@brief Value that reduces an object's linear velocity over time.\n\n"
|
||||
"Larger values will cause velocity to decay quicker.\n\n" );
|
||||
|
||||
addField( "angularDamping", TypeF32, Offset( angularDamping, PhysicsDebrisData ),
|
||||
"@brief Value that reduces an object's rotational velocity over time.\n\n"
|
||||
"Larger values will cause velocity to decay quicker.\n\n" );
|
||||
|
||||
addField( "linearSleepThreshold", TypeF32, Offset( linearSleepThreshold, PhysicsDebrisData ),
|
||||
"@brief Minimum linear velocity before the shape can be put to sleep.\n\n"
|
||||
"This should be a positive value. Shapes put to sleep will not be simulated in order to save system resources.\n\n"
|
||||
"@note The shape must be dynamic.");
|
||||
|
||||
addField( "angularSleepThreshold", TypeF32, Offset( angularSleepThreshold, PhysicsDebrisData ),
|
||||
"@brief Minimum rotational velocity before the shape can be put to sleep.\n\n"
|
||||
"This should be a positive value. Shapes put to sleep will not be simulated in order to save system resources.\n\n"
|
||||
"@note The shape must be dynamic.");
|
||||
|
||||
addField( "waterDampingScale", TypeF32, Offset( waterDampingScale, PhysicsDebrisData ),
|
||||
"@brief Scale to apply to linear and angular dampening while underwater.\n\n "
|
||||
"@see angularDamping linearDamping" );
|
||||
|
||||
addField( "buoyancyDensity", TypeF32, Offset( buoyancyDensity, PhysicsDebrisData ),
|
||||
"@brief The density of this shape for purposes of calculating buoyant forces.\n\n"
|
||||
"The result of the calculated buoyancy is relative to the density of the WaterObject the PhysicsDebris is within."
|
||||
"@see WaterObject::density");
|
||||
|
||||
endGroup( "Physical Properties" );
|
||||
|
||||
Parent::initPersistFields();
|
||||
}
|
||||
|
||||
void PhysicsDebrisData::packData(BitStream* stream)
|
||||
{
|
||||
Parent::packData(stream);
|
||||
|
||||
stream->writeFlag( castShadows );
|
||||
stream->write( lifetime );
|
||||
stream->write( lifetimeVariance );
|
||||
stream->write( mass );
|
||||
stream->write( dynamicFriction );
|
||||
stream->write( staticFriction );
|
||||
stream->write( restitution );
|
||||
stream->write( linearDamping );
|
||||
stream->write( angularDamping );
|
||||
stream->write( linearSleepThreshold );
|
||||
stream->write( angularSleepThreshold );
|
||||
stream->write( waterDampingScale );
|
||||
stream->write( buoyancyDensity );
|
||||
stream->writeString( shapeName );
|
||||
}
|
||||
|
||||
void PhysicsDebrisData::unpackData(BitStream* stream)
|
||||
{
|
||||
Parent::unpackData(stream);
|
||||
|
||||
castShadows = stream->readFlag();
|
||||
stream->read( &lifetime );
|
||||
stream->read( &lifetimeVariance );
|
||||
stream->read( &mass );
|
||||
stream->read( &dynamicFriction );
|
||||
stream->read( &staticFriction );
|
||||
stream->read( &restitution );
|
||||
stream->read( &linearDamping );
|
||||
stream->read( &angularDamping );
|
||||
stream->read( &linearSleepThreshold );
|
||||
stream->read( &angularSleepThreshold );
|
||||
stream->read( &waterDampingScale );
|
||||
stream->read( &buoyancyDensity );
|
||||
|
||||
shapeName = stream->readSTString();
|
||||
}
|
||||
|
||||
ConsoleMethod( PhysicsDebrisData, preload, void, 2, 2,
|
||||
"@brief Loads some information to have readily available at simulation time.\n\n"
|
||||
"Forces generation of shaders, materials, and other data used by the %PhysicsDebris object. "
|
||||
"This function should be used while a level is loading in order to shorten "
|
||||
"the amount of time to create a PhysicsDebris in game.\n\n")
|
||||
{
|
||||
String errorStr;
|
||||
|
||||
object->shape = NULL;
|
||||
if( !object->preload( false, errorStr ) )
|
||||
Con::errorf( "PhsysicsDebrisData::preload - error: %s", errorStr.c_str() );
|
||||
}
|
||||
|
||||
|
||||
IMPLEMENT_CO_NETOBJECT_V1( PhysicsDebris );
|
||||
|
||||
ConsoleDocClass( PhysicsDebris,
|
||||
|
||||
"@brief Represents one or more rigid bodies defined in a single mesh file with "
|
||||
"a limited lifetime.\n\n"
|
||||
|
||||
"A PhysicsDebris object can be viewed as a single system capable of generating multiple "
|
||||
"@link PhysicsBody PhysicsBodies@endlink as debris when triggered. Vaguely similar to how "
|
||||
"a ParticleEmitter is capable of creating Particles, but isn't a particle in itself. "
|
||||
|
||||
"After it's lifetime has elapsed, the object will be deleted.\n\n"
|
||||
|
||||
"%PhysicsDebris loads a standard .DAE or .DTS file and creates a rigid body for "
|
||||
"each defined collision node.\n\n"
|
||||
|
||||
"For collision nodes to work correctly, they must be setup as follows:\n"
|
||||
" - Visible mesh nodes are siblings of the collision node under a common parent dummy node.\n"
|
||||
" - Collision node is a child of its visible mesh node.\n\n"
|
||||
|
||||
"Colmesh type nodes are NOT supported; physx and most standard rigid "
|
||||
"body simulations do not support arbitrary triangle meshs for dynamics "
|
||||
"do to the computational expense.\n\n"
|
||||
"Therefore, collision nodes must be one of the following:\n"
|
||||
" - Colbox\n"
|
||||
" - Colsphere\n"
|
||||
" - Colcapsule\n"
|
||||
" - Col (convex).\n\n"
|
||||
|
||||
"%PhysicsDebris should NOT be created on the server.\n\n"
|
||||
|
||||
"@ingroup Physics"
|
||||
);
|
||||
|
||||
PhysicsDebris* PhysicsDebris::create( PhysicsDebrisData *datablock,
|
||||
const MatrixF &transform,
|
||||
const VectorF &linVel )
|
||||
{
|
||||
// Skip out if we don't have a datablock or the
|
||||
// global lifetime scale has it living less than
|
||||
// a second.
|
||||
if ( !datablock ||
|
||||
( datablock->lifetime > 0.0f &&
|
||||
datablock->lifetime * smLifetimeScale < 1.0f ) )
|
||||
return NULL;
|
||||
|
||||
PhysicsDebris *debris = new PhysicsDebris();
|
||||
debris->setDataBlock( datablock );
|
||||
debris->setTransform( transform );
|
||||
debris->mInitialLinVel = linVel;
|
||||
if ( !debris->registerObject() )
|
||||
{
|
||||
delete debris;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return debris;
|
||||
}
|
||||
|
||||
PhysicsDebris::PhysicsDebris()
|
||||
: mLifetime( 0.0f ),
|
||||
mShapeInstance( NULL ),
|
||||
mWorld( NULL ),
|
||||
mInitialLinVel( Point3F::Zero )
|
||||
{
|
||||
mTypeMask |= DebrisObjectType | DynamicShapeObjectType;
|
||||
|
||||
// Only allocated client side.
|
||||
mNetFlags.set( IsGhost );
|
||||
}
|
||||
|
||||
PhysicsDebris::~PhysicsDebris()
|
||||
{
|
||||
}
|
||||
|
||||
void PhysicsDebris::initPersistFields()
|
||||
{
|
||||
Con::addVariable( "$pref::PhysicsDebris::lifetimeScale", TypeF32, &smLifetimeScale,
|
||||
"@brief Scales how long %PhysicsDebris will live before being removed.\n"
|
||||
"@note A value of 0 will disable PhysicsDebris entirely.");
|
||||
|
||||
Parent::initPersistFields();
|
||||
}
|
||||
|
||||
bool PhysicsDebris::onAdd()
|
||||
{
|
||||
AssertFatal( isClientObject(), "PhysicsDebris::onAdd - This shouldn't be added on the server!" );
|
||||
|
||||
if ( !Parent::onAdd() )
|
||||
return false;
|
||||
|
||||
// If it has a fixed lifetime then calculate it.
|
||||
if ( mDataBlock->lifetime > 0.0f )
|
||||
{
|
||||
F32 lifeVar = (mDataBlock->lifetimeVariance * 2.0f * gRandGen.randF(-1.0,1.0)) - mDataBlock->lifetimeVariance;
|
||||
mLifetime = mDataBlock->lifetime + lifeVar;
|
||||
}
|
||||
|
||||
// Setup our bounding box
|
||||
mObjBox = mDataBlock->shape->bounds;
|
||||
resetWorldBox();
|
||||
|
||||
// Add it to the client scene.
|
||||
addToScene();
|
||||
|
||||
// We add the debris to the net connection so that
|
||||
// it is cleaned up when the client disconnects.
|
||||
NetConnection *conn = NetConnection::getConnectionToServer();
|
||||
AssertFatal( conn != NULL, "PhysicsDebris::onAdd - Got null net connection!");
|
||||
conn->addObject(this);
|
||||
|
||||
PhysicsPlugin::getPhysicsResetSignal().notify( this, &PhysicsDebris::_onPhysicsReset );
|
||||
_createFragments();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PhysicsDebris::onNewDataBlock( GameBaseData *dptr, bool reload )
|
||||
{
|
||||
if ( !dptr )
|
||||
return false;
|
||||
|
||||
mDataBlock = dynamic_cast< PhysicsDebrisData* >( dptr );
|
||||
if ( !mDataBlock )
|
||||
{
|
||||
Con::errorf( ConsoleLogEntry::General, "PhysicsDebris::onNewDataBlock - datablock ( %i ) is not of type PhysicsDebrisData.", dptr->getId() );
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void PhysicsDebris::onRemove()
|
||||
{
|
||||
PhysicsPlugin::getPhysicsResetSignal().remove( this, &PhysicsDebris::_onPhysicsReset );
|
||||
|
||||
_deleteFragments();
|
||||
|
||||
removeFromScene();
|
||||
|
||||
Parent::onRemove();
|
||||
}
|
||||
|
||||
void PhysicsDebris::processTick( const Move* )
|
||||
{
|
||||
PROFILE_SCOPE( PhysicsDebris_processTick );
|
||||
|
||||
// Delete the debris if our lifetime has expired.
|
||||
if ( mDataBlock->lifetime > 0.0f &&
|
||||
mIsZero( mLifetime ) )
|
||||
{
|
||||
deleteObject();
|
||||
return;
|
||||
}
|
||||
|
||||
MatrixF mat;
|
||||
mWorldBox = Box3F::Invalid;
|
||||
Box3F bounds;
|
||||
|
||||
FragmentVector::iterator fragment = mFragments.begin();
|
||||
for ( ; fragment != mFragments.end(); fragment++ )
|
||||
{
|
||||
// Store the last position.
|
||||
fragment->lastPos = fragment->pos;
|
||||
fragment->lastRot = fragment->rot;
|
||||
|
||||
// Get the new position.
|
||||
fragment->body->getTransform( &mat );
|
||||
|
||||
// Calculate the delta between the current
|
||||
// global pose and the last global pose.
|
||||
fragment->pos = mat.getPosition();
|
||||
fragment->rot.set( mat );
|
||||
|
||||
// Update the bounds.
|
||||
bounds = fragment->body->getWorldBounds();
|
||||
mWorldBox.intersect( bounds );
|
||||
|
||||
// Apply forces for the next tick.
|
||||
_updateForces( fragment->body, bounds );
|
||||
}
|
||||
|
||||
// Finish up the bounds update.
|
||||
mWorldSphere.radius = (mWorldBox.maxExtents - mWorldSphere.center).len();
|
||||
mObjBox = mWorldBox;
|
||||
mWorldToObj.mul(mObjBox);
|
||||
mRenderWorldBox = mWorldBox;
|
||||
mRenderWorldSphere = mWorldSphere;
|
||||
}
|
||||
|
||||
void PhysicsDebris::_updateForces( PhysicsBody *body, const Box3F &bounds )
|
||||
{
|
||||
PROFILE_SCOPE( PhysicsDebris_updateForces );
|
||||
|
||||
// If we're not simulating don't update forces.
|
||||
if ( !mWorld->isEnabled() )
|
||||
return;
|
||||
|
||||
ContainerQueryInfo info;
|
||||
info.box = bounds;
|
||||
info.mass = mDataBlock->mass;
|
||||
|
||||
// Find and retreive physics info from intersecting WaterObject(s)
|
||||
getContainer()->findObjects( bounds, WaterObjectType|PhysicalZoneObjectType, findRouter, &info );
|
||||
|
||||
// Calculate buoyancy and drag
|
||||
F32 angDrag = mDataBlock->angularDamping;
|
||||
F32 linDrag = mDataBlock->linearDamping;
|
||||
F32 buoyancy = 0.0f;
|
||||
Point3F cmass = body->getCMassPosition();
|
||||
|
||||
F32 density = mDataBlock->buoyancyDensity;
|
||||
if ( density > 0.0f )
|
||||
{
|
||||
if ( info.waterCoverage > 0.0f )
|
||||
{
|
||||
F32 waterDragScale = info.waterViscosity * mDataBlock->waterDampingScale;
|
||||
F32 powCoverage = mPow( info.waterCoverage, 0.25f );
|
||||
|
||||
angDrag = mLerp( angDrag, angDrag * waterDragScale, powCoverage );
|
||||
linDrag = mLerp( linDrag, linDrag * waterDragScale, powCoverage );
|
||||
}
|
||||
|
||||
// A little hackery to prevent oscillation
|
||||
// Based on this blog post:
|
||||
// (http://reinot.blogspot.com/2005/11/oh-yes-they-float-georgie-they-all.html)
|
||||
|
||||
buoyancy = ( info.waterDensity / density ) * mPow( info.waterCoverage, 2.0f );
|
||||
|
||||
Point3F buoyancyForce = buoyancy * -mWorld->getGravity() * TickSec * mDataBlock->mass;
|
||||
body->applyImpulse( cmass, buoyancyForce );
|
||||
}
|
||||
|
||||
// Update the dampening as the container might have changed.
|
||||
body->setDamping( linDrag, angDrag );
|
||||
|
||||
// Apply physical zone forces.
|
||||
if ( !info.appliedForce.isZero() )
|
||||
body->applyImpulse( cmass, info.appliedForce );
|
||||
}
|
||||
|
||||
void PhysicsDebris::advanceTime( F32 dt )
|
||||
{
|
||||
// Decrement the lifetime.
|
||||
if ( smLifetimeScale > 0.0f )
|
||||
mLifetime = getMax( 0.0f, mLifetime - ( dt / smLifetimeScale ) );
|
||||
else
|
||||
mLifetime = 0.0f;
|
||||
}
|
||||
|
||||
void PhysicsDebris::interpolateTick( F32 dt )
|
||||
{
|
||||
PROFILE_SCOPE( PhysicsDebris_interpolateTick );
|
||||
|
||||
mShapeInstance->animate();
|
||||
if ( mShapeInstance->getCurrentDetail() < 0 )
|
||||
return;
|
||||
|
||||
const MatrixF &objectXfm = getRenderWorldTransform();
|
||||
Vector<MatrixF> &nodeXfms = mShapeInstance->mNodeTransforms;
|
||||
|
||||
MatrixF globalXfm;
|
||||
MatrixF tempXfm;
|
||||
QuatF newRot;
|
||||
Point3F newPos;
|
||||
|
||||
FragmentVector::iterator fragment = mFragments.begin();
|
||||
for ( ; fragment != mFragments.end(); fragment++ )
|
||||
{
|
||||
// Do the interpolation.
|
||||
newRot.interpolate( fragment->rot, fragment->lastRot, dt );
|
||||
newRot.setMatrix( &globalXfm );
|
||||
newPos.interpolate( fragment->pos, fragment->lastPos, dt );
|
||||
globalXfm.setPosition( newPos );
|
||||
|
||||
tempXfm = objectXfm * globalXfm;
|
||||
|
||||
for ( S32 i = 0; i < fragment->nodeIds.size(); i++ )
|
||||
{
|
||||
S32 n = fragment->nodeIds[i];
|
||||
nodeXfms[n] = tempXfm;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PhysicsDebris::prepRenderImage( SceneRenderState *state )
|
||||
{
|
||||
if( !mShapeInstance )
|
||||
return;
|
||||
|
||||
// Skip shadow rendering if this debris doesn't support it.
|
||||
if ( state->isShadowPass() &&
|
||||
!mDataBlock->castShadows )
|
||||
return;
|
||||
|
||||
// If the debris is completed LOD'd out then skip it.
|
||||
if ( mShapeInstance->setDetailFromPosAndScale( state, getRenderPosition(), getScale() ) < 0 )
|
||||
return;
|
||||
|
||||
// Fade out the debris over the last second of its lifetime.
|
||||
F32 alpha = 1.0;
|
||||
if ( mDataBlock->lifetime > 0.0f )
|
||||
alpha = getMin( mLifetime * smLifetimeScale, 1.0f );
|
||||
|
||||
// Set up our TS render state.
|
||||
TSRenderState rdata;
|
||||
rdata.setSceneState( state );
|
||||
rdata.setFadeOverride( alpha );
|
||||
|
||||
// We might have some forward lit materials
|
||||
// so pass down a query to gather lights.
|
||||
LightQuery query;
|
||||
query.init( getWorldSphere() );
|
||||
rdata.setLightQuery( &query );
|
||||
|
||||
GFXTransformSaver saver;
|
||||
|
||||
MatrixF mat = getRenderTransform();
|
||||
mat.scale( getScale() );
|
||||
GFX->setWorldMatrix( mat );
|
||||
|
||||
mShapeInstance->animate();
|
||||
mShapeInstance->render( rdata );
|
||||
}
|
||||
|
||||
void PhysicsDebris::applyImpulse( const Point3F &pos, const VectorF &vec )
|
||||
{
|
||||
FragmentVector::iterator fragment = mFragments.begin();
|
||||
for ( ; fragment != mFragments.end(); fragment++ )
|
||||
fragment->body->applyImpulse( pos, vec );
|
||||
}
|
||||
|
||||
void PhysicsDebris::applyRadialImpulse( const Point3F &origin, F32 radius, F32 magnitude )
|
||||
{
|
||||
FragmentVector::iterator fragment = mFragments.begin();
|
||||
for ( ; fragment != mFragments.end(); fragment++ )
|
||||
{
|
||||
PhysicsBody &body = *fragment->body;
|
||||
|
||||
Box3F bounds = body.getWorldBounds();
|
||||
|
||||
VectorF force = bounds.getCenter() - origin;
|
||||
F32 dist = force.magnitudeSafe();
|
||||
force.normalize();
|
||||
|
||||
if ( dist == 0.0f )
|
||||
force *= magnitude;
|
||||
else
|
||||
force *= mClampF( radius / dist, 0.0f, 1.0f ) * magnitude;
|
||||
|
||||
body.applyImpulse( origin, force );
|
||||
}
|
||||
}
|
||||
|
||||
void PhysicsDebris::_createFragments()
|
||||
{
|
||||
_deleteFragments();
|
||||
|
||||
mWorld = PHYSICSMGR->getWorld( "client" );
|
||||
if ( !mWorld )
|
||||
return;
|
||||
|
||||
TSShape *shape = mDataBlock->shape;
|
||||
|
||||
mShapeInstance = new TSShapeInstance( shape, true );
|
||||
mShapeInstance->animate();
|
||||
|
||||
Vector< CollisionShapeInfo > infoList;
|
||||
shape->buildColShapes( false, Point3F::One, &infoList );
|
||||
|
||||
mFragments.setSize( infoList.size() );
|
||||
dMemset( mFragments.address(), 0, mFragments.memSize() );
|
||||
|
||||
const Point3F damageDir( 0, 0, 1 );
|
||||
|
||||
MatrixF bodyMat( true );
|
||||
bodyMat = getTransform();
|
||||
|
||||
const U32 bodyFlags = PhysicsBody::BF_DEBRIS;
|
||||
mWorldBox = Box3F::Invalid;
|
||||
|
||||
for ( S32 i = 0; i < infoList.size(); i++ )
|
||||
{
|
||||
const CollisionShapeInfo &info = infoList[i];
|
||||
|
||||
Fragment &fragment = mFragments[i];
|
||||
|
||||
if ( info.colNode == -1 )
|
||||
Con::errorf( "PhysicsDebris::_createFragments, Missing or couldnt find a colNode." );
|
||||
else
|
||||
_findNodes( info.colNode, fragment.nodeIds );
|
||||
|
||||
PhysicsBody *body = PHYSICSMGR->createBody();
|
||||
body->init( info.colShape, mDataBlock->mass, bodyFlags, this, mWorld );
|
||||
body->setMaterial( mDataBlock->restitution, mDataBlock->dynamicFriction, mDataBlock->staticFriction );
|
||||
body->setDamping( mDataBlock->linearDamping, mDataBlock->angularDamping );
|
||||
body->setSleepThreshold( mDataBlock->linearSleepThreshold, mDataBlock->angularSleepThreshold );
|
||||
body->setTransform( bodyMat );
|
||||
body->setLinVelocity( mInitialLinVel );
|
||||
fragment.body = body;
|
||||
|
||||
// Set the initial delta state.
|
||||
fragment.pos = bodyMat.getPosition();
|
||||
fragment.rot.set( bodyMat );
|
||||
fragment.lastPos = fragment.pos;
|
||||
fragment.lastRot = fragment.rot;
|
||||
|
||||
// Update the bounds.
|
||||
mWorldBox.intersect( body->getWorldBounds() );
|
||||
}
|
||||
|
||||
// Finish up updating the bounds.
|
||||
mWorldSphere.radius = (mWorldBox.maxExtents - mWorldSphere.center).len();
|
||||
mObjBox = mWorldBox;
|
||||
mWorldToObj.mul(mObjBox);
|
||||
mRenderWorldBox = mWorldBox;
|
||||
mRenderWorldSphere = mWorldSphere;
|
||||
}
|
||||
|
||||
void PhysicsDebris::_deleteFragments()
|
||||
{
|
||||
FragmentVector::iterator fragment = mFragments.begin();
|
||||
for ( ; fragment != mFragments.end(); fragment++ )
|
||||
delete fragment->body;
|
||||
|
||||
mFragments.clear();
|
||||
|
||||
SAFE_DELETE( mShapeInstance );
|
||||
}
|
||||
|
||||
void PhysicsDebris::_findNodes( U32 colNode, Vector<U32> &nodeIds )
|
||||
{
|
||||
// Two possible cases:
|
||||
// 1. Visible mesh nodes are siblings of the collision node under a common parent dummy node
|
||||
// 2. Collision node is a child of its visible mesh node
|
||||
|
||||
TSShape *shape = mDataBlock->shape;
|
||||
S32 itr = shape->nodes[colNode].parentIndex;
|
||||
itr = shape->nodes[itr].firstChild;
|
||||
|
||||
while ( itr != -1 )
|
||||
{
|
||||
if ( itr != colNode )
|
||||
nodeIds.push_back(itr);
|
||||
itr = shape->nodes[itr].nextSibling;
|
||||
}
|
||||
|
||||
// If we didn't find any siblings of the collision node we assume
|
||||
// it is case #2 and the collision nodes direct parent is the visible mesh.
|
||||
if ( nodeIds.size() == 0 && shape->nodes[colNode].parentIndex != -1 )
|
||||
nodeIds.push_back( shape->nodes[colNode].parentIndex );
|
||||
}
|
||||
|
||||
extern bool gEditingMission;
|
||||
|
||||
void PhysicsDebris::_onPhysicsReset( PhysicsResetEvent reset )
|
||||
{
|
||||
if ( gEditingMission )
|
||||
{
|
||||
// Editing stuff, clean up the trash!
|
||||
safeDeleteObject();
|
||||
}
|
||||
}
|
||||
190
Engine/source/T3D/physics/physicsDebris.h
Normal file
190
Engine/source/T3D/physics/physicsDebris.h
Normal file
|
|
@ -0,0 +1,190 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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 _PHYSICS_DEBRIS_H_
|
||||
#define _PHYSICS_DEBRIS_H_
|
||||
|
||||
#ifndef __RESOURCE_H__
|
||||
#include "core/resource.h"
|
||||
#endif
|
||||
#ifndef _GAMEBASE_H_
|
||||
#include "T3D/gameBase/gameBase.h"
|
||||
#endif
|
||||
#ifndef _T3D_PHYSICSCOMMON_H_
|
||||
#include "T3D/physics/physicsCommon.h"
|
||||
#endif
|
||||
|
||||
|
||||
class TSShapeInstance;
|
||||
class TSShape;
|
||||
|
||||
//**************************************************************************
|
||||
// Debris Data
|
||||
//**************************************************************************
|
||||
class PhysicsDebrisData : public GameBaseData
|
||||
{
|
||||
typedef GameBaseData Parent;
|
||||
|
||||
public:
|
||||
|
||||
|
||||
F32 lifetime;
|
||||
F32 lifetimeVariance;
|
||||
|
||||
///
|
||||
F32 mass;
|
||||
|
||||
///
|
||||
F32 dynamicFriction;
|
||||
|
||||
///
|
||||
F32 staticFriction;
|
||||
|
||||
///
|
||||
F32 restitution;
|
||||
|
||||
///
|
||||
F32 linearDamping;
|
||||
|
||||
///
|
||||
F32 angularDamping;
|
||||
|
||||
///
|
||||
F32 linearSleepThreshold;
|
||||
|
||||
///
|
||||
F32 angularSleepThreshold;
|
||||
|
||||
// A scale applied to the normal linear and angular damping
|
||||
// when the object enters a water volume.
|
||||
F32 waterDampingScale;
|
||||
|
||||
// The density of this object used for water buoyancy effects.
|
||||
F32 buoyancyDensity;
|
||||
|
||||
/// Is rendererd during shadow passes.
|
||||
bool castShadows;
|
||||
|
||||
const char* shapeName;
|
||||
Resource<TSShape> shape;
|
||||
|
||||
PhysicsDebrisData();
|
||||
|
||||
bool onAdd();
|
||||
bool preload( bool server, String &errorStr );
|
||||
static void initPersistFields();
|
||||
void packData( BitStream *stream );
|
||||
void unpackData( BitStream *stream );
|
||||
|
||||
DECLARE_CONOBJECT( PhysicsDebrisData );
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
class PhysicsBody;
|
||||
class PhysicsWorld;
|
||||
|
||||
|
||||
class PhysicsDebris : public GameBase
|
||||
{
|
||||
typedef GameBase Parent;
|
||||
|
||||
public:
|
||||
|
||||
/// Helper method which creates debris based on the
|
||||
/// datablock and initial state.
|
||||
///
|
||||
/// It can return NULL if the system quality settings
|
||||
/// are set to disable the debris.
|
||||
///
|
||||
static PhysicsDebris* create( PhysicsDebrisData *datablock,
|
||||
const MatrixF &transform,
|
||||
const VectorF &linVel );
|
||||
|
||||
PhysicsDebris();
|
||||
virtual ~PhysicsDebris();
|
||||
|
||||
DECLARE_CONOBJECT(PhysicsDebris);
|
||||
static void initPersistFields();
|
||||
|
||||
bool onAdd();
|
||||
void onRemove();
|
||||
|
||||
void applyImpulse( const Point3F &pos, const VectorF &vec );
|
||||
void applyRadialImpulse( const Point3F &origin, F32 radius, F32 magnitude );
|
||||
|
||||
protected:
|
||||
|
||||
/// The global object lifetime scalar.
|
||||
static F32 smLifetimeScale;
|
||||
|
||||
void processTick( const Move *move );
|
||||
void advanceTime( F32 dt );
|
||||
void interpolateTick( F32 delta );
|
||||
bool onNewDataBlock( GameBaseData *dptr, bool reload );
|
||||
|
||||
void prepRenderImage( SceneRenderState *state );
|
||||
void prepBatchRender( SceneRenderState *state );
|
||||
|
||||
void _deleteFragments();
|
||||
void _createFragments();
|
||||
|
||||
void _updateForces( PhysicsBody *body, const Box3F &bounds );
|
||||
|
||||
void _findNodes( U32 objId, Vector<U32> &nodeIds );
|
||||
|
||||
void _onPhysicsReset( PhysicsResetEvent reset );
|
||||
|
||||
protected:
|
||||
|
||||
F32 mLifetime;
|
||||
|
||||
Point3F mInitialLinVel;
|
||||
|
||||
PhysicsDebrisData *mDataBlock;
|
||||
|
||||
TSShapeInstance *mShapeInstance;
|
||||
|
||||
PhysicsWorld *mWorld;
|
||||
|
||||
struct Fragment
|
||||
{
|
||||
Vector<U32> nodeIds;
|
||||
|
||||
PhysicsBody *body;
|
||||
|
||||
// The delta state.
|
||||
Point3F pos;
|
||||
Point3F lastPos;
|
||||
QuatF rot;
|
||||
QuatF lastRot;
|
||||
};
|
||||
|
||||
typedef Vector<Fragment> FragmentVector;
|
||||
|
||||
FragmentVector mFragments;
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif // _PHYSICS_DEBRIS_H_
|
||||
148
Engine/source/T3D/physics/physicsEvents.cpp
Normal file
148
Engine/source/T3D/physics/physicsEvents.cpp
Normal file
|
|
@ -0,0 +1,148 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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/physicsEvents.h"
|
||||
|
||||
#include "math/mathIO.h"
|
||||
#include "core/stream/bitStream.h"
|
||||
#include "T3D/physics/physicsPlugin.h"
|
||||
#include "T3D/physics/physicsWorld.h"
|
||||
#include "scene/sceneObject.h"
|
||||
#include "T3D/gameBase/gameConnection.h"
|
||||
#include "console/engineAPI.h"
|
||||
|
||||
|
||||
RadialImpulseEvent::RadialImpulseEvent()
|
||||
: mPosition( 0, 0, 0 ),
|
||||
mRadius( 0 ),
|
||||
mMagnitude( 0 )
|
||||
{
|
||||
}
|
||||
|
||||
RadialImpulseEvent::RadialImpulseEvent( const Point3F &pos, F32 radius, F32 magnitude )
|
||||
: mPosition( pos ),
|
||||
mRadius( radius ),
|
||||
mMagnitude( magnitude )
|
||||
{
|
||||
}
|
||||
|
||||
RadialImpulseEvent::~RadialImpulseEvent()
|
||||
{
|
||||
}
|
||||
|
||||
void RadialImpulseEvent::pack( NetConnection* /*ps*/, BitStream *bstream )
|
||||
{
|
||||
mathWrite( *bstream, mPosition );
|
||||
bstream->write( mRadius );
|
||||
bstream->write( mMagnitude );
|
||||
}
|
||||
|
||||
void RadialImpulseEvent::write( NetConnection*, BitStream *bstream )
|
||||
{
|
||||
mathWrite( *bstream, mPosition );
|
||||
bstream->write( mRadius );
|
||||
bstream->write( mMagnitude );
|
||||
}
|
||||
|
||||
void RadialImpulseEvent::unpack( NetConnection *ps, BitStream *bstream )
|
||||
{
|
||||
mathRead( *bstream, &mPosition );
|
||||
bstream->read( &mRadius );
|
||||
bstream->read( &mMagnitude );
|
||||
}
|
||||
|
||||
void RadialImpulseEvent::process(NetConnection *con)
|
||||
{
|
||||
impulse( &gClientContainer, mPosition, mRadius, mMagnitude );
|
||||
}
|
||||
|
||||
void RadialImpulseEvent::_impulseCallback( SceneObject *obj, void *key )
|
||||
{
|
||||
ImpulseInfo *info = (ImpulseInfo*)key;
|
||||
obj->applyRadialImpulse( info->pos, info->radius, info->magnitude );
|
||||
}
|
||||
|
||||
void RadialImpulseEvent::impulse( SceneContainer *con, const Point3F &position, F32 radius, F32 magnitude )
|
||||
{
|
||||
Point3F offset( radius, radius, radius );
|
||||
Box3F bounds( position - offset, position + offset );
|
||||
|
||||
ImpulseInfo info;
|
||||
info.pos = position;
|
||||
info.radius = radius;
|
||||
info.magnitude = magnitude;
|
||||
|
||||
con->findObjects( bounds, -1, _impulseCallback, &info );
|
||||
}
|
||||
|
||||
IMPLEMENT_CO_NETEVENT_V1( RadialImpulseEvent );
|
||||
|
||||
ConsoleDocClass( RadialImpulseEvent,
|
||||
"@brief Creates a physics-based impulse effect from a defined central point and magnitude.\n\n"
|
||||
"@see RadialImpulseEvent::send\n"
|
||||
"@ingroup Physics\n"
|
||||
);
|
||||
|
||||
|
||||
DefineEngineStaticMethod(RadialImpulseEvent, send, void, (const char* inPosition, F32 radius, F32 magnitude), ("1.0 1.0 1.0", 10.0f, 20.0f),
|
||||
"@brief Applies a radial impulse to any SceneObjects within the area of effect.\n\n"
|
||||
"This event is performed both server and client-side.\n\n"
|
||||
"@param position Center point for this radial impulse.\n"
|
||||
"@param radius Distance from the position for this radial impulse to affect.\n"
|
||||
"@param magnitude The force applied to objects within the radius from the position of this radial impulse effect.\n\n"
|
||||
"@tsexample\n"
|
||||
"// Define the Position\n"
|
||||
"%position = \"10.0 15.0 10.0\";\n\n"
|
||||
"// Define the Radius\n"
|
||||
"%radius = \"25.0\";\n\n"
|
||||
"// Define the Magnitude\n"
|
||||
"%magnitude = \"30.0\"\n\n"
|
||||
"// Create a globalRadialImpulse physics effect.\n"
|
||||
"RadialImpulseEvent::send(%position,%radius,%magnitude);\n"
|
||||
"@endtsexample\n\n")
|
||||
{
|
||||
// Scan out arguments...
|
||||
Point3F position;
|
||||
|
||||
dSscanf( inPosition, "%f %f %f", &position.x, &position.y, &position.z );
|
||||
|
||||
// Apply server-side.
|
||||
RadialImpulseEvent::impulse( &gServerContainer, position, radius, magnitude );
|
||||
|
||||
// Transmit event to each client to perform client-side...
|
||||
|
||||
SimGroup *pClientGroup = Sim::getClientGroup();
|
||||
if ( !pClientGroup )
|
||||
{
|
||||
Con::errorf( "globalRadialImpulse() - Client group not found!" );
|
||||
return;
|
||||
}
|
||||
|
||||
SimGroup::iterator itr = pClientGroup->begin();
|
||||
for ( ; itr != pClientGroup->end(); itr++ )
|
||||
{
|
||||
GameConnection* gc = static_cast<GameConnection*>(*itr);
|
||||
if ( gc )
|
||||
gc->postNetEvent( new RadialImpulseEvent( position, radius, magnitude ) );
|
||||
}
|
||||
}
|
||||
73
Engine/source/T3D/physics/physicsEvents.h
Normal file
73
Engine/source/T3D/physics/physicsEvents.h
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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 _PHYSICSEVENTS_H_
|
||||
#define _PHYSICSEVENTS_H_
|
||||
|
||||
#ifndef _NETCONNECTION_H_
|
||||
#include "sim/netConnection.h"
|
||||
#endif
|
||||
|
||||
class SceneObject;
|
||||
class SceneContainer;
|
||||
|
||||
|
||||
/// When this NetEvent is processed on the client-side it
|
||||
/// applies a radial impulse to objects in the physics
|
||||
/// simulation.
|
||||
class RadialImpulseEvent : public NetEvent
|
||||
{
|
||||
typedef NetEvent Parent;
|
||||
|
||||
protected:
|
||||
|
||||
struct ImpulseInfo
|
||||
{
|
||||
Point3F pos;
|
||||
F32 radius;
|
||||
F32 magnitude;
|
||||
};
|
||||
|
||||
Point3F mPosition;
|
||||
F32 mRadius;
|
||||
F32 mMagnitude;
|
||||
|
||||
static void _impulseCallback( SceneObject *obj, void *key );
|
||||
|
||||
public:
|
||||
|
||||
RadialImpulseEvent();
|
||||
RadialImpulseEvent( const Point3F &pos, F32 radius, F32 magnitude );
|
||||
~RadialImpulseEvent();
|
||||
|
||||
virtual void pack( NetConnection* /*ps*/, BitStream *bstream );
|
||||
virtual void write( NetConnection*, BitStream *bstream );
|
||||
virtual void unpack( NetConnection *ps, BitStream *bstream );
|
||||
virtual void process(NetConnection *);
|
||||
|
||||
static void impulse( SceneContainer *con, const Point3F &position, F32 radius, F32 magnitude );
|
||||
|
||||
DECLARE_CONOBJECT( RadialImpulseEvent );
|
||||
};
|
||||
|
||||
|
||||
#endif // _PHYSICSEVENTS_H_
|
||||
220
Engine/source/T3D/physics/physicsForce.cpp
Normal file
220
Engine/source/T3D/physics/physicsForce.cpp
Normal file
|
|
@ -0,0 +1,220 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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/physicsForce.h"
|
||||
|
||||
#include "T3D/physics/physicsPlugin.h"
|
||||
#include "T3D/physics/physicsWorld.h"
|
||||
#include "T3D/physics/physicsBody.h"
|
||||
#include "console/engineAPI.h"
|
||||
|
||||
|
||||
IMPLEMENT_CONOBJECT(PhysicsForce);
|
||||
|
||||
|
||||
ConsoleDocClass( PhysicsForce,
|
||||
"@brief Helper object for gameplay physical forces.\n\n"
|
||||
"%PhysicsForces can be created and \"attached\" to other @link PhysicsBody PhysicsBodies@endlink "
|
||||
"to attract them to the position of the PhysicsForce."
|
||||
"@ingroup Physics\n"
|
||||
);
|
||||
|
||||
|
||||
PhysicsForce::PhysicsForce()
|
||||
: mWorld( NULL ),
|
||||
mBody( NULL ),
|
||||
mPhysicsTick( false )
|
||||
{
|
||||
}
|
||||
|
||||
PhysicsForce::~PhysicsForce()
|
||||
{
|
||||
}
|
||||
|
||||
void PhysicsForce::initPersistFields()
|
||||
{
|
||||
Parent::initPersistFields();
|
||||
}
|
||||
|
||||
|
||||
bool PhysicsForce::onAdd()
|
||||
{
|
||||
if ( !Parent::onAdd() )
|
||||
return false;
|
||||
|
||||
// Find the physics world we're in.
|
||||
if ( PHYSICSMGR )
|
||||
mWorld = PHYSICSMGR->getWorld( isServerObject() ? "server" : "client" );
|
||||
|
||||
setProcessTick( true );
|
||||
getProcessList()->preTickSignal().notify( this, &PhysicsForce::_preTick );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void PhysicsForce::onRemove()
|
||||
{
|
||||
mWorld = NULL;
|
||||
mBody = NULL;
|
||||
getProcessList()->preTickSignal().remove( this, &PhysicsForce::_preTick );
|
||||
setProcessTick( false );
|
||||
|
||||
Parent::onRemove();
|
||||
}
|
||||
|
||||
void PhysicsForce::attach( const Point3F &start, const Point3F &direction, F32 maxDist )
|
||||
{
|
||||
detach();
|
||||
|
||||
// If there is no physics world then we cannot apply any forces.
|
||||
if ( !mWorld )
|
||||
return;
|
||||
|
||||
PhysicsBody *body = mWorld->castRay( start, start + ( direction * maxDist ), PhysicsWorld::BT_Dynamic );
|
||||
if ( !body )
|
||||
return;
|
||||
|
||||
mBody = body;
|
||||
}
|
||||
|
||||
void PhysicsForce::detach( const Point3F &force )
|
||||
{
|
||||
if ( mBody && !force.isZero() )
|
||||
{
|
||||
Point3F cMass = mBody->getCMassPosition();
|
||||
F32 mass = mBody->getMass();
|
||||
|
||||
Point3F impulse = ( mass * force ) / TickSec;
|
||||
mBody->applyImpulse( cMass, impulse );
|
||||
}
|
||||
|
||||
mBody = NULL;
|
||||
}
|
||||
|
||||
void PhysicsForce::onMount( SceneObject *obj, S32 node )
|
||||
{
|
||||
Parent::onMount( obj, node );
|
||||
|
||||
processAfter( obj );
|
||||
|
||||
MatrixF mat( true );
|
||||
mMount.object->getMountTransform( mMount.node, mMount.xfm, &mat );
|
||||
setTransform( mat );
|
||||
}
|
||||
|
||||
void PhysicsForce::onUnmount( SceneObject *obj, S32 node )
|
||||
{
|
||||
clearProcessAfter();
|
||||
Parent::onUnmount( obj, node );
|
||||
}
|
||||
|
||||
void PhysicsForce::_preTick()
|
||||
{
|
||||
// How Torque works we sometimes get double or more
|
||||
// ticks within a single simulation step. This occurs
|
||||
// for various reasons including odd timesteps and low
|
||||
// framerate.
|
||||
//
|
||||
// In order to keep performance from plumeting we do
|
||||
// not tick physics multiple times... instead it just
|
||||
// looses time.
|
||||
//
|
||||
// We set this variable below to let processTick know
|
||||
// that physics hasn't stepped yet and to skip processing.
|
||||
//
|
||||
// This doesn't completely solve the issue, but it does
|
||||
// make things much better.
|
||||
//
|
||||
mPhysicsTick = true;
|
||||
}
|
||||
|
||||
void PhysicsForce::processTick( const Move * )
|
||||
{
|
||||
if ( isMounted() )
|
||||
{
|
||||
MatrixF test( true );
|
||||
test.setPosition( Point3F( 0, 4, 0 ) );
|
||||
AssertFatal( test != mMount.xfm, "Error!" );
|
||||
|
||||
MatrixF mat( true );
|
||||
mMount.object->getMountTransform( mMount.node, mMount.xfm, &mat );
|
||||
setTransform( mat );
|
||||
}
|
||||
|
||||
// Nothing to do without a body or if physics hasn't ticked.
|
||||
if ( !mBody || !mPhysicsTick )
|
||||
return;
|
||||
|
||||
mPhysicsTick = false;
|
||||
|
||||
// If we lost the body then release it.
|
||||
if ( !mBody->isDynamic() || !mBody->isSimulationEnabled() )
|
||||
{
|
||||
detach();
|
||||
return;
|
||||
}
|
||||
|
||||
// Get our distance to the body.
|
||||
Point3F cMass = mBody->getCMassPosition();
|
||||
Point3F vector = getPosition() - cMass;
|
||||
|
||||
// Apply the force!
|
||||
F32 mass = mBody->getMass();
|
||||
Point3F impulse = ( mass * vector ) / TickSec;
|
||||
|
||||
// Counter balance the linear impulse.
|
||||
Point3F linVel = mBody->getLinVelocity();
|
||||
Point3F currentForce = linVel * mass;
|
||||
|
||||
// Apply it.
|
||||
mBody->applyImpulse( cMass, impulse - currentForce );
|
||||
}
|
||||
|
||||
DefineEngineMethod( PhysicsForce, attach, void, ( Point3F start, Point3F direction, F32 maxDist ),,
|
||||
"@brief Attempts to associate the PhysicsForce with a PhysicsBody.\n\n"
|
||||
"Performs a physics ray cast of the provided length and direction. The %PhysicsForce "
|
||||
"will attach itself to the first dynamic PhysicsBody the ray collides with. "
|
||||
"On every tick, the attached body will be attracted towards the position of the %PhysicsForce.\n\n"
|
||||
"A %PhysicsForce can only be attached to one body at a time.\n\n"
|
||||
"@note To determine if an %attach was successful, check isAttached() immediately after "
|
||||
"calling this function.n\n")
|
||||
{
|
||||
object->attach( start, direction, maxDist );
|
||||
}
|
||||
|
||||
DefineEngineMethod( PhysicsForce, detach, void, ( Point3F force ), ( Point3F::Zero ),
|
||||
"@brief Disassociates the PhysicsForce from any attached PhysicsBody.\n\n"
|
||||
"@param force Optional force to apply to the attached PhysicsBody "
|
||||
"before detaching.\n\n"
|
||||
"@note Has no effect if the %PhysicsForce is not attached to anything.\n\n")
|
||||
{
|
||||
object->detach( force );
|
||||
}
|
||||
|
||||
DefineEngineMethod( PhysicsForce, isAttached, bool, (),,
|
||||
"@brief Returns true if the %PhysicsForce is currently attached to an object.\n\n"
|
||||
"@see PhysicsForce::attach()")
|
||||
{
|
||||
return object->isAttached();
|
||||
}
|
||||
|
||||
91
Engine/source/T3D/physics/physicsForce.h
Normal file
91
Engine/source/T3D/physics/physicsForce.h
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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_PHYSICSFORCE_H_
|
||||
#define _T3D_PHYSICS_PHYSICSFORCE_H_
|
||||
|
||||
#ifndef _SCENEOBJECT_H_
|
||||
#include "scene/sceneObject.h"
|
||||
#endif
|
||||
#ifndef _T3D_PHYSICSCOMMON_H_
|
||||
#include "T3D/physics/physicsCommon.h"
|
||||
#endif
|
||||
#ifndef _T3D_PHYSICS_PHYSICSOBJECT_H_
|
||||
#include "T3D/physics/physicsObject.h"
|
||||
#endif
|
||||
|
||||
class PhysicsBody;
|
||||
class PhysicsWorld;
|
||||
|
||||
|
||||
/// A physics force controller used for gameplay effects.
|
||||
class PhysicsForce : public SceneObject
|
||||
{
|
||||
typedef SceneObject Parent;
|
||||
|
||||
public:
|
||||
|
||||
PhysicsForce();
|
||||
virtual ~PhysicsForce();
|
||||
|
||||
DECLARE_CONOBJECT( PhysicsForce );
|
||||
|
||||
// SimObject
|
||||
static void initPersistFields();
|
||||
bool onAdd();
|
||||
void onRemove();
|
||||
|
||||
// SceneObject
|
||||
void onMount( SceneObject *obj, S32 node );
|
||||
void onUnmount( SceneObject *obj, S32 node );
|
||||
|
||||
// ProcessObject
|
||||
void processTick( const Move *move );
|
||||
|
||||
///
|
||||
void attach( const Point3F &start, const Point3F &direction, F32 maxDist );
|
||||
|
||||
///
|
||||
void detach( const Point3F &force = Point3F::Zero );
|
||||
|
||||
///
|
||||
bool isAttached() const { return mBody != NULL; }
|
||||
|
||||
protected:
|
||||
|
||||
void _preTick();
|
||||
|
||||
///
|
||||
PhysicsWorld *mWorld;
|
||||
|
||||
F32 mForce;
|
||||
|
||||
///
|
||||
bool mPhysicsTick;
|
||||
|
||||
///
|
||||
WeakRefPtr<PhysicsBody> mBody;
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif // _T3D_PHYSICS_PHYSICSFORCE_H_
|
||||
52
Engine/source/T3D/physics/physicsObject.cpp
Normal file
52
Engine/source/T3D/physics/physicsObject.cpp
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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/physicsObject.h"
|
||||
|
||||
#include "console/simEvents.h"
|
||||
#include "console/simSet.h"
|
||||
|
||||
|
||||
PhysicsObject::PhysicsObject()
|
||||
: mQueuedEvent( InvalidEventId )
|
||||
{
|
||||
}
|
||||
|
||||
PhysicsObject::~PhysicsObject()
|
||||
{
|
||||
if ( mQueuedEvent != InvalidEventId )
|
||||
Sim::cancelEvent( mQueuedEvent );
|
||||
}
|
||||
|
||||
void PhysicsObject::queueCallback( U32 ms, Delegate<void()> callback )
|
||||
{
|
||||
// Cancel any existing event we may have pending.
|
||||
if ( mQueuedEvent != InvalidEventId )
|
||||
Sim::cancelEvent( mQueuedEvent );
|
||||
|
||||
// Fire off a new event.
|
||||
SimDelegateEvent *event_ = new SimDelegateEvent();
|
||||
event_->mCallback = callback;
|
||||
event_->mEventId = &mQueuedEvent;
|
||||
mQueuedEvent = Sim::postEvent( Sim::getRootGroup(), event_, Sim::getCurrentTime() + ms );
|
||||
}
|
||||
91
Engine/source/T3D/physics/physicsObject.h
Normal file
91
Engine/source/T3D/physics/physicsObject.h
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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_PHYSICSOBJECT_H_
|
||||
#define _T3D_PHYSICS_PHYSICSOBJECT_H_
|
||||
|
||||
#ifndef _PHYSICS_PHYSICSUSERDATA_H_
|
||||
#include "T3D/physics/physicsUserData.h"
|
||||
#endif
|
||||
#ifndef _UTIL_DELEGATE_H_
|
||||
#include "core/util/delegate.h"
|
||||
#endif
|
||||
#ifndef _REFBASE_H_
|
||||
#include "core/util/refBase.h"
|
||||
#endif
|
||||
|
||||
class PhysicsWorld;
|
||||
class MatrixF;
|
||||
class Point3F;
|
||||
class Box3F;
|
||||
|
||||
|
||||
///
|
||||
class PhysicsObject : public WeakRefBase
|
||||
{
|
||||
public:
|
||||
|
||||
virtual ~PhysicsObject();
|
||||
|
||||
/// Returns the physics world this object is a member of.
|
||||
virtual PhysicsWorld* getWorld() = 0;
|
||||
|
||||
/// Sets the transform on the physics object.
|
||||
///
|
||||
/// For static objects this is only intended to be used for
|
||||
/// for infrequent changes when editing the mission.
|
||||
///
|
||||
virtual void setTransform( const MatrixF &transform ) = 0;
|
||||
|
||||
/// Returns the transform of the physics body at
|
||||
/// the last processed simulation tick.
|
||||
virtual MatrixF& getTransform( MatrixF *outMatrix ) = 0;
|
||||
|
||||
/// Returns the world aligned bounding box containing the PhysicsObject.
|
||||
virtual Box3F getWorldBounds() = 0;
|
||||
|
||||
///
|
||||
void queueCallback( U32 ms, Delegate<void()> callback );
|
||||
|
||||
const PhysicsUserData& getUserData() const { return mUserData; }
|
||||
|
||||
PhysicsUserData& getUserData() { return mUserData; }
|
||||
|
||||
/// Set false to skip simulation of this object or temporarily remove
|
||||
/// it from the physics simulation. Implementation is PhysicsPlugin specific.
|
||||
virtual void setSimulationEnabled( bool enabled ) = 0;
|
||||
virtual bool isSimulationEnabled() = 0;
|
||||
|
||||
protected:
|
||||
|
||||
/// You shouldn't be creating this object directly.
|
||||
PhysicsObject();
|
||||
|
||||
/// The user data object assigned to this object.
|
||||
PhysicsUserData mUserData;
|
||||
|
||||
/// The last queued callback event.
|
||||
/// @see queueCallback
|
||||
U32 mQueuedEvent;
|
||||
};
|
||||
|
||||
#endif // _T3D_PHYSICS_PHYSICSOBJECT_H_
|
||||
25
Engine/source/T3D/physics/physicsPlayer.cpp
Normal file
25
Engine/source/T3D/physics/physicsPlayer.cpp
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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/physicsPlayer.h"
|
||||
|
||||
74
Engine/source/T3D/physics/physicsPlayer.h
Normal file
74
Engine/source/T3D/physics/physicsPlayer.h
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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_PHYSICSPLAYER_H_
|
||||
#define _T3D_PHYSICS_PHYSICSPLAYER_H_
|
||||
|
||||
#ifndef _T3D_PHYSICS_PHYSICSOBJECT_H_
|
||||
#include "T3D/physics/physicsObject.h"
|
||||
#endif
|
||||
#ifndef _MMATH_H_
|
||||
#include "math/mMath.h"
|
||||
#endif
|
||||
|
||||
class CollisionList;
|
||||
//struct ObjectRenderInst;
|
||||
//class BaseMatInstance;
|
||||
//class Player;
|
||||
//class SceneState;
|
||||
class SceneObject;
|
||||
|
||||
|
||||
///
|
||||
class PhysicsPlayer : public PhysicsObject
|
||||
{
|
||||
public:
|
||||
|
||||
PhysicsPlayer() {}
|
||||
|
||||
virtual ~PhysicsPlayer() {};
|
||||
|
||||
///
|
||||
virtual void init( const char *type,
|
||||
const Point3F &size,
|
||||
F32 runSurfaceCos,
|
||||
F32 stepHeight,
|
||||
SceneObject *obj,
|
||||
PhysicsWorld *world ) = 0;
|
||||
|
||||
virtual void findContact( SceneObject **contactObject,
|
||||
VectorF *contactNormal,
|
||||
Vector<SceneObject*> *outOverlapObjects ) const = 0;
|
||||
|
||||
virtual Point3F move( const VectorF &displacement, CollisionList &outCol ) = 0;
|
||||
|
||||
virtual bool testSpacials( const Point3F &nPos, const Point3F &nSize ) const = 0;
|
||||
|
||||
virtual void setSpacials( const Point3F &nPos, const Point3F &nSize ) = 0;
|
||||
|
||||
virtual void enableCollision() = 0;
|
||||
|
||||
virtual void disableCollision() = 0;
|
||||
};
|
||||
|
||||
|
||||
#endif // _T3D_PHYSICS_PHYSICSPLAYER_H_
|
||||
216
Engine/source/T3D/physics/physicsPlugin.cpp
Normal file
216
Engine/source/T3D/physics/physicsPlugin.cpp
Normal file
|
|
@ -0,0 +1,216 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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/physicsPlugin.h"
|
||||
|
||||
#include "console/console.h"
|
||||
#include "console/consoleTypes.h"
|
||||
#include "console/simSet.h"
|
||||
#include "core/strings/stringFunctions.h"
|
||||
#include "scene/sceneObject.h"
|
||||
#include "scene/sceneManager.h"
|
||||
#include "scene/sceneRenderState.h"
|
||||
#include "T3D/physics/physicsObject.h"
|
||||
#include "T3D/physics/physicsWorld.h"
|
||||
#include "core/util/tNamedFactory.h"
|
||||
|
||||
|
||||
PhysicsPlugin* PhysicsPlugin::smSingleton = NULL;
|
||||
PhysicsResetSignal PhysicsPlugin::smPhysicsResetSignal;
|
||||
bool PhysicsPlugin::smSinglePlayer = false;
|
||||
U32 PhysicsPlugin::smThreadCount = 2;
|
||||
|
||||
|
||||
String PhysicsPlugin::smServerWorldName( "server" );
|
||||
String PhysicsPlugin::smClientWorldName( "client" );
|
||||
|
||||
AFTER_MODULE_INIT( Sim )
|
||||
{
|
||||
Con::addVariable( "$Physics::isSinglePlayer", TypeBool, &PhysicsPlugin::smSinglePlayer,
|
||||
"@brief Informs the physics simulation if only a single player exists.\n\n"
|
||||
"If true, optimizations will be implemented to better cater to a single player environmnent.\n\n"
|
||||
"@ingroup Physics\n");
|
||||
Con::addVariable( "$pref::Physics::threadCount", TypeS32, &PhysicsPlugin::smThreadCount,
|
||||
"@brief Number of threads to use in a single pass of the physics engine.\n\n"
|
||||
"Defaults to 2 if not set.\n\n"
|
||||
"@ingroup Physics\n");
|
||||
}
|
||||
|
||||
bool PhysicsPlugin::activate( const char *library )
|
||||
{
|
||||
// Cleanup any previous plugin.
|
||||
if ( smSingleton )
|
||||
{
|
||||
smSingleton->destroyPlugin();
|
||||
AssertFatal( smSingleton == NULL,
|
||||
"PhysicsPlugin::activate - destroyPlugin didn't delete the plugin!" );
|
||||
}
|
||||
|
||||
// Create it thru the factory.
|
||||
PhysicsPlugin *plugin = NamedFactory<PhysicsPlugin>::create( library );
|
||||
if ( !plugin )
|
||||
{
|
||||
// One last try... try the first available one.
|
||||
plugin = NamedFactory<PhysicsPlugin>::create();
|
||||
if ( !plugin )
|
||||
return false;
|
||||
}
|
||||
|
||||
smSingleton = plugin;
|
||||
return true;
|
||||
}
|
||||
|
||||
PhysicsPlugin::PhysicsPlugin()
|
||||
{
|
||||
mPhysicsCleanup = new SimSet();
|
||||
mPhysicsCleanup->assignName( "PhysicsCleanupSet" );
|
||||
mPhysicsCleanup->registerObject();
|
||||
Sim::getRootGroup()->addObject( mPhysicsCleanup );
|
||||
}
|
||||
|
||||
PhysicsPlugin::~PhysicsPlugin()
|
||||
{
|
||||
AssertFatal( smSingleton == this, "PhysicsPlugin::~PhysicsPlugin() - Wrong active plugin!" );
|
||||
|
||||
if ( mPhysicsCleanup )
|
||||
mPhysicsCleanup->deleteObject();
|
||||
|
||||
smSingleton = NULL;
|
||||
}
|
||||
|
||||
void PhysicsPlugin::enableDebugDraw( bool enabled )
|
||||
{
|
||||
if ( enabled )
|
||||
SceneManager::getPostRenderSignal().notify( &PhysicsPlugin::_debugDraw );
|
||||
else
|
||||
SceneManager::getPostRenderSignal().remove( &PhysicsPlugin::_debugDraw );
|
||||
|
||||
_onDebugDrawEnabled( enabled );
|
||||
}
|
||||
|
||||
void PhysicsPlugin::_debugDraw( SceneManager *graph, const SceneRenderState *state )
|
||||
{
|
||||
// We only debug draw in the diffuse pass if we have a physics object.
|
||||
if ( !PHYSICSMGR || !state->isDiffusePass() )
|
||||
return;
|
||||
|
||||
// Render the server by default... else the client.
|
||||
PhysicsWorld *world = PHYSICSMGR->getWorld( smServerWorldName );
|
||||
if ( !world )
|
||||
world = PHYSICSMGR->getWorld( smClientWorldName );
|
||||
|
||||
if ( world )
|
||||
world->onDebugDraw( state );
|
||||
}
|
||||
|
||||
ConsoleFunction( physicsPluginPresent, bool, 1, 1, "physicsPluginPresent()\n"
|
||||
"@brief Returns true if a physics plugin exists and is initialized.\n\n"
|
||||
"@ingroup Physics" )
|
||||
{
|
||||
return PHYSICSMGR != NULL;
|
||||
}
|
||||
|
||||
ConsoleFunction( physicsInit, bool, 1, 2, "physicsInit( [string library] )" )
|
||||
{
|
||||
const char *library = "default";
|
||||
if ( argc > 1 )
|
||||
library = argv[1];
|
||||
|
||||
return PhysicsPlugin::activate( library );
|
||||
}
|
||||
|
||||
ConsoleFunction( physicsDestroy, void, 1, 1, "physicsDestroy()" )
|
||||
{
|
||||
if ( PHYSICSMGR )
|
||||
PHYSICSMGR->destroyPlugin();
|
||||
}
|
||||
|
||||
ConsoleFunction( physicsInitWorld, bool, 2, 2, "physicsInitWorld( String worldName )" )
|
||||
{
|
||||
return PHYSICSMGR && PHYSICSMGR->createWorld( String( argv[1] ) );
|
||||
}
|
||||
|
||||
ConsoleFunction( physicsDestroyWorld, void, 2, 2, "physicsDestroyWorld( String worldName )" )
|
||||
{
|
||||
if ( PHYSICSMGR )
|
||||
PHYSICSMGR->destroyWorld( String( argv[1] ) );
|
||||
}
|
||||
|
||||
|
||||
// Control/query of the stop/started state
|
||||
// of the currently running simulation.
|
||||
ConsoleFunction( physicsStartSimulation, void, 2, 2, "physicsStartSimulation( String worldName )" )
|
||||
{
|
||||
if ( PHYSICSMGR )
|
||||
PHYSICSMGR->enableSimulation( String( argv[1] ), true );
|
||||
}
|
||||
|
||||
ConsoleFunction( physicsStopSimulation, void, 2, 2, "physicsStopSimulation( String worldName )" )
|
||||
{
|
||||
if ( PHYSICSMGR )
|
||||
PHYSICSMGR->enableSimulation( String( argv[1] ), false );
|
||||
}
|
||||
|
||||
ConsoleFunction( physicsSimulationEnabled, bool, 1, 1, "physicsSimulationEnabled()" )
|
||||
{
|
||||
return PHYSICSMGR && PHYSICSMGR->isSimulationEnabled();
|
||||
}
|
||||
|
||||
// Used for slowing down time on the
|
||||
// physics simulation, and for pausing/restarting
|
||||
// the simulation.
|
||||
ConsoleFunction( physicsSetTimeScale, void, 2, 2, "physicsSetTimeScale( F32 scale )" )
|
||||
{
|
||||
if ( PHYSICSMGR )
|
||||
PHYSICSMGR->setTimeScale( dAtof( argv[1] ) );
|
||||
}
|
||||
|
||||
// Get the currently set time scale.
|
||||
ConsoleFunction( physicsGetTimeScale, F32, 1, 1, "physicsGetTimeScale()" )
|
||||
{
|
||||
return PHYSICSMGR && PHYSICSMGR->getTimeScale();
|
||||
}
|
||||
|
||||
// Used to send a signal to objects in the
|
||||
// physics simulation that they should store
|
||||
// their current state for later restoration,
|
||||
// such as when the editor is closed.
|
||||
ConsoleFunction( physicsStoreState, void, 1, 1, "physicsStoreState()" )
|
||||
{
|
||||
PhysicsPlugin::getPhysicsResetSignal().trigger( PhysicsResetEvent_Store );
|
||||
}
|
||||
|
||||
// Used to send a signal to objects in the
|
||||
// physics simulation that they should restore
|
||||
// their saved state, such as when the editor is opened.
|
||||
ConsoleFunction( physicsRestoreState, void, 1, 1, "physicsRestoreState()" )
|
||||
{
|
||||
if ( PHYSICSMGR )
|
||||
PHYSICSMGR->reset();
|
||||
}
|
||||
|
||||
ConsoleFunction( physicsDebugDraw, void, 2, 2, "physicsDebugDraw( bool enable )" )
|
||||
{
|
||||
if ( PHYSICSMGR )
|
||||
PHYSICSMGR->enableDebugDraw( dAtoi( argv[1] ) );
|
||||
}
|
||||
147
Engine/source/T3D/physics/physicsPlugin.h
Normal file
147
Engine/source/T3D/physics/physicsPlugin.h
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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_PHYSICSPLUGIN_H_
|
||||
#define _T3D_PHYSICS_PHYSICSPLUGIN_H_
|
||||
|
||||
#ifndef _SIMSET_H_
|
||||
#include "console/simSet.h"
|
||||
#endif
|
||||
#ifndef _TSIGNAL_H_
|
||||
#include "core/util/tSignal.h"
|
||||
#endif
|
||||
#ifndef _TORQUE_STRING_H_
|
||||
#include "core/util/str.h"
|
||||
#endif
|
||||
#ifndef _TDICTIONARY_H_
|
||||
#include "core/util/tDictionary.h"
|
||||
#endif
|
||||
#ifndef _UTIL_DELEGATE_H_
|
||||
#include "core/util/delegate.h"
|
||||
#endif
|
||||
#ifndef _T3D_PHYSICSCOMMON_H_
|
||||
#include "T3D/physics/physicsCommon.h"
|
||||
#endif
|
||||
|
||||
|
||||
class Player;
|
||||
class SceneRenderState;
|
||||
class SceneManager;
|
||||
class SceneObject;
|
||||
class PhysicsObject;
|
||||
class PhysicsBody;
|
||||
class PhysicsWorld;
|
||||
class PhysicsPlayer;
|
||||
class PhysicsCollision;
|
||||
|
||||
|
||||
typedef Delegate<PhysicsObject*( const SceneObject *)> CreatePhysicsObjectFn;
|
||||
typedef Map<StringNoCase, CreatePhysicsObjectFn> CreateFnMap;
|
||||
|
||||
|
||||
///
|
||||
class PhysicsPlugin
|
||||
{
|
||||
|
||||
protected:
|
||||
|
||||
/// The current active physics plugin.
|
||||
static PhysicsPlugin* smSingleton;
|
||||
|
||||
static PhysicsResetSignal smPhysicsResetSignal;
|
||||
|
||||
// Our map of Strings to PhysicsWorld pointers.
|
||||
Map<StringNoCase, PhysicsWorld*> mPhysicsWorldLookup;
|
||||
|
||||
static String smServerWorldName;
|
||||
static String smClientWorldName;
|
||||
|
||||
/// A SimSet of objects to delete before the
|
||||
/// physics reset/restore event occurs.
|
||||
SimObjectPtr<SimSet> mPhysicsCleanup;
|
||||
|
||||
/// Delegate method for debug drawing.
|
||||
static void _debugDraw( SceneManager *graph, const SceneRenderState *state );
|
||||
|
||||
public:
|
||||
|
||||
/// Note this should go away when we have "real" singleplayer.
|
||||
static bool smSinglePlayer;
|
||||
static bool isSinglePlayer() { return smSinglePlayer; }
|
||||
|
||||
/// Number of threads to use if supported by the plugin.
|
||||
static U32 smThreadCount;
|
||||
static U32 getThreadCount() { return smThreadCount; }
|
||||
|
||||
/// Returns the active physics plugin.
|
||||
/// @see PHYSICSPLUGIN
|
||||
static PhysicsPlugin* getSingleton() { return smSingleton; }
|
||||
|
||||
///
|
||||
static bool activate( const char *library );
|
||||
|
||||
PhysicsPlugin();
|
||||
virtual ~PhysicsPlugin();
|
||||
|
||||
/// Cleans up, deactivates, and deletes the plugin.
|
||||
virtual void destroyPlugin() = 0;
|
||||
|
||||
virtual void reset() = 0;
|
||||
|
||||
/// Returns the physics cleanup set.
|
||||
SimSet* getPhysicsCleanup() const { return mPhysicsCleanup; }
|
||||
|
||||
void enableDebugDraw( bool enabled );
|
||||
|
||||
virtual PhysicsCollision* createCollision() = 0;
|
||||
|
||||
virtual PhysicsBody* createBody() = 0;
|
||||
|
||||
virtual PhysicsPlayer* createPlayer() = 0;
|
||||
|
||||
virtual bool isSimulationEnabled() const = 0;
|
||||
virtual void enableSimulation( const String &worldName, bool enable ) = 0;
|
||||
|
||||
virtual void setTimeScale( const F32 timeScale ) = 0;
|
||||
virtual const F32 getTimeScale() const = 0;
|
||||
|
||||
static PhysicsResetSignal& getPhysicsResetSignal() { return smPhysicsResetSignal; }
|
||||
|
||||
virtual bool createWorld( const String &worldName ) = 0;
|
||||
virtual void destroyWorld( const String &worldName ) = 0;
|
||||
|
||||
virtual PhysicsWorld* getWorld( const String &worldName ) const = 0;
|
||||
|
||||
protected:
|
||||
|
||||
/// Overload this to toggle any physics engine specific stuff
|
||||
/// when debug rendering is enabled or disabled.
|
||||
virtual void _onDebugDrawEnabled( bool enabled ) {}
|
||||
|
||||
};
|
||||
|
||||
/// Helper macro for accessing the physics plugin. It will
|
||||
/// return NULL if no plugin is initialized.
|
||||
/// @see PhysicsPlugin
|
||||
#define PHYSICSMGR PhysicsPlugin::getSingleton()
|
||||
|
||||
#endif // _T3D_PHYSICS_PHYSICSPLUGIN_H_
|
||||
1172
Engine/source/T3D/physics/physicsShape.cpp
Normal file
1172
Engine/source/T3D/physics/physicsShape.cpp
Normal file
File diff suppressed because it is too large
Load diff
269
Engine/source/T3D/physics/physicsShape.h
Normal file
269
Engine/source/T3D/physics/physicsShape.h
Normal file
|
|
@ -0,0 +1,269 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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 _PHYSICSSHAPE_H_
|
||||
#define _PHYSICSSHAPE_H_
|
||||
|
||||
#ifndef _GAMEBASE_H_
|
||||
#include "T3D/gameBase/gameBase.h"
|
||||
#endif
|
||||
#ifndef __RESOURCE_H__
|
||||
#include "core/resource.h"
|
||||
#endif
|
||||
#ifndef _TSSHAPE_H_
|
||||
#include "ts/tsShape.h"
|
||||
#endif
|
||||
#ifndef _T3D_PHYSICSCOMMON_H_
|
||||
#include "T3D/physics/physicsCommon.h"
|
||||
#endif
|
||||
#ifndef _DYNAMIC_CONSOLETYPES_H_
|
||||
#include "console/dynamicTypes.h"
|
||||
#endif
|
||||
#ifndef _SIMOBJECTREF_H_
|
||||
#include "console/simObjectRef.h"
|
||||
#endif
|
||||
|
||||
class TSShapeInstance;
|
||||
class PhysicsBody;
|
||||
class PhysicsWorld;
|
||||
class PhysicsDebrisData;
|
||||
class ExplosionData;
|
||||
|
||||
|
||||
class PhysicsShapeData : public GameBaseData
|
||||
{
|
||||
typedef GameBaseData Parent;
|
||||
|
||||
void _onResourceChanged( const Torque::Path &path );
|
||||
|
||||
public:
|
||||
|
||||
PhysicsShapeData();
|
||||
virtual ~PhysicsShapeData();
|
||||
|
||||
DECLARE_CONOBJECT(PhysicsShapeData);
|
||||
static void initPersistFields();
|
||||
bool onAdd();
|
||||
void onRemove();
|
||||
|
||||
// GameBaseData
|
||||
void packData(BitStream* stream);
|
||||
void unpackData(BitStream* stream);
|
||||
bool preload(bool server, String &errorBuffer );
|
||||
|
||||
public:
|
||||
|
||||
/// The shape to load.
|
||||
StringTableEntry shapeName;
|
||||
|
||||
/// The shape resource.
|
||||
Resource<TSShape> shape;
|
||||
|
||||
/// The shared unscaled collision shape.
|
||||
PhysicsCollisionRef colShape;
|
||||
|
||||
///
|
||||
F32 mass;
|
||||
|
||||
///
|
||||
F32 dynamicFriction;
|
||||
|
||||
///
|
||||
F32 staticFriction;
|
||||
|
||||
///
|
||||
F32 restitution;
|
||||
|
||||
///
|
||||
F32 linearDamping;
|
||||
|
||||
///
|
||||
F32 angularDamping;
|
||||
|
||||
///
|
||||
F32 linearSleepThreshold;
|
||||
|
||||
///
|
||||
F32 angularSleepThreshold;
|
||||
|
||||
// A scale applied to the normal linear and angular damping
|
||||
// when the object enters a water volume.
|
||||
F32 waterDampingScale;
|
||||
|
||||
// The density of this object used for water buoyancy effects.
|
||||
F32 buoyancyDensity;
|
||||
|
||||
|
||||
enum SimType
|
||||
{
|
||||
/// This physics representation only exists on the client
|
||||
/// world and the server only does ghosting.
|
||||
SimType_ClientOnly,
|
||||
|
||||
/// The physics representation only exists on the server world
|
||||
/// and the client gets delta updates for rendering.
|
||||
SimType_ServerOnly,
|
||||
|
||||
/// The physics representation exists on the client and the server
|
||||
/// worlds with corrections occuring when the client gets out of sync.
|
||||
SimType_ClientServer,
|
||||
|
||||
/// The bits used to pack the SimType field.
|
||||
SimType_Bits = 3,
|
||||
|
||||
} simType;
|
||||
|
||||
SimObjectRef< PhysicsDebrisData > debris;
|
||||
SimObjectRef< ExplosionData > explosion;
|
||||
SimObjectRef< PhysicsShapeData > destroyedShape;
|
||||
};
|
||||
|
||||
typedef PhysicsShapeData::SimType PhysicsSimType;
|
||||
DefineEnumType( PhysicsSimType );
|
||||
|
||||
class TSThread;
|
||||
|
||||
|
||||
/// A simple single body dynamic physics object.
|
||||
class PhysicsShape : public GameBase
|
||||
{
|
||||
typedef GameBase Parent;
|
||||
|
||||
protected:
|
||||
|
||||
/// The abstracted physics actor.
|
||||
PhysicsBody *mPhysicsRep;
|
||||
|
||||
///
|
||||
PhysicsWorld *mWorld;
|
||||
|
||||
/// The starting position to place the shape when
|
||||
/// the level begins or is reset.
|
||||
MatrixF mResetPos;
|
||||
|
||||
//VectorF mBuildScale;
|
||||
//F32 mBuildAngDrag;
|
||||
//F32 mBuildLinDrag;
|
||||
|
||||
/// The rendered shape.
|
||||
TSShapeInstance *mShapeInst;
|
||||
|
||||
/// The current physics state.
|
||||
PhysicsState mState;
|
||||
|
||||
/// The previous and current render states.
|
||||
PhysicsState mRenderState[2];
|
||||
|
||||
/// True if the PhysicsShape has been destroyed ( gameplay ).
|
||||
bool mDestroyed;
|
||||
|
||||
/// Enables automatic playing of the animation named "ambient" (if it exists)
|
||||
/// when the PhysicsShape is loaded.
|
||||
bool mPlayAmbient;
|
||||
S32 mAmbientSeq;
|
||||
TSThread* mAmbientThread;
|
||||
|
||||
/// If a specified to create one in the PhysicsShape data, this is the
|
||||
/// subshape created when this PhysicsShape is destroyed.
|
||||
/// Is only assigned (non null) on the serverside PhysicsShape.
|
||||
SimObjectPtr< PhysicsShape > mDestroyedShape;
|
||||
|
||||
///
|
||||
enum MaskBits
|
||||
{
|
||||
StateMask = Parent::NextFreeMask << 0,
|
||||
ResetPosMask = Parent::NextFreeMask << 1,
|
||||
DamageMask = Parent::NextFreeMask << 2,
|
||||
|
||||
NextFreeMask = Parent::NextFreeMask << 3
|
||||
};
|
||||
|
||||
bool _createShape();
|
||||
|
||||
void _initAmbient();
|
||||
|
||||
///
|
||||
void _applyCorrection( const MatrixF &mat );
|
||||
|
||||
void _onPhysicsReset( PhysicsResetEvent reset );
|
||||
|
||||
void _updateContainerForces();
|
||||
|
||||
/// If true then no corrections are sent from the server
|
||||
/// and/or applied from the client.
|
||||
///
|
||||
/// This is only ment for debugging.
|
||||
///
|
||||
static bool smNoCorrections;
|
||||
|
||||
/// If true then no smoothing is done on the client when
|
||||
/// applying server corrections.
|
||||
///
|
||||
/// This is only ment for debugging.
|
||||
///
|
||||
static bool smNoSmoothing;
|
||||
|
||||
public:
|
||||
|
||||
PhysicsShape();
|
||||
virtual ~PhysicsShape();
|
||||
|
||||
DECLARE_CONOBJECT( PhysicsShape );
|
||||
|
||||
/// Returns the PhysicsShapeData datablock.
|
||||
PhysicsShapeData* getDataBlock() { return static_cast<PhysicsShapeData*>( Parent::getDataBlock() ); }
|
||||
|
||||
// SimObject
|
||||
static void consoleInit();
|
||||
static void initPersistFields();
|
||||
void inspectPostApply();
|
||||
bool onAdd();
|
||||
void onRemove();
|
||||
|
||||
// SceneObject
|
||||
void prepRenderImage( SceneRenderState *state );
|
||||
void setTransform( const MatrixF &mat );
|
||||
F32 getMass() const;
|
||||
Point3F getVelocity() const { return mState.linVelocity; }
|
||||
void applyImpulse( const Point3F &pos, const VectorF &vec );
|
||||
void applyRadialImpulse( const Point3F &origin, F32 radius, F32 magnitude );
|
||||
void setScale(const VectorF & scale);
|
||||
|
||||
// GameBase
|
||||
bool onNewDataBlock( GameBaseData *dptr, bool reload );
|
||||
void interpolateTick( F32 delta );
|
||||
void processTick( const Move *move );
|
||||
void advanceTime( F32 timeDelta );
|
||||
U32 packUpdate( NetConnection *conn, U32 mask, BitStream *stream );
|
||||
void unpackUpdate( NetConnection *conn, BitStream *stream );
|
||||
|
||||
bool isDestroyed() const { return mDestroyed; }
|
||||
void destroy();
|
||||
void restore();
|
||||
|
||||
/// Save the current transform as where we return to when a physics reset
|
||||
/// event occurs. This is automatically set in onAdd but some manipulators
|
||||
/// such as Prefab need to make use of this.
|
||||
void storeRestorePos();
|
||||
};
|
||||
|
||||
#endif // _PHYSICSSHAPE_H_
|
||||
29
Engine/source/T3D/physics/physicsUserData.cpp
Normal file
29
Engine/source/T3D/physics/physicsUserData.cpp
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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/physicsUserData.h"
|
||||
|
||||
|
||||
#ifdef TORQUE_DEBUG
|
||||
const char* PhysicsUserData::smTypeName = "PhysicsUserData";
|
||||
#endif
|
||||
120
Engine/source/T3D/physics/physicsUserData.h
Normal file
120
Engine/source/T3D/physics/physicsUserData.h
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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 _PHYSICS_PHYSICSUSERDATA_H_
|
||||
#define _PHYSICS_PHYSICSUSERDATA_H_
|
||||
|
||||
#ifndef _SIGNAL_H_
|
||||
#include "core/util/tSignal.h"
|
||||
#endif
|
||||
|
||||
class PhysicsUserData;
|
||||
class SceneObject;
|
||||
class Point3F;
|
||||
class PhysicsBody;
|
||||
|
||||
|
||||
/// Signal used for contact reports.
|
||||
///
|
||||
/// @param us The physics user data for the signaling object.
|
||||
/// @param them The other physics user data involved in the contact.
|
||||
/// @param hitPoint The approximate position of the impact.
|
||||
/// @param hitForce
|
||||
///
|
||||
/// @see PhysicsUserData
|
||||
///
|
||||
typedef Signal<void( PhysicsUserData *us,
|
||||
PhysicsUserData *them,
|
||||
const Point3F &hitPoint,
|
||||
const Point3F &hitForce )> PhysicsContactSignal;
|
||||
|
||||
|
||||
/// The base class for physics user data.
|
||||
class PhysicsUserData
|
||||
{
|
||||
public:
|
||||
|
||||
/// The constructor.
|
||||
PhysicsUserData()
|
||||
: mObject( NULL ),
|
||||
mBody( NULL )
|
||||
#ifdef TORQUE_DEBUG
|
||||
, mTypeId( smTypeName )
|
||||
#endif
|
||||
{}
|
||||
|
||||
/// The destructor.
|
||||
virtual ~PhysicsUserData() {}
|
||||
|
||||
///
|
||||
void setObject( SceneObject *object ) { mObject = object; }
|
||||
SceneObject* getObject() const { return mObject; }
|
||||
|
||||
void setBody( PhysicsBody *body ) { mBody = body; }
|
||||
PhysicsBody* getBody() const { return mBody; }
|
||||
|
||||
/// Helper method for casting a void pointer to a userdata pointer.
|
||||
static inline SceneObject* getObject( void *data )
|
||||
{
|
||||
PhysicsUserData *result = cast( data );
|
||||
return result ? result->getObject() : NULL;
|
||||
}
|
||||
|
||||
PhysicsContactSignal& getContactSignal() { return mContactSignal; }
|
||||
|
||||
/// Helper method for casting a void pointer to a userdata pointer.
|
||||
static inline PhysicsUserData* cast( void *data )
|
||||
{
|
||||
PhysicsUserData *result = (PhysicsUserData*)data;
|
||||
|
||||
// If the typeid doesn't equal the value we assigned to it at
|
||||
// construction then this isn't a PhysicsUserData object.
|
||||
#ifdef TORQUE_DEBUG
|
||||
AssertFatal( !result || result->mTypeId == smTypeName,
|
||||
"PhysicsUserData::cast - The pointer is the wrong type!" );
|
||||
#endif
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
#ifdef TORQUE_DEBUG
|
||||
|
||||
/// The type string used to validate the void* cast.
|
||||
/// @see cast
|
||||
static const char *smTypeName;
|
||||
|
||||
/// The type string assigned at construction used to
|
||||
/// validate the void* cast.
|
||||
/// @see cast
|
||||
const char *mTypeId;
|
||||
#endif
|
||||
|
||||
PhysicsContactSignal mContactSignal;
|
||||
|
||||
SceneObject *mObject;
|
||||
|
||||
PhysicsBody *mBody;
|
||||
};
|
||||
|
||||
#endif // _PHYSICS_PHYSICSUSERDATA_H_
|
||||
30
Engine/source/T3D/physics/physicsWorld.cpp
Normal file
30
Engine/source/T3D/physics/physicsWorld.cpp
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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/physicsWorld.h"
|
||||
|
||||
|
||||
PhysicsWorld::PhysicsWorld()
|
||||
: mGravity( 0, 0, -20.0f ) // NOTE: This matches the gravity used for player objects.
|
||||
{
|
||||
}
|
||||
112
Engine/source/T3D/physics/physicsWorld.h
Normal file
112
Engine/source/T3D/physics/physicsWorld.h
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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_PHYSICSWORLD_H_
|
||||
#define _T3D_PHYSICS_PHYSICSWORLD_H_
|
||||
|
||||
#ifndef _SIGNAL_H_
|
||||
#include "core/util/tSignal.h"
|
||||
#endif
|
||||
#ifndef _MPOINT3_H_
|
||||
#include "math/mPoint3.h"
|
||||
#endif
|
||||
|
||||
class ProcessList;
|
||||
class Point3F;
|
||||
struct RayInfo;
|
||||
class SceneRenderState;
|
||||
class PhysicsBody;
|
||||
|
||||
|
||||
|
||||
class PhysicsWorld
|
||||
{
|
||||
protected:
|
||||
|
||||
Signal<void()> mUpdateSignal;
|
||||
|
||||
/// The current gravity force.
|
||||
Point3F mGravity;
|
||||
|
||||
public:
|
||||
|
||||
/// The constructor.
|
||||
PhysicsWorld();
|
||||
|
||||
/// The destructor.
|
||||
virtual ~PhysicsWorld() {};
|
||||
|
||||
///
|
||||
Signal<void()>& getUpdateSignal() { return mUpdateSignal; }
|
||||
|
||||
/// Overloaded to do debug drawing.
|
||||
///
|
||||
/// It is assumed the GFX state is setup prior to this call for
|
||||
/// rendering in world space.
|
||||
///
|
||||
virtual void onDebugDraw( const SceneRenderState *state ) = 0;
|
||||
|
||||
/// Prepare the physics world for use.
|
||||
virtual bool initWorld( bool isServer, ProcessList *processList ) = 0;
|
||||
|
||||
/// Tears down the physics world destroying any existing
|
||||
/// bodies, joints, and controllers.
|
||||
virtual void destroyWorld() = 0;
|
||||
|
||||
///
|
||||
virtual void reset() = 0;
|
||||
|
||||
/// Returns true if the physics world is active and simulating.
|
||||
virtual bool isEnabled() const = 0;
|
||||
|
||||
/// Returns the active gravity force.
|
||||
const Point3F& getGravity() const { return mGravity; }
|
||||
|
||||
/// An abstract way to raycast into any type of PhysicsWorld, in a way
|
||||
/// that mirrors a Torque-style raycast.
|
||||
//
|
||||
/// This method is not fully developed or very sophisticated. For example,
|
||||
/// there is no system of collision groups or raycast masks, which could
|
||||
/// be very complex to write in a PhysicsPlugin-Abstract way...
|
||||
//
|
||||
// Optional forceAmt parameter will also apply a force to hit objects.
|
||||
virtual bool castRay( const Point3F &startPnt, const Point3F &endPnt, RayInfo *ri, const Point3F &impulse ) = 0;
|
||||
|
||||
|
||||
///
|
||||
enum BodyType
|
||||
{
|
||||
BT_Static = BIT( 0 ),
|
||||
BT_Dynamic = BIT( 1 ),
|
||||
BT_Player = BIT( 2 ),
|
||||
|
||||
BT_All = BT_Static | BT_Dynamic | BT_Player
|
||||
};
|
||||
|
||||
///
|
||||
virtual PhysicsBody* castRay( const Point3F &start, const Point3F &end, U32 bodyTypes = BT_All ) = 0;
|
||||
|
||||
virtual void explosion( const Point3F &pos, F32 radius, F32 forceMagnitude ) = 0;
|
||||
};
|
||||
|
||||
|
||||
#endif // _T3D_PHYSICS_PHYSICSWORLD_H_
|
||||
80
Engine/source/T3D/physics/physx/px.h
Normal file
80
Engine/source/T3D/physics/physx/px.h
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
//
|
||||
// This PhysX implementation for Torque was originally based on
|
||||
// the "PhysX in TGEA" resource written by Shannon Scarvaci.
|
||||
//
|
||||
// http://www.garagegames.com/index.php?sec=mg&mod=resource&page=view&qid=12711
|
||||
//
|
||||
|
||||
#ifndef _PHYSX_H_
|
||||
#define _PHYSX_H_
|
||||
|
||||
/*
|
||||
#ifndef _TORQUE_TYPES_H_
|
||||
# include "platform/types.h"
|
||||
#endif
|
||||
*/
|
||||
|
||||
#include "platform/tmm_off.h"
|
||||
|
||||
#ifdef TORQUE_DEBUG
|
||||
#include <crtdbg.h>
|
||||
#endif
|
||||
|
||||
#if defined(TORQUE_OS_MAC) && !defined(__APPLE__)
|
||||
#define __APPLE__
|
||||
#elif defined(TORQUE_OS_LINUX) && !defined(LINUX)
|
||||
#define LINUX
|
||||
#elif defined(TORQUE_OS_WIN32) && !defined(WIN32)
|
||||
#define WIN32
|
||||
#endif
|
||||
|
||||
#ifndef NX_PHYSICS_NXPHYSICS
|
||||
#include <NxPhysics.h>
|
||||
#endif
|
||||
#ifndef NX_FOUNDATION_NXSTREAM
|
||||
#include <NxStream.h>
|
||||
#endif
|
||||
#ifndef NX_COOKING_H
|
||||
#include <NxCooking.h>
|
||||
#endif
|
||||
#ifndef NX_FOUNDATION_NXUSEROUTPUTSTREAM
|
||||
#include <NxUserOutputStream.h>
|
||||
#endif
|
||||
#ifndef NX_PHYSICS_NXBIG
|
||||
#include "NxExtended.h"
|
||||
#endif
|
||||
#include <NxUserAllocatorDefault.h>
|
||||
#include <CCTAllocator.h>
|
||||
#include <NxControllerManager.h>
|
||||
#include <CharacterControllerManager.h>
|
||||
#include <NxController.h>
|
||||
#include <NxCapsuleController.h>
|
||||
|
||||
/// The single global physx sdk object for this process.
|
||||
extern NxPhysicsSDK *gPhysicsSDK;
|
||||
|
||||
#include "platform/tmm_on.h"
|
||||
|
||||
#endif // _PHYSX_H_
|
||||
404
Engine/source/T3D/physics/physx/pxBody.cpp
Normal file
404
Engine/source/T3D/physics/physx/pxBody.cpp
Normal file
|
|
@ -0,0 +1,404 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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/physX/pxBody.h"
|
||||
|
||||
#include "T3D/physics/physX/px.h"
|
||||
#include "T3D/physics/physX/pxCasts.h"
|
||||
#include "T3D/physics/physX/pxWorld.h"
|
||||
#include "T3D/physics/physX/pxCollision.h"
|
||||
|
||||
|
||||
PxBody::PxBody() :
|
||||
mActor( NULL ),
|
||||
mMaterial( NULL ),
|
||||
mWorld( NULL ),
|
||||
mBodyFlags( 0 ),
|
||||
mIsEnabled( true )
|
||||
{
|
||||
}
|
||||
|
||||
PxBody::~PxBody()
|
||||
{
|
||||
_releaseActor();
|
||||
}
|
||||
|
||||
void PxBody::_releaseActor()
|
||||
{
|
||||
if ( !mActor )
|
||||
return;
|
||||
|
||||
// This sucks, but it has to happen if we want
|
||||
// to avoid write lock errors from PhysX right now.
|
||||
mWorld->releaseWriteLock();
|
||||
|
||||
mActor->userData = NULL;
|
||||
|
||||
mWorld->releaseActor( *mActor );
|
||||
mActor = NULL;
|
||||
mBodyFlags = 0;
|
||||
|
||||
if ( mMaterial )
|
||||
{
|
||||
mWorld->releaseMaterial( *mMaterial );
|
||||
mMaterial = NULL;
|
||||
}
|
||||
|
||||
mColShape = NULL;
|
||||
}
|
||||
|
||||
bool PxBody::init( PhysicsCollision *shape,
|
||||
F32 mass,
|
||||
U32 bodyFlags,
|
||||
SceneObject *obj,
|
||||
PhysicsWorld *world )
|
||||
{
|
||||
AssertFatal( obj, "PxBody::init - Got a null scene object!" );
|
||||
AssertFatal( world, "PxBody::init - Got a null world!" );
|
||||
AssertFatal( dynamic_cast<PxWorld*>( world ), "PxBody::init - The world is the wrong type!" );
|
||||
AssertFatal( shape, "PxBody::init - Got a null collision shape!" );
|
||||
AssertFatal( dynamic_cast<PxCollision*>( shape ), "PxBody::init - The collision shape is the wrong type!" );
|
||||
AssertFatal( !((PxCollision*)shape)->getShapes().empty(), "PxBody::init - Got empty collision shape!" );
|
||||
|
||||
// Cleanup any previous actor.
|
||||
_releaseActor();
|
||||
|
||||
mWorld = (PxWorld*)world;
|
||||
mColShape = (PxCollision*)shape;
|
||||
mBodyFlags = bodyFlags;
|
||||
|
||||
NxActorDesc actorDesc;
|
||||
NxBodyDesc bodyDesc;
|
||||
|
||||
const bool isKinematic = mBodyFlags & BF_KINEMATIC;
|
||||
const bool isTrigger = mBodyFlags & BF_TRIGGER;
|
||||
const bool isDebris = mBodyFlags & BF_DEBRIS;
|
||||
|
||||
if ( isKinematic )
|
||||
{
|
||||
// Kinematics are dynamics... so they need
|
||||
// a body description.
|
||||
actorDesc.body = &bodyDesc;
|
||||
bodyDesc.mass = getMax( mass, 1.0f );
|
||||
bodyDesc.flags |= NX_BF_KINEMATIC;
|
||||
}
|
||||
else if ( mass > 0.0f )
|
||||
{
|
||||
// We have mass so its a dynamic.
|
||||
actorDesc.body = &bodyDesc;
|
||||
bodyDesc.mass = mass;
|
||||
}
|
||||
|
||||
if ( isTrigger )
|
||||
actorDesc.flags |= NX_AF_DISABLE_RESPONSE;
|
||||
|
||||
// Add all the shapes.
|
||||
const Vector<NxShapeDesc*> &shapes = mColShape->getShapes();
|
||||
for ( U32 i=0; i < shapes.size(); i++ )
|
||||
{
|
||||
NxShapeDesc *desc = shapes[i];
|
||||
|
||||
// If this hits then something is broken with
|
||||
// this descrption... check all the fields to be
|
||||
// sure their values are correctly filled out.
|
||||
AssertFatal( desc->isValid(), "PxBody::init - Got invalid shape description!" );
|
||||
|
||||
if ( isTrigger )
|
||||
desc->group = 31;
|
||||
|
||||
if ( isDebris )
|
||||
desc->group = 30;
|
||||
|
||||
actorDesc.shapes.push_back( desc );
|
||||
}
|
||||
|
||||
// This sucks, but it has to happen if we want
|
||||
// to avoid write lock errors from PhysX right now.
|
||||
mWorld->releaseWriteLock();
|
||||
|
||||
mActor = mWorld->getScene()->createActor( actorDesc );
|
||||
mIsEnabled = true;
|
||||
|
||||
if ( isDebris )
|
||||
mActor->setDominanceGroup( 31 );
|
||||
|
||||
mUserData.setObject( obj );
|
||||
mUserData.setBody( this );
|
||||
mActor->userData = &mUserData;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void PxBody::setMaterial( F32 restitution,
|
||||
F32 friction,
|
||||
F32 staticFriction )
|
||||
{
|
||||
AssertFatal( mActor, "PxBody::setMaterial - The actor is null!" );
|
||||
|
||||
// If the body is dynamic then wake it up as
|
||||
// it may need to change behavior.
|
||||
if ( isDynamic() )
|
||||
mActor->wakeUp();
|
||||
|
||||
NxMaterialDesc desc;
|
||||
desc.restitution = restitution;
|
||||
desc.dynamicFriction = friction;
|
||||
desc.staticFriction = staticFriction;
|
||||
|
||||
// If we have a material then just update it as the shapes
|
||||
// should already have them mapped.
|
||||
if ( mMaterial )
|
||||
{
|
||||
mMaterial->loadFromDesc( desc );
|
||||
return;
|
||||
}
|
||||
|
||||
// If we got here then create a new material and
|
||||
// assign it to all our shapes.
|
||||
mMaterial = mWorld->createMaterial( desc );
|
||||
U32 matIndex = mMaterial->getMaterialIndex();
|
||||
U32 count = mActor->getNbShapes();
|
||||
NxShape*const* shapes = mActor->getShapes();
|
||||
for ( U32 i=0; i < count; i++ )
|
||||
shapes[i]->setMaterial( matIndex );
|
||||
}
|
||||
|
||||
void PxBody::setSleepThreshold( F32 linear, F32 angular )
|
||||
{
|
||||
AssertFatal( mActor, "PxBody::setSleepThreshold - The actor is null!" );
|
||||
|
||||
mActor->setSleepLinearVelocity( linear );
|
||||
mActor->setSleepAngularVelocity( angular );
|
||||
}
|
||||
|
||||
void PxBody::setDamping( F32 linear, F32 angular )
|
||||
{
|
||||
AssertFatal( mActor, "PxBody::setDamping - The actor is null!" );
|
||||
mActor->setLinearDamping( linear );
|
||||
mActor->setAngularDamping( angular );
|
||||
}
|
||||
|
||||
void PxBody::getState( PhysicsState *outState )
|
||||
{
|
||||
AssertFatal( mActor, "PxBody::getState - The actor is null!" );
|
||||
AssertFatal( isDynamic(), "PxBody::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.
|
||||
|
||||
outState->position = pxCast<Point3F>( mActor->getGlobalPosition() );
|
||||
outState->orientation = pxCast<QuatF>( mActor->getGlobalOrientationQuat() );
|
||||
outState->linVelocity = pxCast<Point3F>( mActor->getLinearVelocity() );
|
||||
outState->angVelocity = pxCast<Point3F>( mActor->getAngularVelocity() );
|
||||
outState->sleeping = mActor->isSleeping();
|
||||
outState->momentum = pxCast<Point3F>( mActor->getLinearMomentum() );
|
||||
}
|
||||
|
||||
F32 PxBody::getMass() const
|
||||
{
|
||||
AssertFatal( mActor, "PxBody::getCMassPosition - The actor is null!" );
|
||||
return mActor->getMass();
|
||||
}
|
||||
|
||||
Point3F PxBody::getCMassPosition() const
|
||||
{
|
||||
AssertFatal( mActor, "PxBody::getCMassPosition - The actor is null!" );
|
||||
return pxCast<Point3F>( mActor->getCMassGlobalPosition() );
|
||||
}
|
||||
|
||||
void PxBody::setLinVelocity( const Point3F &vel )
|
||||
{
|
||||
AssertFatal( mActor, "PxBody::setLinVelocity - The actor is null!" );
|
||||
AssertFatal( isDynamic(), "PxBody::setLinVelocity - This call is only for dynamics!" );
|
||||
|
||||
mActor->setLinearVelocity( pxCast<NxVec3>( vel ) );
|
||||
}
|
||||
|
||||
void PxBody::setAngVelocity( const Point3F &vel )
|
||||
{
|
||||
AssertFatal( mActor, "PxBody::setAngVelocity - The actor is null!" );
|
||||
AssertFatal( isDynamic(), "PxBody::setAngVelocity - This call is only for dynamics!" );
|
||||
|
||||
mActor->setAngularVelocity( pxCast<NxVec3>( vel ) );
|
||||
}
|
||||
|
||||
Point3F PxBody::getLinVelocity() const
|
||||
{
|
||||
AssertFatal( mActor, "PxBody::getLinVelocity - The actor is null!" );
|
||||
AssertFatal( isDynamic(), "PxBody::getLinVelocity - This call is only for dynamics!" );
|
||||
|
||||
return pxCast<Point3F>( mActor->getLinearVelocity() );
|
||||
}
|
||||
|
||||
Point3F PxBody::getAngVelocity() const
|
||||
{
|
||||
AssertFatal( mActor, "PxBody::getAngVelocity - The actor is null!" );
|
||||
AssertFatal( isDynamic(), "PxBody::getAngVelocity - This call is only for dynamics!" );
|
||||
|
||||
return pxCast<Point3F>( mActor->getAngularVelocity() );
|
||||
}
|
||||
|
||||
void PxBody::setSleeping( bool sleeping )
|
||||
{
|
||||
AssertFatal( mActor, "PxBody::setSleeping - The actor is null!" );
|
||||
AssertFatal( isDynamic(), "PxBody::setSleeping - This call is only for dynamics!" );
|
||||
|
||||
if ( sleeping )
|
||||
mActor->putToSleep();
|
||||
else
|
||||
mActor->wakeUp();
|
||||
}
|
||||
|
||||
bool PxBody::isDynamic() const
|
||||
{
|
||||
AssertFatal( mActor, "PxBody::isDynamic - The actor is null!" );
|
||||
return mActor->isDynamic() && ( mBodyFlags & BF_KINEMATIC ) == 0;
|
||||
}
|
||||
|
||||
PhysicsWorld* PxBody::getWorld()
|
||||
{
|
||||
return mWorld;
|
||||
}
|
||||
|
||||
PhysicsCollision* PxBody::getColShape()
|
||||
{
|
||||
return mColShape;
|
||||
}
|
||||
|
||||
MatrixF& PxBody::getTransform( MatrixF *outMatrix )
|
||||
{
|
||||
AssertFatal( mActor, "PxBody::getTransform - The actor is null!" );
|
||||
|
||||
mActor->getGlobalPose().getRowMajor44( *outMatrix );
|
||||
|
||||
return *outMatrix;
|
||||
}
|
||||
|
||||
Box3F PxBody::getWorldBounds()
|
||||
{
|
||||
AssertFatal( mActor, "PxBody::getTransform - The actor is null!" );
|
||||
|
||||
NxBounds3 bounds;
|
||||
bounds.setEmpty();
|
||||
NxBounds3 shapeBounds;
|
||||
|
||||
NxShape *const* pShapeArray = mActor->getShapes();
|
||||
U32 shapeCount = mActor->getNbShapes();
|
||||
|
||||
for ( U32 i = 0; i < shapeCount; i++ )
|
||||
{
|
||||
// Get the shape's bounds.
|
||||
pShapeArray[i]->getWorldBounds( shapeBounds );
|
||||
|
||||
// Combine them into the total bounds.
|
||||
bounds.combine( shapeBounds );
|
||||
}
|
||||
|
||||
return pxCast<Box3F>( bounds );
|
||||
}
|
||||
|
||||
void PxBody::setSimulationEnabled( bool enabled )
|
||||
{
|
||||
if ( mIsEnabled == enabled )
|
||||
return;
|
||||
|
||||
// This sucks, but it has to happen if we want
|
||||
// to avoid write lock errors from PhysX right now.
|
||||
mWorld->releaseWriteLock();
|
||||
|
||||
if ( enabled )
|
||||
{
|
||||
mIsEnabled = true;
|
||||
mActor->clearActorFlag( NX_AF_DISABLE_RESPONSE );
|
||||
mActor->clearActorFlag( NX_AF_DISABLE_COLLISION );
|
||||
|
||||
// Don't clear the flag if its supposed to be kinematic.
|
||||
if ( !(mBodyFlags & BF_KINEMATIC) )
|
||||
mActor->clearBodyFlag( NX_BF_KINEMATIC );
|
||||
|
||||
if ( isDynamic() )
|
||||
mActor->wakeUp();
|
||||
}
|
||||
else
|
||||
{
|
||||
mIsEnabled = false;
|
||||
mActor->raiseActorFlag( NX_AF_DISABLE_RESPONSE );
|
||||
mActor->raiseActorFlag( NX_AF_DISABLE_COLLISION );
|
||||
mActor->raiseBodyFlag( NX_BF_KINEMATIC );
|
||||
}
|
||||
|
||||
NxShape *const* shapes = mActor->getShapes();
|
||||
for ( S32 i = 0; i < mActor->getNbShapes(); i++ )
|
||||
shapes[i]->setFlag( NX_SF_DISABLE_RAYCASTING, !mIsEnabled );
|
||||
}
|
||||
|
||||
void PxBody::setTransform( const MatrixF &transform )
|
||||
{
|
||||
AssertFatal( mActor, "PxBody::setTransform - The actor is null!" );
|
||||
|
||||
// This sucks, but it has to happen if we want
|
||||
// to avoid write lock errors from PhysX right now.
|
||||
mWorld->releaseWriteLock();
|
||||
|
||||
NxMat34 xfm;
|
||||
xfm.setRowMajor44( transform );
|
||||
mActor->setGlobalPose( xfm );
|
||||
|
||||
// If its dynamic we have more to do.
|
||||
if ( mActor->isDynamic() && !mActor->readBodyFlag( NX_BF_KINEMATIC ) )
|
||||
{
|
||||
mActor->setLinearVelocity( NxVec3( 0, 0, 0 ) );
|
||||
mActor->setAngularVelocity( NxVec3( 0, 0, 0 ) );
|
||||
mActor->wakeUp();
|
||||
}
|
||||
}
|
||||
|
||||
void PxBody::applyCorrection( const MatrixF &transform )
|
||||
{
|
||||
AssertFatal( mActor, "PxBody::applyCorrection - The actor is null!" );
|
||||
AssertFatal( isDynamic(), "PxBody::applyCorrection - This call is only for dynamics!" );
|
||||
|
||||
// This sucks, but it has to happen if we want
|
||||
// to avoid write lock errors from PhysX right now.
|
||||
mWorld->releaseWriteLock();
|
||||
|
||||
NxMat34 xfm;
|
||||
xfm.setRowMajor44( transform );
|
||||
mActor->setGlobalPose( xfm );
|
||||
}
|
||||
|
||||
void PxBody::applyImpulse( const Point3F &origin, const Point3F &force )
|
||||
{
|
||||
AssertFatal( mActor, "PxBody::applyImpulse - The actor is null!" );
|
||||
|
||||
// This sucks, but it has to happen if we want
|
||||
// to avoid write lock errors from PhysX right now.
|
||||
mWorld->releaseWriteLock();
|
||||
|
||||
if ( mIsEnabled && isDynamic() )
|
||||
mActor->addForceAtPos( pxCast<NxVec3>( force ),
|
||||
pxCast<NxVec3>( origin ),
|
||||
NX_IMPULSE );
|
||||
}
|
||||
|
||||
114
Engine/source/T3D/physics/physx/pxBody.h
Normal file
114
Engine/source/T3D/physics/physx/pxBody.h
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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_PXBODY_H_
|
||||
#define _T3D_PHYSICS_PXBODY_H_
|
||||
|
||||
#ifndef _T3D_PHYSICS_PHYSICSBODY_H_
|
||||
#include "T3D/physics/physicsBody.h"
|
||||
#endif
|
||||
#ifndef _PHYSICS_PHYSICSUSERDATA_H_
|
||||
#include "T3D/physics/physicsUserData.h"
|
||||
#endif
|
||||
#ifndef _REFBASE_H_
|
||||
#include "core/util/refBase.h"
|
||||
#endif
|
||||
#ifndef _MMATRIX_H_
|
||||
#include "math/mMatrix.h"
|
||||
#endif
|
||||
|
||||
class PxWorld;
|
||||
class NxActor;
|
||||
class PxCollision;
|
||||
class NxMaterial;
|
||||
|
||||
|
||||
class PxBody : public PhysicsBody
|
||||
{
|
||||
protected:
|
||||
|
||||
/// The physics world we are in.
|
||||
PxWorld *mWorld;
|
||||
|
||||
/// The physics actor.
|
||||
NxActor *mActor;
|
||||
|
||||
/// The unshared local material used on all the
|
||||
/// shapes on this actor.
|
||||
NxMaterial *mMaterial;
|
||||
|
||||
/// We hold the collision reference as it contains
|
||||
/// allocated objects that we own and must free.
|
||||
StrongRefPtr<PxCollision> mColShape;
|
||||
|
||||
///
|
||||
MatrixF mInternalTransform;
|
||||
|
||||
/// The body flags set at creation time.
|
||||
U32 mBodyFlags;
|
||||
|
||||
/// Is true if this body is enabled and active
|
||||
/// in the simulation of the scene.
|
||||
bool mIsEnabled;
|
||||
|
||||
///
|
||||
void _releaseActor();
|
||||
|
||||
public:
|
||||
|
||||
PxBody();
|
||||
virtual ~PxBody();
|
||||
|
||||
// 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;
|
||||
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;
|
||||
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_PXBODY_H_
|
||||
150
Engine/source/T3D/physics/physx/pxCasts.h
Normal file
150
Engine/source/T3D/physics/physx/pxCasts.h
Normal file
|
|
@ -0,0 +1,150 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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 _PHYSX_CASTS_H_
|
||||
#define _PHYSX_CASTS_H_
|
||||
|
||||
#ifndef _MPOINT3_H_
|
||||
#include "math/mPoint3.h"
|
||||
#endif
|
||||
#ifndef _MBOX_H_
|
||||
#include "math/mBox.h"
|
||||
#endif
|
||||
#ifndef _MQUAT_H_
|
||||
#include "math/mQuat.h"
|
||||
#endif
|
||||
|
||||
|
||||
template <class T, class F> inline T pxCast( const F &from );
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
template<>
|
||||
inline Point3F pxCast( const NxVec3 &vec )
|
||||
{
|
||||
return Point3F( vec.x, vec.y, vec.z );
|
||||
}
|
||||
|
||||
template<>
|
||||
inline NxVec3 pxCast( const Point3F &point )
|
||||
{
|
||||
return NxVec3( point.x, point.y, point.z );
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
template<>
|
||||
inline QuatF pxCast( const NxQuat &quat )
|
||||
{
|
||||
/// The Torque quat has the opposite winding order.
|
||||
return QuatF( -quat.x, -quat.y, -quat.z, quat.w );
|
||||
}
|
||||
|
||||
template<>
|
||||
inline NxQuat pxCast( const QuatF &quat )
|
||||
{
|
||||
/// The Torque quat has the opposite winding order.
|
||||
NxQuat result;
|
||||
result.setWXYZ( quat.w, -quat.x, -quat.y, -quat.z );
|
||||
return result;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
template<>
|
||||
inline NxBounds3 pxCast( const Box3F &box )
|
||||
{
|
||||
NxBounds3 bounds;
|
||||
bounds.set( box.minExtents.x,
|
||||
box.minExtents.y,
|
||||
box.minExtents.z,
|
||||
box.maxExtents.x,
|
||||
box.maxExtents.y,
|
||||
box.maxExtents.z );
|
||||
return bounds;
|
||||
}
|
||||
|
||||
template<>
|
||||
inline Box3F pxCast( const NxBounds3 &bounds )
|
||||
{
|
||||
return Box3F( bounds.min.x,
|
||||
bounds.min.y,
|
||||
bounds.min.z,
|
||||
bounds.max.x,
|
||||
bounds.max.y,
|
||||
bounds.max.z );
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
template<>
|
||||
inline NxVec3 pxCast( const NxExtendedVec3 &xvec )
|
||||
{
|
||||
return NxVec3( xvec.x, xvec.y, xvec.z );
|
||||
}
|
||||
|
||||
template<>
|
||||
inline NxExtendedVec3 pxCast( const NxVec3 &vec )
|
||||
{
|
||||
return NxExtendedVec3( vec.x, vec.y, vec.z );
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
template<>
|
||||
inline NxExtendedVec3 pxCast( const Point3F &point )
|
||||
{
|
||||
return NxExtendedVec3( point.x, point.y, point.z );
|
||||
}
|
||||
|
||||
template<>
|
||||
inline Point3F pxCast( const NxExtendedVec3 &xvec )
|
||||
{
|
||||
return Point3F( xvec.x, xvec.y, xvec.z );
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
template<>
|
||||
inline NxBox pxCast( const NxExtendedBounds3 &exBounds )
|
||||
{
|
||||
NxExtendedVec3 center;
|
||||
exBounds.getCenter( center );
|
||||
NxVec3 extents;
|
||||
exBounds.getExtents( extents );
|
||||
|
||||
NxBox box;
|
||||
box.center.set( center.x, center.y, center.z );
|
||||
box.extents = extents;
|
||||
box.rot.id();
|
||||
|
||||
return box;
|
||||
}
|
||||
|
||||
template<>
|
||||
inline NxExtendedBounds3 pxCast( const NxBox &box )
|
||||
{
|
||||
AssertFatal( false, "Casting a NxBox to NxExtendedBounds3 is impossible without losing rotation data!" );
|
||||
return NxExtendedBounds3();
|
||||
}
|
||||
|
||||
#endif // _PHYSX_CASTS_H_
|
||||
923
Engine/source/T3D/physics/physx/pxCloth.cpp
Normal file
923
Engine/source/T3D/physics/physx/pxCloth.cpp
Normal file
|
|
@ -0,0 +1,923 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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/physX/pxCloth.h"
|
||||
|
||||
#include "console/consoleTypes.h"
|
||||
#include "scene/sceneManager.h"
|
||||
#include "scene/sceneRenderState.h"
|
||||
#include "renderInstance/renderPassManager.h"
|
||||
#include "lighting/lightQuery.h"
|
||||
#include "T3D/physics/physicsPlugin.h"
|
||||
#include "T3D/physics/physx/pxWorld.h"
|
||||
#include "T3D/physics/physx/pxStream.h"
|
||||
#include "T3D/physics/physx/pxCasts.h"
|
||||
#include "gfx/gfxDrawUtil.h"
|
||||
#include "math/mathIO.h"
|
||||
#include "core/stream/bitStream.h"
|
||||
#include "materials/materialManager.h"
|
||||
#include "materials/baseMatInstance.h"
|
||||
|
||||
|
||||
IMPLEMENT_CO_NETOBJECT_V1( PxCloth );
|
||||
|
||||
ConsoleDocClass( PxCloth,
|
||||
|
||||
"@brief Rectangular patch of cloth simulated by PhysX.\n\n"
|
||||
|
||||
"PxCloth is affected by other objects in the simulation but does not itself "
|
||||
"affect others, it is essentially a visual effect. Eg, shooting at cloth will "
|
||||
"disturb it but will not explode the projectile.\n\n"
|
||||
|
||||
"Be careful with the cloth size and resolution because it can easily become "
|
||||
"performance intensive to simulate. A single piece of cloth that is very "
|
||||
"large or high resolution is also much more expensive than multiple pieces "
|
||||
"that add up to the same number of verts.\n\n"
|
||||
|
||||
"Note that most field docs have been copied from their PhysX counterpart.\n\n"
|
||||
|
||||
"@ingroup Physics"
|
||||
);
|
||||
|
||||
enum PxClothAttachment {};
|
||||
DefineBitfieldType( PxClothAttachment );
|
||||
|
||||
ImplementBitfieldType( PxClothAttachment,
|
||||
"Soon to be deprecated\n"
|
||||
"@internal" )
|
||||
{ 0, "Bottom Right" },
|
||||
{ 1, "Bottom Left" },
|
||||
{ 2, "Top Right" },
|
||||
{ 3, "Top Left" },
|
||||
{ 4, "Top Center" },
|
||||
{ 5, "Bottom Center" },
|
||||
{ 6, "Right Center" },
|
||||
{ 7, "Left Center" },
|
||||
{ 8, "Top Edge" },
|
||||
{ 9, "Bottom Edge" },
|
||||
{ 10, "Right Edge" },
|
||||
{ 11, "Left Edge" }
|
||||
EndImplementBitfieldType;
|
||||
|
||||
|
||||
PxCloth::PxCloth()
|
||||
: mWorld( NULL ),
|
||||
mScene( NULL ),
|
||||
mMatInst( NULL )
|
||||
{
|
||||
mVertexRenderBuffer = NULL;
|
||||
mIndexRenderBuffer = NULL;
|
||||
|
||||
mMaxVertices = 0;
|
||||
mMaxIndices = 0;
|
||||
|
||||
mClothMesh = NULL;
|
||||
mCloth = NULL;
|
||||
|
||||
mPatchVerts.set( 8, 8 );
|
||||
mPatchSize.set( 8.0f, 8.0f );
|
||||
|
||||
mNetFlags.set( Ghostable | ScopeAlways );
|
||||
mTypeMask |= StaticObjectType | StaticShapeObjectType;
|
||||
|
||||
mReceiveBuffers.setToDefault();
|
||||
|
||||
mBendingEnabled = false;
|
||||
mDampingEnabled = false;
|
||||
mTriangleCollisionEnabled = false;
|
||||
mSelfCollisionEnabled = false;
|
||||
|
||||
mDensity = 1.0f;
|
||||
mThickness = 0.1f;
|
||||
mFriction = 0.25f;
|
||||
mBendingStiffness = 0.5f;
|
||||
mDampingCoefficient = 0.25f;
|
||||
|
||||
mAttachmentMask = 0;
|
||||
}
|
||||
|
||||
PxCloth::~PxCloth()
|
||||
{
|
||||
}
|
||||
|
||||
bool PxCloth::onAdd()
|
||||
{
|
||||
if ( !Parent::onAdd() )
|
||||
return false;
|
||||
|
||||
// Cloth is only created on the client.
|
||||
if ( isClientObject() )
|
||||
{
|
||||
mWorld = dynamic_cast<PxWorld*>( PHYSICSMGR->getWorld( "client" ) );
|
||||
|
||||
if ( !mWorld || !mWorld->getScene() )
|
||||
{
|
||||
Con::errorf( "PxCloth::onAdd() - PhysXWorld not initialized... cloth disabled!" );
|
||||
return true;
|
||||
}
|
||||
|
||||
mScene = mWorld->getScene();
|
||||
|
||||
mResetXfm = getTransform();
|
||||
|
||||
_createClothPatch();
|
||||
|
||||
PhysicsPlugin::getPhysicsResetSignal().notify( this, &PxCloth::onPhysicsReset, 1053.0f );
|
||||
}
|
||||
|
||||
// On the server we use the static update
|
||||
// to setup the bounds of the cloth.
|
||||
if ( isServerObject() )
|
||||
_updateStaticCloth();
|
||||
|
||||
addToScene();
|
||||
|
||||
// Also the server object never ticks.
|
||||
if ( isServerObject() )
|
||||
setProcessTick( false );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void PxCloth::onRemove()
|
||||
{
|
||||
SAFE_DELETE( mMatInst );
|
||||
|
||||
if ( isClientObject() )
|
||||
{
|
||||
_releaseCloth();
|
||||
_releaseMesh();
|
||||
|
||||
PhysicsPlugin::getPhysicsResetSignal().remove( this, &PxCloth::onPhysicsReset );
|
||||
}
|
||||
|
||||
removeFromScene();
|
||||
|
||||
Parent::onRemove();
|
||||
}
|
||||
|
||||
void PxCloth::onPhysicsReset( PhysicsResetEvent reset )
|
||||
{
|
||||
// Store the reset transform for later use.
|
||||
if ( reset == PhysicsResetEvent_Store )
|
||||
mResetXfm = getTransform();
|
||||
|
||||
// Recreate the cloth at the last reset position.
|
||||
_recreateCloth( mResetXfm );
|
||||
}
|
||||
|
||||
void PxCloth::initPersistFields()
|
||||
{
|
||||
Parent::initPersistFields();
|
||||
|
||||
addField( "material", TypeMaterialName, Offset( mMaterialName, PxCloth ),
|
||||
"@brief Name of the material to render.\n\n" );
|
||||
|
||||
addField( "samples", TypePoint2I, Offset( mPatchVerts, PxCloth ),
|
||||
"@brief The number of cloth vertices in width and length.\n\n"
|
||||
"At least two verts should be defined.\n\n");
|
||||
|
||||
addField( "size", TypePoint2F, Offset( mPatchSize, PxCloth ),
|
||||
"@brief The width and height of the cloth.\n\n" );
|
||||
|
||||
addField( "bending", TypeBool, Offset( mBendingEnabled, PxCloth ),
|
||||
"@brief Enables or disables bending resistance.\n\n"
|
||||
"Set the bending resistance through PxCloth::bendingStiffness." );
|
||||
|
||||
addField( "damping", TypeBool, Offset( mDampingEnabled, PxCloth ),
|
||||
"@brief Enable/disable damping of internal velocities.\n\n" );
|
||||
|
||||
addField( "triangleCollision", TypeBool, Offset( mTriangleCollisionEnabled, PxCloth ),
|
||||
"@brief Not supported in current release (according to PhysX docs).\n\n"
|
||||
"Enables or disables collision detection of cloth triangles against the scene. "
|
||||
"If not set, only collisions of cloth particles are detected. If set, "
|
||||
"collisions of cloth triangles are detected as well." );
|
||||
|
||||
addField( "selfCollision", TypeBool, Offset( mSelfCollisionEnabled, PxCloth ),
|
||||
"@brief Enables or disables self-collision handling within a single piece of cloth.\n\n" );
|
||||
|
||||
addField( "density", TypeF32, Offset( mDensity, PxCloth ),
|
||||
"@brief Density of the cloth (Mass per Area).\n\n" );
|
||||
|
||||
addField( "thickness", TypeF32, Offset( mThickness, PxCloth ),
|
||||
"@brief Value representing how thick the cloth is.\n\n"
|
||||
"The thickness is usually a fraction of the overall extent of the cloth and "
|
||||
"should not be set to a value greater than that. A good value is the maximal "
|
||||
"distance between two adjacent cloth particles in their rest pose. Visual "
|
||||
"artifacts or collision problems may appear if the thickness is too small.\n\n" );
|
||||
|
||||
addField( "friction", TypeF32, Offset( mFriction, PxCloth ),
|
||||
"@brief Friction coefficient in the range 0 to 1.\n\n"
|
||||
"Defines the damping of the velocities of cloth particles that are in contact." );
|
||||
|
||||
addField( "bendingStiffness", TypeF32, Offset( mBendingStiffness, PxCloth ),
|
||||
"@brief Bending stiffness of the cloth in the range 0 to 1.\n\n" );
|
||||
|
||||
addField( "dampingCoefficient", TypeF32, Offset( mDampingCoefficient, PxCloth ),
|
||||
"@brief Spring damping of the cloth in the range 0 to 1.\n\n" );
|
||||
|
||||
addField( "attachments", TYPEID< PxClothAttachment >(), Offset( mAttachmentMask, PxCloth ),
|
||||
"@brief Optional way to specify cloth verts that will be attached to the world position "
|
||||
"it is created at.\n\n" );
|
||||
|
||||
// Cloth doesn't support scale.
|
||||
removeField( "scale" );
|
||||
}
|
||||
|
||||
void PxCloth::inspectPostApply()
|
||||
{
|
||||
Parent::inspectPostApply();
|
||||
|
||||
// Must have at least 2 verts.
|
||||
mPatchVerts.x = getMax( 2, mPatchVerts.x );
|
||||
mPatchVerts.y = getMax( 2, mPatchVerts.y );
|
||||
if ( isServerObject() )
|
||||
_updateStaticCloth();
|
||||
|
||||
setMaskBits( TransformMask | MaterialMask | ClothMask );
|
||||
}
|
||||
|
||||
U32 PxCloth::packUpdate( NetConnection *conn, U32 mask, BitStream *stream )
|
||||
{
|
||||
U32 retMask = Parent::packUpdate( conn, mask, stream );
|
||||
|
||||
if ( stream->writeFlag( mask & TransformMask ) )
|
||||
mathWrite( *stream, getTransform() );
|
||||
|
||||
if ( stream->writeFlag( mask & MaterialMask ) )
|
||||
stream->write( mMaterialName );
|
||||
|
||||
if ( stream->writeFlag( mask & ClothMask ) )
|
||||
{
|
||||
mathWrite( *stream, mPatchVerts );
|
||||
mathWrite( *stream, mPatchSize );
|
||||
|
||||
stream->write( mAttachmentMask );
|
||||
|
||||
stream->writeFlag( mBendingEnabled );
|
||||
stream->writeFlag( mDampingEnabled );
|
||||
stream->writeFlag( mTriangleCollisionEnabled );
|
||||
stream->writeFlag( mSelfCollisionEnabled );
|
||||
stream->write( mThickness );
|
||||
stream->write( mFriction );
|
||||
stream->write( mBendingStiffness );
|
||||
stream->write( mDampingCoefficient );
|
||||
|
||||
stream->write( mDensity );
|
||||
}
|
||||
|
||||
return retMask;
|
||||
}
|
||||
|
||||
void PxCloth::unpackUpdate( NetConnection *conn, BitStream *stream )
|
||||
{
|
||||
Parent::unpackUpdate( conn, stream );
|
||||
|
||||
// TransformMask
|
||||
if ( stream->readFlag() )
|
||||
{
|
||||
MatrixF mat;
|
||||
mathRead( *stream, &mat );
|
||||
setTransform( mat );
|
||||
}
|
||||
|
||||
// MaterialMask
|
||||
if ( stream->readFlag() )
|
||||
{
|
||||
stream->read( &mMaterialName );
|
||||
SAFE_DELETE( mMatInst );
|
||||
}
|
||||
|
||||
// ClothMask
|
||||
if ( stream->readFlag() )
|
||||
{
|
||||
Point2I patchVerts;
|
||||
Point2F patchSize;
|
||||
mathRead( *stream, &patchVerts );
|
||||
mathRead( *stream, &patchSize );
|
||||
|
||||
if ( patchVerts != mPatchVerts ||
|
||||
!patchSize.equal( mPatchSize ) )
|
||||
{
|
||||
mPatchVerts = patchVerts;
|
||||
mPatchSize = patchSize;
|
||||
_releaseMesh();
|
||||
}
|
||||
|
||||
U32 attachMask;
|
||||
stream->read( &attachMask );
|
||||
if ( attachMask != mAttachmentMask )
|
||||
{
|
||||
mAttachmentMask = attachMask;
|
||||
_releaseCloth();
|
||||
}
|
||||
|
||||
mBendingEnabled = stream->readFlag();
|
||||
mDampingEnabled = stream->readFlag();
|
||||
mTriangleCollisionEnabled = stream->readFlag();
|
||||
mSelfCollisionEnabled = stream->readFlag();
|
||||
stream->read( &mThickness );
|
||||
stream->read( &mFriction );
|
||||
stream->read( &mBendingStiffness );
|
||||
stream->read( &mDampingCoefficient );
|
||||
|
||||
F32 density;
|
||||
stream->read( &density );
|
||||
if ( density != mDensity )
|
||||
{
|
||||
mDensity = density;
|
||||
_releaseCloth();
|
||||
}
|
||||
|
||||
if ( isClientObject() &&
|
||||
isProperlyAdded() &&
|
||||
mWorld &&
|
||||
!mCloth )
|
||||
{
|
||||
_createClothPatch();
|
||||
}
|
||||
|
||||
_updateClothProperties();
|
||||
}
|
||||
}
|
||||
|
||||
void PxCloth::_recreateCloth( const MatrixF &transform )
|
||||
{
|
||||
if ( !mWorld )
|
||||
return;
|
||||
|
||||
mWorld->getPhysicsResults();
|
||||
|
||||
Parent::setTransform( transform );
|
||||
|
||||
_createClothPatch();
|
||||
}
|
||||
|
||||
void PxCloth::setTransform( const MatrixF &mat )
|
||||
{
|
||||
Parent::setTransform( mat );
|
||||
setMaskBits( TransformMask );
|
||||
|
||||
// Only need to do this if we're on the server
|
||||
// or if we're not currently ticking physics.
|
||||
if ( !mWorld || !mWorld->isEnabled() )
|
||||
_updateStaticCloth();
|
||||
}
|
||||
|
||||
void PxCloth::setScale( const VectorF &scale )
|
||||
{
|
||||
// Cloth doesn't support scale as it has plenty
|
||||
// of complications... sharing meshes, thickness,
|
||||
// transform origin, etc.
|
||||
return;
|
||||
}
|
||||
|
||||
void PxCloth::prepRenderImage( SceneRenderState *state )
|
||||
{
|
||||
if ( mIsVBDirty )
|
||||
_updateVBIB();
|
||||
|
||||
// Recreate the material if we need to.
|
||||
if ( !mMatInst )
|
||||
_initMaterial();
|
||||
|
||||
// If we don't have a material instance after the override then
|
||||
// we can skip rendering all together.
|
||||
BaseMatInstance *matInst = state->getOverrideMaterial( mMatInst );
|
||||
if ( !matInst )
|
||||
return;
|
||||
|
||||
MeshRenderInst *ri = state->getRenderPass()->allocInst<MeshRenderInst>();
|
||||
|
||||
// If we need lights then set them up.
|
||||
if ( matInst->isForwardLit() )
|
||||
{
|
||||
LightQuery query;
|
||||
query.init( getWorldSphere() );
|
||||
query.getLights( ri->lights, 8 );
|
||||
}
|
||||
|
||||
ri->projection = state->getRenderPass()->allocSharedXform(RenderPassManager::Projection);
|
||||
ri->objectToWorld = &MatrixF::Identity;
|
||||
|
||||
ri->worldToCamera = state->getRenderPass()->allocSharedXform(RenderPassManager::View);
|
||||
ri->type = RenderPassManager::RIT_Mesh;
|
||||
|
||||
ri->primBuff = &mPrimBuffer;
|
||||
ri->vertBuff = &mVB;
|
||||
|
||||
ri->matInst = matInst;
|
||||
ri->prim = state->getRenderPass()->allocPrim();
|
||||
ri->prim->type = GFXTriangleList;
|
||||
ri->prim->minIndex = 0;
|
||||
ri->prim->startIndex = 0;
|
||||
ri->prim->numPrimitives = mNumIndices / 3;
|
||||
|
||||
ri->prim->startVertex = 0;
|
||||
ri->prim->numVertices = mNumVertices;
|
||||
|
||||
ri->defaultKey = matInst->getStateHint();
|
||||
ri->defaultKey2 = (U32)ri->vertBuff;
|
||||
|
||||
state->getRenderPass()->addInst( ri );
|
||||
}
|
||||
|
||||
void PxCloth::_releaseMesh()
|
||||
{
|
||||
if ( !mClothMesh )
|
||||
return;
|
||||
|
||||
_releaseCloth();
|
||||
|
||||
mWorld->releaseClothMesh( *mClothMesh );
|
||||
mClothMesh = NULL;
|
||||
|
||||
delete [] mVertexRenderBuffer;
|
||||
mVertexRenderBuffer = NULL;
|
||||
delete [] mIndexRenderBuffer;
|
||||
mIndexRenderBuffer = NULL;
|
||||
}
|
||||
|
||||
void PxCloth::_releaseCloth()
|
||||
{
|
||||
if ( !mCloth )
|
||||
return;
|
||||
|
||||
mWorld->releaseCloth( *mCloth );
|
||||
mCloth = NULL;
|
||||
}
|
||||
|
||||
void PxCloth::_initClothMesh()
|
||||
{
|
||||
// Make sure we can change the world.
|
||||
mWorld->releaseWriteLock();
|
||||
|
||||
_releaseMesh();
|
||||
|
||||
// Must have at least 2 verts.
|
||||
mPatchVerts.x = getMax( 2, mPatchVerts.x );
|
||||
mPatchVerts.y = getMax( 2, mPatchVerts.y );
|
||||
|
||||
// Generate a uniform cloth patch,
|
||||
// w and h are the width and height,
|
||||
// d is the distance between vertices.
|
||||
mNumVertices = mPatchVerts.x * mPatchVerts.y;
|
||||
mNumIndices = (mPatchVerts.x-1) * (mPatchVerts.y-1) * 2;
|
||||
|
||||
NxClothMeshDesc desc;
|
||||
desc.numVertices = mNumVertices;
|
||||
desc.numTriangles = mNumIndices;
|
||||
desc.pointStrideBytes = sizeof(NxVec3);
|
||||
desc.triangleStrideBytes = 3*sizeof(NxU32);
|
||||
desc.points = (NxVec3*)dMalloc(sizeof(NxVec3)*desc.numVertices);
|
||||
desc.triangles = (NxU32*)dMalloc(sizeof(NxU32)*desc.numTriangles*3);
|
||||
desc.flags = 0;
|
||||
|
||||
U32 i,j;
|
||||
NxVec3 *p = (NxVec3*)desc.points;
|
||||
|
||||
F32 patchWidth = mPatchSize.x / (F32)( mPatchVerts.x - 1 );
|
||||
F32 patchHeight = mPatchSize.y / (F32)( mPatchVerts.y - 1 );
|
||||
|
||||
for (i = 0; i < mPatchVerts.y; i++)
|
||||
{
|
||||
for (j = 0; j < mPatchVerts.x; j++)
|
||||
{
|
||||
p->set( patchWidth * j, 0.0f, patchHeight * i );
|
||||
p++;
|
||||
}
|
||||
}
|
||||
|
||||
NxU32 *id = (NxU32*)desc.triangles;
|
||||
|
||||
for (i = 0; i < mPatchVerts.y-1; i++)
|
||||
{
|
||||
for (j = 0; j < mPatchVerts.x-1; j++)
|
||||
{
|
||||
NxU32 i0 = i * mPatchVerts.x + j;
|
||||
NxU32 i1 = i0 + 1;
|
||||
NxU32 i2 = i0 + mPatchVerts.x;
|
||||
NxU32 i3 = i2 + 1;
|
||||
if ( (j+i) % 2 )
|
||||
{
|
||||
*id++ = i0;
|
||||
*id++ = i2;
|
||||
*id++ = i1;
|
||||
*id++ = i1;
|
||||
*id++ = i2;
|
||||
*id++ = i3;
|
||||
}
|
||||
else
|
||||
{
|
||||
*id++ = i0;
|
||||
*id++ = i2;
|
||||
*id++ = i3;
|
||||
*id++ = i0;
|
||||
*id++ = i3;
|
||||
*id++ = i1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NxCookingInterface *cooker = PxWorld::getCooking();
|
||||
cooker->NxInitCooking();
|
||||
|
||||
// Ok... cook the mesh!
|
||||
NxCookingParams params;
|
||||
params.targetPlatform = PLATFORM_PC;
|
||||
params.skinWidth = 0.01f;
|
||||
params.hintCollisionSpeed = false;
|
||||
|
||||
cooker->NxSetCookingParams( params );
|
||||
|
||||
PxMemStream cooked;
|
||||
|
||||
if ( cooker->NxCookClothMesh( desc, cooked ) )
|
||||
{
|
||||
cooked.resetPosition();
|
||||
mClothMesh = gPhysicsSDK->createClothMesh( cooked );
|
||||
}
|
||||
|
||||
cooker->NxCloseCooking();
|
||||
|
||||
NxVec3 *ppoints = (NxVec3*)desc.points;
|
||||
NxU32 *triangs = (NxU32*)desc.triangles;
|
||||
|
||||
dFree( ppoints );
|
||||
dFree( triangs );
|
||||
|
||||
if ( mClothMesh )
|
||||
_initReceiveBuffers();
|
||||
}
|
||||
|
||||
void PxCloth::_initReceiveBuffers()
|
||||
{
|
||||
// here we setup the buffers through which the SDK returns the dynamic cloth data
|
||||
// we reserve more memory for vertices than the initial mesh takes
|
||||
// because tearing creates new vertices
|
||||
// the SDK only tears cloth as long as there is room in these buffers
|
||||
|
||||
mMaxVertices = 3 * mNumVertices;
|
||||
mMaxIndices = 3 * mNumIndices;
|
||||
|
||||
// Allocate Render Buffer for Vertices if it hasn't been done before
|
||||
mVertexRenderBuffer = new GFXVertexPNTT[mMaxVertices];
|
||||
mIndexRenderBuffer = new U16[mMaxIndices];
|
||||
|
||||
mReceiveBuffers.verticesPosBegin = &(mVertexRenderBuffer[0].point);
|
||||
mReceiveBuffers.verticesNormalBegin = &(mVertexRenderBuffer[0].normal);
|
||||
mReceiveBuffers.verticesPosByteStride = sizeof(GFXVertexPNTT);
|
||||
mReceiveBuffers.verticesNormalByteStride = sizeof(GFXVertexPNTT);
|
||||
mReceiveBuffers.maxVertices = mMaxVertices;
|
||||
mReceiveBuffers.numVerticesPtr = &mNumVertices;
|
||||
|
||||
// the number of triangles is constant, even if the cloth is torn
|
||||
mReceiveBuffers.indicesBegin = &mIndexRenderBuffer[0];
|
||||
mReceiveBuffers.indicesByteStride = sizeof(NxU16);
|
||||
mReceiveBuffers.maxIndices = mMaxIndices;
|
||||
mReceiveBuffers.numIndicesPtr = &mNumIndices;
|
||||
|
||||
// Set up texture coords.
|
||||
|
||||
F32 dx = 1.0f / (F32)(mPatchVerts.x-1);
|
||||
F32 dy = 1.0f / (F32)(mPatchVerts.y-1);
|
||||
|
||||
F32 *coord = (F32*)&mVertexRenderBuffer[0].texCoord;
|
||||
for ( U32 i = 0; i < mPatchVerts.y; i++)
|
||||
{
|
||||
for ( U32 j = 0; j < mPatchVerts.x; j++)
|
||||
{
|
||||
coord[0] = j*dx;
|
||||
coord[1] = i*-dy;
|
||||
coord += sizeof( GFXVertexPNTT ) / sizeof( F32 );
|
||||
}
|
||||
}
|
||||
|
||||
// the parent index information would be needed if we used textured cloth
|
||||
//mReceiveBuffers.parentIndicesBegin = (U32*)malloc(sizeof(U32)*mMaxVertices);
|
||||
//mReceiveBuffers.parentIndicesByteStride = sizeof(U32);
|
||||
//mReceiveBuffers.maxParentIndices = mMaxVertices;
|
||||
//mReceiveBuffers.numParentIndicesPtr = &mNumParentIndices;
|
||||
|
||||
mMeshDirtyFlags = 0;
|
||||
mReceiveBuffers.dirtyBufferFlagsPtr = &mMeshDirtyFlags;
|
||||
|
||||
// init the buffers in case we want to draw the mesh
|
||||
// before the SDK as filled in the correct values
|
||||
|
||||
mReceiveBuffers.flags |= NX_MDF_16_BIT_INDICES;
|
||||
}
|
||||
|
||||
bool PxCloth::_createClothPatch()
|
||||
{
|
||||
// Make sure we have a mesh.
|
||||
if ( !mClothMesh )
|
||||
{
|
||||
_initClothMesh();
|
||||
if ( !mClothMesh )
|
||||
return false;
|
||||
}
|
||||
|
||||
// Make sure we can change the world.
|
||||
mWorld->releaseWriteLock();
|
||||
|
||||
_releaseCloth();
|
||||
|
||||
NxClothDesc desc;
|
||||
desc.globalPose.setRowMajor44( getTransform() );
|
||||
desc.thickness = mThickness;
|
||||
desc.density = mDensity;
|
||||
desc.bendingStiffness = mBendingStiffness;
|
||||
desc.dampingCoefficient = mDampingCoefficient;
|
||||
desc.friction = mFriction;
|
||||
|
||||
if ( mBendingEnabled )
|
||||
desc.flags |= NX_CLF_BENDING;
|
||||
if ( mDampingEnabled )
|
||||
desc.flags |= NX_CLF_DAMPING;
|
||||
if ( mTriangleCollisionEnabled )
|
||||
desc.flags |= NX_CLF_TRIANGLE_COLLISION;
|
||||
if ( mSelfCollisionEnabled )
|
||||
desc.flags |= NX_CLF_SELFCOLLISION;
|
||||
|
||||
desc.clothMesh = mClothMesh;
|
||||
desc.meshData = mReceiveBuffers;
|
||||
|
||||
if ( !desc.isValid() )
|
||||
return false;
|
||||
|
||||
mCloth = mScene->createCloth( desc );
|
||||
mIsVBDirty = true;
|
||||
|
||||
_updateStaticCloth();
|
||||
_setupAttachments();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void PxCloth::_updateClothProperties()
|
||||
{
|
||||
if ( !mCloth )
|
||||
return;
|
||||
|
||||
mCloth->setThickness( mThickness );
|
||||
mCloth->setBendingStiffness( mBendingStiffness );
|
||||
mCloth->setDampingCoefficient( mDampingCoefficient );
|
||||
mCloth->setFriction( mFriction );
|
||||
|
||||
NxU32 flags = NX_CLF_GRAVITY; // TODO: Expose this?
|
||||
if ( mBendingEnabled )
|
||||
flags |= NX_CLF_BENDING;
|
||||
if ( mDampingEnabled )
|
||||
flags |= NX_CLF_DAMPING;
|
||||
if ( mTriangleCollisionEnabled )
|
||||
flags |= NX_CLF_TRIANGLE_COLLISION;
|
||||
if ( mSelfCollisionEnabled )
|
||||
flags |= NX_CLF_SELFCOLLISION;
|
||||
mCloth->setFlags( flags );
|
||||
}
|
||||
|
||||
void PxCloth::_initMaterial()
|
||||
{
|
||||
SAFE_DELETE( mMatInst );
|
||||
|
||||
Material *material = NULL;
|
||||
if (mMaterialName.isNotEmpty() )
|
||||
Sim::findObject( mMaterialName, material );
|
||||
|
||||
if ( material )
|
||||
mMatInst = material->createMatInstance();
|
||||
else
|
||||
mMatInst = MATMGR->createMatInstance( "WarningMaterial" );
|
||||
|
||||
GFXStateBlockDesc desc;
|
||||
desc.setCullMode( GFXCullNone );
|
||||
mMatInst->addStateBlockDesc( desc );
|
||||
|
||||
mMatInst->init( MATMGR->getDefaultFeatures(), getGFXVertexFormat<GFXVertexPNTT>() );
|
||||
}
|
||||
|
||||
void PxCloth::_updateVBIB()
|
||||
{
|
||||
PROFILE_SCOPE( PxCloth_UpdateVBIB );
|
||||
|
||||
mIsVBDirty = false;
|
||||
|
||||
// Don't set the VB if the vertex count is the same!
|
||||
if ( mVB.isNull() || mVB->mNumVerts < mNumVertices )
|
||||
mVB.set( GFX, mNumVertices, GFXBufferTypeDynamic );
|
||||
|
||||
GFXVertexPNTT *vert = mVertexRenderBuffer;
|
||||
GFXVertexPNTT *secondVert = NULL;
|
||||
|
||||
for ( U32 i = 0; i < mNumVertices; i++ )
|
||||
{
|
||||
if ( i % (U32)mPatchSize.x == 0 && i != 0 )
|
||||
{
|
||||
secondVert = vert;
|
||||
secondVert--;
|
||||
vert->tangent = -(vert->point - secondVert->point);
|
||||
}
|
||||
else
|
||||
{
|
||||
secondVert = vert;
|
||||
secondVert++;
|
||||
vert->tangent = vert->point - secondVert->point;
|
||||
}
|
||||
|
||||
vert->tangent.normalize();
|
||||
vert++;
|
||||
}
|
||||
|
||||
GFXVertexPNTT *vpPtr = mVB.lock();
|
||||
dMemcpy( vpPtr, mVertexRenderBuffer, sizeof( GFXVertexPNTT ) * mNumVertices );
|
||||
mVB.unlock();
|
||||
|
||||
if ( mPrimBuffer.isNull() || mPrimBuffer->mIndexCount < mNumIndices )
|
||||
mPrimBuffer.set( GFX, mNumIndices, 0, GFXBufferTypeDynamic );
|
||||
|
||||
U16 *pbPtr;
|
||||
mPrimBuffer.lock( &pbPtr );
|
||||
dMemcpy( pbPtr, mIndexRenderBuffer, sizeof( U16 ) * mNumIndices );
|
||||
mPrimBuffer.unlock();
|
||||
}
|
||||
|
||||
void PxCloth::_updateStaticCloth()
|
||||
{
|
||||
// Setup the unsimulated world bounds.
|
||||
mObjBox.set( 0, mThickness * -0.5f, 0,
|
||||
mPatchSize.x, mThickness * 0.5f, mPatchSize.y );
|
||||
resetWorldBox();
|
||||
|
||||
// If we don't have render buffers then we're done.
|
||||
if ( !mVertexRenderBuffer || !mIndexRenderBuffer )
|
||||
return;
|
||||
|
||||
// Make sure the VBs are updated.
|
||||
mIsVBDirty = true;
|
||||
|
||||
F32 patchWidth = mPatchSize.x / (F32)(mPatchVerts.x-1);
|
||||
F32 patchHeight = mPatchSize.y / (F32)(mPatchVerts.y-1);
|
||||
|
||||
Point3F normal( 0, 1, 0 );
|
||||
getTransform().mulV( normal );
|
||||
|
||||
GFXVertexPNTT *vert = mVertexRenderBuffer;
|
||||
|
||||
for (U32 y = 0; y < mPatchVerts.y; y++)
|
||||
{
|
||||
for (U32 x = 0; x < mPatchVerts.x; x++)
|
||||
{
|
||||
vert->point.set( patchWidth * x, 0.0f, patchHeight * y );
|
||||
getTransform().mulP( vert->point );
|
||||
vert->normal = normal;
|
||||
vert++;
|
||||
}
|
||||
}
|
||||
|
||||
U16 *index = mIndexRenderBuffer;
|
||||
mNumIndices = (mPatchVerts.x-1) * (mPatchVerts.y-1) * 6;
|
||||
U16 yOffset = mPatchVerts.x;
|
||||
|
||||
for (U32 y = 0; y < mPatchVerts.y-1; y++)
|
||||
{
|
||||
for (U32 x = 0; x < mPatchVerts.x-1; x++)
|
||||
{
|
||||
U16 base = x + ( yOffset * y );
|
||||
|
||||
index[0] = base;
|
||||
index[1] = base + 1;
|
||||
index[2] = base + 1 + yOffset;
|
||||
|
||||
index[3] = base + 1 + yOffset;
|
||||
index[4] = base + yOffset;
|
||||
index[5] = base;
|
||||
|
||||
index += 6;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PxCloth::processTick( const Move *move )
|
||||
{
|
||||
// Make sure the cloth is created.
|
||||
if ( !mCloth )
|
||||
return;
|
||||
|
||||
// TODO: Remove this hack!
|
||||
const bool enableWind = Con::getBoolVariable( "$PxCloth::enableWind", false );
|
||||
|
||||
if ( enableWind )
|
||||
{
|
||||
NxVec3 windVec( 25.0f + NxMath::rand(-5.0f, 5.0f),
|
||||
NxMath::rand(-5.0f, 5.0f),
|
||||
NxMath::rand(-5.0f, 5.0f) );
|
||||
|
||||
mCloth->setWindAcceleration( windVec );
|
||||
|
||||
// Wake the cloth!
|
||||
mCloth->wakeUp();
|
||||
}
|
||||
else
|
||||
mCloth->setWindAcceleration( NxVec3( 0, 0, 0 ) );
|
||||
|
||||
// Update bounds.
|
||||
if ( mWorld->getEnabled() )
|
||||
{
|
||||
NxBounds3 box;
|
||||
mCloth->getWorldBounds( box );
|
||||
|
||||
Point3F min = pxCast<Point3F>( box.min );
|
||||
Point3F max = pxCast<Point3F>( box.max );
|
||||
|
||||
mWorldBox.set( min, max );
|
||||
mObjBox = mWorldBox;
|
||||
|
||||
getWorldTransform().mul( mObjBox );
|
||||
}
|
||||
else
|
||||
{
|
||||
mObjBox.set( 0, mThickness * -0.5f, 0,
|
||||
mPatchSize.x, mThickness * 0.5f, mPatchSize.y );
|
||||
}
|
||||
|
||||
resetWorldBox();
|
||||
|
||||
// Update the VB on the next render.
|
||||
mIsVBDirty = true;
|
||||
}
|
||||
|
||||
void PxCloth::interpolateTick( F32 delta )
|
||||
{
|
||||
// Nothing to do for now!
|
||||
}
|
||||
|
||||
bool PxCloth::onNewDataBlock( GameBaseData *dptr, bool reload )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void PxCloth::_setupAttachments()
|
||||
{
|
||||
if ( !mCloth || !mWorld )
|
||||
return;
|
||||
|
||||
// Set up attachments
|
||||
// Bottom right = bit 0
|
||||
// Bottom left = bit 1
|
||||
// Top right = bit 2
|
||||
// Top left = bit 3
|
||||
|
||||
if ( mAttachmentMask & BIT( 0 ) )
|
||||
mCloth->attachVertexToGlobalPosition( 0, mCloth->getPosition( 0 ) );
|
||||
if ( mAttachmentMask & BIT( 1 ) )
|
||||
mCloth->attachVertexToGlobalPosition( mPatchVerts.x-1, mCloth->getPosition( mPatchVerts.x-1 ) );
|
||||
if ( mAttachmentMask & BIT( 2 ) )
|
||||
mCloth->attachVertexToGlobalPosition( mPatchVerts.x * mPatchVerts.y - mPatchVerts.x, mCloth->getPosition( mPatchVerts.x * mPatchVerts.y - mPatchVerts.x ) );
|
||||
if ( mAttachmentMask & BIT( 3 ) )
|
||||
mCloth->attachVertexToGlobalPosition( mPatchVerts.x * mPatchVerts.y - 1, mCloth->getPosition( mPatchVerts.x * mPatchVerts.y - 1 ) );
|
||||
if ( mAttachmentMask & BIT( 4 ) )
|
||||
mCloth->attachVertexToGlobalPosition( mPatchVerts.x * mPatchVerts.y - (mPatchVerts.x/2), mCloth->getPosition( mPatchVerts.x * mPatchVerts.y - (mPatchVerts.x/2) ) );
|
||||
if ( mAttachmentMask & BIT( 5 ) )
|
||||
mCloth->attachVertexToGlobalPosition( (mPatchVerts.x/2), mCloth->getPosition( (mPatchVerts.x/2) ) );
|
||||
if ( mAttachmentMask & BIT( 6 ) )
|
||||
mCloth->attachVertexToGlobalPosition( mPatchVerts.x * (mPatchVerts.y/2), mCloth->getPosition( mPatchVerts.x * (mPatchVerts.y/2) ) );
|
||||
if ( mAttachmentMask & BIT( 7 ) )
|
||||
mCloth->attachVertexToGlobalPosition( mPatchVerts.x * (mPatchVerts.y/2) + (mPatchVerts.x-1), mCloth->getPosition( mPatchVerts.x * (mPatchVerts.y/2) + (mPatchVerts.x-1) ) );
|
||||
|
||||
if ( mAttachmentMask & BIT( 8 ) )
|
||||
for ( U32 i = mPatchVerts.x * mPatchVerts.y - mPatchVerts.x; i < mPatchVerts.x * mPatchVerts.y; i++ )
|
||||
mCloth->attachVertexToGlobalPosition( i, mCloth->getPosition( i ) );
|
||||
|
||||
if ( mAttachmentMask & BIT( 9 ) )
|
||||
for ( U32 i = 0; i < mPatchVerts.x; i++ )
|
||||
mCloth->attachVertexToGlobalPosition( i, mCloth->getPosition( i ) );
|
||||
|
||||
if ( mAttachmentMask & BIT( 10 ) )
|
||||
for ( U32 i = 0; i < mPatchVerts.x * mPatchVerts.y; i+=mPatchVerts.x )
|
||||
mCloth->attachVertexToGlobalPosition( i, mCloth->getPosition( i ) );
|
||||
|
||||
if ( mAttachmentMask & BIT( 11 ) )
|
||||
for ( U32 i = mPatchVerts.x-1; i < mPatchVerts.x * mPatchVerts.y; i+=mPatchVerts.x )
|
||||
mCloth->attachVertexToGlobalPosition( i, mCloth->getPosition( i ) );
|
||||
}
|
||||
176
Engine/source/T3D/physics/physx/pxCloth.h
Normal file
176
Engine/source/T3D/physics/physx/pxCloth.h
Normal file
|
|
@ -0,0 +1,176 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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 _PXCLOTH_H_
|
||||
#define _PXCLOTH_H_
|
||||
|
||||
#ifndef _GAMEBASE_H_
|
||||
#include "T3D/gameBase/gameBase.h"
|
||||
#endif
|
||||
#ifndef _GFXPRIMITIVEBUFFER_H_
|
||||
#include "gfx/gfxPrimitiveBuffer.h"
|
||||
#endif
|
||||
#ifndef _GFXVERTEXBUFFER_H_
|
||||
#include "gfx/gfxVertexBuffer.h"
|
||||
#endif
|
||||
#ifndef _PHYSX_H_
|
||||
#include "T3D/physics/physx/px.h"
|
||||
#endif
|
||||
#ifndef _T3D_PHYSICS_PHYSICSPLUGIN_H_
|
||||
#include "T3D/physics/physicsPlugin.h"
|
||||
#endif
|
||||
|
||||
class Material;
|
||||
class BaseMatInstance;
|
||||
class PxWorld;
|
||||
class NxScene;
|
||||
class NxClothMesh;
|
||||
class NxCloth;
|
||||
|
||||
|
||||
class PxCloth : public GameBase
|
||||
{
|
||||
typedef GameBase Parent;
|
||||
|
||||
enum MaskBits
|
||||
{
|
||||
TransformMask = Parent::NextFreeMask << 0,
|
||||
ClothMask = Parent::NextFreeMask << 1,
|
||||
MaterialMask = Parent::NextFreeMask << 3,
|
||||
NextFreeMask = Parent::NextFreeMask << 4
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
PxCloth();
|
||||
virtual ~PxCloth();
|
||||
|
||||
DECLARE_CONOBJECT( PxCloth );
|
||||
|
||||
// SimObject
|
||||
virtual bool onAdd();
|
||||
virtual void onRemove();
|
||||
static void initPersistFields();
|
||||
virtual void inspectPostApply();
|
||||
void onPhysicsReset( PhysicsResetEvent reset );
|
||||
|
||||
// NetObject
|
||||
virtual U32 packUpdate( NetConnection *conn, U32 mask, BitStream *stream );
|
||||
virtual void unpackUpdate( NetConnection *conn, BitStream *stream );
|
||||
|
||||
// SceneObject
|
||||
virtual void setTransform( const MatrixF &mat );
|
||||
virtual void setScale( const VectorF &scale );
|
||||
virtual void prepRenderImage( SceneRenderState *state );
|
||||
|
||||
// GameBase
|
||||
virtual bool onNewDataBlock( GameBaseData *dptr, bool reload );
|
||||
virtual void processTick( const Move *move );
|
||||
virtual void interpolateTick( F32 delta );
|
||||
|
||||
protected:
|
||||
|
||||
PxWorld *mWorld;
|
||||
|
||||
NxScene *mScene;
|
||||
|
||||
/// Cooked cloth collision mesh.
|
||||
NxClothMesh *mClothMesh;
|
||||
|
||||
/// The cloth actor used
|
||||
NxCloth *mCloth;
|
||||
|
||||
NxMeshData mReceiveBuffers;
|
||||
|
||||
bool mBendingEnabled;
|
||||
bool mDampingEnabled;
|
||||
bool mTriangleCollisionEnabled;
|
||||
bool mSelfCollisionEnabled;
|
||||
|
||||
F32 mDensity;
|
||||
F32 mThickness;
|
||||
F32 mFriction;
|
||||
F32 mBendingStiffness;
|
||||
F32 mStretchingStiffness;
|
||||
F32 mDampingCoefficient;
|
||||
F32 mCollisionResponseCoefficient;
|
||||
F32 mAttachmentResponseCoefficient;
|
||||
|
||||
U32 mAttachmentMask;
|
||||
|
||||
static EnumTable mAttachmentFlagTable;
|
||||
|
||||
String mMaterialName;
|
||||
SimObjectPtr<Material> mMaterial;
|
||||
BaseMatInstance *mMatInst;
|
||||
|
||||
String lookupName;
|
||||
|
||||
/// The output verts from the PhysX simulation.
|
||||
GFXVertexPNTT *mVertexRenderBuffer;
|
||||
|
||||
/// The output indices from the PhysX simulation.
|
||||
U16 *mIndexRenderBuffer;
|
||||
|
||||
U32 mMaxVertices;
|
||||
U32 mMaxIndices;
|
||||
|
||||
/// The number of indices in the cloth which
|
||||
/// is updated by the PhysX simulation.
|
||||
U32 mNumIndices;
|
||||
|
||||
/// The number of verts in the cloth which
|
||||
/// is updated by the PhysX simulation.
|
||||
U32 mNumVertices;
|
||||
|
||||
U32 mMeshDirtyFlags;
|
||||
bool mIsVBDirty;
|
||||
|
||||
GFXPrimitiveBufferHandle mPrimBuffer;
|
||||
GFXVertexBufferHandle<GFXVertexPNTT> mVB;
|
||||
|
||||
Point2I mPatchVerts;
|
||||
Point2F mPatchSize;
|
||||
|
||||
MatrixF mResetXfm;
|
||||
|
||||
void _initMaterial();
|
||||
|
||||
void _releaseMesh();
|
||||
void _releaseCloth();
|
||||
|
||||
bool _createClothPatch();
|
||||
|
||||
void _recreateCloth( const MatrixF &transform );
|
||||
|
||||
void _updateClothProperties();
|
||||
|
||||
void _initClothMesh();
|
||||
void _initReceiveBuffers();
|
||||
void _setupAttachments();
|
||||
|
||||
void _updateStaticCloth();
|
||||
|
||||
void _updateVBIB();
|
||||
};
|
||||
|
||||
#endif // _PXCLOTH_H_
|
||||
291
Engine/source/T3D/physics/physx/pxCollision.cpp
Normal file
291
Engine/source/T3D/physics/physx/pxCollision.cpp
Normal file
|
|
@ -0,0 +1,291 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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/physX/pxCollision.h"
|
||||
|
||||
#include "math/mPoint3.h"
|
||||
#include "math/mMatrix.h"
|
||||
#include "T3D/physics/physX/px.h"
|
||||
#include "T3D/physics/physX/pxCasts.h"
|
||||
#include "T3D/physics/physX/pxWorld.h"
|
||||
#include "T3D/physics/physX/pxStream.h"
|
||||
|
||||
|
||||
PxCollision::PxCollision()
|
||||
{
|
||||
}
|
||||
|
||||
PxCollision::~PxCollision()
|
||||
{
|
||||
// We may be deleteting SDK data... so make
|
||||
// sure we have the the scene write lock.
|
||||
PxWorld::releaseWriteLocks();
|
||||
|
||||
for ( U32 i=0; i < mColShapes.size(); i++ )
|
||||
{
|
||||
// Check for special types which need cleanup.
|
||||
NxShapeDesc *desc = mColShapes[i];
|
||||
|
||||
if ( desc->getType() == NX_SHAPE_CONVEX )
|
||||
gPhysicsSDK->releaseConvexMesh( *((NxConvexShapeDesc*)desc)->meshData );
|
||||
else if ( desc->getType() == NX_SHAPE_MESH )
|
||||
gPhysicsSDK->releaseTriangleMesh( *((NxTriangleMeshShapeDesc*)desc)->meshData );
|
||||
else if ( desc->getType() == NX_SHAPE_HEIGHTFIELD )
|
||||
gPhysicsSDK->releaseHeightField( *((NxHeightFieldShapeDesc*)desc)->heightField );
|
||||
|
||||
// Delete the descriptor.
|
||||
delete desc;
|
||||
}
|
||||
|
||||
mColShapes.clear();
|
||||
}
|
||||
|
||||
void PxCollision::addPlane( const PlaneF &plane )
|
||||
{
|
||||
NxBoxShapeDesc *desc = new NxBoxShapeDesc;
|
||||
desc->skinWidth = 0.01f;
|
||||
desc->dimensions.set( 10000.0f, 10000.0f, 100.0f );
|
||||
desc->localPose.t.z = -100.0f;
|
||||
|
||||
// TODO: Fix rotation to match plane normal!
|
||||
//boxDesc->localPose.M.setColumn( 0, NxVec3( plane.x, plane.y, plane.z ) );
|
||||
//boxDesc->localPose.M.setColumn( 1, NxVec3( plane.x, plane.y, plane.z ) );
|
||||
//boxDesc->localPose.M.setColumn( 2, NxVec3( plane.x, plane.y, plane.z ) );
|
||||
|
||||
mColShapes.push_back( desc );
|
||||
}
|
||||
|
||||
void PxCollision::addBox( const Point3F &halfWidth,
|
||||
const MatrixF &localXfm )
|
||||
{
|
||||
NxBoxShapeDesc *desc = new NxBoxShapeDesc;
|
||||
desc->skinWidth = 0.01f;
|
||||
desc->dimensions.set( halfWidth.x, halfWidth.y, halfWidth.z );
|
||||
desc->localPose.setRowMajor44( localXfm );
|
||||
mColShapes.push_back( desc );
|
||||
}
|
||||
|
||||
void PxCollision::addSphere( F32 radius,
|
||||
const MatrixF &localXfm )
|
||||
{
|
||||
NxSphereShapeDesc *desc = new NxSphereShapeDesc;
|
||||
desc->skinWidth = 0.01f;
|
||||
desc->radius = radius;
|
||||
desc->localPose.setRowMajor44( localXfm );
|
||||
mColShapes.push_back( desc );
|
||||
}
|
||||
|
||||
void PxCollision::addCapsule( F32 radius,
|
||||
F32 height,
|
||||
const MatrixF &localXfm )
|
||||
{
|
||||
NxCapsuleShapeDesc *desc = new NxCapsuleShapeDesc;
|
||||
desc->skinWidth = 0.01f;
|
||||
desc->radius = radius;
|
||||
desc->height = height;
|
||||
desc->localPose.setRowMajor44( localXfm );
|
||||
mColShapes.push_back( desc );
|
||||
}
|
||||
|
||||
bool PxCollision::addConvex( const Point3F *points,
|
||||
U32 count,
|
||||
const MatrixF &localXfm )
|
||||
{
|
||||
// Mesh cooking requires that both
|
||||
// scenes not be write locked!
|
||||
PxWorld::releaseWriteLocks();
|
||||
|
||||
NxCookingInterface *cooker = PxWorld::getCooking();
|
||||
cooker->NxInitCooking();
|
||||
|
||||
NxConvexMeshDesc meshDesc;
|
||||
meshDesc.numVertices = count;
|
||||
meshDesc.pointStrideBytes = sizeof(Point3F);
|
||||
meshDesc.points = points;
|
||||
meshDesc.flags = NX_CF_COMPUTE_CONVEX | NX_CF_INFLATE_CONVEX;
|
||||
|
||||
// Cook it!
|
||||
NxCookingParams params;
|
||||
#ifdef TORQUE_OS_XENON
|
||||
params.targetPlatform = PLATFORM_XENON;
|
||||
#else
|
||||
params.targetPlatform = PLATFORM_PC;
|
||||
#endif
|
||||
params.skinWidth = 0.01f;
|
||||
params.hintCollisionSpeed = true;
|
||||
cooker->NxSetCookingParams( params );
|
||||
|
||||
PxMemStream stream;
|
||||
bool cooked = cooker->NxCookConvexMesh( meshDesc, stream );
|
||||
cooker->NxCloseCooking();
|
||||
|
||||
if ( !cooked )
|
||||
return false;
|
||||
|
||||
stream.resetPosition();
|
||||
NxConvexMesh *meshData = gPhysicsSDK->createConvexMesh( stream );
|
||||
if ( !meshData )
|
||||
return false;
|
||||
|
||||
NxConvexShapeDesc *desc = new NxConvexShapeDesc;
|
||||
desc->skinWidth = 0.01f;
|
||||
desc->meshData = meshData;
|
||||
desc->localPose.setRowMajor44( localXfm );
|
||||
mColShapes.push_back( desc );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PxCollision::addTriangleMesh( const Point3F *vert,
|
||||
U32 vertCount,
|
||||
const U32 *index,
|
||||
U32 triCount,
|
||||
const MatrixF &localXfm )
|
||||
{
|
||||
// Mesh cooking requires that both
|
||||
// scenes not be write locked!
|
||||
PxWorld::releaseWriteLocks();
|
||||
|
||||
NxCookingInterface *cooker = PxWorld::getCooking();
|
||||
cooker->NxInitCooking();
|
||||
|
||||
NxTriangleMeshDesc meshDesc;
|
||||
meshDesc.numVertices = vertCount;
|
||||
meshDesc.numTriangles = triCount;
|
||||
meshDesc.pointStrideBytes = sizeof(Point3F);
|
||||
meshDesc.triangleStrideBytes = 3*sizeof(U32);
|
||||
meshDesc.points = vert;
|
||||
meshDesc.triangles = index;
|
||||
meshDesc.flags = NX_MF_FLIPNORMALS;
|
||||
|
||||
// Cook it!
|
||||
NxCookingParams params;
|
||||
#ifdef TORQUE_OS_XENON
|
||||
params.targetPlatform = PLATFORM_XENON;
|
||||
#else
|
||||
params.targetPlatform = PLATFORM_PC;
|
||||
#endif
|
||||
params.skinWidth = 0.01f;
|
||||
params.hintCollisionSpeed = true;
|
||||
cooker->NxSetCookingParams( params );
|
||||
|
||||
PxMemStream stream;
|
||||
bool cooked = cooker->NxCookTriangleMesh( meshDesc, stream );
|
||||
cooker->NxCloseCooking();
|
||||
if ( !cooked )
|
||||
return false;
|
||||
|
||||
stream.resetPosition();
|
||||
NxTriangleMesh *meshData = gPhysicsSDK->createTriangleMesh( stream );
|
||||
if ( !meshData )
|
||||
return false;
|
||||
|
||||
NxTriangleMeshShapeDesc *desc = new NxTriangleMeshShapeDesc;
|
||||
desc->skinWidth = 0.01f;
|
||||
desc->meshData = meshData;
|
||||
desc->localPose.setRowMajor44( localXfm );
|
||||
mColShapes.push_back( desc );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PxCollision::addHeightfield( const U16 *heights,
|
||||
const bool *holes,
|
||||
U32 blockSize,
|
||||
F32 metersPerSample,
|
||||
const MatrixF &localXfm )
|
||||
{
|
||||
// Since we're creating SDK level data we
|
||||
// have to have access to all active worlds.
|
||||
PxWorld::releaseWriteLocks();
|
||||
|
||||
// Init the heightfield description.
|
||||
NxHeightFieldDesc heightFieldDesc;
|
||||
heightFieldDesc.nbColumns = blockSize;
|
||||
heightFieldDesc.nbRows = blockSize;
|
||||
heightFieldDesc.thickness = -10.0f;
|
||||
heightFieldDesc.convexEdgeThreshold = 0;
|
||||
|
||||
// Allocate the samples.
|
||||
heightFieldDesc.samples = new NxU32[ blockSize * blockSize ];
|
||||
heightFieldDesc.sampleStride = sizeof(NxU32);
|
||||
NxU8 *currentByte = (NxU8*)heightFieldDesc.samples;
|
||||
|
||||
for ( U32 row = 0; row < blockSize; row++ )
|
||||
{
|
||||
const U32 tess = ( row + 1 ) % 2;
|
||||
|
||||
for ( U32 column = 0; column < blockSize; column++ )
|
||||
{
|
||||
NxHeightFieldSample *currentSample = (NxHeightFieldSample*)currentByte;
|
||||
|
||||
U32 index = ( blockSize - row - 1 ) + ( column * blockSize );
|
||||
currentSample->height = heights[ index ];
|
||||
|
||||
if ( holes && holes[ getMax( (S32)index - 1, 0 ) ] ) // row index for holes adjusted so PhysX collision shape better matches rendered terrain
|
||||
{
|
||||
currentSample->materialIndex0 = 0;
|
||||
currentSample->materialIndex1 = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
currentSample->materialIndex0 = 1; //materialIds[0];
|
||||
currentSample->materialIndex1 = 1; //materialIds[0];
|
||||
}
|
||||
|
||||
currentSample->tessFlag = ( column + tess ) % 2;
|
||||
|
||||
currentByte += heightFieldDesc.sampleStride;
|
||||
}
|
||||
}
|
||||
|
||||
// Build it.
|
||||
NxHeightFieldShapeDesc *desc = new NxHeightFieldShapeDesc;
|
||||
desc->heightField = gPhysicsSDK->createHeightField( heightFieldDesc );
|
||||
|
||||
// Destroy the temp sample array.
|
||||
delete [] heightFieldDesc.samples;
|
||||
|
||||
// TerrainBlock uses a 11.5 fixed point height format
|
||||
// giving it a maximum height range of 0 to 2048.
|
||||
desc->heightScale = 0.03125f;
|
||||
|
||||
desc->rowScale = metersPerSample;
|
||||
desc->columnScale = metersPerSample;
|
||||
desc->materialIndexHighBits = 0;
|
||||
desc->skinWidth = 0.01f;
|
||||
|
||||
// Use the local pose to align the heightfield
|
||||
// to what Torque will expect.
|
||||
NxMat33 rotX;
|
||||
rotX.rotX( Float_HalfPi );
|
||||
NxMat33 rotZ;
|
||||
rotZ.rotZ( Float_Pi );
|
||||
NxMat34 rot;
|
||||
rot.M.multiply( rotZ, rotX );
|
||||
rot.t.set( ( blockSize - 1 ) * metersPerSample, 0, 0 );
|
||||
desc->localPose = rot;
|
||||
|
||||
mColShapes.push_back( desc );
|
||||
return true;
|
||||
}
|
||||
78
Engine/source/T3D/physics/physx/pxCollision.h
Normal file
78
Engine/source/T3D/physics/physx/pxCollision.h
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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_PXCOLLISION_H_
|
||||
#define _T3D_PHYSICS_PXCOLLISION_H_
|
||||
|
||||
#ifndef _T3D_PHYSICS_PHYSICSCOLLISION_H_
|
||||
#include "T3D/physics/physicsCollision.h"
|
||||
#endif
|
||||
#ifndef _TVECTOR_H_
|
||||
#include "core/util/tVector.h"
|
||||
#endif
|
||||
|
||||
class NxShapeDesc;
|
||||
|
||||
|
||||
class PxCollision : public PhysicsCollision
|
||||
{
|
||||
protected:
|
||||
|
||||
/// The collision representation.
|
||||
Vector<NxShapeDesc*> mColShapes;
|
||||
|
||||
/// Helper for adding shapes.
|
||||
//void _addShape( btCollisionShape *shape, const MatrixF &localXfm );
|
||||
|
||||
public:
|
||||
|
||||
PxCollision();
|
||||
virtual ~PxCollision();
|
||||
|
||||
/// Return the PhysX shape descriptions.
|
||||
const Vector<NxShapeDesc*>& getShapes() const { return mColShapes; }
|
||||
|
||||
// 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_PXCOLLISION_H_
|
||||
108
Engine/source/T3D/physics/physx/pxContactReporter.cpp
Normal file
108
Engine/source/T3D/physics/physx/pxContactReporter.cpp
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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/physX/pxContactReporter.h"
|
||||
|
||||
#include "T3D/physics/physX/pxCasts.h"
|
||||
#include "T3D/physics/physicsUserData.h"
|
||||
#include "T3D/physics/physX/pxMultiActor.h"
|
||||
#include "platform/profiler.h"
|
||||
|
||||
|
||||
PxContactReporter::PxContactReporter()
|
||||
{
|
||||
}
|
||||
|
||||
PxContactReporter::~PxContactReporter()
|
||||
{
|
||||
}
|
||||
|
||||
void PxContactReporter::onContactNotify( NxContactPair &pair, NxU32 events )
|
||||
{
|
||||
PROFILE_SCOPE( PxContactReporter_OnContactNotify );
|
||||
|
||||
// For now we only care about start touch events.
|
||||
if ( !( events & NX_NOTIFY_ON_START_TOUCH ) )
|
||||
return;
|
||||
|
||||
// Skip if either actor is deleted.
|
||||
if ( pair.isDeletedActor[0] || pair.isDeletedActor[1] )
|
||||
return;
|
||||
|
||||
NxActor *actor0 = pair.actors[0];
|
||||
NxActor *actor1 = pair.actors[1];
|
||||
|
||||
PhysicsUserData *userData0 = PhysicsUserData::cast( actor0->userData );
|
||||
PhysicsUserData *userData1 = PhysicsUserData::cast( actor1->userData );
|
||||
|
||||
// Early out if we don't have user data or signals to notify.
|
||||
if ( ( !userData0 || userData0->getContactSignal().isEmpty() ) &&
|
||||
( !userData1 || userData1->getContactSignal().isEmpty() ) )
|
||||
return;
|
||||
|
||||
// Get an average contact point.
|
||||
U32 points = 0;
|
||||
NxVec3 hitPoint( 0.0f );
|
||||
NxContactStreamIterator iter( pair.stream );
|
||||
while( iter.goNextPair() )
|
||||
{
|
||||
while( iter.goNextPatch() )
|
||||
{
|
||||
while( iter.goNextPoint() )
|
||||
{
|
||||
hitPoint += iter.getPoint();
|
||||
++points;
|
||||
}
|
||||
}
|
||||
}
|
||||
hitPoint /= (F32)points;
|
||||
|
||||
if ( userData0 )
|
||||
userData0->getContactSignal().trigger( userData0,
|
||||
userData1,
|
||||
pxCast<Point3F>( hitPoint ),
|
||||
pxCast<Point3F>( pair.sumNormalForce ) );
|
||||
|
||||
if ( userData1 )
|
||||
userData1->getContactSignal().trigger( userData1,
|
||||
userData0,
|
||||
pxCast<Point3F>( hitPoint ),
|
||||
pxCast<Point3F>( -pair.sumNormalForce ) );
|
||||
}
|
||||
|
||||
bool PxUserNotify::onJointBreak( NxReal breakingForce, NxJoint &brokenJoint )
|
||||
{
|
||||
PROFILE_SCOPE( PxUserNotify_OnJointBreak );
|
||||
|
||||
PxUserData *userData = PxUserData::getData( brokenJoint );
|
||||
|
||||
if ( userData )
|
||||
userData->getOnJointBreakSignal().trigger( breakingForce, brokenJoint );
|
||||
|
||||
// NOTE: Returning true here will tell the
|
||||
// PhysX SDK to delete the joint, which will
|
||||
// cause MANY problems if any of the user app's
|
||||
// objects still hold references to it.
|
||||
|
||||
return false;
|
||||
}
|
||||
54
Engine/source/T3D/physics/physx/pxContactReporter.h
Normal file
54
Engine/source/T3D/physics/physx/pxContactReporter.h
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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 _PXCONTACTREPORTER_H_
|
||||
#define _PXCONTACTREPORTER_H_
|
||||
|
||||
#ifndef _PHYSX_H_
|
||||
#include "T3D/physics/physX/px.h"
|
||||
#endif
|
||||
|
||||
|
||||
class PxContactReporter : public NxUserContactReport
|
||||
{
|
||||
protected:
|
||||
|
||||
virtual void onContactNotify( NxContactPair& pair, NxU32 events );
|
||||
|
||||
public:
|
||||
|
||||
PxContactReporter();
|
||||
virtual ~PxContactReporter();
|
||||
};
|
||||
|
||||
|
||||
|
||||
class PxUserNotify : public NxUserNotify
|
||||
{
|
||||
public:
|
||||
virtual bool onJointBreak( NxReal breakingForce, NxJoint &brokenJoint );
|
||||
virtual void onWake( NxActor **actors, NxU32 count ) {}
|
||||
virtual void onSleep ( NxActor **actors, NxU32 count ) {}
|
||||
};
|
||||
|
||||
|
||||
#endif // _PXCONTACTREPORTER_H_
|
||||
310
Engine/source/T3D/physics/physx/pxFluid.cpp
Normal file
310
Engine/source/T3D/physics/physx/pxFluid.cpp
Normal file
|
|
@ -0,0 +1,310 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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/physx/pxFluid.h"
|
||||
|
||||
#include "console/consoleTypes.h"
|
||||
#include "scene/sceneRenderState.h"
|
||||
#include "renderInstance/renderPassManager.h"
|
||||
#include "T3D/physics/physicsPlugin.h"
|
||||
#include "T3D/physics/physx/pxWorld.h"
|
||||
#include "T3D/physics/physx/pxCasts.h"
|
||||
#include "gfx/gfxDrawUtil.h"
|
||||
#include "math/mathIO.h"
|
||||
#include "core/stream/bitStream.h"
|
||||
|
||||
|
||||
IMPLEMENT_CO_NETOBJECT_V1( PxFluid );
|
||||
|
||||
ConsoleDocClass( PxFluid,
|
||||
"@brief Experimental and unfinished Torque wrapper class for NxFluid.\n\n"
|
||||
"@internal\n"
|
||||
);
|
||||
|
||||
PxFluid::PxFluid()
|
||||
: mWorld( NULL ),
|
||||
mScene( NULL ),
|
||||
mParticles( NULL ),
|
||||
mFluid( NULL ),
|
||||
mEmitter( NULL ),
|
||||
mParticleCount( 0 )
|
||||
{
|
||||
mNetFlags.set( Ghostable | ScopeAlways );
|
||||
mTypeMask |= StaticObjectType | StaticShapeObjectType;
|
||||
}
|
||||
|
||||
PxFluid::~PxFluid()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool PxFluid::onAdd()
|
||||
{
|
||||
if ( !Parent::onAdd() )
|
||||
return false;
|
||||
|
||||
mWorld = dynamic_cast<PxWorld*>( PHYSICSMGR->getWorld( isServerObject() ? "server" : "client" ) );
|
||||
|
||||
if ( !mWorld || !mWorld->getScene() )
|
||||
{
|
||||
Con::errorf( "PxMultiActor::onAdd() - PhysXWorld not initialized!" );
|
||||
return false;
|
||||
}
|
||||
|
||||
mScene = mWorld->getScene();
|
||||
|
||||
if ( isClientObject() )
|
||||
_createFluid();
|
||||
|
||||
Point3F halfScale = Point3F::One * 0.5f;
|
||||
mObjBox.minExtents = -halfScale;
|
||||
mObjBox.maxExtents = halfScale;
|
||||
resetWorldBox();
|
||||
|
||||
addToScene();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void PxFluid::onRemove()
|
||||
{
|
||||
if ( isClientObject() )
|
||||
_destroyFluid();
|
||||
|
||||
removeFromScene();
|
||||
|
||||
Parent::onRemove();
|
||||
}
|
||||
|
||||
void PxFluid::initPersistFields()
|
||||
{
|
||||
Parent::initPersistFields();
|
||||
}
|
||||
|
||||
void PxFluid::inspectPostApply()
|
||||
{
|
||||
Parent::inspectPostApply();
|
||||
|
||||
setMaskBits( UpdateMask );
|
||||
}
|
||||
|
||||
U32 PxFluid::packUpdate( NetConnection *conn, U32 mask, BitStream *stream )
|
||||
{
|
||||
U32 retMask = Parent::packUpdate( conn, mask, stream );
|
||||
|
||||
if ( stream->writeFlag( mask & UpdateMask ) )
|
||||
{
|
||||
mathWrite( *stream, getTransform() );
|
||||
mathWrite( *stream, getScale() );
|
||||
|
||||
stream->write( mEmitter ? mEmitter->getRate() : 0 );
|
||||
}
|
||||
|
||||
stream->writeFlag( isProperlyAdded() && mask & ResetMask );
|
||||
|
||||
return retMask;
|
||||
}
|
||||
|
||||
void PxFluid::unpackUpdate( NetConnection *conn, BitStream *stream )
|
||||
{
|
||||
Parent::unpackUpdate( conn, stream );
|
||||
|
||||
// UpdateMask
|
||||
if ( stream->readFlag() )
|
||||
{
|
||||
MatrixF mat;
|
||||
mathRead( *stream, &mat );
|
||||
Point3F scale;
|
||||
mathRead( *stream, &scale );
|
||||
|
||||
setScale( scale );
|
||||
setTransform( mat );
|
||||
|
||||
F32 rate;
|
||||
stream->read( &rate );
|
||||
setRate( rate );
|
||||
}
|
||||
|
||||
// ResetMask
|
||||
if ( stream->readFlag() )
|
||||
resetParticles();
|
||||
}
|
||||
|
||||
void PxFluid::setTransform( const MatrixF &mat )
|
||||
{
|
||||
Parent::setTransform( mat );
|
||||
|
||||
if ( mEmitter )
|
||||
{
|
||||
NxMat34 nxMat;
|
||||
nxMat.setRowMajor44( mat );
|
||||
mEmitter->setGlobalPose( nxMat );
|
||||
}
|
||||
}
|
||||
|
||||
void PxFluid::setScale( const VectorF &scale )
|
||||
{
|
||||
Point3F lastScale = getScale();
|
||||
|
||||
Point3F halfScale = Point3F::One * 0.5f;
|
||||
mObjBox.minExtents = -halfScale;
|
||||
mObjBox.maxExtents = halfScale;
|
||||
resetWorldBox();
|
||||
|
||||
Parent::setScale( scale );
|
||||
|
||||
if ( lastScale != getScale() &&
|
||||
mEmitter )
|
||||
{
|
||||
_destroyFluid();
|
||||
_createFluid();
|
||||
}
|
||||
}
|
||||
|
||||
void PxFluid::prepRenderImage( SceneRenderState *state )
|
||||
{
|
||||
if ( !state->isDiffusePass() )
|
||||
return;
|
||||
|
||||
ObjectRenderInst *ri = state->getRenderPass()->allocInst<ObjectRenderInst>();
|
||||
ri->renderDelegate.bind( this, &PxFluid::renderObject );
|
||||
ri->type = RenderPassManager::RIT_Object;
|
||||
state->getRenderPass()->addInst( ri );
|
||||
}
|
||||
|
||||
void PxFluid::resetParticles()
|
||||
{
|
||||
if ( mEmitter )
|
||||
mEmitter->resetEmission( MAX_PARTICLES );
|
||||
setMaskBits( ResetMask );
|
||||
}
|
||||
|
||||
void PxFluid::setRate( F32 rate )
|
||||
{
|
||||
if ( mEmitter )
|
||||
mEmitter->setRate( rate );
|
||||
setMaskBits( UpdateMask );
|
||||
}
|
||||
|
||||
void PxFluid::renderObject( ObjectRenderInst *ri, SceneRenderState *state, BaseMatInstance *overrideMat )
|
||||
{
|
||||
GFXStateBlockDesc desc;
|
||||
desc.setBlend( true );
|
||||
desc.setZReadWrite( true, false );
|
||||
|
||||
for ( U32 i = 0; i < mParticleCount; i++ )
|
||||
{
|
||||
FluidParticle &particle = mParticles[i];
|
||||
Point3F pnt = pxCast<Point3F>( particle.position );
|
||||
|
||||
Box3F box( 0.2f );
|
||||
box.minExtents += pnt;
|
||||
box.maxExtents += pnt;
|
||||
|
||||
GFX->getDrawUtil()->drawCube( desc, box, ColorI::BLUE );
|
||||
}
|
||||
}
|
||||
|
||||
void PxFluid::_createFluid()
|
||||
{
|
||||
/*
|
||||
// Set structure to pass particles, and receive them after every simulation step
|
||||
NxParticleData particleData;
|
||||
particleData.numParticlesPtr = &mParticleCount;
|
||||
particleData.bufferPos = &mParticles[0].position.x;
|
||||
particleData.bufferPosByteStride = sizeof(FluidParticle);
|
||||
particleData.bufferVel = &mParticles[0].velocity.x;
|
||||
particleData.bufferVelByteStride = sizeof(FluidParticle);
|
||||
particleData.bufferLife = &mParticles[0].lifetime;
|
||||
particleData.bufferLifeByteStride = sizeof(FluidParticle);
|
||||
|
||||
// Create a fluid descriptor
|
||||
NxFluidDesc fluidDesc;
|
||||
fluidDesc.kernelRadiusMultiplier = 2.3f;
|
||||
fluidDesc.restParticlesPerMeter = 10.0f;
|
||||
fluidDesc.stiffness = 200.0f;
|
||||
fluidDesc.viscosity = 22.0f;
|
||||
fluidDesc.restDensity = 1000.0f;
|
||||
fluidDesc.damping = 0.0f;
|
||||
fluidDesc.simulationMethod = NX_F_SPH;
|
||||
fluidDesc.initialParticleData = particleData;
|
||||
fluidDesc.particlesWriteData = particleData;
|
||||
*/
|
||||
|
||||
NxFluidDesc fluidDesc;
|
||||
fluidDesc.setToDefault();
|
||||
fluidDesc.simulationMethod = NX_F_SPH;
|
||||
fluidDesc.maxParticles = MAX_PARTICLES;
|
||||
fluidDesc.restParticlesPerMeter = 50;
|
||||
fluidDesc.stiffness = 1;
|
||||
fluidDesc.viscosity = 6;
|
||||
fluidDesc.flags = NX_FF_VISUALIZATION|NX_FF_ENABLED;
|
||||
|
||||
mParticles = new FluidParticle[MAX_PARTICLES];
|
||||
dMemset( mParticles, 0, sizeof(FluidParticle) * MAX_PARTICLES );
|
||||
|
||||
NxParticleData &particleData = fluidDesc.particlesWriteData;
|
||||
|
||||
particleData.numParticlesPtr = &mParticleCount;
|
||||
particleData.bufferPos = &mParticles[0].position.x;
|
||||
particleData.bufferPosByteStride = sizeof(FluidParticle);
|
||||
particleData.bufferVel = &mParticles[0].velocity.x;
|
||||
particleData.bufferVelByteStride = sizeof(FluidParticle);
|
||||
particleData.bufferLife = &mParticles[0].lifetime;
|
||||
particleData.bufferLifeByteStride = sizeof(FluidParticle);
|
||||
|
||||
mFluid = mScene->createFluid( fluidDesc );
|
||||
|
||||
|
||||
//Create Emitter.
|
||||
NxFluidEmitterDesc emitterDesc;
|
||||
emitterDesc.setToDefault();
|
||||
emitterDesc.dimensionX = getScale().x;
|
||||
emitterDesc.dimensionY = getScale().y;
|
||||
emitterDesc.relPose.setColumnMajor44( getTransform() );
|
||||
emitterDesc.rate = 5.0f;
|
||||
emitterDesc.randomAngle = 0.1f;
|
||||
emitterDesc.fluidVelocityMagnitude = 6.5f;
|
||||
emitterDesc.maxParticles = 0;
|
||||
emitterDesc.particleLifetime = 4.0f;
|
||||
emitterDesc.type = NX_FE_CONSTANT_FLOW_RATE;
|
||||
emitterDesc.shape = NX_FE_ELLIPSE;
|
||||
mEmitter = mFluid->createEmitter(emitterDesc);
|
||||
}
|
||||
|
||||
void PxFluid::_destroyFluid()
|
||||
{
|
||||
delete[] mParticles;
|
||||
mScene->releaseFluid( *mFluid );
|
||||
mEmitter = NULL;
|
||||
}
|
||||
|
||||
ConsoleMethod( PxFluid, resetParticles, void, 2, 2, "" )
|
||||
{
|
||||
object->resetParticles();
|
||||
}
|
||||
|
||||
ConsoleMethod( PxFluid, setRate, void, 2, 2, "" )
|
||||
{
|
||||
object->setRate( dAtof(argv[2]) );
|
||||
}
|
||||
107
Engine/source/T3D/physics/physx/pxFluid.h
Normal file
107
Engine/source/T3D/physics/physx/pxFluid.h
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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 _PXFLUID_H_
|
||||
#define _PXFLUID_H_
|
||||
|
||||
#ifndef _SCENEOBJECT_H_
|
||||
#include "scene/sceneObject.h"
|
||||
#endif
|
||||
#ifndef _PHYSX_H_
|
||||
#include "T3D/physics/physx/px.h"
|
||||
#endif
|
||||
|
||||
class BaseMatInstance;
|
||||
class PxWorld;
|
||||
class NxScene;
|
||||
|
||||
|
||||
class PxFluid : public SceneObject
|
||||
{
|
||||
typedef SceneObject Parent;
|
||||
|
||||
protected:
|
||||
|
||||
enum NetMasks
|
||||
{
|
||||
UpdateMask = Parent::NextFreeMask,
|
||||
ResetMask = Parent::NextFreeMask << 1,
|
||||
NextFreeMask = Parent::NextFreeMask << 2
|
||||
};
|
||||
|
||||
struct FluidParticle
|
||||
{
|
||||
NxVec3 position;
|
||||
NxVec3 velocity;
|
||||
NxReal density;
|
||||
NxReal lifetime;
|
||||
NxU32 id;
|
||||
NxVec3 collisionNormal;
|
||||
};
|
||||
|
||||
#define MAX_PARTICLES 100
|
||||
|
||||
public:
|
||||
|
||||
PxFluid();
|
||||
virtual ~PxFluid();
|
||||
|
||||
DECLARE_CONOBJECT( PxFluid );
|
||||
|
||||
// SimObject
|
||||
virtual bool onAdd();
|
||||
virtual void onRemove();
|
||||
static void initPersistFields();
|
||||
virtual void inspectPostApply();
|
||||
|
||||
// NetObject
|
||||
virtual U32 packUpdate( NetConnection *conn, U32 mask, BitStream *stream );
|
||||
virtual void unpackUpdate( NetConnection *conn, BitStream *stream );
|
||||
|
||||
// SceneObject
|
||||
virtual void setTransform( const MatrixF &mat );
|
||||
virtual void setScale( const VectorF &scale );
|
||||
virtual void prepRenderImage( SceneRenderState *state );
|
||||
|
||||
void resetParticles();
|
||||
void setRate( F32 rate );
|
||||
|
||||
protected:
|
||||
|
||||
void renderObject( ObjectRenderInst *ri, SceneRenderState *state, BaseMatInstance *overrideMat );
|
||||
|
||||
void _createFluid();
|
||||
void _destroyFluid();
|
||||
|
||||
protected:
|
||||
|
||||
PxWorld *mWorld;
|
||||
NxScene *mScene;
|
||||
|
||||
FluidParticle *mParticles;
|
||||
//NxParticleData *mParticleData;
|
||||
NxFluid *mFluid;
|
||||
U32 mParticleCount;
|
||||
NxFluidEmitter *mEmitter;
|
||||
};
|
||||
|
||||
#endif // _PXFLUID_H_
|
||||
150
Engine/source/T3D/physics/physx/pxMaterial.cpp
Normal file
150
Engine/source/T3D/physics/physx/pxMaterial.cpp
Normal file
|
|
@ -0,0 +1,150 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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/physX/px.h"
|
||||
|
||||
#include "T3D/physics/physX/pxMaterial.h"
|
||||
|
||||
#include "T3D/physics/physX/pxWorld.h"
|
||||
#include "T3D/physics/physicsPlugin.h"
|
||||
#include "console/consoleTypes.h"
|
||||
#include "core/stream/bitStream.h"
|
||||
|
||||
|
||||
IMPLEMENT_CO_DATABLOCK_V1( PxMaterial );
|
||||
|
||||
ConsoleDocClass( PxMaterial,
|
||||
|
||||
"@brief Defines a PhysX material assignable to a PxMaterial.\n\n"
|
||||
|
||||
"When two actors collide, the collision behavior that results depends on the material properties "
|
||||
"of the actors' surfaces. For example, the surface properties determine if the actors will or will "
|
||||
"not bounce, or if they will slide or stick. Currently, the only special feature supported by materials "
|
||||
"is anisotropic friction, but according to Nvidia, other effects such as moving surfaces and more types "
|
||||
"of friction are slotted for future release.\n\n"
|
||||
|
||||
"For more information, refer to Nvidia's PhysX docs.\n\n"
|
||||
|
||||
"@ingroup Physics"
|
||||
);
|
||||
|
||||
PxMaterial::PxMaterial()
|
||||
: mNxMat( NULL ),
|
||||
mNxMatId( -1 ),
|
||||
restitution( 0.0f ),
|
||||
staticFriction( 0.1f ),
|
||||
dynamicFriction( 0.95f ),
|
||||
mServer( false )
|
||||
{
|
||||
}
|
||||
|
||||
PxMaterial::~PxMaterial()
|
||||
{
|
||||
}
|
||||
|
||||
void PxMaterial::consoleInit()
|
||||
{
|
||||
Parent::consoleInit();
|
||||
}
|
||||
|
||||
void PxMaterial::initPersistFields()
|
||||
{
|
||||
Parent::initPersistFields();
|
||||
|
||||
addGroup("PxMaterial");
|
||||
|
||||
addField( "restitution", TypeF32, Offset( restitution, PxMaterial ),
|
||||
"@brief Coeffecient of a bounce applied to the shape in response to a collision.\n\n"
|
||||
"A value of 0 makes the object bounce as little as possible, while higher values up to 1.0 result in more bounce.\n\n"
|
||||
"@note Values close to or above 1.0 may cause stability problems and/or increasing energy.");
|
||||
addField( "staticFriction", TypeF32, Offset( staticFriction, PxMaterial ),
|
||||
"@brief Coefficient of static %friction to be applied.\n\n"
|
||||
"Static %friction determines the force needed to start moving an at-rest object in contact with a surface. "
|
||||
"If the force applied onto shape cannot overcome the force of static %friction, the shape will remain at rest. "
|
||||
"A higher coefficient will require a larger force to start motion. "
|
||||
"@note This value should be larger than 0.\n\n");
|
||||
addField( "dynamicFriction", TypeF32, Offset( dynamicFriction, PxMaterial ),
|
||||
"@brief Coefficient of dynamic %friction to be applied.\n\n"
|
||||
"Dynamic %friction reduces the velocity of a moving object while it is in contact with a surface. "
|
||||
"A higher coefficient will result in a larger reduction in velocity. "
|
||||
"A shape's dynamicFriction should be equal to or larger than 0.\n\n");
|
||||
|
||||
endGroup("PxMaterial");
|
||||
}
|
||||
|
||||
void PxMaterial::onStaticModified( const char *slotName, const char *newValue )
|
||||
{
|
||||
if ( isProperlyAdded() && mNxMat != NULL )
|
||||
{
|
||||
mNxMat->setRestitution( restitution );
|
||||
mNxMat->setStaticFriction( staticFriction );
|
||||
mNxMat->setDynamicFriction( dynamicFriction );
|
||||
}
|
||||
}
|
||||
|
||||
bool PxMaterial::preload( bool server, String &errorBuffer )
|
||||
{
|
||||
mServer = server;
|
||||
|
||||
PxWorld *world = dynamic_cast<PxWorld*>( PHYSICSMGR->getWorld( server ? "server" : "client" ) );
|
||||
|
||||
if ( !world )
|
||||
{
|
||||
// TODO: Error... in error buffer?
|
||||
return false;
|
||||
}
|
||||
|
||||
NxMaterialDesc material;
|
||||
material.restitution = restitution;
|
||||
material.staticFriction = staticFriction;
|
||||
material.dynamicFriction = dynamicFriction;
|
||||
|
||||
mNxMat = world->createMaterial( material );
|
||||
mNxMatId = mNxMat->getMaterialIndex();
|
||||
|
||||
if ( mNxMatId == -1 )
|
||||
{
|
||||
errorBuffer = "PxMaterial::preload() - unable to create material!";
|
||||
return false;
|
||||
}
|
||||
|
||||
return Parent::preload( server, errorBuffer );
|
||||
}
|
||||
|
||||
void PxMaterial::packData( BitStream* stream )
|
||||
{
|
||||
Parent::packData( stream );
|
||||
|
||||
stream->write( restitution );
|
||||
stream->write( staticFriction );
|
||||
stream->write( dynamicFriction );
|
||||
}
|
||||
|
||||
void PxMaterial::unpackData( BitStream* stream )
|
||||
{
|
||||
Parent::unpackData( stream );
|
||||
|
||||
stream->read( &restitution );
|
||||
stream->read( &staticFriction );
|
||||
stream->read( &dynamicFriction );
|
||||
}
|
||||
69
Engine/source/T3D/physics/physx/pxMaterial.h
Normal file
69
Engine/source/T3D/physics/physx/pxMaterial.h
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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 _PHYSX_MATERIAL_H
|
||||
#define _PHYSX_MATERIAL_H
|
||||
|
||||
#ifndef _SIMBASE_H_
|
||||
#include "console/simBase.h"
|
||||
#endif
|
||||
#ifndef _DYNAMIC_CONSOLETYPES_H_
|
||||
#include "console/dynamicTypes.h"
|
||||
#endif
|
||||
|
||||
class NxMaterial;
|
||||
|
||||
class PxMaterial : public SimDataBlock
|
||||
{
|
||||
typedef SimDataBlock Parent;
|
||||
|
||||
protected:
|
||||
|
||||
F32 restitution;
|
||||
F32 staticFriction;
|
||||
F32 dynamicFriction;
|
||||
|
||||
NxMaterial *mNxMat;
|
||||
S32 mNxMatId;
|
||||
|
||||
bool mServer;
|
||||
|
||||
public:
|
||||
|
||||
DECLARE_CONOBJECT( PxMaterial );
|
||||
|
||||
PxMaterial();
|
||||
~PxMaterial();
|
||||
|
||||
static void consoleInit();
|
||||
static void initPersistFields();
|
||||
virtual void onStaticModified( const char *slotName, const char *newValue );
|
||||
|
||||
bool preload( bool server, String &errorBuffer );
|
||||
virtual void packData( BitStream* stream );
|
||||
virtual void unpackData( BitStream* stream );
|
||||
|
||||
S32 getMaterialId() const { return mNxMatId; }
|
||||
|
||||
};
|
||||
|
||||
#endif // _PHYSX_MATERIAL_H
|
||||
2651
Engine/source/T3D/physics/physx/pxMultiActor.cpp
Normal file
2651
Engine/source/T3D/physics/physx/pxMultiActor.cpp
Normal file
File diff suppressed because it is too large
Load diff
398
Engine/source/T3D/physics/physx/pxMultiActor.h
Normal file
398
Engine/source/T3D/physics/physx/pxMultiActor.h
Normal file
|
|
@ -0,0 +1,398 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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 _PXMULTIACTOR_H
|
||||
#define _PXMULTIACTOR_H
|
||||
|
||||
#ifndef _GAMEBASE_H_
|
||||
#include "T3D/gameBase/gameBase.h"
|
||||
#endif
|
||||
#ifndef __RESOURCE_H__
|
||||
#include "core/resource.h"
|
||||
#endif
|
||||
#ifndef _T3D_PHYSICS_PHYSICSPLUGIN_H_
|
||||
#include "T3D/physics/physicsPlugin.h"
|
||||
#endif
|
||||
#ifndef _PHYSX_H_
|
||||
#include "T3D/physics/physx/px.h"
|
||||
#endif
|
||||
#ifndef _STRINGUNIT_H_
|
||||
#include "core/strings/stringUnit.h"
|
||||
#endif
|
||||
#ifndef _PHYSICS_PHYSICSUSERDATA_H_
|
||||
#include "T3D/physics/physicsUserData.h"
|
||||
#endif
|
||||
#ifndef _TSSHAPE_H_
|
||||
#include "ts/tsShape.h"
|
||||
#endif
|
||||
|
||||
|
||||
class TSShapeInstance;
|
||||
class BaseMatInstance;
|
||||
class PxMultiActor;
|
||||
class PxWorld;
|
||||
class PxMaterial;
|
||||
class NxScene;
|
||||
class NxActor;
|
||||
class NxShape;
|
||||
class NxCompartment;
|
||||
class NxJoint;
|
||||
class NxMat34;
|
||||
class NxVec3;
|
||||
class ParticleEmitterData;
|
||||
|
||||
|
||||
namespace NXU
|
||||
{
|
||||
class NxuPhysicsCollection;
|
||||
}
|
||||
|
||||
|
||||
class PxUserData : public PhysicsUserData
|
||||
{
|
||||
public:
|
||||
|
||||
/// The constructor.
|
||||
PxUserData()
|
||||
: PhysicsUserData(),
|
||||
mIsBroken( false ),
|
||||
mParticleEmitterData( NULL )
|
||||
{
|
||||
}
|
||||
|
||||
static PxUserData* getData( const NxActor &actor )
|
||||
{
|
||||
PxUserData *result = (PxUserData*)actor.userData;
|
||||
|
||||
AssertFatal( !result || typeid( *result ) == typeid( PxUserData ),
|
||||
"PxUserData::getData - The pointer is the wrong type!" );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static PxUserData* getData( const NxJoint &joint )
|
||||
{
|
||||
PxUserData *result = (PxUserData*)joint.userData;
|
||||
|
||||
AssertFatal( !result || typeid( *result ) == typeid( PxUserData ),
|
||||
"PxUserData::getData - The pointer is the wrong type!" );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
typedef Signal<void(NxReal, NxJoint&)> JointBreakSignal;
|
||||
|
||||
JointBreakSignal& getOnJointBreakSignal() { return mOnJointBreakSignal; }
|
||||
|
||||
// Breakable stuff...
|
||||
Vector<NxActor*> mUnbrokenActors;
|
||||
Vector<NxActor*> mBrokenActors;
|
||||
Vector<NxMat34> mRelXfm;
|
||||
ParticleEmitterData *mParticleEmitterData;
|
||||
bool mIsBroken;
|
||||
JointBreakSignal mOnJointBreakSignal;
|
||||
};
|
||||
|
||||
|
||||
class ParticleEmitterData;
|
||||
|
||||
class PxMultiActorData : public GameBaseData
|
||||
{
|
||||
typedef GameBaseData Parent;
|
||||
|
||||
public:
|
||||
|
||||
PxMultiActorData();
|
||||
virtual ~PxMultiActorData();
|
||||
|
||||
DECLARE_CONOBJECT(PxMultiActorData);
|
||||
|
||||
static void initPersistFields();
|
||||
|
||||
void packData(BitStream* stream);
|
||||
void unpackData(BitStream* stream);
|
||||
|
||||
bool preload( bool server, String &errorBuffer );
|
||||
//bool onAdd();
|
||||
|
||||
void allocPrimBuffer( S32 overrideSize = -1 );
|
||||
|
||||
bool _loadCollection( const UTF8 *path, bool isBinary );
|
||||
|
||||
void _onFileChanged( const Torque::Path &path );
|
||||
|
||||
void reload();
|
||||
|
||||
void dumpModel();
|
||||
|
||||
Signal<void(void)> mReloadSignal;
|
||||
|
||||
public:
|
||||
|
||||
// Rendering
|
||||
StringTableEntry shapeName;
|
||||
Resource<TSShape> shape;
|
||||
|
||||
PxMaterial *material;
|
||||
|
||||
/// Filename to load the physics actor from.
|
||||
StringTableEntry physXStream;
|
||||
|
||||
enum
|
||||
{
|
||||
NumMountPoints = 32,
|
||||
MaxCorrectionNodes = 2
|
||||
};
|
||||
|
||||
StringTableEntry correctionNodeNames[MaxCorrectionNodes];
|
||||
StringTableEntry mountNodeNames[NumMountPoints];
|
||||
S32 correctionNodes[MaxCorrectionNodes];
|
||||
S32 mountPointNode[NumMountPoints]; ///< Node index of mountPoint
|
||||
|
||||
/// If true no network corrections will
|
||||
/// be done during gameplay.
|
||||
bool noCorrection;
|
||||
|
||||
/// Physics collection that holds the actor
|
||||
/// and all associated shapes and data.
|
||||
NXU::NxuPhysicsCollection *collection;
|
||||
|
||||
bool createActors( NxScene *scene,
|
||||
NxCompartment *compartment,
|
||||
const NxMat34 *nxMat,
|
||||
const Point3F& scale,
|
||||
Vector<NxActor*> *outActors,
|
||||
Vector<NxShape*> *outShapes,
|
||||
Vector<NxJoint*> *outJoints,
|
||||
Vector<String> *outActorUserProperties,
|
||||
Vector<String> *outJointUserProperties );
|
||||
|
||||
/// Angular and Linear Drag (dampening) is scaled by this when in water.
|
||||
F32 waterDragScale;
|
||||
|
||||
/// The density of this object (for purposes of buoyancy calculation only).
|
||||
F32 buoyancyDensity;
|
||||
|
||||
F32 angularDrag;
|
||||
F32 linearDrag;
|
||||
|
||||
/// If this flag is set to true,
|
||||
/// the physics actors will only be
|
||||
/// created on the client, and the server
|
||||
/// object is only responsible for ghosting.
|
||||
/// Objects with this flag set will never stop
|
||||
/// the physics player from moving through them.
|
||||
bool clientOnly;
|
||||
|
||||
bool singlePlayerOnly;
|
||||
|
||||
/// When applyImpulse is passed a force of this magnitude or greater
|
||||
/// any actors hit by the force vector that have broken versions
|
||||
/// will become 'broken'.
|
||||
F32 breakForce;
|
||||
};
|
||||
|
||||
|
||||
class PxMultiActor : public GameBase
|
||||
{
|
||||
typedef GameBase Parent;
|
||||
|
||||
enum MaskBits
|
||||
{
|
||||
MoveMask = Parent::NextFreeMask << 0,
|
||||
WarpMask = Parent::NextFreeMask << 1,
|
||||
LightMask = Parent::NextFreeMask << 2,
|
||||
SleepMask = Parent::NextFreeMask << 3,
|
||||
ForceSleepMask = Parent::NextFreeMask << 4,
|
||||
ImpulseMask = Parent::NextFreeMask << 5,
|
||||
UpdateMask = Parent::NextFreeMask << 6,
|
||||
MountedMask = Parent::NextFreeMask << 7,
|
||||
NextFreeMask = Parent::NextFreeMask << 8
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
PxMultiActor();
|
||||
|
||||
DECLARE_CONOBJECT( PxMultiActor );
|
||||
static void initPersistFields();
|
||||
|
||||
// SimObject
|
||||
bool onAdd();
|
||||
void onRemove();
|
||||
void inspectPostApply();
|
||||
void onPhysicsReset( PhysicsResetEvent reset );
|
||||
void onStaticModified( const char *slotName, const char *newValue );
|
||||
void onDeleteNotify( SimObject *obj );
|
||||
|
||||
// NetObject
|
||||
U32 packUpdate( NetConnection *conn, U32 mask, BitStream *stream );
|
||||
void unpackUpdate( NetConnection *conn, BitStream *stream );
|
||||
|
||||
// SceneObject
|
||||
void prepRenderImage( SceneRenderState *state );
|
||||
void setScale( const VectorF &scale );
|
||||
void setTransform( const MatrixF &mat );
|
||||
virtual void mountObject( SceneObject *obj, U32 node );
|
||||
virtual void unmountObject( SceneObject *obj );
|
||||
virtual void getMountTransform( U32 mountPoint, MatrixF *mat );
|
||||
virtual void getRenderMountTransform( U32 index, MatrixF *mat );
|
||||
|
||||
// GameBase
|
||||
virtual bool onNewDataBlock( GameBaseData *dptr, bool reload );
|
||||
virtual void processTick( const Move *move );
|
||||
virtual void interpolateTick( F32 delta );
|
||||
virtual void applyImpulse( const Point3F &pos, const VectorF &vec );
|
||||
virtual void applyRadialImpulse( const Point3F &origin, F32 radius, F32 magnitude );
|
||||
|
||||
/// PxMultiActor
|
||||
/// @{
|
||||
|
||||
/// Set visibility of all broken/unbroken meshes to match this state.
|
||||
void setAllBroken( bool isBroken );
|
||||
|
||||
/// Sets up actors and meshes associated with the passed joint to reflect
|
||||
/// the desired state.
|
||||
void setBroken( const NxMat34 &parentPose,
|
||||
const NxVec3 &parentVel,
|
||||
PxUserData *userData,
|
||||
bool isBroken );
|
||||
|
||||
///
|
||||
void setMeshHidden( String namePrefix, bool hidden );
|
||||
|
||||
void setAllHidden( bool hide );
|
||||
|
||||
void listMeshes( const String &state ) const;
|
||||
|
||||
void _onJointBreak( NxReal breakForce, NxJoint &brokenJoint );
|
||||
|
||||
void _onContact( PhysicsUserData *us,
|
||||
PhysicsUserData *them,
|
||||
const Point3F &hitPoint,
|
||||
const Point3F &hitForce );
|
||||
|
||||
void applyWarp( const MatrixF& mat, bool interpRender, bool sweep );
|
||||
|
||||
void getDynamicXfms( PxMultiActor *srcObj, F32 dt );
|
||||
|
||||
/// @}
|
||||
|
||||
protected:
|
||||
|
||||
/// This creates the physics objects.
|
||||
bool _createActors( const MatrixF &xfm );
|
||||
|
||||
/// Creates a PxUserData for a joint and parses userProperties into it.
|
||||
PxUserData* _createJointUserData( NxJoint *joint, String &userProperties );
|
||||
|
||||
/// Creates a PxUserData and parses userProperties into it.
|
||||
PxUserData* _createActorUserData( NxActor *actor, String &userProperties );
|
||||
|
||||
/// Called to cleanup the physics objects.
|
||||
void _destroyActors();
|
||||
|
||||
NxActor* _findActor( const String &actorName ) const;
|
||||
|
||||
/// Get the corresponding meshName for a given actor.
|
||||
String _getMeshName( const NxActor *actor ) const;
|
||||
|
||||
///
|
||||
void _updateBounds();
|
||||
|
||||
void _updateContainerForces();
|
||||
|
||||
void _debugRender( ObjectRenderInst *ri, SceneRenderState *state, BaseMatInstance *overrideMat );
|
||||
|
||||
void onFileNotify();
|
||||
|
||||
void _applyActorRadialForce( NxActor *inActor, const NxVec3 &origin, F32 radius, F32 magnitude );
|
||||
|
||||
void _updateDeltas( bool clearDelta );
|
||||
|
||||
bool _getNodeTransform( U32 nodeIdx, MatrixF *outXfm );
|
||||
|
||||
protected:
|
||||
|
||||
PxMultiActorData *mDataBlock;
|
||||
|
||||
PxWorld *mWorld;
|
||||
|
||||
Vector<NxActor*> mActors;
|
||||
Vector<NxActor*> mMappedActors;
|
||||
Vector<S32> mMappedToActorIndex;
|
||||
Vector<S32> mMappedActorDL;
|
||||
Vector<NxJoint*> mJoints;
|
||||
Vector<NxShape*> mShapes;
|
||||
|
||||
/// This is the root actor whose transform is the
|
||||
/// transform of this SceneObject.
|
||||
NxActor *mRootActor;
|
||||
|
||||
TSShapeInstance *mShapeInstance;
|
||||
Resource<TSShape> mDebrisShape;
|
||||
|
||||
struct Delta
|
||||
{
|
||||
Point3F pos;
|
||||
Point3F lastPos;
|
||||
QuatF rot;
|
||||
QuatF lastRot;
|
||||
};
|
||||
|
||||
Delta mDelta;
|
||||
|
||||
Vector<Delta> mActorDeltas;
|
||||
|
||||
/// The transform of this actor when it was first
|
||||
/// created. It is used to reset the physics state
|
||||
/// when the editor is enabled.
|
||||
MatrixF mResetXfm;
|
||||
|
||||
|
||||
/// The userdata object assigned to all actors
|
||||
/// and joints of this multi-actor.
|
||||
//PxUserData mUserData;
|
||||
|
||||
///
|
||||
//Vector<MatrixF> mRelXfms;
|
||||
|
||||
/// This is the scale the actors were built at and
|
||||
/// is used to decide if we need to recreate them.
|
||||
VectorF mActorScale;
|
||||
//F32 mBuildAngDrag;
|
||||
//F32 mBuildLinDrag;
|
||||
|
||||
VectorF mStartImpulse;
|
||||
|
||||
bool mDebugRender;
|
||||
|
||||
/// A helper set to true if is a client object and
|
||||
/// is a singlePlayerOnly object.
|
||||
bool mIsDummy;
|
||||
|
||||
/// Helper for
|
||||
bool mBroken;
|
||||
};
|
||||
|
||||
#endif // _PXMULTIACTOR_H
|
||||
|
||||
420
Engine/source/T3D/physics/physx/pxPlayer.cpp
Normal file
420
Engine/source/T3D/physics/physx/pxPlayer.cpp
Normal file
|
|
@ -0,0 +1,420 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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/physX/pxPlayer.h"
|
||||
|
||||
#include "T3D/physics/physicsPlugin.h"
|
||||
#include "T3D/physics/physX/pxWorld.h"
|
||||
#include "T3D/physics/physX/pxCasts.h"
|
||||
#include "collision/collision.h"
|
||||
//#include "gfx/gfxDrawUtil.h"
|
||||
//#include "sim/netConnection.h"
|
||||
|
||||
|
||||
PxPlayer::PxPlayer()
|
||||
: PhysicsPlayer(),
|
||||
mController( NULL ),
|
||||
mWorld( NULL ),
|
||||
mObject( NULL ),
|
||||
mSkinWidth( 0.1f ),
|
||||
mOriginOffset( 0.0f )
|
||||
{
|
||||
PHYSICSMGR->getPhysicsResetSignal().notify( this, &PxPlayer::_onPhysicsReset );
|
||||
}
|
||||
|
||||
PxPlayer::~PxPlayer()
|
||||
{
|
||||
_releaseController();
|
||||
PHYSICSMGR->getPhysicsResetSignal().remove( this, &PxPlayer::_onPhysicsReset );
|
||||
}
|
||||
|
||||
void PxPlayer::_releaseController()
|
||||
{
|
||||
if ( mController )
|
||||
{
|
||||
mController->getActor()->userData = NULL;
|
||||
mWorld->releaseController( *mController );
|
||||
mController = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void PxPlayer::init( const char *type,
|
||||
const Point3F &size,
|
||||
F32 runSurfaceCos,
|
||||
F32 stepHeight,
|
||||
SceneObject *obj,
|
||||
PhysicsWorld *world )
|
||||
{
|
||||
AssertFatal( obj, "PxPlayer::init - Got a null scene object!" );
|
||||
AssertFatal( world, "PxPlayer::init - Got a null world!" );
|
||||
AssertFatal( dynamic_cast<PxWorld*>( world ), "PxPlayer::init - The world is the wrong type!" );
|
||||
|
||||
// Cleanup any previous controller.
|
||||
_releaseController();
|
||||
|
||||
mObject = obj;
|
||||
mWorld = (PxWorld*)world;
|
||||
mOriginOffset = size.z * 0.5f;
|
||||
|
||||
//if ( dStricmp( type, "Capsule" ) == 0 )
|
||||
{
|
||||
NxCapsuleControllerDesc desc;
|
||||
desc.skinWidth = 0.05f; // Expose?
|
||||
desc.radius = getMax( size.x, size.y ) * 0.5f;
|
||||
desc.radius -= desc.skinWidth;
|
||||
desc.height = size.z - ( desc.radius * 2.0f );
|
||||
desc.height -= desc.skinWidth * 2.0f;
|
||||
|
||||
desc.climbingMode = CLIMB_CONSTRAINED;
|
||||
desc.position.set( 0, 0, 0 );
|
||||
desc.upDirection = NX_Z;
|
||||
desc.callback = this; // TODO: Fix this as well!
|
||||
desc.slopeLimit = runSurfaceCos;
|
||||
desc.stepOffset = stepHeight;
|
||||
mController = mWorld->createController( desc );
|
||||
}
|
||||
//else
|
||||
{
|
||||
//mColShape = new btBoxShape( btVector3( 0.5f, 0.5f, 1.0f ) );
|
||||
//mOriginOffset = 1.0f;
|
||||
}
|
||||
|
||||
// Put the kinematic actor on group 29.
|
||||
NxActor *kineActor = mController->getActor();
|
||||
kineActor->setGroup( 29 );
|
||||
NxShape *const *shapes = kineActor->getShapes();
|
||||
for ( U32 i=0; i < kineActor->getNbShapes(); i++ )
|
||||
shapes[i]->setGroup( 29 );
|
||||
|
||||
mUserData.setObject( obj );
|
||||
kineActor->userData = &mUserData;
|
||||
}
|
||||
|
||||
void PxPlayer::_onPhysicsReset( PhysicsResetEvent reset )
|
||||
{
|
||||
// The PhysX controller will crash out if it doesn't clear its
|
||||
// list of static elements when they are deleted. By calling this
|
||||
// on physics events we clear the cache and we don't get crashes.
|
||||
//
|
||||
// This all depends on not doing moves and sweeps when the
|
||||
// simulation is paused... we need to stop operating.
|
||||
|
||||
if ( mController )
|
||||
mController->reportSceneChanged();
|
||||
}
|
||||
|
||||
Point3F PxPlayer::move( const VectorF &disp, CollisionList &outCol )
|
||||
{
|
||||
AssertFatal( mController, "PxPlayer::move - The controller is null!" );
|
||||
|
||||
// Return the last position if the simulation is stopped.
|
||||
//
|
||||
// See PxPlayer::_onPhysicsReset
|
||||
if ( !mWorld->isEnabled() )
|
||||
{
|
||||
Point3F newPos = pxCast<Point3F>( mController->getDebugPosition() );
|
||||
newPos.z -= mOriginOffset;
|
||||
//outCol->point = newPos;
|
||||
//outCol->normal.set( 0, 0, 1 );
|
||||
return newPos;
|
||||
}
|
||||
|
||||
mWorld->releaseWriteLock();
|
||||
|
||||
mCollisionList = &outCol;
|
||||
|
||||
// PhysX 2.8.4 checks up an up displacement and if found will assume
|
||||
// the player is flying and remove the step offset. If we have a small
|
||||
// z displacement here, zero it out.
|
||||
NxVec3 dispNx( disp.x, disp.y, disp.z );
|
||||
if (mIsZero(disp.z))
|
||||
dispNx.z = 0.0f;
|
||||
|
||||
NxU32 activeGroups = 0xFFFFFFFF;
|
||||
activeGroups &= ~( 1<<31 ); // Skip activeGroup for triggers ( 31 )
|
||||
activeGroups &= ~( 1<<30 ); // Skip activeGroup for debris / non interactive dynamics ( 30 )
|
||||
|
||||
NxU32 collisionFlags = NXCC_COLLISION_SIDES | NXCC_COLLISION_DOWN | NXCC_COLLISION_UP;
|
||||
|
||||
mController->move( dispNx, activeGroups, 0.0001f, collisionFlags );
|
||||
|
||||
Point3F newPos = pxCast<Point3F>( mController->getDebugPosition() );
|
||||
newPos.z -= mOriginOffset;
|
||||
|
||||
mCollisionList = NULL;
|
||||
|
||||
return newPos;
|
||||
}
|
||||
|
||||
NxControllerAction PxPlayer::onShapeHit( const NxControllerShapeHit& hit )
|
||||
{
|
||||
if (!mCollisionList || mCollisionList->getCount() >= CollisionList::MaxCollisions)
|
||||
return NX_ACTION_NONE;
|
||||
|
||||
NxActor *actor = &hit.shape->getActor();
|
||||
PhysicsUserData *userData = PhysicsUserData::cast( actor->userData );
|
||||
|
||||
if ( actor->readActorFlag( NX_AF_DISABLE_RESPONSE ) )
|
||||
return NX_ACTION_NONE;
|
||||
|
||||
// Fill out the Collision
|
||||
// structure for use later.
|
||||
Collision &col = mCollisionList->increment();
|
||||
dMemset( &col, 0, sizeof( col ) );
|
||||
|
||||
col.normal = pxCast<Point3F>( hit.worldNormal );
|
||||
col.point.set( hit.worldPos.x, hit.worldPos.y, hit.worldPos.z );
|
||||
col.distance = hit.length;
|
||||
if ( userData )
|
||||
col.object = userData->getObject();
|
||||
|
||||
// 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 (mIsZero(hit.dir.z))
|
||||
{
|
||||
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();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// PhysX doesn't perform callbacks in its upwards collision check so if
|
||||
// this isn't a sideways collision then it must be a downwards one. 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);
|
||||
}
|
||||
|
||||
/*
|
||||
if ( userData &&
|
||||
userData->mCanPush &&
|
||||
actor->isDynamic() &&
|
||||
!actor->readBodyFlag( NX_BF_KINEMATIC ) &&
|
||||
!mDummyMove )
|
||||
{
|
||||
NxActor *ctrlActor = mController->getActor();
|
||||
|
||||
// So the object is neither
|
||||
// a static or a kinematic,
|
||||
// meaning we need to figure out
|
||||
// if we have enough force to push it.
|
||||
|
||||
// Get the hit object's force
|
||||
// and scale it by the amount
|
||||
// that it's acceleration is going
|
||||
// against our acceleration.
|
||||
const Point3F &hitObjLinVel = pxCast<Point3F>( actor->getLinearVelocity() );
|
||||
|
||||
F32 hitObjMass = actor->getMass();
|
||||
|
||||
VectorF hitObjDeltaVel = hitObjLinVel * TickSec;
|
||||
VectorF hitObjAccel = hitObjDeltaVel / TickSec;
|
||||
|
||||
VectorF controllerLinVel = pxCast<Point3F>( controllerActor->getLinearVelocity() );
|
||||
VectorF controllerDeltaVel = controllerLinVel * TickSec;
|
||||
VectorF controllerAccel = controllerDeltaVel / TickSec;
|
||||
|
||||
Point3F hitObjForce = (hitObjMass * hitObjAccel);
|
||||
Point3F playerForce = (controllerActor->getMass() * controllerAccel);
|
||||
|
||||
VectorF normalizedObjVel( hitObjLinVel );
|
||||
normalizedObjVel.normalizeSafe();
|
||||
|
||||
VectorF normalizedPlayerVel( pxCast<Point3F>( controllerActor->getLinearVelocity() ) );
|
||||
normalizedPlayerVel.normalizeSafe();
|
||||
|
||||
F32 forceDot = mDot( normalizedObjVel, normalizedPlayerVel );
|
||||
|
||||
hitObjForce *= forceDot;
|
||||
|
||||
playerForce = playerForce - hitObjForce;
|
||||
|
||||
if ( playerForce.x > 0.0f || playerForce.y > 0.0f || playerForce.z > 0.0f )
|
||||
actor->addForceAtPos( NxVec3( playerForce.x, playerForce.y, playerForce.z ), actor->getCMassGlobalPosition() );
|
||||
|
||||
//Con::printf( "onShapeHit: %f %f %f", playerForce.x, playerForce.y, playerForce.z );
|
||||
}
|
||||
*/
|
||||
|
||||
return NX_ACTION_PUSH;
|
||||
}
|
||||
|
||||
NxControllerAction PxPlayer::onControllerHit( const NxControllersHit& hit )
|
||||
{
|
||||
if (!mCollisionList || mCollisionList->getCount() >= CollisionList::MaxCollisions)
|
||||
return NX_ACTION_NONE;
|
||||
|
||||
NxActor *actor = hit.other->getActor();
|
||||
PhysicsUserData *userData = PhysicsUserData::cast( actor->userData );
|
||||
|
||||
if ( actor->readActorFlag( NX_AF_DISABLE_RESPONSE ) )
|
||||
return NX_ACTION_NONE;
|
||||
|
||||
// For controller-to-controller hit we don't have an actual hit point, so all
|
||||
// we can do is set the hit object.
|
||||
Collision &col = mCollisionList->increment();
|
||||
dMemset( &col, 0, sizeof( col ) );
|
||||
if ( userData )
|
||||
col.object = userData->getObject();
|
||||
|
||||
return NX_ACTION_NONE;
|
||||
}
|
||||
|
||||
void PxPlayer::findContact( SceneObject **contactObject,
|
||||
VectorF *contactNormal,
|
||||
Vector<SceneObject*> *outOverlapObjects ) const
|
||||
{
|
||||
AssertFatal( mController, "PxPlayer::findContact - The controller is null!" );
|
||||
|
||||
// See PxPlayer::_onPhysicsReset
|
||||
if ( !mWorld->isEnabled() )
|
||||
return;
|
||||
|
||||
// Calculate the sweep motion...
|
||||
F32 halfCapSize = mOriginOffset;
|
||||
F32 halfSmallCapSize = halfCapSize * 0.8f;
|
||||
F32 diff = halfCapSize - halfSmallCapSize;
|
||||
|
||||
const F32 mSkinWidth = 0.1f;
|
||||
|
||||
F32 offsetDist = diff + mSkinWidth + 0.01f;
|
||||
NxVec3 motion(0,0,-offsetDist);
|
||||
|
||||
/*
|
||||
// Construct the capsule...
|
||||
F32 radius = mCapsuleController->getRadius();
|
||||
F32 halfHeight = mCapsuleController->getHeight() * 0.5f;
|
||||
|
||||
NxCapsule capsule;
|
||||
capsule.p0 = capsule.p1 = pxCast<NxVec3>( mCapsuleController->getDebugPosition() );
|
||||
capsule.p0.z -= halfHeight;
|
||||
capsule.p1.z += halfHeight;
|
||||
capsule.radius = radius;
|
||||
*/
|
||||
|
||||
NxSweepQueryHit sweepHit;
|
||||
NxU32 hitCount = mController->getActor()->linearSweep( motion, NX_SF_STATICS | NX_SF_DYNAMICS, NULL, 1, &sweepHit, NULL );
|
||||
|
||||
if ( hitCount > 0 )
|
||||
{
|
||||
PhysicsUserData *data = PhysicsUserData::cast( sweepHit.hitShape->getActor().userData );
|
||||
if ( data )
|
||||
{
|
||||
*contactObject = data->getObject();
|
||||
*contactNormal = pxCast<Point3F>( sweepHit.normal );
|
||||
}
|
||||
}
|
||||
|
||||
// Check for overlapped objects ( triggers )
|
||||
|
||||
if ( !outOverlapObjects )
|
||||
return;
|
||||
|
||||
NxCapsuleShape *shape = reinterpret_cast<NxCapsuleShape*>( mController->getActor()->getShapes()[0] );
|
||||
NxCapsule worldCapsule;
|
||||
shape->getWorldCapsule( worldCapsule );
|
||||
|
||||
// Test only against activeGroup with triggers ( 31 ).
|
||||
NxU32 activeGroups = 1 << 31;
|
||||
|
||||
NxShape *shapes[10];
|
||||
|
||||
hitCount = mWorld->getScene()->overlapCapsuleShapes( worldCapsule, NX_ALL_SHAPES, 10, shapes, NULL, activeGroups );
|
||||
|
||||
for ( S32 i = 0; i < hitCount; i++ )
|
||||
{
|
||||
PhysicsUserData *data = PhysicsUserData::cast( shapes[i]->getActor().userData );
|
||||
if ( data )
|
||||
outOverlapObjects->push_back( data->getObject() );
|
||||
}
|
||||
}
|
||||
|
||||
void PxPlayer::enableCollision()
|
||||
{
|
||||
AssertFatal( mController, "PxPlayer::enableCollision - The controller is null!" );
|
||||
|
||||
mWorld->releaseWriteLock();
|
||||
mController->setCollision( true );
|
||||
}
|
||||
|
||||
void PxPlayer::disableCollision()
|
||||
{
|
||||
AssertFatal( mController, "PxPlayer::disableCollision - The controller is null!" );
|
||||
|
||||
mWorld->releaseWriteLock();
|
||||
mController->setCollision( false );
|
||||
}
|
||||
|
||||
PhysicsWorld* PxPlayer::getWorld()
|
||||
{
|
||||
return mWorld;
|
||||
}
|
||||
|
||||
void PxPlayer::setTransform( const MatrixF &transform )
|
||||
{
|
||||
AssertFatal( mController, "PxPlayer::setTransform - The controller is null!" );
|
||||
|
||||
mWorld->releaseWriteLock();
|
||||
|
||||
Point3F newPos = transform.getPosition();
|
||||
newPos.z += mOriginOffset;
|
||||
|
||||
const Point3F &curPos = pxCast<Point3F>(mController->getDebugPosition());
|
||||
|
||||
if ( !(newPos - curPos ).isZero() )
|
||||
mController->setPosition( pxCast<NxExtendedVec3>(newPos) );
|
||||
}
|
||||
|
||||
MatrixF& PxPlayer::getTransform( MatrixF *outMatrix )
|
||||
{
|
||||
AssertFatal( mController, "PxPlayer::getTransform - The controller is null!" );
|
||||
|
||||
Point3F newPos = pxCast<Point3F>( mController->getDebugPosition() );
|
||||
newPos.z -= mOriginOffset;
|
||||
outMatrix->setPosition( newPos );
|
||||
|
||||
return *outMatrix;
|
||||
}
|
||||
|
||||
void PxPlayer::setScale( const Point3F &scale )
|
||||
{
|
||||
}
|
||||
|
||||
Box3F PxPlayer::getWorldBounds()
|
||||
{
|
||||
Con::warnf( "PxPlayer::getWorldBounds - not implemented" );
|
||||
return Box3F::Invalid;
|
||||
}
|
||||
104
Engine/source/T3D/physics/physx/pxPlayer.h
Normal file
104
Engine/source/T3D/physics/physx/pxPlayer.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 _PXPLAYER_H
|
||||
#define _PXPLAYER_H
|
||||
|
||||
#ifndef _PHYSX_H_
|
||||
#include "T3D/physics/physX/px.h"
|
||||
#endif
|
||||
#ifndef _T3D_PHYSICS_PHYSICSPLAYER_H_
|
||||
#include "T3D/physics/physicsPlayer.h"
|
||||
#endif
|
||||
#ifndef _T3D_PHYSICSCOMMON_H_
|
||||
#include "T3D/physics/physicsCommon.h"
|
||||
#endif
|
||||
|
||||
|
||||
class PxWorld;
|
||||
class NxController;
|
||||
|
||||
|
||||
class PxPlayer : public PhysicsPlayer, public NxUserControllerHitReport
|
||||
{
|
||||
protected:
|
||||
|
||||
NxController *mController;
|
||||
|
||||
F32 mSkinWidth;
|
||||
|
||||
PxWorld *mWorld;
|
||||
|
||||
SceneObject *mObject;
|
||||
|
||||
/// Used to get collision info out of the
|
||||
/// NxUserControllerHitReport callbacks.
|
||||
CollisionList *mCollisionList;
|
||||
|
||||
///
|
||||
F32 mOriginOffset;
|
||||
|
||||
///
|
||||
F32 mStepHeight;
|
||||
|
||||
///
|
||||
void _releaseController();
|
||||
|
||||
// NxUserControllerHitReport
|
||||
virtual NxControllerAction onShapeHit( const NxControllerShapeHit& hit );
|
||||
virtual NxControllerAction onControllerHit( const NxControllersHit& hit );
|
||||
|
||||
void _findContact( SceneObject **contactObject, VectorF *contactNormal ) const;
|
||||
|
||||
void _onPhysicsReset( PhysicsResetEvent reset );
|
||||
|
||||
public:
|
||||
|
||||
PxPlayer();
|
||||
virtual ~PxPlayer();
|
||||
|
||||
// PhysicsObject
|
||||
virtual PhysicsWorld* getWorld();
|
||||
virtual void setTransform( const MatrixF &transform );
|
||||
virtual MatrixF& getTransform( MatrixF *outMatrix );
|
||||
virtual void setScale( const Point3F &scale );
|
||||
virtual Box3F getWorldBounds();
|
||||
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 // _PXPLAYER_H
|
||||
297
Engine/source/T3D/physics/physx/pxPlugin.cpp
Normal file
297
Engine/source/T3D/physics/physx/pxPlugin.cpp
Normal file
|
|
@ -0,0 +1,297 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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 "console/consoleTypes.h"
|
||||
#include "T3D/physics/physX/pxPlugin.h"
|
||||
|
||||
#include "T3D/physics/physicsShape.h"
|
||||
#include "T3D/physics/physX/pxWorld.h"
|
||||
#include "T3D/physics/physX/pxBody.h"
|
||||
#include "T3D/physics/physX/pxPlayer.h"
|
||||
#include "T3D/physics/physX/pxCollision.h"
|
||||
#include "T3D/gameBase/gameProcess.h"
|
||||
#include "core/util/tNamedFactory.h"
|
||||
|
||||
|
||||
extern bool gPhysXLogWarnings;
|
||||
|
||||
AFTER_MODULE_INIT( Sim )
|
||||
{
|
||||
NamedFactory<PhysicsPlugin>::add( "PhysX", &PxPlugin::create );
|
||||
|
||||
#if defined(TORQUE_OS_WIN32) || defined(TORQUE_OS_XBOX) || defined(TORQUE_OS_XENON)
|
||||
NamedFactory<PhysicsPlugin>::add( "default", &PxPlugin::create );
|
||||
#endif
|
||||
|
||||
Con::addVariable( "$PhysXLogWarnings", TypeBool, &gPhysXLogWarnings,
|
||||
"@brief Output PhysX warnings to the console.\n\n"
|
||||
"@ingroup Physics\n");
|
||||
}
|
||||
|
||||
|
||||
PhysicsPlugin* PxPlugin::create()
|
||||
{
|
||||
// Only create the plugin if it hasn't been set up AND
|
||||
// the PhysX world is successfully initialized.
|
||||
bool success = PxWorld::restartSDK( false );
|
||||
if ( success )
|
||||
return new PxPlugin();
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PxPlugin::PxPlugin()
|
||||
{
|
||||
}
|
||||
|
||||
PxPlugin::~PxPlugin()
|
||||
{
|
||||
}
|
||||
|
||||
void PxPlugin::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();
|
||||
|
||||
PxWorld::restartSDK( true );
|
||||
|
||||
delete this;
|
||||
}
|
||||
|
||||
void PxPlugin::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* PxPlugin::createCollision()
|
||||
{
|
||||
return new PxCollision();
|
||||
}
|
||||
|
||||
PhysicsBody* PxPlugin::createBody()
|
||||
{
|
||||
return new PxBody();
|
||||
}
|
||||
|
||||
PhysicsPlayer* PxPlugin::createPlayer()
|
||||
{
|
||||
return new PxPlayer();
|
||||
}
|
||||
|
||||
bool PxPlugin::isSimulationEnabled() const
|
||||
{
|
||||
bool ret = false;
|
||||
PxWorld *world = static_cast<PxWorld*>( getWorld( smClientWorldName ) );
|
||||
if ( world )
|
||||
{
|
||||
ret = world->getEnabled();
|
||||
return ret;
|
||||
}
|
||||
|
||||
world = static_cast<PxWorld*>( getWorld( smServerWorldName ) );
|
||||
if ( world )
|
||||
{
|
||||
ret = world->getEnabled();
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void PxPlugin::enableSimulation( const String &worldName, bool enable )
|
||||
{
|
||||
PxWorld *world = static_cast<PxWorld*>( getWorld( worldName ) );
|
||||
if ( world )
|
||||
world->setEnabled( enable );
|
||||
}
|
||||
|
||||
void PxPlugin::setTimeScale( const F32 timeScale )
|
||||
{
|
||||
// Grab both the client and
|
||||
// server worlds and set their time
|
||||
// scales to the passed value.
|
||||
PxWorld *world = static_cast<PxWorld*>( getWorld( smClientWorldName ) );
|
||||
if ( world )
|
||||
world->setEditorTimeScale( timeScale );
|
||||
|
||||
world = static_cast<PxWorld*>( getWorld( smServerWorldName ) );
|
||||
if ( world )
|
||||
world->setEditorTimeScale( timeScale );
|
||||
}
|
||||
|
||||
const F32 PxPlugin::getTimeScale() const
|
||||
{
|
||||
// Grab both the client and
|
||||
// server worlds and call
|
||||
// setEnabled( true ) on them.
|
||||
PxWorld *world = static_cast<PxWorld*>( getWorld( smClientWorldName ) );
|
||||
if ( !world )
|
||||
{
|
||||
world = static_cast<PxWorld*>( getWorld( smServerWorldName ) );
|
||||
if ( !world )
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
return world->getEditorTimeScale();
|
||||
}
|
||||
|
||||
bool PxPlugin::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( "PxPlugin::createWorld - %s world already exists!", worldName.c_str() );
|
||||
return false;
|
||||
}
|
||||
|
||||
world = new PxWorld();
|
||||
|
||||
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 PxPlugin::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* PxPlugin::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* PxPlugin::getWorld() const
|
||||
{
|
||||
if ( mPhysicsWorldLookup.size() == 0 )
|
||||
return NULL;
|
||||
|
||||
Map<StringNoCase, PhysicsWorld*>::ConstIterator iter = mPhysicsWorldLookup.begin();
|
||||
return iter->value;
|
||||
}
|
||||
|
||||
U32 PxPlugin::getWorldCount() const
|
||||
{
|
||||
return mPhysicsWorldLookup.size();
|
||||
}
|
||||
|
||||
void PxPlugin::_onDebugDrawEnabled( bool enabled )
|
||||
{
|
||||
if ( !enabled )
|
||||
gPhysicsSDK->setParameter( NX_VISUALIZATION_SCALE, 0.0f );
|
||||
}
|
||||
|
||||
ConsoleFunction( physXRemoteDebuggerConnect, bool, 1, 3, "" )
|
||||
{
|
||||
if ( !gPhysicsSDK )
|
||||
{
|
||||
Con::errorf( "PhysX SDK not initialized!" );
|
||||
return false;
|
||||
}
|
||||
|
||||
NxRemoteDebugger *debugger = gPhysicsSDK->getFoundationSDK().getRemoteDebugger();
|
||||
|
||||
if ( debugger->isConnected() )
|
||||
{
|
||||
Con::errorf( "RemoteDebugger already connected... call disconnect first!" );
|
||||
return false;
|
||||
}
|
||||
|
||||
const UTF8 *host = "localhost";
|
||||
U32 port = 5425;
|
||||
|
||||
if ( argc >= 2 )
|
||||
host = argv[1];
|
||||
if ( argc >= 3 )
|
||||
port = dAtoi( argv[2] );
|
||||
|
||||
// Before we connect we need to have write access
|
||||
// to both the client and server worlds.
|
||||
PxWorld::releaseWriteLocks();
|
||||
|
||||
// Connect!
|
||||
debugger->connect( host, port );
|
||||
if ( !debugger->isConnected() )
|
||||
{
|
||||
Con::errorf( "RemoteDebugger failed to connect!" );
|
||||
return false;
|
||||
}
|
||||
|
||||
Con::printf( "RemoteDebugger connected to %s at port %u!", host, port );
|
||||
return true;
|
||||
}
|
||||
|
||||
ConsoleFunction( physXRemoteDebuggerDisconnect, void, 1, 1, "" )
|
||||
{
|
||||
if ( !gPhysicsSDK )
|
||||
{
|
||||
Con::errorf( "PhysX SDK not initialized!" );
|
||||
return;
|
||||
}
|
||||
|
||||
NxRemoteDebugger *debugger = gPhysicsSDK->getFoundationSDK().getRemoteDebugger();
|
||||
|
||||
if ( debugger->isConnected() )
|
||||
{
|
||||
debugger->flush();
|
||||
debugger->disconnect();
|
||||
Con::printf( "RemoteDebugger disconnected!" );
|
||||
}
|
||||
}
|
||||
59
Engine/source/T3D/physics/physx/pxPlugin.h
Normal file
59
Engine/source/T3D/physics/physx/pxPlugin.h
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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_PXPLUGIN_H_
|
||||
#define _T3D_PHYSICS_PXPLUGIN_H_
|
||||
|
||||
#ifndef _T3D_PHYSICS_PHYSICSPLUGIN_H_
|
||||
#include "T3D/physics/physicsPlugin.h"
|
||||
#endif
|
||||
|
||||
|
||||
class PxPlugin : public PhysicsPlugin
|
||||
{
|
||||
public:
|
||||
|
||||
PxPlugin();
|
||||
~PxPlugin();
|
||||
|
||||
/// 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;
|
||||
virtual void _onDebugDrawEnabled( bool enabled );
|
||||
};
|
||||
|
||||
#endif // _T3D_PHYSICS_PXPLUGIN_H_
|
||||
174
Engine/source/T3D/physics/physx/pxStream.cpp
Normal file
174
Engine/source/T3D/physics/physx/pxStream.cpp
Normal file
|
|
@ -0,0 +1,174 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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/physX/pxStream.h"
|
||||
|
||||
#include "console/console.h"
|
||||
#include "console/consoleTypes.h"
|
||||
#include "core/strings/stringFunctions.h"
|
||||
|
||||
|
||||
PxMemStream::PxMemStream()
|
||||
: mMemStream( 1024 )
|
||||
{
|
||||
}
|
||||
|
||||
PxMemStream::~PxMemStream()
|
||||
{
|
||||
}
|
||||
|
||||
void PxMemStream::resetPosition()
|
||||
{
|
||||
mMemStream.setPosition( 0 );
|
||||
}
|
||||
|
||||
NxU8 PxMemStream::readByte() const
|
||||
{
|
||||
NxU8 out;
|
||||
mMemStream.read( &out );
|
||||
return out;
|
||||
}
|
||||
|
||||
NxU16 PxMemStream::readWord() const
|
||||
{
|
||||
NxU16 out;
|
||||
mMemStream.read( &out );
|
||||
return out;
|
||||
}
|
||||
|
||||
NxU32 PxMemStream::readDword() const
|
||||
{
|
||||
NxU32 out;
|
||||
mMemStream.read( &out );
|
||||
return out;
|
||||
}
|
||||
|
||||
float PxMemStream::readFloat() const
|
||||
{
|
||||
float out;
|
||||
mMemStream.read( &out );
|
||||
return out;
|
||||
}
|
||||
|
||||
double PxMemStream::readDouble() const
|
||||
{
|
||||
double out;
|
||||
mMemStream.read( &out );
|
||||
return out;
|
||||
}
|
||||
|
||||
void PxMemStream::readBuffer( void *buffer, NxU32 size ) const
|
||||
{
|
||||
mMemStream.read( size, buffer );
|
||||
}
|
||||
|
||||
NxStream& PxMemStream::storeByte( NxU8 b )
|
||||
{
|
||||
mMemStream.write( b );
|
||||
return *this;
|
||||
}
|
||||
|
||||
NxStream& PxMemStream::storeWord( NxU16 w )
|
||||
{
|
||||
mMemStream.write( w );
|
||||
return *this;
|
||||
}
|
||||
|
||||
NxStream& PxMemStream::storeDword( NxU32 d )
|
||||
{
|
||||
mMemStream.write( d );
|
||||
return *this;
|
||||
}
|
||||
|
||||
NxStream& PxMemStream::storeFloat( NxReal f )
|
||||
{
|
||||
mMemStream.write( f );
|
||||
return *this;
|
||||
}
|
||||
|
||||
NxStream& PxMemStream::storeDouble( NxF64 f )
|
||||
{
|
||||
mMemStream.write( f );
|
||||
return *this;
|
||||
}
|
||||
|
||||
NxStream& PxMemStream::storeBuffer( const void *buffer, NxU32 size )
|
||||
{
|
||||
mMemStream.write( size, buffer );
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
bool gPhysXLogWarnings = false;
|
||||
|
||||
PxConsoleStream::PxConsoleStream()
|
||||
{
|
||||
}
|
||||
|
||||
PxConsoleStream::~PxConsoleStream()
|
||||
{
|
||||
}
|
||||
|
||||
void PxConsoleStream::reportError( NxErrorCode code, const char *message, const char* file, int line )
|
||||
{
|
||||
#ifdef TORQUE_DEBUG
|
||||
|
||||
// If we're in debug mode and the error code is serious then
|
||||
// pop up a message box to make sure we see it.
|
||||
if ( code < NXE_DB_INFO )
|
||||
{
|
||||
UTF8 info[1024];
|
||||
dSprintf( info, 1024, "File: %s\nLine: %d\n%s", file, line, message );
|
||||
Platform::AlertOK( "PhysX Error", info );
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// In all other cases we just dump the message to the console.
|
||||
if ( code == NXE_DB_WARNING )
|
||||
{
|
||||
if ( gPhysXLogWarnings )
|
||||
Con::printf( "PhysX Warning:\n %s(%d) : %s\n", file, line, message );
|
||||
}
|
||||
else
|
||||
Con::printf( "PhysX Error:\n %s(%d) : %s\n", file, line, message );
|
||||
}
|
||||
|
||||
NxAssertResponse PxConsoleStream::reportAssertViolation (const char *message, const char *file,int line)
|
||||
{
|
||||
// Assert if we're in debug mode...
|
||||
bool triggerBreak = false;
|
||||
#ifdef TORQUE_DEBUG
|
||||
triggerBreak = PlatformAssert::processAssert( PlatformAssert::Fatal, file, line, message );
|
||||
#endif
|
||||
|
||||
// In all other cases we just dump the message to the console.
|
||||
Con::errorf( "PhysX Assert:\n %s(%d) : %s\n", file, line, message );
|
||||
|
||||
return triggerBreak ? NX_AR_BREAKPOINT : NX_AR_CONTINUE;
|
||||
}
|
||||
|
||||
void PxConsoleStream::print( const char *message )
|
||||
{
|
||||
Con::printf( "PhysX Says: %s\n", message );
|
||||
}
|
||||
78
Engine/source/T3D/physics/physx/pxStream.h
Normal file
78
Engine/source/T3D/physics/physx/pxStream.h
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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_PXSTREAM_H_
|
||||
#define _T3D_PHYSICS_PXSTREAM_H_
|
||||
|
||||
#ifndef _PHYSX_H_
|
||||
#include "T3D/physics/physX/px.h"
|
||||
#endif
|
||||
#ifndef _MEMSTREAM_H_
|
||||
#include "core/stream/memStream.h"
|
||||
#endif
|
||||
|
||||
|
||||
class PxMemStream : public NxStream
|
||||
{
|
||||
public:
|
||||
|
||||
PxMemStream();
|
||||
virtual ~PxMemStream();
|
||||
|
||||
void resetPosition();
|
||||
|
||||
// NxStream
|
||||
NxU8 readByte() const;
|
||||
NxU16 readWord() const;
|
||||
NxU32 readDword() const;
|
||||
float readFloat() const;
|
||||
double readDouble() const;
|
||||
void readBuffer( void *buffer, NxU32 size ) const;
|
||||
NxStream& storeByte( NxU8 b );
|
||||
NxStream& storeWord( NxU16 w );
|
||||
NxStream& storeDword( NxU32 d );
|
||||
NxStream& storeFloat( NxReal f );
|
||||
NxStream& storeDouble( NxF64 f );
|
||||
NxStream& storeBuffer( const void* buffer, NxU32 size );
|
||||
|
||||
protected:
|
||||
|
||||
mutable MemStream mMemStream;
|
||||
};
|
||||
|
||||
|
||||
class PxConsoleStream : public NxUserOutputStream
|
||||
{
|
||||
protected:
|
||||
|
||||
// NxUserOutputStream
|
||||
void reportError( NxErrorCode code, const char *message, const char* file, int line );
|
||||
NxAssertResponse reportAssertViolation( const char *message, const char *file, int line );
|
||||
void print( const char *message );
|
||||
|
||||
public:
|
||||
|
||||
PxConsoleStream();
|
||||
~PxConsoleStream();
|
||||
};
|
||||
|
||||
#endif // _T3D_PHYSICS_PXSTREAM_H_
|
||||
109
Engine/source/T3D/physics/physx/pxUtils.cpp
Normal file
109
Engine/source/T3D/physics/physx/pxUtils.cpp
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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/physx/pxUtils.h"
|
||||
|
||||
#include "gfx/gfxTransformSaver.h"
|
||||
#include "gfx/gfxDrawUtil.h"
|
||||
#include "math/mMatrix.h"
|
||||
#include "math/mPoint3.h"
|
||||
#include "T3D/physics/physX/px.h"
|
||||
#include "T3D/physics/physX/pxCasts.h"
|
||||
|
||||
namespace PxUtils {
|
||||
|
||||
void drawActor( NxActor *inActor )
|
||||
{
|
||||
GFXDrawUtil *drawer = GFX->getDrawUtil();
|
||||
//drawer->setZRead( false );
|
||||
|
||||
// Determine alpha we render shapes with.
|
||||
const U8 enabledAlpha = 255;
|
||||
const U8 disabledAlpha = 100;
|
||||
U8 renderAlpha = inActor->readActorFlag( NX_AF_DISABLE_COLLISION ) ? disabledAlpha : enabledAlpha;
|
||||
|
||||
// Determine color we render actors and shapes with.
|
||||
ColorI actorColor( 0, 0, 255, 200 );
|
||||
ColorI shapeColor = ( inActor->isSleeping() ? ColorI( 0, 0, 255, renderAlpha ) : ColorI( 255, 0, 255, renderAlpha ) );
|
||||
|
||||
MatrixF actorMat(true);
|
||||
inActor->getGlobalPose().getRowMajor44( actorMat );
|
||||
|
||||
GFXStateBlockDesc desc;
|
||||
desc.setBlend( true );
|
||||
desc.setZReadWrite( true, false );
|
||||
desc.setCullMode( GFXCullNone );
|
||||
|
||||
// Draw an xfm gizmo for the actor's globalPose...
|
||||
//drawer->drawTransform( desc, actorMat, Point3F::One, actorColor );
|
||||
|
||||
// Loop through and render all the actor's shapes....
|
||||
|
||||
NxShape *const*pShapeArray = inActor->getShapes();
|
||||
U32 numShapes = inActor->getNbShapes();
|
||||
|
||||
for ( U32 i = 0; i < numShapes; i++ )
|
||||
{
|
||||
const NxShape *shape = pShapeArray[i];
|
||||
|
||||
Point3F shapePos = pxCast<Point3F>( shape->getGlobalPosition() );
|
||||
MatrixF shapeMat(true);
|
||||
shape->getGlobalPose().getRowMajor44(shapeMat);
|
||||
shapeMat.setPosition( Point3F::Zero );
|
||||
|
||||
switch ( shape->getType() )
|
||||
{
|
||||
case NX_SHAPE_SPHERE:
|
||||
{
|
||||
NxSphereShape *sphere = (NxSphereShape*)shape;
|
||||
drawer->drawSphere( desc, sphere->getRadius(), shapePos, shapeColor );
|
||||
|
||||
break;
|
||||
}
|
||||
case NX_SHAPE_BOX:
|
||||
{
|
||||
NxBoxShape *box = (NxBoxShape*)shape;
|
||||
Point3F size = pxCast<Point3F>( box->getDimensions() );
|
||||
drawer->drawCube( desc, size*2, shapePos, shapeColor, &shapeMat );
|
||||
break;
|
||||
}
|
||||
case NX_SHAPE_CAPSULE:
|
||||
{
|
||||
shapeMat.mul( MatrixF( EulerF( mDegToRad(90.0f), mDegToRad(90.0f), 0 ) ) );
|
||||
|
||||
NxCapsuleShape *capsule = (NxCapsuleShape*)shape;
|
||||
drawer->drawCapsule( desc, shapePos, capsule->getRadius(), capsule->getHeight(), shapeColor, &shapeMat );
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//drawer->clearZDefined();
|
||||
}
|
||||
|
||||
} // namespace PxUtils
|
||||
38
Engine/source/T3D/physics/physx/pxUtils.h
Normal file
38
Engine/source/T3D/physics/physx/pxUtils.h
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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 _PXUTILS_H_
|
||||
#define _PXUTILS_H_
|
||||
|
||||
|
||||
class NxActor;
|
||||
|
||||
|
||||
namespace PxUtils {
|
||||
|
||||
/// Debug render an actor, loops through all shapes
|
||||
/// and translates primitive types into drawUtil calls.
|
||||
void drawActor( NxActor *inActor );
|
||||
|
||||
} // namespace PxUtils
|
||||
|
||||
#endif // _PXUTILS_H_
|
||||
872
Engine/source/T3D/physics/physx/pxWorld.cpp
Normal file
872
Engine/source/T3D/physics/physx/pxWorld.cpp
Normal file
|
|
@ -0,0 +1,872 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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/physX/pxWorld.h"
|
||||
|
||||
#include "T3D/physics/physX/px.h"
|
||||
#include "T3D/physics/physX/pxPlugin.h"
|
||||
#include "T3D/physics/physX/pxMaterial.h"
|
||||
#include "T3D/physics/physX/pxContactReporter.h"
|
||||
#include "T3D/physics/physX/pxStream.h"
|
||||
#include "T3D/physics/physX/pxCasts.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 "core/util/safeDelete.h"
|
||||
#include "T3D/tsstatic.h"
|
||||
#include "T3D/gameBase/gameProcess.h"
|
||||
#include "gfx/sim/debugDraw.h"
|
||||
#include "gfx/primBuilder.h"
|
||||
|
||||
#include <NXU_helper.h>
|
||||
|
||||
|
||||
static const F32 PhysicsStepTime = (F32)TickMs / 1000.0f;
|
||||
static const U32 PhysicsMaxIterations = 8;
|
||||
static const F32 PhysicsMaxTimeStep = PhysicsStepTime / 2.0f;
|
||||
|
||||
NxPhysicsSDK *gPhysicsSDK = NULL;
|
||||
NxCookingInterface *PxWorld::smCooking = NULL;
|
||||
PxConsoleStream *PxWorld::smConsoleStream = NULL;
|
||||
|
||||
|
||||
PxWorld::PxWorld() :
|
||||
mScene( NULL ),
|
||||
mConactReporter( NULL ),
|
||||
mProcessList( NULL ),
|
||||
mIsSimulating( false ),
|
||||
mErrorReport( false ),
|
||||
mTickCount( 0 ),
|
||||
mIsEnabled( false ),
|
||||
mEditorTimeScale( 1.0f )
|
||||
{
|
||||
if ( !CCTAllocator::mAllocator )
|
||||
CCTAllocator::mAllocator = new NxUserAllocatorDefault();
|
||||
mControllerManager = new CharacterControllerManager( CCTAllocator::mAllocator );
|
||||
}
|
||||
|
||||
PxWorld::~PxWorld()
|
||||
{
|
||||
delete mControllerManager;
|
||||
}
|
||||
|
||||
NxCookingInterface* PxWorld::getCooking()
|
||||
{
|
||||
if ( !smCooking )
|
||||
smCooking = NxGetCookingLib( NX_PHYSICS_SDK_VERSION );
|
||||
|
||||
return smCooking;
|
||||
}
|
||||
|
||||
bool PxWorld::_init( bool isServer, ProcessList *processList )
|
||||
{
|
||||
if ( !gPhysicsSDK )
|
||||
{
|
||||
Con::errorf( "PhysXWorld::init - PhysXSDK not initialized!" );
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create the scene description.
|
||||
NxSceneDesc sceneDesc;
|
||||
sceneDesc.userData = this;
|
||||
|
||||
// Set up default gravity.
|
||||
sceneDesc.gravity.set( mGravity.x, mGravity.y, mGravity.z );
|
||||
|
||||
// The master scene is always on the CPU and is used
|
||||
// mostly for static shapes.
|
||||
sceneDesc.simType = NX_SIMULATION_SW; // [9/28/2009 Pat] Why is this software? Should be software server, hardware client?
|
||||
|
||||
// Threading... seems to improve performance.
|
||||
//
|
||||
// TODO: I was getting random crashes in debug when doing
|
||||
// edit and continue... lets see if i still get them with
|
||||
// the threading disabled.
|
||||
//
|
||||
sceneDesc.flags |= NX_SF_ENABLE_MULTITHREAD | NX_SF_DISABLE_SCENE_MUTEX;
|
||||
sceneDesc.threadMask = 0xfffffffe;
|
||||
sceneDesc.internalThreadCount = PHYSICSMGR->getThreadCount();
|
||||
|
||||
// Create the scene.
|
||||
mScene = gPhysicsSDK->createScene(sceneDesc);
|
||||
if ( !mScene )
|
||||
{
|
||||
Con::errorf( "PhysXWorld - %s world createScene returned a null scene!", isServer ? "Server" : "Client" );
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
// Make note of what we've created.
|
||||
String simType = sceneDesc.simType == NX_SIMULATION_SW ? "software" : "hardware";
|
||||
String clientOrServer = this == isServer ? "server" : "client";
|
||||
Con::printf( "PhysXWorld::init() - Created %s %s simulation!",
|
||||
clientOrServer.c_str(),
|
||||
simType.c_str() );
|
||||
*/
|
||||
|
||||
mScene->setTiming( PhysicsMaxTimeStep, PhysicsMaxIterations, NX_TIMESTEP_FIXED );
|
||||
|
||||
// TODO: Add dummy actor with scene name!
|
||||
|
||||
// Set the global contact reporter.
|
||||
|
||||
mConactReporter = new PxContactReporter();
|
||||
mScene->setUserContactReport( mConactReporter );
|
||||
|
||||
// Set the global PxUserNotify
|
||||
|
||||
mUserNotify = new PxUserNotify();
|
||||
mScene->setUserNotify( mUserNotify );
|
||||
|
||||
// Now create the dynamic rigid body compartment which
|
||||
// can reside on the hardware when hardware is present.
|
||||
/*
|
||||
NxCompartmentDesc compartmentDesc;
|
||||
compartmentDesc.type = NX_SCT_RIGIDBODY;
|
||||
compartmentDesc.deviceCode = NX_DC_PPU_AUTO_ASSIGN;
|
||||
mRigidCompartment = mScene->createCompartment( compartmentDesc );
|
||||
if ( !mRigidCompartment )
|
||||
{
|
||||
Con::errorf( "PhysXWorld - Creation of rigid body compartment failed!" );
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
|
||||
// Hook up the tick processing signals for advancing physics.
|
||||
//
|
||||
// First an overview of how physics and the game ticks
|
||||
// interact with each other.
|
||||
//
|
||||
// In Torque you normally tick the server and then the client
|
||||
// approximately every 32ms. So before the game tick we call
|
||||
// getPhysicsResults() to get the new physics state and call
|
||||
// tickPhysics() when the game tick is done to start processing
|
||||
// the next physics state. This means PhysX is happily doing
|
||||
// physics in a separate thread while we're doing rendering,
|
||||
// sound, input, networking, etc.
|
||||
//
|
||||
// Because your frame rate is rarely perfectly even you can
|
||||
// get cases where you may tick the server or the client
|
||||
// several times in a row. This happens most often in debug
|
||||
// mode, but can also happen in release.
|
||||
//
|
||||
// The simple implementation is to do a getPhysicsResults() and
|
||||
// tickPhysics() for each tick. But this very bad! It forces
|
||||
// immediate results from PhysX which blocks the primary thread
|
||||
// and further slows down processing. It leads to slower and
|
||||
// slower frame rates as the simulation is never able to catch
|
||||
// up to the current tick.
|
||||
//
|
||||
// The trick is processing physics once for backlogged ticks
|
||||
// with the total of the elapsed tick time. This is a huge
|
||||
// performance gain and keeps you from blocking on PhysX.
|
||||
//
|
||||
// This does have a side effect that when it occurs you'll get
|
||||
// ticks where the physics state hasn't advanced, but this beats
|
||||
// single digit frame rates.
|
||||
//
|
||||
AssertFatal( processList, "PxWorld::init() - We need a process list to create the world!" );
|
||||
mProcessList = processList;
|
||||
mProcessList->preTickSignal().notify( this, &PxWorld::getPhysicsResults );
|
||||
mProcessList->postTickSignal().notify( this, &PxWorld::tickPhysics, 1000.0f );
|
||||
|
||||
// Setup the default material.
|
||||
NxMaterial *dmat = mScene->getMaterialFromIndex( 0 );
|
||||
dmat->setRestitution( 0.2f );
|
||||
dmat->setStaticFriction( 0.6f );
|
||||
dmat->setDynamicFriction( 0.4f );
|
||||
|
||||
// Setup dominance groups.
|
||||
|
||||
// Group 31 is for debris and other objects which can be pushed but cannot push back.
|
||||
// Group 0 is for everything else.
|
||||
|
||||
NxConstraintDominance debrisDominance( 0.0f, 1.0f );
|
||||
mScene->setDominanceGroupPair( 0, 31, debrisDominance );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void PxWorld::_destroy()
|
||||
{
|
||||
// Make sure the simulation is stopped!
|
||||
getPhysicsResults();
|
||||
_releaseQueues();
|
||||
|
||||
#ifdef TORQUE_DEBUG
|
||||
|
||||
U32 actorCount = mScene->getNbActors();
|
||||
U32 jointCount = mScene->getNbJoints();
|
||||
|
||||
if ( actorCount != 0 || jointCount != 0 )
|
||||
{
|
||||
// Dump the names of any actors or joints that
|
||||
// were not released before the destruction of
|
||||
// this scene.
|
||||
|
||||
for ( U32 i=0; i < actorCount; i++ )
|
||||
{
|
||||
const NxActor *actor = mScene->getActors()[i];
|
||||
Con::errorf( "Orphan NxActor - '%s'!", actor->getName() );
|
||||
}
|
||||
|
||||
mScene->resetJointIterator();
|
||||
for ( ;; )
|
||||
{
|
||||
const NxJoint *joint = mScene->getNextJoint();
|
||||
if ( !joint )
|
||||
break;
|
||||
|
||||
Con::errorf( "Orphan NxJoint - '%s'!", joint->getName() );
|
||||
}
|
||||
|
||||
AssertFatal( false, "PhysXWorld::_destroy() - Some actors and/or joints were not released!" );
|
||||
}
|
||||
|
||||
#endif // TORQUE_DEBUG
|
||||
|
||||
//NxCloseCooking();
|
||||
|
||||
// Release the tick processing signals.
|
||||
if ( mProcessList )
|
||||
{
|
||||
mProcessList->preTickSignal().remove( this, &PxWorld::getPhysicsResults );
|
||||
mProcessList->postTickSignal().remove( this, &PxWorld::tickPhysics );
|
||||
mProcessList = NULL;
|
||||
}
|
||||
|
||||
// Destroy the scene.
|
||||
if ( mScene )
|
||||
{
|
||||
// Delete the contact reporter.
|
||||
mScene->setUserContactReport( NULL );
|
||||
SAFE_DELETE( mConactReporter );
|
||||
|
||||
// First shut down threads... this makes it
|
||||
// safe to release the scene.
|
||||
mScene->shutdownWorkerThreads();
|
||||
|
||||
// Release the scene.
|
||||
gPhysicsSDK->releaseScene( *mScene );
|
||||
mScene = NULL;
|
||||
}
|
||||
|
||||
// Try to restart the sdk if we can.
|
||||
//restartSDK();
|
||||
}
|
||||
|
||||
bool PxWorld::restartSDK( bool destroyOnly, PxWorld *clientWorld, PxWorld *serverWorld )
|
||||
{
|
||||
// If either the client or the server still exist
|
||||
// then we cannot reset the SDK.
|
||||
if ( clientWorld || serverWorld )
|
||||
return false;
|
||||
|
||||
// Destroy the existing SDK.
|
||||
if ( gPhysicsSDK )
|
||||
{
|
||||
NXU::releasePersistentMemory();
|
||||
gPhysicsSDK->release();
|
||||
gPhysicsSDK = NULL;
|
||||
smCooking = NULL;
|
||||
SAFE_DELETE( smConsoleStream );
|
||||
}
|
||||
|
||||
// If we're not supposed to restart... return.
|
||||
if ( destroyOnly )
|
||||
return true;
|
||||
|
||||
smConsoleStream = new PxConsoleStream();
|
||||
|
||||
NxPhysicsSDKDesc sdkDesc;
|
||||
sdkDesc.flags |= NX_SDKF_NO_HARDWARE; // [9/28/2009 Pat] Why is this disabled?
|
||||
|
||||
NxSDKCreateError error;
|
||||
gPhysicsSDK = NxCreatePhysicsSDK( NX_PHYSICS_SDK_VERSION,
|
||||
NULL,
|
||||
smConsoleStream,
|
||||
sdkDesc,
|
||||
&error );
|
||||
if ( !gPhysicsSDK )
|
||||
{
|
||||
Con::errorf( "PhysX failed to initialize! Error code: %d", error );
|
||||
Platform::messageBox( Con::getVariable( "$appName" ),
|
||||
avar("PhysX could not be started!\r\n"
|
||||
"Please be sure you have the latest version of PhysX installed.\r\n"
|
||||
"Error Code: %d", error),
|
||||
MBOk, MIStop );
|
||||
Platform::forceShutdown( -1 );
|
||||
|
||||
// We shouldn't get here, but this shuts up
|
||||
// source diagnostic tools.
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set the default skin width for all actors.
|
||||
gPhysicsSDK->setParameter( NX_SKIN_WIDTH, 0.01f );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void PxWorld::tickPhysics( U32 elapsedMs )
|
||||
{
|
||||
if ( !mScene || !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(PxWorld_TickPhysics);
|
||||
|
||||
// Convert it to seconds.
|
||||
const F32 elapsedSec = (F32)elapsedMs * 0.001f;
|
||||
|
||||
// For some reason this gets reset all the time
|
||||
// and it must be called before the simulate.
|
||||
mScene->setFilterOps( NX_FILTEROP_OR,
|
||||
NX_FILTEROP_OR,
|
||||
NX_FILTEROP_AND );
|
||||
mScene->setFilterBool( false );
|
||||
NxGroupsMask zeroMask;
|
||||
zeroMask.bits0=zeroMask.bits1=zeroMask.bits2=zeroMask.bits3=0;
|
||||
mScene->setFilterConstant0( zeroMask );
|
||||
mScene->setFilterConstant1( zeroMask );
|
||||
|
||||
mScene->simulate( elapsedSec * mEditorTimeScale );
|
||||
mScene->flushStream();
|
||||
mIsSimulating = true;
|
||||
|
||||
//Con::printf( "%s PhysXWorld::tickPhysics!", this == smClientWorld ? "Client" : "Server" );
|
||||
}
|
||||
|
||||
void PxWorld::releaseWriteLocks()
|
||||
{
|
||||
PxWorld *world = dynamic_cast<PxWorld*>( PHYSICSMGR->getWorld( "server" ) );
|
||||
|
||||
if ( world )
|
||||
world->releaseWriteLock();
|
||||
|
||||
world = dynamic_cast<PxWorld*>( PHYSICSMGR->getWorld( "client" ) );
|
||||
|
||||
if ( world )
|
||||
world->releaseWriteLock();
|
||||
}
|
||||
|
||||
void PxWorld::releaseWriteLock()
|
||||
{
|
||||
if ( !mScene || !mIsSimulating )
|
||||
return;
|
||||
|
||||
PROFILE_SCOPE(PxWorld_ReleaseWriteLock);
|
||||
|
||||
// We use checkResults here to release the write lock
|
||||
// but we do not change the simulation flag or increment
|
||||
// the tick count... we may have gotten results, but the
|
||||
// simulation hasn't really ticked!
|
||||
mScene->checkResults( NX_RIGID_BODY_FINISHED, true );
|
||||
AssertFatal( mScene->isWritable(), "PhysXWorld::releaseWriteLock() - We should have been writable now!" );
|
||||
}
|
||||
|
||||
void PxWorld::getPhysicsResults()
|
||||
{
|
||||
if ( !mScene || !mIsSimulating )
|
||||
return;
|
||||
|
||||
PROFILE_SCOPE(PxWorld_GetPhysicsResults);
|
||||
|
||||
// Get results from scene.
|
||||
mScene->fetchResults( NX_RIGID_BODY_FINISHED, true );
|
||||
mIsSimulating = false;
|
||||
mTickCount++;
|
||||
|
||||
// Release any joints/actors that were waiting
|
||||
// for the scene to become writable.
|
||||
_releaseQueues();
|
||||
|
||||
//Con::printf( "%s PhysXWorld::getPhysicsResults!", this == smClientWorld ? "Client" : "Server" );
|
||||
}
|
||||
|
||||
NxMaterial* PxWorld::createMaterial( NxMaterialDesc &material )
|
||||
{
|
||||
if ( !mScene )
|
||||
return NULL;
|
||||
|
||||
// We need the writelock to create a material!
|
||||
releaseWriteLock();
|
||||
|
||||
NxMaterial *mat = mScene->createMaterial( material );
|
||||
if ( !mat )
|
||||
return NULL;
|
||||
|
||||
return mat;
|
||||
}
|
||||
|
||||
NxController* PxWorld::createController( NxControllerDesc &desc )
|
||||
{
|
||||
if ( !mScene )
|
||||
return NULL;
|
||||
|
||||
// We need the writelock!
|
||||
releaseWriteLock();
|
||||
|
||||
return mControllerManager->createController( mScene, desc );
|
||||
}
|
||||
|
||||
void PxWorld::releaseActor( NxActor &actor )
|
||||
{
|
||||
AssertFatal( &actor.getScene() == mScene, "PhysXWorld::releaseActor() - Bad scene!" );
|
||||
|
||||
// Clear the userdata.
|
||||
actor.userData = NULL;
|
||||
|
||||
// If the scene is not simulating then we have the
|
||||
// write lock and can safely delete it now.
|
||||
if ( !mIsSimulating )
|
||||
{
|
||||
mScene->releaseActor( actor );
|
||||
}
|
||||
else
|
||||
{
|
||||
mReleaseActorQueue.push_back( &actor );
|
||||
}
|
||||
}
|
||||
|
||||
void PxWorld::releaseMaterial( NxMaterial &mat )
|
||||
{
|
||||
AssertFatal( &mat.getScene() == mScene, "PhysXWorld::releaseMaterial() - Bad scene!" );
|
||||
|
||||
// If the scene is not simulating then we have the
|
||||
// write lock and can safely delete it now.
|
||||
if ( !mIsSimulating )
|
||||
mScene->releaseMaterial( mat );
|
||||
else
|
||||
mReleaseMaterialQueue.push_back( &mat );
|
||||
}
|
||||
|
||||
void PxWorld::releaseHeightField( NxHeightField &heightfield )
|
||||
{
|
||||
// Always delay releasing a heightfield, for whatever reason,
|
||||
// it causes lots of deadlock asserts if we do it here, even if
|
||||
// the scene "says" its writable.
|
||||
//
|
||||
// Actually this is probably because a heightfield is owned by the "sdk" and
|
||||
// not an individual scene so if either the client "or" server scene are
|
||||
// simulating it asserts, thats just my theory.
|
||||
|
||||
mReleaseHeightFieldQueue.push_back( &heightfield );
|
||||
}
|
||||
|
||||
void PxWorld::releaseJoint( NxJoint &joint )
|
||||
{
|
||||
AssertFatal( &joint.getScene() == mScene, "PhysXWorld::releaseJoint() - Bad scene!" );
|
||||
|
||||
AssertFatal( !mReleaseJointQueue.contains( &joint ),
|
||||
"PhysXWorld::releaseJoint() - Joint already exists in the release queue!" );
|
||||
|
||||
// Clear the userdata.
|
||||
joint.userData = NULL;
|
||||
|
||||
// If the scene is not simulating then we have the
|
||||
// write lock and can safely delete it now.
|
||||
if ( !mIsSimulating )
|
||||
mScene->releaseJoint( joint );
|
||||
else
|
||||
mReleaseJointQueue.push_back( &joint );
|
||||
}
|
||||
|
||||
void PxWorld::releaseCloth( NxCloth &cloth )
|
||||
{
|
||||
AssertFatal( &cloth.getScene() == mScene, "PhysXWorld::releaseCloth() - Bad scene!" );
|
||||
|
||||
// Clear the userdata.
|
||||
cloth.userData = NULL;
|
||||
|
||||
// If the scene is not simulating then we have the
|
||||
// write lock and can safely delete it now.
|
||||
if ( !mIsSimulating )
|
||||
mScene->releaseCloth( cloth );
|
||||
else
|
||||
mReleaseClothQueue.push_back( &cloth );
|
||||
}
|
||||
|
||||
void PxWorld::releaseFluid( NxFluid &fluid )
|
||||
{
|
||||
AssertFatal( &fluid.getScene() == mScene, "PhysXWorld::releaseFluid() - Bad scene!" );
|
||||
|
||||
// Clear the userdata.
|
||||
fluid.userData = NULL;
|
||||
|
||||
// If the scene is not simulating then we have the
|
||||
// write lock and can safely delete it now.
|
||||
if ( !mIsSimulating )
|
||||
mScene->releaseFluid( fluid );
|
||||
else
|
||||
mReleaseFluidQueue.push_back( &fluid );
|
||||
}
|
||||
|
||||
void PxWorld::releaseClothMesh( NxClothMesh &clothMesh )
|
||||
{
|
||||
// We need the writelock to release.
|
||||
releaseWriteLock();
|
||||
|
||||
gPhysicsSDK->releaseClothMesh( clothMesh );
|
||||
}
|
||||
|
||||
void PxWorld::releaseController( NxController &controller )
|
||||
{
|
||||
// TODO: This isn't safe to do with actors and
|
||||
// joints, so we probably need a queue like we
|
||||
// do for them.
|
||||
|
||||
// We need the writelock to release.
|
||||
releaseWriteLock();
|
||||
|
||||
mControllerManager->releaseController( controller );
|
||||
}
|
||||
|
||||
void PxWorld::_releaseQueues()
|
||||
{
|
||||
AssertFatal( mScene, "PhysXWorld::_releaseQueues() - The scene is null!" );
|
||||
|
||||
// We release joints still pending in the queue
|
||||
// first as they depend on the actors.
|
||||
for ( S32 i = 0; i < mReleaseJointQueue.size(); i++ )
|
||||
{
|
||||
NxJoint *currJoint = mReleaseJointQueue[i];
|
||||
mScene->releaseJoint( *currJoint );
|
||||
}
|
||||
|
||||
// All the joints should be released, clear the queue.
|
||||
mReleaseJointQueue.clear();
|
||||
|
||||
// Now release any actors still pending in the queue.
|
||||
for ( S32 i = 0; i < mReleaseActorQueue.size(); i++ )
|
||||
{
|
||||
NxActor *currActor = mReleaseActorQueue[i];
|
||||
mScene->releaseActor( *currActor );
|
||||
}
|
||||
|
||||
// All the actors should be released, clear the queue.
|
||||
mReleaseActorQueue.clear();
|
||||
|
||||
// Now release any materials still pending in the queue.
|
||||
for ( S32 i = 0; i < mReleaseMaterialQueue.size(); i++ )
|
||||
{
|
||||
NxMaterial *currMat = mReleaseMaterialQueue[i];
|
||||
mScene->releaseMaterial( *currMat );
|
||||
}
|
||||
|
||||
// All the materials should be released, clear the queue.
|
||||
mReleaseMaterialQueue.clear();
|
||||
|
||||
// Now release any cloth still pending in the queue.
|
||||
for ( S32 i = 0; i < mReleaseClothQueue.size(); i++ )
|
||||
{
|
||||
NxCloth *currCloth = mReleaseClothQueue[i];
|
||||
mScene->releaseCloth( *currCloth );
|
||||
}
|
||||
|
||||
// All the actors should be released, clear the queue.
|
||||
mReleaseClothQueue.clear();
|
||||
|
||||
// Release heightfields that don't still have references.
|
||||
for ( S32 i = 0; i < mReleaseHeightFieldQueue.size(); i++ )
|
||||
{
|
||||
NxHeightField *currHeightfield = mReleaseHeightFieldQueue[i];
|
||||
|
||||
if ( currHeightfield->getReferenceCount() == 0 )
|
||||
{
|
||||
gPhysicsSDK->releaseHeightField( *currHeightfield );
|
||||
mReleaseHeightFieldQueue.erase_fast( i );
|
||||
i--;
|
||||
}
|
||||
}
|
||||
|
||||
// Clear fluid queue
|
||||
for ( S32 i = 0; i < mReleaseFluidQueue.size(); i++ )
|
||||
{
|
||||
NxFluid *currFluid = mReleaseFluidQueue[i];
|
||||
mScene->releaseFluid( *currFluid );
|
||||
}
|
||||
mReleaseFluidQueue.clear();
|
||||
}
|
||||
|
||||
void PxWorld::setEnabled( bool enabled )
|
||||
{
|
||||
mIsEnabled = enabled;
|
||||
|
||||
if ( !mIsEnabled )
|
||||
getPhysicsResults();
|
||||
}
|
||||
|
||||
bool PxWorld::initWorld( bool isServer, ProcessList *processList )
|
||||
{
|
||||
/* This stuff is handled outside.
|
||||
PxWorld* world = PxWorld::getWorld( isServer );
|
||||
if ( world )
|
||||
{
|
||||
Con::errorf( "PhysXWorld::initWorld - %s world already exists!", isServer ? "Server" : "Client" );
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
|
||||
if ( !_init( isServer, processList ) )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void PxWorld::destroyWorld()
|
||||
{
|
||||
//PxWorld* world = PxWorld::getWorld( serverWorld );
|
||||
/*
|
||||
if ( !world )
|
||||
{
|
||||
Con::errorf( "PhysXWorld::destroyWorld - %s world already destroyed!", serverWorld ? "Server" : "Client" );
|
||||
return;
|
||||
}
|
||||
*/
|
||||
//world->_destroy();
|
||||
//delete world;
|
||||
|
||||
_destroy();
|
||||
}
|
||||
|
||||
bool PxWorld::castRay( const Point3F &startPnt, const Point3F &endPnt, RayInfo *ri, const Point3F &impulse )
|
||||
{
|
||||
NxRay worldRay;
|
||||
worldRay.orig = pxCast<NxVec3>( startPnt );
|
||||
worldRay.dir = pxCast<NxVec3>( endPnt - startPnt );
|
||||
NxF32 maxDist = worldRay.dir.magnitude();
|
||||
worldRay.dir.normalize();
|
||||
|
||||
U32 groups = 0xffffffff;
|
||||
groups &= ~( 1<<31 ); // No trigger shapes!
|
||||
|
||||
NxRaycastHit hitInfo;
|
||||
NxShape *hitShape = mScene->raycastClosestShape( worldRay, NX_ALL_SHAPES, hitInfo, groups, maxDist );
|
||||
|
||||
if ( !hitShape )
|
||||
return false;
|
||||
|
||||
//if ( hitShape->userData != NULL )
|
||||
// return false;
|
||||
|
||||
NxActor &actor = hitShape->getActor();
|
||||
PhysicsUserData *userData = PhysicsUserData::cast( actor.userData );
|
||||
|
||||
if ( ri )
|
||||
{
|
||||
ri->object = ( userData != NULL ) ? userData->getObject() : NULL;
|
||||
|
||||
// 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 = hitInfo.distance;
|
||||
ri->normal = pxCast<Point3F>( hitInfo.worldNormal );
|
||||
ri->point = pxCast<Point3F>( hitInfo.worldImpact );
|
||||
ri->t = maxDist / hitInfo.distance;
|
||||
}
|
||||
|
||||
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* PxWorld::castRay( const Point3F &start, const Point3F &end, U32 bodyTypes )
|
||||
{
|
||||
NxRay worldRay;
|
||||
worldRay.orig = pxCast<NxVec3>( start );
|
||||
worldRay.dir = pxCast<NxVec3>( end - start );
|
||||
F32 maxDist = worldRay.dir.normalize();
|
||||
|
||||
U32 groups = 0xFFFFFFFF;
|
||||
if ( !( bodyTypes & BT_Player ) )
|
||||
groups &= ~( 1<<29 );
|
||||
|
||||
// TODO: For now always skip triggers and debris,
|
||||
// but we should consider how game specifc this API
|
||||
// should be in the future.
|
||||
groups &= ~( 1<<31 ); // triggers
|
||||
groups &= ~( 1<<30 ); // debris
|
||||
|
||||
U32 shapesType = 0;
|
||||
if ( bodyTypes & BT_Static )
|
||||
shapesType |= NX_STATIC_SHAPES;
|
||||
if ( bodyTypes & BT_Dynamic )
|
||||
shapesType |= NX_DYNAMIC_SHAPES;
|
||||
|
||||
NxRaycastHit hitInfo;
|
||||
NxShape *hitShape = mScene->raycastClosestShape( worldRay, (NxShapesType)shapesType, hitInfo, groups, maxDist );
|
||||
if ( !hitShape )
|
||||
return NULL;
|
||||
|
||||
NxActor &actor = hitShape->getActor();
|
||||
PhysicsUserData *userData = PhysicsUserData::cast( actor.userData );
|
||||
if ( !userData )
|
||||
return NULL;
|
||||
|
||||
return userData->getBody();
|
||||
}
|
||||
|
||||
void PxWorld::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 );
|
||||
}
|
||||
}
|
||||
|
||||
static ColorI getDebugColor( NxU32 packed )
|
||||
{
|
||||
ColorI col;
|
||||
col.blue = (packed)&0xff;
|
||||
col.green = (packed>>8)&0xff;
|
||||
col.red = (packed>>16)&0xff;
|
||||
col.alpha = 255;
|
||||
|
||||
return col;
|
||||
}
|
||||
|
||||
void PxWorld::onDebugDraw( const SceneRenderState *state )
|
||||
{
|
||||
if ( !mScene )
|
||||
return;
|
||||
|
||||
// We need the write lock to be able to request
|
||||
// the NxDebugRenderable object.
|
||||
releaseWriteLock();
|
||||
|
||||
// TODO: We need to expose the different types of visualization
|
||||
// options to script and add a GUI for toggling them!
|
||||
|
||||
gPhysicsSDK->setParameter( NX_VISUALIZATION_SCALE, 1.0f );
|
||||
//gPhysicsSDK->setParameter( NX_VISUALIZE_BODY_MASS_AXES, 0.0f );
|
||||
gPhysicsSDK->setParameter( NX_VISUALIZE_BODY_AXES, 1.0f );
|
||||
gPhysicsSDK->setParameter( NX_VISUALIZE_COLLISION_SHAPES, 1.0f );
|
||||
|
||||
const NxDebugRenderable *data = mScene->getDebugRenderable();
|
||||
if ( !data )
|
||||
return;
|
||||
|
||||
// Render points
|
||||
{
|
||||
NxU32 numPoints = data->getNbPoints();
|
||||
const NxDebugPoint *points = data->getPoints();
|
||||
|
||||
PrimBuild::begin( GFXPointList, numPoints );
|
||||
|
||||
while ( numPoints-- )
|
||||
{
|
||||
PrimBuild::color( getDebugColor(points->color) );
|
||||
PrimBuild::vertex3fv( &points->p.x );
|
||||
points++;
|
||||
}
|
||||
|
||||
PrimBuild::end();
|
||||
}
|
||||
|
||||
// Render lines
|
||||
{
|
||||
NxU32 numLines = data->getNbLines();
|
||||
const NxDebugLine *lines = data->getLines();
|
||||
|
||||
PrimBuild::begin( GFXLineList, numLines * 2 );
|
||||
|
||||
while ( numLines-- )
|
||||
{
|
||||
PrimBuild::color( getDebugColor( lines->color ) );
|
||||
PrimBuild::vertex3fv( &lines->p0.x );
|
||||
PrimBuild::vertex3fv( &lines->p1.x );
|
||||
lines++;
|
||||
}
|
||||
|
||||
PrimBuild::end();
|
||||
}
|
||||
|
||||
// Render triangles
|
||||
{
|
||||
NxU32 numTris = data->getNbTriangles();
|
||||
const NxDebugTriangle *triangles = data->getTriangles();
|
||||
|
||||
PrimBuild::begin( GFXTriangleList, numTris * 3 );
|
||||
|
||||
while ( numTris-- )
|
||||
{
|
||||
PrimBuild::color( getDebugColor( triangles->color ) );
|
||||
PrimBuild::vertex3fv( &triangles->p0.x );
|
||||
PrimBuild::vertex3fv( &triangles->p1.x );
|
||||
PrimBuild::vertex3fv( &triangles->p2.x );
|
||||
triangles++;
|
||||
}
|
||||
|
||||
PrimBuild::end();
|
||||
}
|
||||
}
|
||||
193
Engine/source/T3D/physics/physx/pxWorld.h
Normal file
193
Engine/source/T3D/physics/physx/pxWorld.h
Normal file
|
|
@ -0,0 +1,193 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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 _PHYSX_WORLD_H_
|
||||
#define _PHYSX_WORLD_H_
|
||||
|
||||
#ifndef _T3D_PHYSICS_PHYSICSWORLD_H_
|
||||
#include "T3D/physics/physicsWorld.h"
|
||||
#endif
|
||||
#ifndef _MMATH_H_
|
||||
#include "math/mMath.h"
|
||||
#endif
|
||||
#ifndef _PHYSX_H_
|
||||
#include "T3D/physics/physX/px.h"
|
||||
#endif
|
||||
#ifndef _TVECTOR_H_
|
||||
#include "core/util/tVector.h"
|
||||
#endif
|
||||
|
||||
class PxContactReporter;
|
||||
class PxUserNotify;
|
||||
class NxController;
|
||||
class NxControllerDesc;
|
||||
class ShapeBase;
|
||||
class TSStatic;
|
||||
class SceneObject;
|
||||
class ProcessList;
|
||||
class GameBase;
|
||||
class CharacterControllerManager;
|
||||
class PxConsoleStream;
|
||||
|
||||
|
||||
class PxWorld : public PhysicsWorld
|
||||
{
|
||||
protected:
|
||||
|
||||
F32 mEditorTimeScale;
|
||||
|
||||
Vector<NxCloth*> mReleaseClothQueue;
|
||||
Vector<NxJoint*> mReleaseJointQueue;
|
||||
Vector<NxActor*> mReleaseActorQueue;
|
||||
Vector<NxMaterial*> mReleaseMaterialQueue;
|
||||
Vector<NxHeightField*> mReleaseHeightFieldQueue;
|
||||
Vector<NxFluid*> mReleaseFluidQueue;
|
||||
//Vector<StrongRefPtr<PxCollision>> mReleaseColQueue;
|
||||
|
||||
Vector<NxActor*> mCatchupQueue;
|
||||
|
||||
PxContactReporter *mConactReporter;
|
||||
|
||||
PxUserNotify *mUserNotify;
|
||||
|
||||
NxScene *mScene;
|
||||
|
||||
CharacterControllerManager *mControllerManager;
|
||||
|
||||
bool mErrorReport;
|
||||
|
||||
bool mIsEnabled;
|
||||
|
||||
bool mIsSimulating;
|
||||
|
||||
U32 mTickCount;
|
||||
|
||||
ProcessList *mProcessList;
|
||||
|
||||
bool _init( bool isServer, ProcessList *processList );
|
||||
|
||||
void _destroy();
|
||||
|
||||
void _releaseQueues();
|
||||
|
||||
void _updateScheduledStatics();
|
||||
|
||||
/// The mesh cooking interface which is loaded on first use.
|
||||
/// @see getCooking
|
||||
static NxCookingInterface *smCooking;
|
||||
|
||||
/// The console stream for PhysX error reporting.
|
||||
static PxConsoleStream *smConsoleStream;
|
||||
|
||||
public:
|
||||
|
||||
// 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 = BT_All );
|
||||
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; }
|
||||
|
||||
/// @name Static Methods
|
||||
/// @{
|
||||
|
||||
static bool restartSDK( bool destroyOnly = false, PxWorld *clientWorld = NULL, PxWorld *serverWorld = NULL );
|
||||
|
||||
static void releaseWriteLocks();
|
||||
|
||||
/// @}
|
||||
|
||||
PxWorld();
|
||||
virtual ~PxWorld();
|
||||
|
||||
public:
|
||||
|
||||
NxScene* getScene() { return mScene; }
|
||||
|
||||
/// Returns the cooking interface. Will only return NULL
|
||||
/// in the case of a missing or bad PhysX install.
|
||||
static NxCookingInterface* getCooking();
|
||||
|
||||
U32 getTick() { return mTickCount; }
|
||||
|
||||
void tickPhysics( U32 elapsedMs );
|
||||
|
||||
void getPhysicsResults();
|
||||
|
||||
//void enableCatchupMode( GameBase *obj );
|
||||
|
||||
bool isWritable() const { return !mIsSimulating; /* mScene->isWritable(); */ }
|
||||
|
||||
void releaseWriteLock();
|
||||
|
||||
void setEnabled( bool enabled );
|
||||
bool getEnabled() const { return mIsEnabled; }
|
||||
|
||||
NxMaterial* createMaterial( NxMaterialDesc &material );
|
||||
|
||||
///
|
||||
/// @see releaseController
|
||||
NxController* createController( NxControllerDesc &desc );
|
||||
|
||||
//U16 setMaterial(NxMaterialDesc &material, U16 id);
|
||||
|
||||
// NOTE: This is all a mess, but its a side effect of how
|
||||
// PhysX works. Many objects cannot be deleted without write
|
||||
// access to the scene. Worse some objects cannot be deleted
|
||||
// until their owner objects are deleted first.
|
||||
//
|
||||
// For these reasons we have these methods to register objects to be
|
||||
// released after the Scene has been ticked.
|
||||
//
|
||||
// Since there is no common base to PhysX objects we're stuck with
|
||||
// this list of release methods.
|
||||
//
|
||||
|
||||
void releaseActor( NxActor &actor );
|
||||
|
||||
void releaseMaterial( NxMaterial &mat );
|
||||
|
||||
void releaseJoint( NxJoint &joint );
|
||||
|
||||
void releaseCloth( NxCloth &cloth );
|
||||
|
||||
void releaseClothMesh( NxClothMesh &clothMesh );
|
||||
|
||||
void releaseController( NxController &controller );
|
||||
|
||||
void releaseHeightField( NxHeightField &heightfield );
|
||||
|
||||
void releaseFluid( NxFluid &fluid );
|
||||
|
||||
//void releaseCol( PxCollision *col );
|
||||
|
||||
/// Returns the contact reporter for this scene.
|
||||
PxContactReporter* getContactReporter() { return mConactReporter; }
|
||||
|
||||
void setEditorTimeScale( F32 timeScale ) { mEditorTimeScale = timeScale; }
|
||||
const F32 getEditorTimeScale() const { return mEditorTimeScale; }
|
||||
};
|
||||
|
||||
#endif // _PHYSX_WORLD_H_
|
||||
Loading…
Add table
Add a link
Reference in a new issue