Skip to content

Instantly share code, notes, and snippets.

@andr3wmac
Last active January 4, 2016 02:08
Show Gist options
  • Save andr3wmac/8552604 to your computer and use it in GitHub Desktop.
Save andr3wmac/8552604 to your computer and use it in GitHub Desktop.
Torque3D 3.5 MIT - PhysX 3.3 Cloth
//-----------------------------------------------------------------------------
// Copyright (c) 2014 Andrew MacIntyre
//
// 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/physx3/px3Cloth.h"
#include "T3D/physics/physx3/px3.h"
#include "T3D/physics/physx3/px3World.h"
#include "T3D/physics/physx3/px3Plugin.h"
#include "T3D/physics/physx3/px3Cast.h"
#include "T3D/physics/physx3/px3Stream.h"
#include "console/consoleTypes.h"
#include "scene/sceneManager.h"
#include "scene/sceneRenderState.h"
#include "renderInstance/renderPassManager.h"
#include "lighting/lightQuery.h"
#include "gfx/gfxDrawUtil.h"
#include "math/mathIO.h"
#include "core/stream/bitStream.h"
#include "materials/materialManager.h"
#include "materials/baseMatInstance.h"
#include "T3D/fx/particleEmitter.h"
IMPLEMENT_CO_NETOBJECT_V1( Px3Cloth );
ConsoleDocClass( Px3Cloth,
"@brief Rectangular patch of cloth simulated by PhysX.\n\n"
"@ingroup Physics"
);
enum Px3ClothAttachment {};
DefineBitfieldType( Px3ClothAttachment );
ImplementBitfieldType( Px3ClothAttachment,
"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;
Px3Cloth::Px3Cloth()
: mWorld( NULL ),
mScene( NULL ),
mMatInst( NULL )
{
mVertexRenderBuffer = NULL;
mIndexRenderBuffer = NULL;
mClothMesh = NULL;
mCloth = NULL;
mVertices.clear();
mPrimitives.clear();
mPatchVerts.set( 8, 8 );
mPatchSize.set( 8.0f, 8.0f );
mNetFlags.set( Ghostable | ScopeAlways );
mTypeMask |= StaticObjectType | StaticShapeObjectType;
mCollisionEnabled = false;
mWindEnabled = false;
mThickness = 0.1f;
mSolverFrequency = 120.0f;
mDampingCoef = 0.0f;
mStretchVertical = 1.0f;
mStretchHorizontal = 0.9f;
mStretchShearing = 0.75f;
mStretchBending = 0.5f;
mAttachmentMask = 0;
}
Px3Cloth::~Px3Cloth()
{
}
bool Px3Cloth::onAdd()
{
if ( !Parent::onAdd() )
return false;
// Cloth is only created on the client.
if ( isClientObject() )
{
mWorld = dynamic_cast<Px3World*>( PHYSICSMGR->getWorld( "client" ) );
if ( !mWorld || !mWorld->getScene() )
{
Con::errorf( "Px3Cloth::onAdd() - PhysXWorld not initialized... cloth disabled!" );
return true;
}
mScene = mWorld->getScene();
mResetXfm = getTransform();
_createClothPatch();
PhysicsPlugin::getPhysicsResetSignal().notify( this, &Px3Cloth::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 Px3Cloth::onRemove()
{
SAFE_DELETE( mMatInst );
if ( isClientObject() )
{
_releaseMesh();
_releaseCloth();
SAFE_DELETE(mVertexRenderBuffer);
SAFE_DELETE(mIndexRenderBuffer);
PhysicsPlugin::getPhysicsResetSignal().remove( this, &Px3Cloth::onPhysicsReset );
}
removeFromScene();
Parent::onRemove();
}
void Px3Cloth::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 Px3Cloth::initPersistFields()
{
Parent::initPersistFields();
addField( "material", TypeMaterialName, Offset( mMaterialName, Px3Cloth ),
"@brief Name of the material to render.\n\n" );
addField( "size", TypePoint2F, Offset( mPatchSize, Px3Cloth ),
"@brief The width and height of the cloth.\n\n" );
addField( "attachments", TYPEID< Px3ClothAttachment >(), Offset( mAttachmentMask, Px3Cloth ),
"@brief Optional way to specify cloth verts that will be attached to the world position "
"it is created at.\n\n" );
addGroup( "Simulation" );
addField( "frequency", TypeF32, Offset( mSolverFrequency, Px3Cloth ),
"@brief Iterations per second of cloth simulation.\n\n" );
addField( "samples", TypePoint2I, Offset( mPatchVerts, Px3Cloth ),
"@brief The number of cloth vertices in width and length.\n\n"
"At least two verts should be defined.\n\n");
endGroup( "Simulation" );
addGroup( "Stretching" );
addField( "damping_coef", TypeF32, Offset( mDampingCoef, Px3Cloth ),
"@brief Value between 0 and 1\n\n" );
addField( "stretch_vertical", TypeF32, Offset( mStretchVertical, Px3Cloth ),
"@brief Value between 0 and 1\n\n" );
addField( "stretch_horizontal", TypeF32, Offset( mStretchHorizontal, Px3Cloth ),
"@brief Value between 0 and 1\n\n" );
addField( "stretch_shearing", TypeF32, Offset( mStretchShearing, Px3Cloth ),
"@brief Value between 0 and 1\n\n" );
addField( "stretch_bending", TypeF32, Offset( mStretchBending, Px3Cloth ),
"@brief Value between 0 and 1\n\n" );
endGroup( "Stretching" );
addField( "Collision", TypeBool, Offset( mCollisionEnabled, Px3Cloth ),
"@brief Enables or disables collision with the rest of the world.\n\n" );
addField( "Wind", TypeBool, Offset( mWindEnabled, Px3Cloth ),
"@brief Enables or disables wind driven by forest wind emitter.\n\n" );
// Cloth doesn't support scale.
removeField( "scale" );
}
void Px3Cloth::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 Px3Cloth::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( mCollisionEnabled );
stream->writeFlag( mWindEnabled );
stream->write( mSolverFrequency );
stream->write( mDampingCoef );
stream->write( mStretchVertical );
stream->write( mStretchHorizontal );
stream->write( mStretchShearing );
stream->write( mStretchBending );
}
return retMask;
}
void Px3Cloth::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();
}
mCollisionEnabled = stream->readFlag();
mWindEnabled = stream->readFlag();
stream->read( &mSolverFrequency );
stream->read( &mDampingCoef );
stream->read( &mStretchVertical );
stream->read( &mStretchHorizontal );
stream->read( &mStretchShearing );
stream->read( &mStretchBending );
if ( isClientObject() &&
isProperlyAdded() &&
mWorld && !mCloth )
{
_createClothPatch();
}
_updateClothProperties();
}
}
void Px3Cloth::_recreateCloth( const MatrixF &transform )
{
if ( !mWorld )
{
_updateStaticCloth();
return;
}
mWorld->getPhysicsResults();
Parent::setTransform( transform );
_createClothPatch();
}
void Px3Cloth::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 Px3Cloth::setScale( const VectorF &scale )
{
// Cloth doesn't support scale as it has plenty
// of complications... sharing meshes, thickness,
// transform origin, etc.
return;
}
void Px3Cloth::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 Px3Cloth::_releaseMesh()
{
if ( !mClothMesh )
return;
mClothMesh->release();
}
void Px3Cloth::_releaseCloth()
{
if ( !mCloth )
return;
mScene->removeActor( *mCloth );
mCloth->release();
mCloth = NULL;
}
void Px3Cloth::_initBuffers()
{
// Allocate Render Buffer for Vertices if it hasn't been done before+
int maxVertices = mNumVertices * 3;
int maxIndicies = mNumIndices * 3;
mVertexRenderBuffer = new GFXVertexPNTT[maxVertices];
mIndexRenderBuffer = new U16[maxIndicies];
// 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 );
}
}
mMeshDirtyFlags = 0;
}
void Px3Cloth::_generateVertices()
{
// 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;
F32 patchWidth = mPatchSize.x / (F32)( mPatchVerts.x - 1 );
F32 patchHeight = mPatchSize.y / (F32)( mPatchVerts.y - 1 );
// Set up attachments
// Bottom right = bit 0
// Bottom left = bit 1
// Top right = bit 2
// Top left = bit 3
bool bRight = mAttachmentMask & BIT( 0 );
bool bLeft = mAttachmentMask & BIT( 1 );
bool tRight = mAttachmentMask & BIT( 2 );
bool tLeft = mAttachmentMask & BIT( 3 );
mVertices.clear();
for (U32 i = 0; i < mPatchVerts.y; i++)
{
for (U32 j = 0; j < mPatchVerts.x; j++)
{
// Attachments handled with inverse weighting.
float weight = 0.8f;
if ( i == 0 && j == 0 && bLeft ) weight = 0.0f;
if ( i == 0 && j == (mPatchVerts.x - 1) && bRight ) weight = 0.0f;
if ( i == (mPatchVerts.y - 1) && j == 0 && tLeft ) weight = 0.0f;
if ( i == (mPatchVerts.y - 1) && j == (mPatchVerts.x - 1) && tRight ) weight = 0.0f;
mVertices.push_back(physx::PxClothParticle(physx::PxVec3(patchWidth * j, 0.0f, patchHeight * i), weight));
}
}
int width = mPatchVerts.x;
int height = mPatchVerts.y;
// Generate list of primitives
mNumPrimitives = 0;
mPrimitives.clear();
for (U32 y = 0; y < height - 1; y++)
{
for (U32 x = 0; x < width - 1; x++)
{
U32 x1 = x + (y * width);
mPrimitives.push_back(x1);
mPrimitives.push_back(x1 + 1);
U32 y1 = x1 + width;
mPrimitives.push_back(y1);
mPrimitives.push_back(y1 + 1);
mNumPrimitives++;
}
}
_initBuffers();
}
bool Px3Cloth::_createClothPatch()
{
// Make sure we can change the world.
mWorld->releaseWriteLock();
// Generate Vert/Prim data.
_generateVertices();
// Create Cloth Mesh Description.
physx::PxClothMeshDesc meshDesc;
meshDesc.points.data = &mVertices[0];
meshDesc.points.count = mNumVertices;
meshDesc.points.stride = sizeof(physx::PxClothParticle);
meshDesc.invMasses.data = &mVertices[0].invWeight;
meshDesc.invMasses.count = mNumVertices;
meshDesc.invMasses.stride = sizeof(physx::PxClothParticle);
meshDesc.quads.data = &mPrimitives[0];
meshDesc.quads.count = mNumPrimitives;
meshDesc.quads.stride = sizeof(physx::PxU32) * 4;
physx::PxClothFabric* clothFabric = physx::PxClothFabricCreate(*gPhysics3SDK, meshDesc, physx::PxVec3(0, 0, 0));
// Apply transform
physx::PxTransform out;
QuatF q;
q.set(getTransform());
out.q = px3Cast<physx::PxQuat>(q);
out.p = px3Cast<physx::PxVec3>(getTransform().getPosition());
// Delete old cloth, create new cloth.
_releaseCloth();
physx::PxCloth* cloth = gPhysics3SDK->createCloth(out, *clothFabric, &mVertices[0], physx::PxClothFlags());
if ( cloth )
{
mScene->addActor(*cloth);
mCloth = cloth;
_updateClothProperties();
mIsVBDirty = true;
}
_updateStaticCloth();
return true;
}
void Px3Cloth::_updateClothProperties()
{
if ( !mCloth )
return;
mCloth->setClothFlag(physx::PxClothFlag::eSCENE_COLLISION, mCollisionEnabled);
mCloth->setSolverFrequency(mSolverFrequency);
mCloth->setDampingCoefficient(physx::PxVec3(mDampingCoef));
// Stretch Config
mCloth->setStretchConfig(physx::PxClothFabricPhaseType::eVERTICAL, physx::PxClothStretchConfig(mStretchVertical)); //1.0f
mCloth->setStretchConfig(physx::PxClothFabricPhaseType::eHORIZONTAL, physx::PxClothStretchConfig(mStretchHorizontal)); //0.9f
mCloth->setStretchConfig(physx::PxClothFabricPhaseType::eSHEARING, physx::PxClothStretchConfig(mStretchShearing)); // 0.75f
mCloth->setStretchConfig(physx::PxClothFabricPhaseType::eBENDING, physx::PxClothStretchConfig(mStretchBending)); // 0.5f
}
void Px3Cloth::_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 Px3Cloth::_updateVBIB()
{
if ( !mCloth )
return;
PROFILE_SCOPE( Px3Cloth_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 *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 Px3Cloth::_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 Px3Cloth::processTick( const Move *move )
{
// Make sure the cloth is created.
if ( !mCloth )
return;
// Update bounds.
if ( mWorld->isEnabled() )
{
Point3F vel = ParticleEmitter::mWindVelocity;
physx::PxVec3 windVec( vel.x, vel.y, vel.z );
mCloth->setExternalAcceleration(windVec);
// Update particle positions.
physx::PxClothParticleData* pData = mCloth->lockParticleData(physx::PxDataAccessFlag::eREADABLE);
if ( pData != NULL )
{
for(int i = 0; i < mNumVertices; i++)
{
physx::PxClothParticle* particle = &pData->particles[i];
mVertexRenderBuffer[i].point.set(particle->pos.x, particle->pos.y, particle->pos.z);
getTransform().mulP( mVertexRenderBuffer[i].point );
}
pData->unlock();
}
// Update Bounding Box : Currently Broken.
physx::PxBounds3 box;
box = mCloth->getWorldBounds();
Point3F min = px3Cast<Point3F>( box.minimum );
Point3F max = px3Cast<Point3F>( box.minimum );
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 Px3Cloth::interpolateTick( F32 delta )
{
// Nothing to do for now!
}
bool Px3Cloth::onNewDataBlock( GameBaseData *dptr, bool reload )
{
return false;
}
//-----------------------------------------------------------------------------
// Copyright (c) 2014 Andrew MacIntyre
//
// 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 _Px3Cloth_H
#define _Px3Cloth_H
#ifndef _PHYSX3_H_
#include "T3D/physics/physx3/px3.h"
#endif
#ifndef _T3D_PHYSICSCOMMON_H_
#include "T3D/physics/physicsCommon.h"
#endif
#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
class Material;
class BaseMatInstance;
class Px3World;
class Px3Cloth : public GameBase
{
typedef GameBase Parent;
enum MaskBits
{
TransformMask = Parent::NextFreeMask << 0,
ClothMask = Parent::NextFreeMask << 1,
MaterialMask = Parent::NextFreeMask << 3,
NextFreeMask = Parent::NextFreeMask << 4
};
public:
Px3Cloth();
virtual ~Px3Cloth();
DECLARE_CONOBJECT( Px3Cloth );
static Point3F mWindVelocity;
static void setWindVelocity( const Point3F &vel ){ mWindVelocity = vel; }
// 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:
Px3World *mWorld;
physx::PxScene *mScene;
physx::PxClothFabric *mClothMesh;
physx::PxCloth *mCloth;
bool mCollisionEnabled;
bool mWindEnabled;
F32 mThickness;
F32 mSolverFrequency;
F32 mDampingCoef;
F32 mStretchVertical; //1.0f
F32 mStretchHorizontal; //0.9f
F32 mStretchShearing; // 0.75f
F32 mStretchBending; // 0.5f
U32 mAttachmentMask;
static EnumTable mAttachmentFlagTable;
String mMaterialName;
SimObjectPtr<Material> mMaterial;
BaseMatInstance *mMatInst;
String lookupName;
///
GFXVertexPNTT *mVertexRenderBuffer;
U16 *mIndexRenderBuffer;
U32 mNumIndices;
U32 mNumVertices;
U32 mNumPrimitives;
Vector<physx::PxClothParticle> mVertices;
Vector<physx::PxU32> mPrimitives;
U32 mMeshDirtyFlags;
bool mIsVBDirty;
GFXPrimitiveBufferHandle mPrimBuffer;
GFXVertexBufferHandle<GFXVertexPNTT> mVB;
Point2I mPatchVerts;
Point2F mPatchSize;
MatrixF mResetXfm;
void _initMaterial();
void _releaseMesh();
void _releaseCloth();
void _initBuffers();
void _generateVertices();
bool _createClothPatch();
void _recreateCloth( const MatrixF &transform );
void _updateClothProperties();
void _updateStaticCloth();
void _updateVBIB();
};
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment