Physx 2.8 removal

This commit is contained in:
rextimmy 2017-01-04 13:34:33 +10:00
parent f42c9bd9b7
commit 215ae090b4
26 changed files with 0 additions and 8421 deletions

View file

@ -1,80 +0,0 @@
//-----------------------------------------------------------------------------
// 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_WIN) && !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_

View file

@ -1,404 +0,0 @@
//-----------------------------------------------------------------------------
// 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 );
}

View file

@ -1,114 +0,0 @@
//-----------------------------------------------------------------------------
// 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_

View file

@ -1,150 +0,0 @@
//-----------------------------------------------------------------------------
// 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_

View file

@ -1,923 +0,0 @@
//-----------------------------------------------------------------------------
// 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 ) );
}

View file

@ -1,176 +0,0 @@
//-----------------------------------------------------------------------------
// 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_

View file

@ -1,291 +0,0 @@
//-----------------------------------------------------------------------------
// 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;
}

View file

@ -1,78 +0,0 @@
//-----------------------------------------------------------------------------
// 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_

View file

@ -1,108 +0,0 @@
//-----------------------------------------------------------------------------
// 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;
}

View file

@ -1,54 +0,0 @@
//-----------------------------------------------------------------------------
// 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_

View file

@ -1,310 +0,0 @@
//-----------------------------------------------------------------------------
// 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]) );
}

View file

@ -1,107 +0,0 @@
//-----------------------------------------------------------------------------
// 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_

View file

@ -1,150 +0,0 @@
//-----------------------------------------------------------------------------
// 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 );
}

View file

@ -1,69 +0,0 @@
//-----------------------------------------------------------------------------
// 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

File diff suppressed because it is too large Load diff

View file

@ -1,398 +0,0 @@
//-----------------------------------------------------------------------------
// 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

View file

@ -1,428 +0,0 @@
//-----------------------------------------------------------------------------
// 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->getStaticChangedSignal().remove( this, &PxPlayer::_onStaticChanged );
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;
}
mWorld->getStaticChangedSignal().notify( this, &PxPlayer::_onStaticChanged );
// 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::_onStaticChanged()
{
mController->reportSceneChanged();
}
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;
}

View file

@ -1,106 +0,0 @@
//-----------------------------------------------------------------------------
// 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 );
void _onStaticChanged();
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

View file

@ -1,297 +0,0 @@
//-----------------------------------------------------------------------------
// 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_WIN) || 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!" );
}
}

View file

@ -1,59 +0,0 @@
//-----------------------------------------------------------------------------
// 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_

View file

@ -1,174 +0,0 @@
//-----------------------------------------------------------------------------
// 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 );
}

View file

@ -1,78 +0,0 @@
//-----------------------------------------------------------------------------
// 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_

View file

@ -1,109 +0,0 @@
//-----------------------------------------------------------------------------
// 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

View file

@ -1,38 +0,0 @@
//-----------------------------------------------------------------------------
// 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_

View file

@ -1,876 +0,0 @@
//-----------------------------------------------------------------------------
// 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;
// actors are one of the few objects that are stable removing this way in physx 2.8
if (mScene->isWritable() )
{
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.
bool staticChanged = false;
for ( S32 i = 0; i < mReleaseActorQueue.size(); i++ )
{
NxActor *currActor = mReleaseActorQueue[i];
staticChanged |= !currActor->isDynamic();
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();
if ( staticChanged )
mStaticChangedSignal.trigger();
}
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();
}
}

View file

@ -1,193 +0,0 @@
//-----------------------------------------------------------------------------
// 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_