123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354 |
- //-----------------------------------------------------------------------------
- // 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/physx3/px3Player.h"
- #include "T3D/physics/physicsPlugin.h"
- #include "T3D/physics/physx3/px3World.h"
- #include "T3D/physics/physx3/px3Casts.h"
- #include "T3D/physics/physx3/px3Utils.h"
- #include "collision/collision.h"
- Px3Player::Px3Player()
- : PhysicsPlayer(),
- mController( NULL ),
- mWorld( NULL ),
- mObject( NULL ),
- mSkinWidth( 0.05f ),
- mOriginOffset( 0.0f ),
- mElapsed(0)
- {
- PHYSICSMGR->getPhysicsResetSignal().notify( this, &Px3Player::_onPhysicsReset );
- }
- Px3Player::~Px3Player()
- {
- _releaseController();
- PHYSICSMGR->getPhysicsResetSignal().remove( this, &Px3Player::_onPhysicsReset );
- }
- void Px3Player::_releaseController()
- {
- if ( mController )
- {
- mController->getActor()->userData = NULL;
- mWorld->getStaticChangedSignal().remove( this, &Px3Player::_onStaticChanged );
- SafeReleasePhysx(mController);
- }
- }
- void Px3Player::init( const char *type,
- const Point3F &size,
- F32 runSurfaceCos,
- F32 stepHeight,
- SceneObject *obj,
- PhysicsWorld *world )
- {
- AssertFatal( obj, "Px3Player::init - Got a null scene object!" );
- AssertFatal( world, "Px3Player::init - Got a null world!" );
- AssertFatal( dynamic_cast<Px3World*>( world ), "Px3Player::init - The world is the wrong type!" );
- // Cleanup any previous controller.
- _releaseController();
- mObject = obj;
- mWorld = (Px3World*)world;
- mOriginOffset = size.z * 0.5f;
- physx::PxCapsuleControllerDesc desc;
- desc.contactOffset = mSkinWidth;
- desc.radius = getMax( size.x, size.y ) * 0.5f;
- desc.radius -= mSkinWidth;
- desc.height = size.z - ( desc.radius * 2.0f );
- desc.height -= mSkinWidth * 2.0f;
- desc.climbingMode = physx::PxCapsuleClimbingMode::eCONSTRAINED;
- desc.position.set( 0, 0, 0 );
- desc.upDirection = physx::PxVec3(0,0,1);
- desc.reportCallback = this;
- desc.slopeLimit = runSurfaceCos;
- desc.stepOffset = stepHeight;
- desc.behaviorCallback = NULL;
- desc.material = gPhysics3SDK->createMaterial(0.1f, 0.1f, 0.2f);
- mController = mWorld->createController( desc );
- mWorld->getStaticChangedSignal().notify( this, &Px3Player::_onStaticChanged );
- physx::PxRigidDynamic *kineActor = mController->getActor();
- //player only has one shape
- physx::PxShape *shape = px3GetFirstShape(kineActor);
- physx::PxFilterData colData;
- colData.word0 = PX3_PLAYER;
- shape->setSimulationFilterData(colData);
- shape->setQueryFilterData(colData);
- //store geometry for later use in findContact calls
- shape->getCapsuleGeometry(mGeometry);
- mUserData.setObject( obj );
- kineActor->userData = &mUserData;
- }
- void Px3Player::_onStaticChanged()
- {
- if(mController)
- mController->invalidateCache();
- }
- void Px3Player::_onPhysicsReset( PhysicsResetEvent reset )
- {
- if(mController)
- mController->invalidateCache();
- }
- Point3F Px3Player::move( const VectorF &disp, CollisionList &outCol )
- {
- AssertFatal( mController, "Px3Player::move - The controller is null!" );
- // Return the last position if the simulation is stopped.
- //
- // See PxPlayer::_onPhysicsReset
- if ( !mWorld->isEnabled() )
- {
- Point3F newPos = px3Cast<Point3F>( mController->getPosition() );
- newPos.z -= mOriginOffset;
- return newPos;
- }
- mCollisionList = &outCol;
- physx::PxVec3 dispNx( disp.x, disp.y, disp.z );
- if (mIsZero(disp.z))
- dispNx.z = 0.0f;
-
- U32 groups = 0xffffffff;
- groups &= ~( PX3_TRIGGER ); // No trigger shapes!
- groups &= ~( PX3_DEBRIS);
- physx::PxControllerFilters filter;
- physx::PxFilterData data;
- data.word0=groups;
- filter.mFilterData = &data;
- filter.mFilterFlags = physx::PxQueryFlags(physx::PxQueryFlag::eDYNAMIC | physx::PxQueryFlag::eSTATIC);
-
- mController->move( dispNx,0.0001f,0, filter );
- Point3F newPos = px3Cast<Point3F>( mController->getPosition() );
- newPos.z -= mOriginOffset;
- mCollisionList = NULL;
- return newPos;
- }
- void Px3Player::onShapeHit( const physx::PxControllerShapeHit& hit )
- {
- if (!mCollisionList || mCollisionList->getCount() >= CollisionList::MaxCollisions)
- return;
- physx::PxRigidActor *actor = hit.actor;
- PhysicsUserData *userData = PhysicsUserData::cast( actor->userData );
- // Fill out the Collision
- // structure for use later.
- Collision &col = mCollisionList->increment();
- dMemset( &col, 0, sizeof( col ) );
- col.normal = px3Cast<Point3F>( hit.worldNormal );
- col.point = px3Cast<Point3F>( hit.worldPos );
- col.distance = hit.length;
- if ( userData )
- col.object = userData->getObject();
- if (mIsZero(hit.dir.z))
- {
- if (col.normal.z > 0.0f)
- {
- col.normal.z = 0.0f;
- col.normal.normalizeSafe();
- }
- }
- else
- {
- col.normal.set(0.0f, 0.0f, 1.0f);
- }
- }
- void Px3Player::onControllerHit( const physx::PxControllersHit& hit )
- {
- if (!mCollisionList || mCollisionList->getCount() >= CollisionList::MaxCollisions)
- return;
- physx::PxRigidActor *actor = hit.other->getActor();
- PhysicsUserData *userData = PhysicsUserData::cast( actor->userData );
- // 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();
- }
- void Px3Player::findContact( SceneObject **contactObject,
- VectorF *contactNormal,
- Vector<SceneObject*> *outOverlapObjects ) const
- {
- // Calculate the sweep motion...
- F32 halfCapSize = mOriginOffset;
- F32 halfSmallCapSize = halfCapSize * 0.8f;
- F32 diff = halfCapSize - halfSmallCapSize;
- F32 distance = diff + mSkinWidth + 0.01f;
- physx::PxVec3 dir(0,0,-1);
-
- physx::PxScene *scene = mWorld->getScene();
- physx::PxHitFlags hitFlags(physx::PxHitFlag::eDEFAULT);
- physx::PxQueryFilterData filterData(physx::PxQueryFlag::eDYNAMIC|physx::PxQueryFlag::eSTATIC);
- filterData.data.word0 = PX3_DEFAULT;
- physx::PxSweepHit sweepHit;
- physx::PxRigidDynamic *actor= mController->getActor();
- physx::PxU32 shapeIndex;
- bool hit = physx::PxRigidBodyExt::linearSweepSingle(*actor,*scene,dir,distance,hitFlags,sweepHit,shapeIndex,filterData);
- if ( hit )
- {
- PhysicsUserData *data = PhysicsUserData::cast( sweepHit.actor->userData);
- if ( data )
- {
- *contactObject = data->getObject();
- *contactNormal = px3Cast<Point3F>( sweepHit.normal );
- }
- }
- // Check for overlapped objects ( triggers )
- if ( !outOverlapObjects )
- return;
- filterData.data.word0 = PX3_TRIGGER;
- const physx::PxU32 bufferSize = 10;
- physx::PxOverlapBufferN<bufferSize> hitBuffer;
- hit = scene->overlap(mGeometry,actor->getGlobalPose(),hitBuffer,filterData);
- if(hit)
- {
- for ( U32 i = 0; i < hitBuffer.nbTouches; i++ )
- {
- PhysicsUserData *data = PhysicsUserData::cast( hitBuffer.touches[i].actor->userData );
- if ( data )
- outOverlapObjects->push_back( data->getObject() );
- }
- }
- }
- void Px3Player::enableCollision()
- {
- AssertFatal( mController, "Px3Player::enableCollision - The controller is null!" );
- px3GetFirstShape(mController->getActor())->setFlag(physx::PxShapeFlag::eSIMULATION_SHAPE,true);
- }
- void Px3Player::disableCollision()
- {
- AssertFatal( mController, "Px3Player::disableCollision - The controller is null!" );
- px3GetFirstShape(mController->getActor())->setFlag(physx::PxShapeFlag::eSIMULATION_SHAPE,false);
- }
- PhysicsWorld* Px3Player::getWorld()
- {
- return mWorld;
- }
- void Px3Player::setTransform( const MatrixF &transform )
- {
- AssertFatal( mController, "Px3Player::setTransform - The controller is null!" );
- Point3F newPos = transform.getPosition();
- newPos.z += mOriginOffset;
- const Point3F &curPos = px3Cast<Point3F>(mController->getPosition());
-
- if ( !(newPos - curPos ).isZero() )
- mController->setPosition( px3Cast<physx::PxExtendedVec3>(newPos) );
- }
- MatrixF& Px3Player::getTransform( MatrixF *outMatrix )
- {
- AssertFatal( mController, "Px3Player::getTransform - The controller is null!" );
- Point3F newPos = px3Cast<Point3F>( mController->getPosition() );
- newPos.z -= mOriginOffset;
- outMatrix->setPosition( newPos );
- return *outMatrix;
- }
- void Px3Player::setScale( const Point3F &scale )
- {
- //Ignored
- }
- Box3F Px3Player::getWorldBounds()
- {
- physx::PxBounds3 bounds;
- physx::PxRigidDynamic *actor = mController->getActor();
- physx::PxShape *shape = px3GetFirstShape(actor);
- bounds = physx::PxShapeExt::getWorldBounds(*shape,*actor);
- return px3Cast<Box3F>( bounds );
- }
- bool Px3Player::testSpacials(const Point3F &nPos, const Point3F &nSize) const
- {
- F32 offset = nSize.z * 0.5f;
- F32 radius = getMax(nSize.x, nSize.y) * 0.5f - mSkinWidth;
- F32 height = (nSize.z - (radius * 2.0f)) * 0.5f;
- height -= mSkinWidth * 2.0f;
- physx::PxCapsuleGeometry geom(radius, height);
- physx::PxVec3 pos(nPos.x, nPos.y, nPos.z + offset);
- physx::PxQuat orientation(Float_HalfPi, physx::PxVec3(0.0f, 1.0f, 0.0f));
- physx::PxOverlapBuffer hit;
- physx::PxQueryFilterData queryFilter(physx::PxQueryFlag::eANY_HIT | physx::PxQueryFlag::eSTATIC | physx::PxQueryFlag::eDYNAMIC);
- queryFilter.data.word0 = PX3_DEFAULT;
- bool hasHit = mWorld->getScene()->overlap(geom, physx::PxTransform(pos, orientation), hit, queryFilter);
- return !hasHit; // Return true if there are no overlapping objects
- }
- void Px3Player::setSpacials(const Point3F &nPos, const Point3F &nSize)
- {
- mOriginOffset = nSize.z * 0.5f;
- F32 radius = getMax(nSize.x, nSize.y) * 0.5f - mSkinWidth;
- F32 height = nSize.z - (radius * 2.0f);
- height -= mSkinWidth * 2.0f;
- mController->resize(height);
- px3GetFirstShape(mController->getActor())->getCapsuleGeometry(mGeometry);
- }
|