123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923 |
- //-----------------------------------------------------------------------------
- // 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 ) );
- }
|