diff options
| author | git perforce import user <a@b> | 2016-10-25 12:29:14 -0600 |
|---|---|---|
| committer | Sheikh Dawood Abdul Ajees <Sheikh Dawood Abdul Ajees> | 2016-10-25 18:56:37 -0500 |
| commit | 3dfe2108cfab31ba3ee5527e217d0d8e99a51162 (patch) | |
| tree | fa6485c169e50d7415a651bf838f5bcd0fd3bfbd /PhysX_3.4/Samples/SampleSubmarine | |
| download | physx-3.4-3dfe2108cfab31ba3ee5527e217d0d8e99a51162.tar.xz physx-3.4-3dfe2108cfab31ba3ee5527e217d0d8e99a51162.zip | |
Initial commit:
PhysX 3.4.0 Update @ 21294896
APEX 1.4.0 Update @ 21275617
[CL 21300167]
Diffstat (limited to 'PhysX_3.4/Samples/SampleSubmarine')
| -rw-r--r-- | PhysX_3.4/Samples/SampleSubmarine/Crab.cpp | 822 | ||||
| -rw-r--r-- | PhysX_3.4/Samples/SampleSubmarine/Crab.h | 163 | ||||
| -rw-r--r-- | PhysX_3.4/Samples/SampleSubmarine/SampleSubmarine.cpp | 1278 | ||||
| -rw-r--r-- | PhysX_3.4/Samples/SampleSubmarine/SampleSubmarine.h | 157 | ||||
| -rw-r--r-- | PhysX_3.4/Samples/SampleSubmarine/SampleSubmarineInputEventIds.h | 56 | ||||
| -rw-r--r-- | PhysX_3.4/Samples/SampleSubmarine/SubmarineCameraController.h | 64 |
6 files changed, 2540 insertions, 0 deletions
diff --git a/PhysX_3.4/Samples/SampleSubmarine/Crab.cpp b/PhysX_3.4/Samples/SampleSubmarine/Crab.cpp new file mode 100644 index 00000000..bcccca1c --- /dev/null +++ b/PhysX_3.4/Samples/SampleSubmarine/Crab.cpp @@ -0,0 +1,822 @@ +// This code contains NVIDIA Confidential Information and is disclosed to you +// under a form of NVIDIA software license agreement provided separately to you. +// +// Notice +// NVIDIA Corporation and its licensors retain all intellectual property and +// proprietary rights in and to this software and related documentation and +// any modifications thereto. Any use, reproduction, disclosure, or +// distribution of this software and related documentation without an express +// license agreement from NVIDIA Corporation is strictly prohibited. +// +// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES +// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO +// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT, +// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE. +// +// Information and code furnished is believed to be accurate and reliable. +// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such +// information or for any infringement of patents or other rights of third parties that may +// result from its use. No license is granted by implication or otherwise under any patent +// or patent rights of NVIDIA Corporation. Details are subject to change without notice. +// This code supersedes and replaces all information previously supplied. +// NVIDIA Corporation products are not authorized for use as critical +// components in life support devices or systems without express written approval of +// NVIDIA Corporation. +// +// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved. +// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved. +// Copyright (c) 2001-2004 NovodeX AG. All rights reserved. + +#include "PxPhysicsAPI.h" +#include "extensions/PxExtensionsAPI.h" +#include "SampleSubmarine.h" +#include "Crab.h" +#include "RendererColor.h" +#include "RenderPhysX3Debug.h" + +#include "PxTkStream.h" + +#include "PhysXSample.h" +#include "PxTkFile.h" +using namespace PxToolkit; +// if enabled: runs the crab AI in sync, not as a parallel task to physx. +#define DEBUG_RENDERING 0 + +void setupFiltering(PxRigidActor* actor, PxU32 filterGroup, PxU32 filterMask); + +// table with default times in seconds how the crab AI will try to stay in a state +static const PxReal gDefaultStateTime[CrabState::eNUM_STATES] = {5.0f, 10.0f, 10.0f, 10.0f, 10.0f, 6.0f}; + +Crab::Crab(SampleSubmarine& sample, const PxVec3& crabPos, RenderMaterial* material) +: ClassType(ClassType::eCRAB) +, mSampleSubmarine(&sample) +, mMaterial(material) +{ + initMembers(); + create(crabPos); +} + +Crab::Crab(SampleSubmarine& sample, const char* filename, RenderMaterial* material) +: ClassType(ClassType::eCRAB) +, mSampleSubmarine(&sample) +, mMaterial(material) +{ + initMembers(); + load(filename); +} + +void Crab::initMembers() +{ + mMemory = NULL; + mCrabBody = NULL; + mSqRayBuffer = NULL; + mLegHeight = 0; + mRespawnMe = false; + mCrabState = CrabState::eWAITING; + mStateTime = gDefaultStateTime[CrabState::eWAITING]; + mAccumTime = 0; + mElapsedTime = 0; + mRunning = 0; + + mAcceleration[0] = 0; + mAcceleration[1] = 0; + + mAccelerationBuffer[0] = 0; + mAccelerationBuffer[1] = 0; + + // setup buffer for 10 batched rays and 10 hits + mSqRayBuffer = SAMPLE_NEW(SqRayBuffer)(*mSampleSubmarine, 10, 10); + + mSubmarinePos = PxVec3(0); + +} +Crab::~Crab() +{ + // wait until background task is finished + while(mRunning) + ; + + for(PxU32 i = 0; i < mJoints.size(); i++) + mJoints[i]->release(); + mJoints.clear(); + + for(PxU32 i = 0; i < mActors.size(); i++) + mSampleSubmarine->removeActor(mActors[i]); + mActors.clear(); + + if(mMemory) + { + SAMPLE_FREE(mMemory); + } + + delete mSqRayBuffer; +} + +static void setShapeFlag(PxRigidActor* actor, PxShapeFlag::Enum flag, bool flagValue) +{ + const PxU32 numShapes = actor->getNbShapes(); + PxShape** shapes = (PxShape**)SAMPLE_ALLOC(sizeof(PxShape*)*numShapes); + actor->getShapes(shapes, numShapes); + for(PxU32 i = 0; i < numShapes; i++) + { + PxShape* shape = shapes[i]; + shape->setFlag(flag, flagValue); + } + SAMPLE_FREE(shapes); +} + +PxVec3 Crab::getPlaceOnFloor(PxVec3 start) +{ + PxRaycastBuffer rayHit; + mSampleSubmarine->getActiveScene().raycast(start, PxVec3(0,-1,0), 1000.0f, rayHit); + + return rayHit.block.position + PxVec3(0,mLegHeight,0); +} + +static const PxSerialObjectId mMaterial_id = (PxSerialObjectId)0x01; +static const PxSerialObjectId mCrabBody_id = (PxSerialObjectId)0x02; +static const PxSerialObjectId mMotorJoint0_id = (PxSerialObjectId)0x03; +static const PxSerialObjectId mMotorJoint1_id = (PxSerialObjectId)0x04; + +void Crab::save(const char* filename) +{ + PxPhysics& physics = mSampleSubmarine->getPhysics(); + PxCollection* thePxCollection = PxCreateCollection(); + PxSerializationRegistry* sr = PxSerialization::createSerializationRegistry(physics); + for(PxU32 i = 0; i < mActors.size(); ++i) + { + thePxCollection->add(*mActors[i]); + } + + for(PxU32 i = 0; i < mJoints.size(); ++i) + { + thePxCollection->add(*mJoints[i]); + } + + thePxCollection->addId(*mCrabBody, mCrabBody_id); + thePxCollection->addId(*mMotorJoint[0], mMotorJoint0_id); + thePxCollection->addId(*mMotorJoint[1], mMotorJoint1_id); + + PxCollection* theExtRef = PxCreateCollection(); + theExtRef->add(*mSampleSubmarine->mMaterial, mMaterial_id); + + PxSerialization::complete(*thePxCollection, *sr, theExtRef); + + PxDefaultFileOutputStream s(filename); + PxSerialization::serializeCollectionToBinary(s, *thePxCollection, *sr, theExtRef); + + theExtRef->release(); + thePxCollection->release(); + sr->release(); +} + +static PxU32 GetFileSize(const char* name) +{ + if(!name) return 0; + +#ifndef SEEK_END +#define SEEK_END 2 +#endif + + SampleFramework::File* fp; + if (PxToolkit::fopen_s(&fp, name, "rb")) + return 0; + fseek(fp, 0, SEEK_END); + PxU32 eof_ftell = (PxU32)ftell(fp); + fclose(fp); + return eof_ftell; +} + +void Crab::load(const char* filename) +{ + PxPhysics& thePhysics = mSampleSubmarine->getPhysics(); + + SampleFramework::File* fp = NULL; + if (!PxToolkit::fopen_s(&fp, filename, "rb")) + { + PxU32 theFileSize = GetFileSize(filename); + + if(!mMemory) + mMemory = SAMPLE_ALLOC(theFileSize + PX_SERIAL_FILE_ALIGN); + + void* theMemory16 = (void*)((size_t(mMemory) + PX_SERIAL_FILE_ALIGN)&~(PX_SERIAL_FILE_ALIGN-1)); + const size_t theNumRead = fread(theMemory16, 1, theFileSize, fp); + PX_ASSERT(PxU32(theNumRead) == theFileSize); + PX_UNUSED(theNumRead); + fclose(fp); + + PxCollection* theExtRef = PxCreateCollection(); + theExtRef->add(*mSampleSubmarine->mMaterial, mMaterial_id); + PxSerializationRegistry* sr = PxSerialization::createSerializationRegistry(thePhysics); + PxCollection* thePxCollection = PxSerialization::createCollectionFromBinary(theMemory16, *sr, theExtRef); + PX_ASSERT(thePxCollection); + + mSampleSubmarine->getActiveScene().addCollection(*thePxCollection); + + mMotorJoint[0] = reinterpret_cast<PxRevoluteJoint*>( thePxCollection->find(mMotorJoint0_id)); + mMotorJoint[1] = reinterpret_cast<PxRevoluteJoint*>( thePxCollection->find(mMotorJoint1_id)); + mCrabBody = reinterpret_cast<PxRigidDynamic*>( thePxCollection->find(mCrabBody_id)); + PX_ASSERT(mMotorJoint[0] && mMotorJoint[1] && mCrabBody ); + + PxU32 nbObjs = thePxCollection->getNbObjects(); + PX_ASSERT(nbObjs != 0); + for(PxU32 i = 0; i < nbObjs; ++i) + { + PxBase* object = &thePxCollection->getObject(i); + if(object) + { + const PxType serialType = object->getConcreteType(); + if(serialType == PxConcreteType::eRIGID_DYNAMIC) + { + PxRigidDynamic* actor = reinterpret_cast<PxRigidDynamic*>(object); + + mSampleSubmarine->createRenderObjectsFromActor(actor , mMaterial ); + mSampleSubmarine->addPhysicsActors( actor ); + mActors.push_back( actor ); + } + else if(serialType == PxConcreteType::eCONSTRAINT) + { + PxU32 typeID = 0; + PxConstraint* constraint = reinterpret_cast<PxConstraint*>(object); + PxJoint* joint = reinterpret_cast<PxJoint*>(constraint->getExternalReference(typeID)); + mJoints.push_back( joint ); + } + else if(serialType == PxConcreteType::eSHAPE) + { + //giving up application shape ownership early + PxShape* shape = reinterpret_cast<PxShape*>(object); + shape->release(); + } + } + } + + theExtRef->release(); + thePxCollection->release(); + sr->release(); + } + + if( !mCrabBody ) mSampleSubmarine->fatalError( "createBox failed!" ); + setupFiltering( mCrabBody, FilterGroup::eCRAB, FilterGroup::eHEIGHTFIELD ); +} + + +void Crab::create(const PxVec3& _crabPos) +{ + static const PxReal scale = 0.8f; + static const PxReal crabDepth = 2.0f; + static const PxVec3 crabBodyDim = PxVec3(0.8f, 0.8f, crabDepth*0.5f)*scale; + static const PxReal legMass = 0.03f; + static const PxReal velocity = 0.0f; + static const PxReal maxForce = 4000.0f; + + LegParameters params; // check edge ascii art in Crab.h + params.a = 0.5f; + params.b = 0.6f; + params.c = 0.5f; + params.d = 0.5f; + params.e = 1.5f; + params.m = 0.3f; + params.n = 0.1f; + + mLegHeight = scale*2.0f*(params.d+params.c); + mLegHeight += 0.5f; + PxVec3 crabPos = getPlaceOnFloor(_crabPos); + mCrabBody = mSampleSubmarine->createBox(crabPos, crabBodyDim, NULL, mMaterial, 1.0f)->is<PxRigidDynamic>(); + if(!mCrabBody) mSampleSubmarine->fatalError("createBox failed!"); + PxShape* shape; mCrabBody->getShapes(&shape, 1); + shape->setLocalPose(PxTransform(PxQuat(PxHalfPi*0.5f, PxVec3(0,0,1)))); + PxRigidBodyExt::setMassAndUpdateInertia(*mCrabBody, legMass*10.0f); + PxTransform cmPose = mCrabBody->getCMassLocalPose(); + cmPose.p.y -= 0.8f; + mCrabBody->setCMassLocalPose(cmPose); + mCrabBody->setAngularDamping(100.0f); + mCrabBody->userData = this; + mActors.push_back(mCrabBody); + + // legs + static const PxU32 numLegs = 4; + PxReal recipNumLegs = 1.0f/PxReal(numLegs); + PxReal recipNumLegsMinus1 = 1.0f/PxReal(numLegs-1); + PX_COMPILE_TIME_ASSERT((numLegs&1) == 0); + + PxRigidDynamic* motor[2]; + { + static const PxReal density = 1.0f; + static const PxReal m = params.m * scale; + static const PxReal n = params.n * scale; + static const PxBoxGeometry boxGeomM = PxBoxGeometry(m, m, crabBodyDim.z * 0.5f); + + // create left and right motor + PxVec3 motorPos = crabPos+PxVec3(0,n,0); + for(PxU32 i = 0; i < 2; i++) + { + PxVec3 motorOfs = i==0 ? PxVec3(0,0, boxGeomM.halfExtents.z) : -PxVec3(0,0,boxGeomM.halfExtents.z); + motor[i] = mSampleSubmarine->createBox(motorPos+motorOfs, boxGeomM.halfExtents, NULL, mMaterial, density)->is<PxRigidDynamic>(); + if(!motor[i]) mSampleSubmarine->fatalError("createBox failed!"); + + PxRigidBodyExt::setMassAndUpdateInertia(*motor[i], legMass); + motor[i]->setActorFlag(PxActorFlag::eDISABLE_GRAVITY, true); + setShapeFlag(motor[i], PxShapeFlag::eSIMULATION_SHAPE, false); + + mMotorJoint[i] = PxRevoluteJointCreate(mSampleSubmarine->getPhysics(), + mCrabBody, PxTransform(motorOfs, PxQuat(-PxHalfPi, PxVec3(0,1,0))), + motor[i], PxTransform(PxVec3(0, 0, 0), PxQuat(-PxHalfPi, PxVec3(0,1,0)))); + if(!mMotorJoint[i]) mSampleSubmarine->fatalError("PxRevoluteJointCreate failed!"); + + mMotorJoint[i]->setDriveVelocity(velocity); + mMotorJoint[i]->setDriveForceLimit(maxForce); + mMotorJoint[i]->setRevoluteJointFlag(PxRevoluteJointFlag::eDRIVE_ENABLED, true); + mActors.push_back(motor[i]); + mJoints.push_back(mMotorJoint[i]); + } + + // create legs and attach to left and right motor + PxReal legSpacing = crabDepth*recipNumLegsMinus1*scale; + PxVec3 bodyToLegPos0 = PxVec3(0, 0, crabBodyDim.z); + PxVec3 bodyToLegPos1 = PxVec3(0, 0, crabBodyDim.z-(numLegs/2)*legSpacing); + PxVec3 motorToLegPos0 = PxVec3(0, 0, crabBodyDim.z*0.5f); + PxVec3 motorToLegPos1 = PxVec3(0, 0, (crabBodyDim.z - legSpacing)*0.5f); + for(PxU32 i = 0; i < numLegs/2; i++) + { + PxReal angle0 = -PxHalfPi + PxTwoPi*recipNumLegs*i; + PxReal angle1 = angle0 + PxPi; + + createLeg(mCrabBody, bodyToLegPos0, legMass, params, scale, motor[0], motorToLegPos0 + m * PxVec3(PxCos(angle0), PxSin(angle0), 0)); + createLeg(mCrabBody, bodyToLegPos1, legMass, params, scale, motor[1], motorToLegPos1 + m * PxVec3(PxCos(angle1), PxSin(angle1), 0)); + bodyToLegPos0.z -= legSpacing; + bodyToLegPos1.z -= legSpacing; + motorToLegPos0.z -= legSpacing; + motorToLegPos1.z -= legSpacing; + } + } + + setupFiltering(mCrabBody, FilterGroup::eCRAB, FilterGroup::eHEIGHTFIELD); +} + +void Crab::createLeg(PxRigidDynamic* mainBody, PxVec3 localPos, PxReal mass, const LegParameters& params, PxReal scale, PxRigidDynamic* motor, PxVec3 motorAttachmentPos) +{ + PxVec3 crabLegPos = mainBody->getGlobalPose().p + localPos; + + // params for Theo Jansen's machine + // check edge ascii art in Crab.h + static const PxReal stickExt = 0.125f * 0.5f * scale; + const PxReal a = params.a * scale; + const PxReal b = params.b * scale; + const PxReal c = params.c * scale; + const PxReal d = params.d * scale; + const PxReal e = params.e * scale; + const PxReal m = params.m * scale; + const PxReal n = params.n * scale; + + const PxReal density = 1.0f; + + std::vector<PxTransform> poses; + std::vector<const PxGeometry*> geometries; + + PxBoxGeometry boxGeomA = PxBoxGeometry(a, stickExt, stickExt); + PxBoxGeometry boxGeomB = PxBoxGeometry(stickExt, b, stickExt); + PxBoxGeometry boxGeomC = PxBoxGeometry(stickExt, c, stickExt); + + PxCapsuleGeometry capsGeomD = PxCapsuleGeometry(stickExt*2.0f, d); + + for(PxU32 leg = 0; leg < 2; leg++) + { + bool left = (leg==0); + #define MIRROR(X) left ? -1.0f*(X) : (X) + PxVec3 startPos = crabLegPos + PxVec3(MIRROR(e), 0, 0); + + // create upper triangle from boxes + PxRigidDynamic* upperTriangle = NULL; + { + PxTransform poseA = PxTransform(PxVec3(MIRROR(a), 0, 0)); + PxTransform poseB = PxTransform(PxVec3(MIRROR(0), b, 0)); + poses.clear(); geometries.clear(); + poses.push_back(poseA); poses.push_back(poseB); + geometries.push_back(&boxGeomA); geometries.push_back(&boxGeomB); + upperTriangle = mSampleSubmarine->createCompound(startPos, poses, geometries, NULL, mMaterial, density)->is<PxRigidDynamic>(); + if(!upperTriangle) mSampleSubmarine->fatalError("createCompound failed!"); + mActors.push_back(upperTriangle); + } + + // create lower triangle from boxes + PxRigidDynamic* lowerTriangle = NULL; + { + PxTransform poseA = PxTransform(PxVec3(MIRROR(a), 0, 0)); + //PxTransform poseD = PxTransform(PxVec3(MIRROR(0), -d, 0)); + PxTransform poseD = PxTransform(PxVec3(MIRROR(0), -d, 0), PxQuat(PxHalfPi, PxVec3(0,0,1))); + poses.clear(); geometries.clear(); + poses.push_back(poseA); poses.push_back(poseD); + //geometries.push_back(&boxGeomA); geometries.push_back(&boxGeomD); + geometries.push_back(&boxGeomA); geometries.push_back(&capsGeomD); + lowerTriangle = mSampleSubmarine->createCompound(startPos + PxVec3(0, -2.0f*c, 0), poses, geometries, NULL, mMaterial, density)->is<PxRigidDynamic>(); + if(!lowerTriangle) mSampleSubmarine->fatalError("createCompound failed!"); + mActors.push_back(lowerTriangle); + } + + // create vertical boxes to connect the triangles + PxRigidDynamic* verticalBox0 = mSampleSubmarine->createBox(startPos + PxVec3(0, -c, 0), boxGeomC.halfExtents ,NULL, mMaterial, density)->is<PxRigidDynamic>(); + if(!verticalBox0) mSampleSubmarine->fatalError("createBox failed!"); + PxRigidDynamic* verticalBox1 = mSampleSubmarine->createBox(startPos + PxVec3(MIRROR(2.0f*a), -c, 0), boxGeomC.halfExtents ,NULL, mMaterial, density)->is<PxRigidDynamic>(); + if(!verticalBox1) mSampleSubmarine->fatalError("createBox failed!"); + mActors.push_back(verticalBox0); + mActors.push_back(verticalBox1); + + // disable gravity + upperTriangle->setActorFlag(PxActorFlag::eDISABLE_GRAVITY, true); + lowerTriangle->setActorFlag(PxActorFlag::eDISABLE_GRAVITY, true); + verticalBox0->setActorFlag(PxActorFlag::eDISABLE_GRAVITY, true); + verticalBox1->setActorFlag(PxActorFlag::eDISABLE_GRAVITY, true); + + // set mass + PxRigidBodyExt::setMassAndUpdateInertia(*upperTriangle, mass); + PxRigidBodyExt::setMassAndUpdateInertia(*lowerTriangle, mass); + PxRigidBodyExt::setMassAndUpdateInertia(*verticalBox0, mass); + PxRigidBodyExt::setMassAndUpdateInertia(*verticalBox1, mass); + + // turn off collision upper triangle and vertical boxes + setShapeFlag(upperTriangle, PxShapeFlag::eSIMULATION_SHAPE, false); + setShapeFlag(verticalBox0, PxShapeFlag::eSIMULATION_SHAPE, false); + setShapeFlag(verticalBox1, PxShapeFlag::eSIMULATION_SHAPE, false); + + // revolute joint in lower corner of upper triangle + PxRevoluteJoint* joint; + joint = PxRevoluteJointCreate(mSampleSubmarine->getPhysics(), + mainBody, PxTransform(PxVec3(MIRROR(e), 0, 0)+localPos, PxQuat(-PxHalfPi, PxVec3(0,1,0))), + upperTriangle, PxTransform(PxVec3(0, 0, 0), PxQuat(-PxHalfPi, PxVec3(0,1,0)))); + if(!joint) mSampleSubmarine->fatalError("PxRevoluteJointCreate failed!"); + mJoints.push_back(joint); + + // 4 revolute joints to connect triangles + joint = PxRevoluteJointCreate(mSampleSubmarine->getPhysics(), + upperTriangle, PxTransform(PxVec3(0, 0, 0), PxQuat(-PxHalfPi, PxVec3(0,1,0))), + verticalBox0, PxTransform(PxVec3(0, c, 0), PxQuat(-PxHalfPi, PxVec3(0,1,0)))); + if(!joint) mSampleSubmarine->fatalError("PxRevoluteJointCreate failed!"); + mJoints.push_back(joint); + + joint = PxRevoluteJointCreate(mSampleSubmarine->getPhysics(), + upperTriangle, PxTransform(PxVec3(MIRROR(2.0f*a), 0, 0),PxQuat(-PxHalfPi, PxVec3(0,1,0))), + verticalBox1, PxTransform(PxVec3(0, c, 0), PxQuat(-PxHalfPi, PxVec3(0,1,0)))); + if(!joint) mSampleSubmarine->fatalError("PxRevoluteJointCreate failed!"); + mJoints.push_back(joint); + + joint = PxRevoluteJointCreate(mSampleSubmarine->getPhysics(), + lowerTriangle, PxTransform(PxVec3(0, 0, 0), PxQuat(-PxHalfPi, PxVec3(0,1,0))), + verticalBox0, PxTransform(PxVec3(0, -c, 0), PxQuat(-PxHalfPi, PxVec3(0,1,0)))); + if(!joint) mSampleSubmarine->fatalError("PxRevoluteJointCreate failed!"); + mJoints.push_back(joint); + + joint = PxRevoluteJointCreate(mSampleSubmarine->getPhysics(), + lowerTriangle, PxTransform(PxVec3(MIRROR(2.0f*a), 0, 0),PxQuat(-PxHalfPi, PxVec3(0,1,0))), + verticalBox1, PxTransform(PxVec3(0, -c, 0), PxQuat(-PxHalfPi, PxVec3(0,1,0)))); + if(!joint) mSampleSubmarine->fatalError("PxRevoluteJointCreate failed!"); + mJoints.push_back(joint); + + // 2 distance constraints to connect motor with the triangles + PxTransform motorTransform = PxTransform(motorAttachmentPos); + PxReal dist0 = PxSqrt( (2.0f*b - n)*(2.0f*b - n) + (e-m)*(e-m)); + PxReal dist1 = PxSqrt( (2.0f*c + n)*(2.0f*c + n) + (e-m)*(e-m)); + + PxDistanceJoint* distJoint0 = PxDistanceJointCreate(mSampleSubmarine->getPhysics(), upperTriangle, PxTransform(PxVec3(0, 2.0f*b, 0)), motor, motorTransform); + if(!distJoint0) mSampleSubmarine->fatalError("PxDistanceJointCreate failed!"); + // set min & max distance to dist0 + distJoint0->setMaxDistance(dist0); + distJoint0->setMinDistance(dist0); + // setup damping & spring + distJoint0->setDamping(0.1f); + distJoint0->setStiffness(100.0f); + distJoint0->setDistanceJointFlags(PxDistanceJointFlag::eMAX_DISTANCE_ENABLED | PxDistanceJointFlag::eMIN_DISTANCE_ENABLED | PxDistanceJointFlag::eSPRING_ENABLED); + + PxDistanceJoint* distJoint1 = PxDistanceJointCreate(mSampleSubmarine->getPhysics(), lowerTriangle, PxTransform(PxVec3(0, 0, 0)), motor, motorTransform); + if(!distJoint1) mSampleSubmarine->fatalError("PxDistanceJointCreate failed!"); + // set min & max distance to dist0 + distJoint1->setMaxDistance(dist1); + distJoint1->setMinDistance(dist1); + // setup damping & spring + distJoint1->setDamping(0.1f); + distJoint1->setStiffness(100.0f); + distJoint1->setDistanceJointFlags(PxDistanceJointFlag::eMAX_DISTANCE_ENABLED | PxDistanceJointFlag::eMIN_DISTANCE_ENABLED | PxDistanceJointFlag::eSPRING_ENABLED); + + // one distance joint to ensure that the vertical boxes do not get stuck if they cross the diagonal. + PxReal halfDiagDist = PxSqrt(a*a + c*c); + PxDistanceJoint* noFlip = PxDistanceJointCreate(mSampleSubmarine->getPhysics(), lowerTriangle, PxTransform(PxVec3(MIRROR(2.0f*a), 0, 0)), upperTriangle, PxTransform(PxVec3(0))); + if(!noFlip) mSampleSubmarine->fatalError("PxDistanceJointCreate failed!"); + // set min & max distance to dist0 + noFlip->setMaxDistance(2.0f * (a+c)); + noFlip->setMinDistance(halfDiagDist); + // setup damping & spring + noFlip->setDamping(1.0f); + noFlip->setStiffness(100.0f); + noFlip->setDistanceJointFlags(PxDistanceJointFlag::eMAX_DISTANCE_ENABLED | PxDistanceJointFlag::eMIN_DISTANCE_ENABLED | PxDistanceJointFlag::eSPRING_ENABLED); + + mJoints.push_back(distJoint0); + mJoints.push_back(distJoint1); + mJoints.push_back(noFlip); + } +} + + +void Crab::update(PxReal dt) +{ + PxSceneWriteLock scopedLock(mSampleSubmarine->getActiveScene()); + + { + // check if I have to be reset + PxTransform pose = mCrabBody->getGlobalPose(); + PxVec3 upVect = PxVec3(0,1,0); + PxVec3 crabUp = pose.rotate(upVect); + PxReal angle = upVect.dot(crabUp); + if(angle <= 0.1f) + { + mRespawnMe = true; + } + } + + PxReal maxVelocity = 16.0f; + PxReal velDamping = 0.8f; + + if(mRunning == 0) + flushAccelerationBuffer(); + + for(PxU32 i = 0; i < 2; i++) + { + PxReal prevVelocity = mMotorJoint[i]->getDriveVelocity(); + PxReal velocityChange = mAcceleration[i] ? mAcceleration[i]*dt : -prevVelocity*velDamping*dt; + PxReal newVelocity = PxClamp(prevVelocity + velocityChange, -maxVelocity, maxVelocity); + mMotorJoint[i]->setDriveVelocity(newVelocity); + + if(mAcceleration[i] != 0.0f) + mCrabBody->wakeUp(); + + mAcceleration[i] = 0; + } + + // add up elapsed time + mAccumTime += dt; + + // submit accum time to AI time before starting the PxTask + if(mRunning == 0) + { + mElapsedTime = mAccumTime; + mAccumTime = 0; + mSubmarinePos = mSampleSubmarine->mSubmarineActor ? mSampleSubmarine->mSubmarineActor->getGlobalPose().p : PxVec3(0); + +#if DEBUG_RENDERING + // run immediately + scanForObstacles(); + updateState(); +#endif + } +} + +void Crab::run() +{ +#if !DEBUG_RENDERING + mRunning = 1; + + // run as a separate task/thread + scanForObstacles(); + updateState(); + + mRunning = 0; +#endif +} + + +void Crab::setAcceleration(PxReal leftAcc, PxReal rightAcc) +{ + mAccelerationBuffer[0] = -leftAcc; + mAccelerationBuffer[1] = -rightAcc; +} + + +void Crab::flushAccelerationBuffer() +{ + mAcceleration[0] = mAccelerationBuffer[0]; + mAcceleration[1] = mAccelerationBuffer[1]; +} + + +void Crab::scanForObstacles() +{ + PxSceneReadLock scopedLock(mSampleSubmarine->getActiveScene()); + + PxTransform crabPose = mCrabBody->getGlobalPose(); + PxVec3 rayStart[2] = {PxVec3(2.0f, 0.0f, 0.0f), PxVec3(-2.0f, 0.0f, 0.0f)} ; + rayStart[0] = crabPose.transform(rayStart[0]); + rayStart[1] = crabPose.transform(rayStart[1]); + PxReal rayDist = 100.0f; + + // setup raycasts + // 3 front & 3 back + for(PxU32 j = 0; j < 2; j++) + { + PxVec3 rayDir = crabPose.rotate(PxVec3(j?-1.0f:1.0f,0,0)); + PxQuat rotY = PxQuat(0.4f, PxVec3(0,1,0)); + rayDir = rotY.rotateInv(rayDir); + for(PxU32 i = 0; i < 3; i++) + { + mSqRayBuffer->mBatchQuery->raycast(rayStart[j], rayDir, rayDist); + rayDir = rotY.rotate(rayDir); + } + } + + // add submarine visibility query + if(mSampleSubmarine->mSubmarineActor) + { + PxVec3 rayStart = crabPose.transform(PxVec3(0,2,0)); + PxVec3 crabToSub = mSubmarinePos - rayStart; + mSqRayBuffer->mBatchQuery->raycast(rayStart, crabToSub.getNormalized(), rayDist); + } + + mSqRayBuffer->mBatchQuery->execute(); + + for(PxU32 i = 0; i < mSqRayBuffer->mQueryResultSize; i++) + { + PxRaycastQueryResult& result = mSqRayBuffer->mRayCastResults[i]; + if(result.queryStatus == PxBatchQueryStatus::eSUCCESS && result.getNbAnyHits() == 1) + { + const PxRaycastHit& hit = result.getAnyHit(0); + mDistances[i] = hit.distance; + + // don't see flat terrain as wall + SampleRenderer::RendererColor rayColor(0,0,255); + PxReal angle = hit.normal.dot(crabPose.q.rotate(PxVec3(0,1,0))); + if(angle > 0.98f) // = 11.5 degree difference + { + mDistances[i] = rayDist; + rayColor = SampleRenderer::RendererColor(0,255,0); + } +#if DEBUG_RENDERING + // debug rendering + PxU8 blue = PxU8(mDistances[i] * (255.0f/rayDist)); + const SampleRenderer::RendererColor color(255, 0, blue); + mSampleSubmarine->getDebugRenderer()->addLine(rayStart[i<3?0:1], hit.position, color); + mSampleSubmarine->getDebugRenderer()->addLine(hit.position, hit.position + hit.normal*3.0f, rayColor); +#endif + } + else + mDistances[i] = rayDist; + } +} + +void Crab::initState(CrabState::Enum state) +{ + mCrabState = state; + mStateTime = gDefaultStateTime[mCrabState]; +} + +void Crab::updateState() +{ + // update remaining time in current state + // transition if needed + mStateTime -= mElapsedTime; + mElapsedTime = 0; + if(mStateTime <= 0.0f) + { + initState(CrabState::eMOVE_FWD); + } + + PxTransform crabPose; + { + PxSceneReadLock scopedLock(mSampleSubmarine->getActiveScene()); + crabPose = mCrabBody->getGlobalPose(); + } + + // check if we should go into panic mode + static const PxReal subMarinePanicDist = 50.0f; + if(mSampleSubmarine->mSubmarineActor && mCrabState != CrabState::ePANIC) + { + PxRaycastQueryResult& rayResult = mSqRayBuffer->mRayCastResults[6]; + if(rayResult.queryStatus == PxBatchQueryStatus::eSUCCESS && rayResult.getNbAnyHits() == 1) + { + const PxRaycastHit& hit = rayResult.getAnyHit(0); + PxVec3 subToCrab = crabPose.p - mSubmarinePos; + PxReal distanceToSubMarine = subToCrab.magnitude(); + if(hit.actor == mSampleSubmarine->mSubmarineActor && distanceToSubMarine <= subMarinePanicDist) + { + initState(CrabState::ePANIC); + } + } + } + + PxReal leftAcc = 0, rightAcc = 0; + // compute fwd and bkwd distances + static const PxReal minDist = 10.0f; + static const PxReal fullSpeedDist = 50.0f; + static const PxReal recipFullSpeedDist = 1.0f/fullSpeedDist; + PxReal fDist = 0, bDist = 0; + fDist = PxMin(mDistances[0], PxMin(mDistances[1], mDistances[2])); + bDist = PxMin(mDistances[3], PxMin(mDistances[4], mDistances[5])); + + // handle states + if(mCrabState == CrabState::eMOVE_FWD) + { + if(fDist < minDist) + { + initState(CrabState::eMOVE_BKWD); + } + else + { + leftAcc = PxMin(fullSpeedDist, mDistances[0])*recipFullSpeedDist*2.0f - 1.0f; + rightAcc = PxMin(fullSpeedDist, mDistances[2])*recipFullSpeedDist*2.0f - 1.0f; + leftAcc *= 3.0f; + rightAcc *= 3.0f; + } + } + else if (mCrabState == CrabState::eMOVE_BKWD) + { + if(bDist < minDist) + { + // find rotation dir, where we have some free space + bool rotateLeft = mDistances[0] < mDistances[2]; + initState(rotateLeft ? CrabState::eROTATE_LEFT : CrabState::eROTATE_RIGHT); + } + else + { + leftAcc = -(PxMin(fullSpeedDist, mDistances[5])*recipFullSpeedDist*2.0f - 1.0f); + rightAcc = -(PxMin(fullSpeedDist, mDistances[3])*recipFullSpeedDist*2.0f - 1.0f); + leftAcc *= 3.0f; + rightAcc *= 3.0f; + } + } + else if (mCrabState == CrabState::eROTATE_LEFT) + { + leftAcc = -3.0f; + rightAcc = 3.0f; + if(fDist > minDist) + { + initState(CrabState::eMOVE_FWD); + } + } + else if (mCrabState == CrabState::eROTATE_RIGHT) + { + leftAcc = 3.0f; + rightAcc = -3.0f; + if(fDist > minDist) + { + initState(CrabState::eMOVE_FWD); + } + } + else if (mCrabState == CrabState::ePANIC) + { + if(mSampleSubmarine->mSubmarineActor) + { + PxVec3 subToCrab = crabPose.p - mSubmarinePos; + PxReal distanceToSubMarine = subToCrab.magnitude(); + if(distanceToSubMarine <= subMarinePanicDist) + { + PxVec3 dir = crabPose.q.rotateInv(subToCrab); + dir.y = 0; + dir.normalize(); +#if DEBUG_RENDERING + PxVec3 startPos = crabPose.p + PxVec3(0,2,0); + mSampleSubmarine->getDebugRenderer()->addLine(startPos, startPos + crabPose.q.rotate(dir)*2.0f, SampleRenderer::RendererColor(0,255,0)); +#endif + leftAcc = (1.0f*dir.x + 0.2f*dir.z) * 6.0f; + rightAcc = (1.0f*dir.x - 0.2f*dir.z) * 6.0f; + } + } + } + else if (mCrabState == CrabState::eWAITING) + { + // have a break + } + + // change acceleration + setAcceleration(leftAcc, rightAcc); + +#if DEBUG_RENDERING + PxVec3 startPosL = crabPose.transform(PxVec3(0,2,-1)); + PxVec3 startPosR = crabPose.transform(PxVec3(0,2,1)); + mSampleSubmarine->getDebugRenderer()->addLine(startPosL, startPosL + crabPose.q.rotate(PxVec3(1,0,0))*leftAcc, SampleRenderer::RendererColor(255,255,0)); + mSampleSubmarine->getDebugRenderer()->addLine(startPosR, startPosR + crabPose.q.rotate(PxVec3(1,0,0))*rightAcc, SampleRenderer::RendererColor(0,255,0)); +#endif +} + + +SqRayBuffer::SqRayBuffer(SampleSubmarine& sampleSubmarine, PxU32 numRays, PxU32 numHits) +: mSampleSubmarine(sampleSubmarine) +, mQueryResultSize(numRays) +, mHitSize(numHits) +{ + mOrigAddresses[0] = malloc(mQueryResultSize*sizeof(PxRaycastQueryResult) + 15); + mOrigAddresses[1] = malloc(mHitSize*sizeof(PxRaycastHit) + 15); + + mRayCastResults = reinterpret_cast<PxRaycastQueryResult*>((size_t(mOrigAddresses[0]) + 15) & ~15); + mRayCastHits = reinterpret_cast<PxRaycastHit*>((size_t(mOrigAddresses[1]) + 15 )& ~15); + + PxBatchQueryDesc batchQueryDesc(mQueryResultSize, 0, 0); + batchQueryDesc.queryMemory.userRaycastResultBuffer = mRayCastResults; + batchQueryDesc.queryMemory.userRaycastTouchBuffer = mRayCastHits; + batchQueryDesc.queryMemory.raycastTouchBufferSize = mHitSize; + + mBatchQuery = mSampleSubmarine.getActiveScene().createBatchQuery(batchQueryDesc); + if(!mBatchQuery) mSampleSubmarine.fatalError("createBatchQuery failed!"); +} + +SqRayBuffer::~SqRayBuffer() +{ + mBatchQuery->release(); + free(mOrigAddresses[0]); + free(mOrigAddresses[1]); +} diff --git a/PhysX_3.4/Samples/SampleSubmarine/Crab.h b/PhysX_3.4/Samples/SampleSubmarine/Crab.h new file mode 100644 index 00000000..f05831b9 --- /dev/null +++ b/PhysX_3.4/Samples/SampleSubmarine/Crab.h @@ -0,0 +1,163 @@ +// This code contains NVIDIA Confidential Information and is disclosed to you +// under a form of NVIDIA software license agreement provided separately to you. +// +// Notice +// NVIDIA Corporation and its licensors retain all intellectual property and +// proprietary rights in and to this software and related documentation and +// any modifications thereto. Any use, reproduction, disclosure, or +// distribution of this software and related documentation without an express +// license agreement from NVIDIA Corporation is strictly prohibited. +// +// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES +// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO +// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT, +// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE. +// +// Information and code furnished is believed to be accurate and reliable. +// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such +// information or for any infringement of patents or other rights of third parties that may +// result from its use. No license is granted by implication or otherwise under any patent +// or patent rights of NVIDIA Corporation. Details are subject to change without notice. +// This code supersedes and replaces all information previously supplied. +// NVIDIA Corporation products are not authorized for use as critical +// components in life support devices or systems without express written approval of +// NVIDIA Corporation. +// +// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved. +// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved. +// Copyright (c) 2001-2004 NovodeX AG. All rights reserved. + +#ifndef CRAB_H +#define CRAB_H + +#include "foundation/Px.h" +#include "foundation/PxSimpleTypes.h" +#include "common/PxPhysXCommonConfig.h" +#include "task/PxTask.h" +#include "SampleAllocator.h" +#include <vector> + +class SampleSubmarine; + +namespace physx +{ + class PxRigidDynamic; + class PxRevoluteJoint; +} + + // Edge Labels for Theo Jansen's Mechanism + // _. + // ,' | m + // ,' |2b ..... + // ,' 2a | e |n + // +-------+---------+ + // | | + // | |2c + // | | + // +-------+ + // `. | + // `. |2d + // `. | + // `| + +struct LegParameters +{ + PxReal a; // half x-dim leg + PxReal b; // half height upper triangle + PxReal c; // half height distance joints (square) + PxReal d; // half height lower triangle + PxReal e; // x distance from main body centre + PxReal m; // half extent of the motor box + PxReal n; // y offset of the motor from the main body centre +}; + +struct CrabState +{ + enum Enum + { + eWAITING, + eMOVE_FWD, + eMOVE_BKWD, + eROTATE_LEFT, + eROTATE_RIGHT, + ePANIC, + eNUM_STATES, + }; +}; +struct SqRayBuffer: public SampleAllocateable +{ + SqRayBuffer(SampleSubmarine& sampleSubmarine, PxU32 numRays, PxU32 numHits); + ~SqRayBuffer(); + + SampleSubmarine& mSampleSubmarine; + PxBatchQuery* mBatchQuery; + + PxRaycastQueryResult* mRayCastResults; + PxRaycastHit* mRayCastHits; + + PxU32 mQueryResultSize; + PxU32 mHitSize; + void* mOrigAddresses[2]; +private: + SqRayBuffer& operator=(const SqRayBuffer&); +}; + +class Crab: public ClassType, public physx::PxLightCpuTask, public SampleAllocateable +{ +public: + Crab(SampleSubmarine& sample, const PxVec3& crabPos, RenderMaterial* material); + Crab(SampleSubmarine& sample, const char* filename, RenderMaterial* material); + ~Crab(); + + void update(PxReal dt); + void setAcceleration(PxReal leftAcc, PxReal rightAcc); + void flushAccelerationBuffer(); + + PX_INLINE const PxRigidDynamic* getCrabBody() const { return mCrabBody; } + PX_INLINE PxRigidDynamic* getCrabBody() { return mCrabBody; } + PX_INLINE bool needsRespawn() { return mRespawnMe; } + void save(const char* filename); + + // Implements LightCpuTask + virtual const char* getName() const { return "Crab AI Task"; } + virtual void run(); + +private: + void initMembers(); + void create(const PxVec3& _crabPos); + void load(const char* filename); + + PxVec3 getPlaceOnFloor(PxVec3 pos); + void createLeg(PxRigidDynamic* mainBody, PxVec3 localPos, PxReal mass, const LegParameters& params, PxReal scale, PxRigidDynamic* motor, PxVec3 motorAttachmentPos); + void scanForObstacles(); + void updateState(); + void initState(CrabState::Enum state); + +private: + SampleSubmarine* mSampleSubmarine; + + PxRigidDynamic* mCrabBody; + PxRevoluteJoint* mMotorJoint[2]; + std::vector<PxRigidDynamic*> mActors; + std::vector<PxJoint*> mJoints; + + + RenderMaterial* mMaterial; + PxReal mAcceleration[2]; + SqRayBuffer* mSqRayBuffer; + PxReal mLegHeight; + bool mRespawnMe; + + CrabState::Enum mCrabState; + PxReal mStateTime; + PxReal mDistances[10]; + PxReal mAccumTime; + PxReal mElapsedTime; + PxVec3 mSubmarinePos; + PxReal mAccelerationBuffer[2]; + + volatile PxU32 mRunning; + void* mMemory; +}; + +#endif diff --git a/PhysX_3.4/Samples/SampleSubmarine/SampleSubmarine.cpp b/PhysX_3.4/Samples/SampleSubmarine/SampleSubmarine.cpp new file mode 100644 index 00000000..4eaac18b --- /dev/null +++ b/PhysX_3.4/Samples/SampleSubmarine/SampleSubmarine.cpp @@ -0,0 +1,1278 @@ +// This code contains NVIDIA Confidential Information and is disclosed to you +// under a form of NVIDIA software license agreement provided separately to you. +// +// Notice +// NVIDIA Corporation and its licensors retain all intellectual property and +// proprietary rights in and to this software and related documentation and +// any modifications thereto. Any use, reproduction, disclosure, or +// distribution of this software and related documentation without an express +// license agreement from NVIDIA Corporation is strictly prohibited. +// +// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES +// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO +// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT, +// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE. +// +// Information and code furnished is believed to be accurate and reliable. +// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such +// information or for any infringement of patents or other rights of third parties that may +// result from its use. No license is granted by implication or otherwise under any patent +// or patent rights of NVIDIA Corporation. Details are subject to change without notice. +// This code supersedes and replaces all information previously supplied. +// NVIDIA Corporation products are not authorized for use as critical +// components in life support devices or systems without express written approval of +// NVIDIA Corporation. +// +// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved. +// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved. +// Copyright (c) 2001-2004 NovodeX AG. All rights reserved. + +#include "SampleSubmarine.h" +#include "SampleUtils.h" +#include "SampleAllocatorSDKClasses.h" +#include "RenderBaseActor.h" +#include "RendererMemoryMacros.h" +#include "RenderMaterial.h" + +#include "PxTkFile.h" +#include "PxPhysicsAPI.h" +#include "extensions/PxExtensionsAPI.h" + +#include <SamplePlatform.h> +#include <SampleUserInput.h> +#include <SampleUserInputIds.h> +#include "SampleSubmarineInputEventIds.h" +#include <SampleUserInputDefines.h> + +#include "Crab.h" + +#include "SubmarineCameraController.h" + +// for loading the HeightField +#include "RenderMeshActor.h" +#include "PxTkBmpLoader.h" +////////////////////////////// + +#include <algorithm> + +using namespace PxToolkit; +using namespace SampleRenderer; +using namespace SampleFramework; + +REGISTER_SAMPLE(SampleSubmarine, "SampleSubmarine") + +static PxVec3 gBuoyancy = PxVec3(0, 1.0f, 0); +static PxRigidDynamic* gTreasureActor = NULL; +static PxVec3 gForce = PxVec3(0, 0, 0); +static PxVec3 gTorque = PxVec3(0, 0, 0); +static const PxReal gLinPower = 200.0f; +static const PxReal gAngPower = 5000.0f; +static const PxReal gSubMarineDensity = 3.0f; +static PxI32 gSubmarineHealth = 100; +static PxU32 gKeyFlags = 0; +static bool gTreasureFound = false; +static bool gResetScene = false; + +static Crab* gCrab = NULL; + +void setupFiltering(PxRigidActor* actor, PxU32 filterGroup, PxU32 filterMask); + +struct Movement +{ + enum Enum + { + eCRAB_FWD = (1 << 0), + eCRAB_BCKWD = (1 << 1), + eCRAB_ROTATE_LEFT = (1 << 2), + eCRAB_ROTATE_RIGHT = (1 << 3), + eSUBMAINE_FWD = (1 << 4), + eSUBMAINE_BCKWD = (1 << 5), + eSUBMAINE_UP = (1 << 6), + eSUBMAINE_DOWN = (1 << 7), + }; +}; + + +enum MaterialID +{ + MATERIAL_TERRAIN_MUD = 1000, +}; + +/////////////////////////////////////////////////////////////////////////////// + + +SampleSubmarine::SampleSubmarine(PhysXSampleApplication& app) + : PhysXSample(app) + , mSubmarineActor(NULL) + , mCameraAttachedToActor(NULL) + , mSubmarineCameraController(NULL) +{ + mCreateGroundPlane = false; + //mStepperType = FIXED_STEPPER; +} + +SampleSubmarine::~SampleSubmarine() +{ +} + +/////////////////////////////////////////////////////////////////////////////// + +void SampleSubmarine::customizeSample(SampleSetup& setup) +{ + setup.mName = "SampleSubmarine"; +} + +/////////////////////////////////////////////////////////////////////////////// + +void SampleSubmarine::onInit() +{ + mNbThreads = PxMax(PxI32(shdfnd::Thread::getNbPhysicalCores())-1, 0); + + mCreateCudaCtxManager = true; + + PhysXSample::onInit(); + + PxSceneWriteLock scopedLock(*mScene); + + mSubmarineCameraController = SAMPLE_NEW(SubmarineCameraController)(); + setCameraController(mSubmarineCameraController); + + mApplication.setMouseCursorHiding(true); + mApplication.setMouseCursorRecentering(true); + mSubmarineCameraController->init(PxTransform(PxIdentity)); + mSubmarineCameraController->setMouseSensitivity(0.5f); + mSubmarineCameraController->setMouseLookOnMouseButton(false); + + getRenderer()->setAmbientColor(RendererColor(60, 60, 60)); + + PxMaterial& material = getDefaultMaterial(); + material.setRestitution(0); + material.setDynamicFriction(50.0f); + material.setStaticFriction(50.0f); + + // set gravity + getActiveScene().setGravity(PxVec3(0, -10.0f, 0)); + + createMaterials(); + + getRenderer()->setFog(SampleRenderer::RendererColor(16,16,40), 125.0f); + + PxRigidActor* heightField = loadTerrain("submarine_heightmap.bmp", 0.4f, 3.0f, 3.0f); + if (!heightField) fatalError("Sample can not load file submarine_heightmap.bmp\n"); + + setupFiltering(heightField, FilterGroup::eHEIGHTFIELD, FilterGroup::eCRAB); + + // create ceiling plane + PxReal d = 60.0f; + PxTransform pose = PxTransform(PxVec3(0.0f, d, 0.0f), PxQuat(PxHalfPi, PxVec3(0.0f, 0.0f, -1.0f))); + PxRigidStatic* plane = getPhysics().createRigidStatic(pose); + if(!plane) fatalError("createRigidStatic failed!"); + PxShape* shape = PxRigidActorExt::createExclusiveShape(*plane, PxPlaneGeometry(), material); + if(!shape) fatalError("createShape failed!"); + getActiveScene().addActor(*plane); + + resetScene(); +} + +void SampleSubmarine::createMaterials() +{ + RAWTexture data; + data.mName = "rock_diffuse2.dds"; + RenderTexture* gravelTexture = createRenderTextureFromRawTexture(data); + + RenderMaterial* terrainMaterial = SAMPLE_NEW(RenderMaterial)(*getRenderer(), PxVec3(0.5f, 0.25f, 0.125f), 1.0f, false, MATERIAL_TERRAIN_MUD, gravelTexture); + mRenderMaterials.push_back(terrainMaterial); + + mSeamineMaterial = SAMPLE_NEW(RenderMaterial)(*getRenderer(), PxVec3(0.50f, 0.50f, 0.5f), 1.0f, false, 0xffffffff, NULL); + mRenderMaterials.push_back(mSeamineMaterial); +} + + +PxRigidActor* SampleSubmarine::loadTerrain(const char* name, const PxReal heightScale, const PxReal rowScale, const PxReal columnScale) +{ + PxRigidActor* heightFieldActor = NULL; + BmpLoader loader; + if(loader.loadBmp(getSampleMediaFilename(name))) + { + PxU16 nbColumns = PxU16(loader.mWidth), nbRows = PxU16(loader.mHeight); + PxHeightFieldDesc heightFieldDesc; + heightFieldDesc.nbColumns = nbColumns; + heightFieldDesc.nbRows = nbRows; + PxU32* samplesData = (PxU32*)SAMPLE_ALLOC(sizeof(PxU32)*nbColumns * nbRows); + heightFieldDesc.samples.data = samplesData; + heightFieldDesc.samples.stride = sizeof(PxU32); + PxU8* currentByte = (PxU8*)heightFieldDesc.samples.data; + PxU8* loader_ptr = loader.mRGB; + PxVec3Alloc* vertexesA = SAMPLE_NEW(PxVec3Alloc)[nbRows * nbColumns]; + PxF32* uvs = (PxF32*)SAMPLE_ALLOC(sizeof(PxF32) * nbRows * nbColumns * 2); + PxVec3* vertexes = vertexesA; + for (PxU32 row = 0; row < nbRows; row++) + { + for (PxU32 column = 0; column < nbColumns; column++) + { + PxHeightFieldSample* currentSample = (PxHeightFieldSample*)currentByte; + currentSample->height = *loader_ptr; + vertexes[row * nbColumns + column] = PxVec3(PxReal(row)*rowScale, + PxReal(currentSample->height * heightScale), + PxReal(column)*columnScale); + + uvs[(row * nbColumns + column)*2 + 0] = (float)column/7.0f; + uvs[(row * nbColumns + column)*2 + 1] = (float)row/7.0f; + + currentSample->materialIndex0 = 0; + currentSample->materialIndex1 = 0; + currentSample->clearTessFlag(); + currentByte += heightFieldDesc.samples.stride; + loader_ptr += 3 * sizeof(PxU8); + } + } + PxHeightField* heightField = getCooking().createHeightField(heightFieldDesc, getPhysics().getPhysicsInsertionCallback()); + if(!heightField) fatalError("createHeightField failed!"); + // create shape for heightfield + PxTransform pose(PxVec3(-((PxReal)nbRows*rowScale) / 2.0f, + 0.0f, + -((PxReal)nbColumns*columnScale) / 2.0f), + PxQuat(PxIdentity)); + heightFieldActor = getPhysics().createRigidStatic(pose); + if(!heightFieldActor) fatalError("createRigidStatic failed!"); + PxShape* shape = PxRigidActorExt::createExclusiveShape(*heightFieldActor, PxHeightFieldGeometry(heightField, PxMeshGeometryFlags(), heightScale, rowScale, columnScale), getDefaultMaterial()); + if(!shape) fatalError("createShape failed!"); + // add actor to the scene + getActiveScene().addActor(*heightFieldActor); + // create indices + PxU32* indices = (PxU32*)SAMPLE_ALLOC(sizeof(PxU32)*((nbColumns - 1) * (nbRows - 1) * 3 * 2)); + for(int i = 0; i < (nbColumns - 1); ++i) + { + for(int j = 0; j < (nbRows - 1); ++j) + { + // first triangle + indices[6 * (i * (nbRows - 1) + j) + 0] = (i + 1) * nbRows + j; + indices[6 * (i * (nbRows - 1) + j) + 1] = i * nbRows + j; + indices[6 * (i * (nbRows - 1) + j) + 2] = i * nbRows + j + 1; + // second triangle + indices[6 * (i * (nbRows - 1) + j) + 3] = (i + 1) * nbRows + j + 1; + indices[6 * (i * (nbRows - 1) + j) + 4] = (i + 1) * nbRows + j; + indices[6 * (i * (nbRows - 1) + j) + 5] = i * nbRows + j + 1; + } + } + // add mesh to renderer + RAWMesh data; + data.mName = name; + data.mTransform = PxTransform(PxIdentity); + data.mNbVerts = nbColumns * nbRows; + data.mVerts = vertexes; + data.mVertexNormals = NULL; + data.mUVs = uvs; + data.mMaterialID = MATERIAL_TERRAIN_MUD; + data.mNbFaces = (nbColumns - 1) * (nbRows - 1) * 2; + data.mIndices = indices; + + RenderMeshActor* hf_mesh = createRenderMeshFromRawMesh(data); + if(!hf_mesh) fatalError("createRenderMeshFromRawMesh failed!"); + hf_mesh->setPhysicsShape(shape, heightFieldActor); + shape->setFlag(PxShapeFlag::eVISUALIZATION, false); + SAMPLE_FREE(indices); + SAMPLE_FREE(uvs); + DELETEARRAY(vertexesA); + SAMPLE_FREE(samplesData); + } + + return heightFieldActor; +} + +/////////////////////////////////////////////////////////////////////////////// + +void setupFiltering(PxRigidActor* actor, PxU32 filterGroup, PxU32 filterMask) +{ + PxFilterData filterData; + filterData.word0 = filterGroup; // word0 = own ID + filterData.word1 = filterMask; // word1 = ID mask to filter pairs that trigger a contact callback; + const PxU32 numShapes = actor->getNbShapes(); + PxShape** shapes = (PxShape**)SAMPLE_ALLOC(sizeof(PxShape*)*numShapes); + actor->getShapes(shapes, numShapes); + for(PxU32 i = 0; i < numShapes; i++) + { + PxShape* shape = shapes[i]; + shape->setSimulationFilterData(filterData); + } + SAMPLE_FREE(shapes); +} + +/////////////////////////////////////////////////////////////////////////////// + +PxRigidDynamic* SampleSubmarine::createSubmarine(const PxVec3& inPosition, const PxReal yRot) +{ + PX_ASSERT(mSubmarineActor == NULL); + + std::vector<PxTransform> localPoses; + std::vector<const PxGeometry*> geometries; + + // cabin + PxSphereGeometry cabinGeom(1.5f); + PxTransform cabinPose = PxTransform(PxIdentity); + cabinPose.p.x = -0.5f; + + // engine + PxBoxGeometry engineGeom(0.25f, 1.0f, 1.0f); + PxTransform enginePose = PxTransform(PxIdentity); + enginePose.p.x = cabinPose.p.x + cabinGeom.radius + engineGeom.halfExtents.x; + + // tanks + PxCapsuleGeometry tankGeom(0.5f, 1.8f); + PxTransform tank1Pose = PxTransform(PxIdentity); + tank1Pose.p = PxVec3(0,-cabinGeom.radius, cabinGeom.radius); + PxTransform tank2Pose = PxTransform(PxIdentity); + tank2Pose.p = PxVec3(0,-cabinGeom.radius, -cabinGeom.radius); + + localPoses.push_back(cabinPose); + geometries.push_back(&cabinGeom); + localPoses.push_back(enginePose); + geometries.push_back(&engineGeom); + localPoses.push_back(tank1Pose); + geometries.push_back(&tankGeom); + localPoses.push_back(tank2Pose); + geometries.push_back(&tankGeom); + + // put the shapes together into one actor + mSubmarineActor = PhysXSample::createCompound(inPosition, localPoses, geometries, 0, mManagedMaterials[MATERIAL_YELLOW], gSubMarineDensity)->is<PxRigidDynamic>(); + + if(!mSubmarineActor) fatalError("createCompound failed!"); + + //disable the current and buoyancy effect for the sub. + mSubmarineActor->setActorFlag(PxActorFlag::eDISABLE_GRAVITY, true); + + // set the filtering group for the submarine + setupFiltering(mSubmarineActor, FilterGroup::eSUBMARINE, FilterGroup::eMINE_HEAD | FilterGroup::eMINE_LINK); + + mSubmarineActor->setLinearDamping(0.15f); + mSubmarineActor->setAngularDamping(15.0f); + + PxTransform globalPose; + globalPose.p = inPosition; + globalPose.q = PxQuat(yRot, PxVec3(0,1,0)); + mSubmarineActor->setGlobalPose(globalPose); + + mSubmarineActor->setCMassLocalPose(PxTransform(PxIdentity)); + + return mSubmarineActor; +} + +/////////////////////////////////////////////////////////////////////////////// + +Seamine* SampleSubmarine::createSeamine(const PxVec3& inPosition, PxReal inHeight) +{ + static const PxReal chainLinkLength = 2.0f; + static const PxReal linkSpacing = 0.05f; + static const PxReal mineHeadRadius = 1.5f; + const PxVec3 mineStartPos = inPosition; + static const PxVec3 linkOffset = PxVec3(0, chainLinkLength + linkSpacing, 0); + static const PxVec3 halfLinkOffset = linkOffset * 0.5f; + static const PxVec3 linkDim = PxVec3(chainLinkLength*0.125f, chainLinkLength*0.5f, chainLinkLength*0.125f); + PxU32 numLinks = PxU32((inHeight - 2.0f*mineHeadRadius) / (chainLinkLength + linkSpacing)); + numLinks = numLinks ? numLinks : 1; + + Seamine* seamine = SAMPLE_NEW(Seamine); + mSeamines.push_back(seamine); + + // create links from floor + PxVec3 linkPos = mineStartPos + halfLinkOffset; + PxRigidActor* prevActor = NULL; + for(PxU32 i = 0; i < numLinks; i++) + { + // create the link actor + PxRigidDynamic* link = createBox(linkPos, linkDim, NULL, mSeamineMaterial, 1.0f)->is<PxRigidDynamic>(); + if(!link) fatalError("createBox failed!"); + // back reference to mineHead + link->userData = seamine; + seamine->mLinks.push_back(link); + + setupFiltering(link, FilterGroup::eMINE_LINK, FilterGroup::eSUBMARINE); + link->setLinearDamping(0.5f); + link->setAngularDamping(0.5f); + link->setActorFlag(PxActorFlag::eDISABLE_GRAVITY, true); + + // create distance joint between link and prevActor + PxTransform linkFrameA = prevActor ? PxTransform(halfLinkOffset, PxQuat(PxIdentity)) : PxTransform(mineStartPos, PxQuat(PxIdentity)); + PxTransform linkFrameB = PxTransform(-halfLinkOffset, PxQuat(PxIdentity)); + PxDistanceJoint *joint = PxDistanceJointCreate(getPhysics(), prevActor, linkFrameA, link, linkFrameB); + if(!joint) fatalError("PxDistanceJointCreate failed!"); + + // set min & max distance to 0 + joint->setMaxDistance(0.0f); + joint->setMinDistance(0.0f); + // setup damping & spring + joint->setDamping(1.0f * link->getMass()); + joint->setStiffness(400.0f * link->getMass()); + joint->setDistanceJointFlags(PxDistanceJointFlag::eMAX_DISTANCE_ENABLED | PxDistanceJointFlag::eMIN_DISTANCE_ENABLED | PxDistanceJointFlag::eSPRING_ENABLED); + + // add to joints array for cleanup + mJoints.push_back(joint); + + prevActor = link; + linkPos += linkOffset; + } + + // create mine head + linkPos.y += mineHeadRadius - (chainLinkLength*0.5f); + PxRigidDynamic* mineHead = createSphere(linkPos, mineHeadRadius, NULL, mSeamineMaterial, 1.0f)->is<PxRigidDynamic>(); + mineHead->userData = seamine; + seamine->mMineHead = mineHead; + + mineHead->setLinearDamping(0.5f); + mineHead->setAngularDamping(0.5f); + mineHead->setActorFlag(PxActorFlag::eDISABLE_GRAVITY, true); + + // setup filtering to trigger contact reports when submarine touches the minehead + setupFiltering(mineHead, FilterGroup::eMINE_HEAD, FilterGroup::eSUBMARINE); + + + // create distance joint between mine head and prevActor + PxTransform linkFrameA = PxTransform(halfLinkOffset, PxQuat(PxIdentity)); + PxTransform linkFrameB = PxTransform(PxVec3(0, -mineHeadRadius - linkSpacing*0.5f, 0), PxQuat(PxIdentity)); + PxDistanceJoint *joint = PxDistanceJointCreate(getPhysics(), prevActor, linkFrameA, mineHead, linkFrameB); + if(!joint) fatalError("PxDistanceJointCreate failed!"); + + // set min & max distance to 0 + joint->setMaxDistance(0.0f); + joint->setMinDistance(0.0f); + // setup damping & spring + joint->setDamping(1.0f * mineHead->getMass()); + joint->setStiffness(400.0f * mineHead->getMass()); + joint->setDistanceJointFlags(PxDistanceJointFlag::eMAX_DISTANCE_ENABLED | PxDistanceJointFlag::eMIN_DISTANCE_ENABLED | PxDistanceJointFlag::eSPRING_ENABLED); + + // add to joints array for cleanup + mJoints.push_back(joint); + + return seamine; +} + +/////////////////////////////////////////////////////////////////////////////// +static const char* getPlatformName() +{ +#if PX_X86 + return "PC32"; +#elif PX_X64 + return "PC64"; +#elif PX_ARM_FAMILY + return "ARM"; +#else + return ""; +#endif +} + +void SampleSubmarine::createDynamicActors() +{ + // create mines + static const PxU32 numMines = 20; + static const PxVec3 mineFieldCenter = PxVec3(0, 64, 0); + static const PxReal minMineDistance = 3.0f; + static const PxI32 mineFieldRadius = 30; + for(PxU32 i = 0; i < numMines; i++) + { + // raycast against floor (height field) to find the height to attach the mine + PxRaycastBuffer rayHit; + bool hit = false; + do + { + PxVec3 offset = PxVec3(PxReal(getSampleRandom().rand(-mineFieldRadius, mineFieldRadius)), 0, PxReal(getSampleRandom().rand(-mineFieldRadius, mineFieldRadius))); + PxVec3 raycastStart = mineFieldCenter + offset*minMineDistance; + hit = getActiveScene().raycast(raycastStart, PxVec3(0,-1,0), 100.0f, rayHit); + } while(!hit || (rayHit.block.position.y > 25.0f) || rayHit.block.actor->is<PxRigidDynamic>()); + createSeamine(rayHit.block.position, getSampleRandom().rand(10.0f, 25.0f)); + } + + // create treasure + { + static const PxVec3 treasureDim = PxVec3(5, 3, 4)*0.5f; + + PxRaycastBuffer rayHit; + PxVec3 raycastStart = PxVec3(-19, 64, -24); + getActiveScene().raycast(raycastStart, PxVec3(0,-1,0), 100.0f, rayHit); + + gTreasureActor = createBox(rayHit.block.position+treasureDim, treasureDim, NULL, mManagedMaterials[MATERIAL_BLUE], 1)->is<PxRigidDynamic>(); + + if(!gTreasureActor) fatalError("createBox failed!"); + gTreasureActor->setActorFlag(PxActorFlag::eDISABLE_GRAVITY, true); + PxShape* treasureShape; + gTreasureActor->getShapes(&treasureShape, 1); + treasureShape->setFlag(PxShapeFlag::eSIMULATION_SHAPE, false); + treasureShape->setFlag(PxShapeFlag::eTRIGGER_SHAPE, true); + } + + // create submarine + createSubmarine(PxVec3(-110, 50, 110), 2.1f); + + char theCrabName[256]; + sprintf(theCrabName, "crab_%s.bin", getPlatformName()); + // If we have already had crab copy, just load it, or will create crab and export it + char thePathBuffer[1024]; + const char* theCrabPath = getSampleOutputDirManager().getFilePath( theCrabName, thePathBuffer, false ); + SampleFramework::File* fp = NULL; + PxToolkit::fopen_s(&fp, theCrabPath, "r" ); + if( fp ) + { + shdfnd::printFormatted("loading the crab from file status: \n"); + gCrab = SAMPLE_NEW(Crab)(*this, theCrabPath, mManagedMaterials[MATERIAL_RED]); + if (gCrab && !gCrab->getCrabBody()) + { + delete gCrab; + gCrab = NULL; + } + shdfnd::printFormatted(gCrab ? "successful\n":"failed\n"); + fclose (fp); + } + + if( !gCrab ) + { + gCrab = SAMPLE_NEW(Crab)(*this, PxVec3(0, 50, 0), mManagedMaterials[MATERIAL_RED]); + shdfnd::printFormatted("crab file not found ... exporting crab file\n"); + gCrab->save(theCrabPath); + } + + PX_ASSERT( gCrab ); + mCrabs.push_back(gCrab); + + static const PxU32 numCrabs = 3; + for(PxU32 i = 0; i < numCrabs; i++) + { + Crab* crab = SAMPLE_NEW(Crab)(*this, PxVec3(getSampleRandom().rand(-20.0f,20.0f), 50, getSampleRandom().rand(-20.0f,20.0f)), mManagedMaterials[MATERIAL_RED]); + mCrabs.push_back(crab); + } +} + +/////////////////////////////////////////////////////////////////////////////// + +void SampleSubmarine::resetScene() +{ + gResetScene = false; + const size_t nbCrabs = mCrabs.size(); + for(PxU32 i=0;i<nbCrabs;i++) + { + delete mCrabs[i]; + } + mCrabs.clear(); + + const size_t nbJoints = mJoints.size(); + for(PxU32 i=0;i<nbJoints;i++) + mJoints[i]->release(); + mJoints.clear(); + + const size_t nbSeamines = mSeamines.size(); + for(PxU32 i=0;i<nbSeamines;i++) + { + const size_t nbLink = mSeamines[i]->mLinks.size(); + for(PxU32 j=0;j<nbLink;j++) + removeActor(mSeamines[i]->mLinks[j]); + removeActor(mSeamines[i]->mMineHead); + delete mSeamines[i]; + } + mSeamines.clear(); + + if(mSubmarineActor) + { + removeActor(mSubmarineActor); + mSubmarineActor = NULL; + } + gSubmarineHealth = 100; + + if (gTreasureActor) + removeActor(gTreasureActor); + gTreasureActor = NULL; + gTreasureFound = false; + + while(mPhysicsActors.size()) + { + removeActor(mPhysicsActors[0]); + } + + freeDeletedActors(); + + createDynamicActors(); + + // init camera orientation + mSubmarineCameraController->init(PxVec3(-90, 60, 50), PxVec3(0.28f, 2.05f, 0.0f)); + mSubmarineCameraController->setMouseSensitivity(0.5f); + mSubmarineCameraController->setFollowingMode(true); + mCameraAttachedToActor = mSubmarineActor; +} + +/////////////////////////////////////////////////////////////////////////////// + +void SampleSubmarine::onShutdown() +{ + { + PxSceneWriteLock scopedLock(*mScene); + + const size_t nbCrabs = mCrabs.size(); + for(PxU32 i=0;i<nbCrabs;i++) + delete mCrabs[i]; + mCrabs.clear(); + + // free crabs' memory + const size_t nbDelCrabsMem = mCrabsMemoryDeleteList.size(); + for(PxU32 i = 0; i < nbDelCrabsMem; i++) + SAMPLE_FREE(mCrabsMemoryDeleteList[i]); + mCrabsMemoryDeleteList.clear(); + + gCrab = NULL; + + const size_t nbJoints = mJoints.size(); + for(PxU32 i=0;i<nbJoints;i++) + mJoints[i]->release(); + mJoints.clear(); + + const size_t nbSeamines = mSeamines.size(); + for(PxU32 i=0;i<nbSeamines;i++) + delete mSeamines[i]; + mSeamines.clear(); + + gTreasureActor = NULL; + + DELETESINGLE(mSubmarineCameraController); + } + + PhysXSample::onShutdown(); +} + +/////////////////////////////////////////////////////////////////////////////// + +void SampleSubmarine::onSubstep(float dtime) +{ + // user input -> forces + handleInput(); + + // delay free crabs' memory + const size_t nbDelCrabsMem = mCrabsMemoryDeleteList.size(); + for(PxU32 i = 0; i < nbDelCrabsMem; i++) + SAMPLE_FREE(mCrabsMemoryDeleteList[i]); + mCrabsMemoryDeleteList.clear(); + + // change current every 0.01s + static PxReal sElapsedTime = 0.0f; + sElapsedTime += mPause ? 0 : dtime; + if(sElapsedTime > 0.01f) + { + static PxReal angle = 0; + angle += sElapsedTime*0.01f; + angle = angle < (PxTwoPi) ? angle : angle - PxTwoPi; + sElapsedTime = 0; + + gBuoyancy.z = 0.15f * PxSin(angle * 50); + PxQuat yRot = PxQuat(angle, PxVec3(0,1,0)); + gBuoyancy = yRot.rotate(gBuoyancy); + + // apply external forces to seamines + PxSceneWriteLock scopedLock(*mScene); + const size_t nbSeamines = mSeamines.size(); + for(PxU32 i = 0; i < nbSeamines; i++) + { + Seamine* mine = mSeamines[i]; + mine->mMineHead->addForce(gBuoyancy, PxForceMode::eACCELERATION); + const size_t nbLinks = mine->mLinks.size(); + for(PxU32 j = 0; j < nbLinks; j++) + { + mine->mLinks[j]->addForce(gBuoyancy, PxForceMode::eACCELERATION); + } + } + } + + if(mSubmarineActor) + { + PxSceneWriteLock scopedLock(*mScene); + + //convert forces from submarine the submarine's body local space to global space + PxQuat submarineOrientation = mSubmarineActor->getGlobalPose().q; + gForce = submarineOrientation.rotate(gForce); + gTorque = submarineOrientation.rotate(gTorque); + + // add also current forces to submarine + gForce.z += gBuoyancy.z * 5.0f; + + // apply forces in global space and reset + mSubmarineActor->addForce(gForce); + mSubmarineActor->addTorque(gTorque); + gForce = PxVec3(0); + gTorque = PxVec3(0); + } +} + +void SampleSubmarine::onSubstepSetup(float dt, PxBaseTask* completionTask) +{ + // set Crabs continuation to ensure the completion task + // is not run before Crab update has completed + const size_t nbCrabs = mCrabs.size(); + for(PxU32 i = 0; i < nbCrabs; i++) + { + Crab* crab = mCrabs[i]; + crab->update(dt); + crab->setContinuation(completionTask); + } +} + +void SampleSubmarine::onSubstepStart(float dtime) +{ + // kick off crab updates in parallel to simulate + const size_t nbCrabs = mCrabs.size(); + for(PxU32 i = 0; i < nbCrabs; i++) + { + Crab* crab = mCrabs[i]; + // inverted stepper: skip crab updates right after creation, + // crab task is not in the pipeline at this point (onSubstepSetup not yet called). + if(crab->getTaskManager() == NULL) + continue; + crab->removeReference(); + } +} + +void SampleSubmarine::onTickPreRender(float dtime) +{ + mScene->lockWrite(); + + if(gResetScene) + resetScene(); + + // handle mine (and submarine) explosion + if(mSubmarineActor) + { + // explode all touched mines, apply damage and force to submarine + PxVec3 subMarinePos = mSubmarineActor->getGlobalPose().p; + const size_t nbExplodeSeamines = mMinesToExplode.size(); + for(PxU32 i=0; i < nbExplodeSeamines; i++) + { + Seamine* mine = mMinesToExplode[i]; + PxVec3 explosionPos = mine->mMineHead->getGlobalPose().p; + + // disable contact trigger callback of the chain & enable gravity + const size_t nbLinks = mine->mLinks.size(); + for(PxU32 j = 0; j < nbLinks; j++) + { + PxRigidDynamic* link = mine->mLinks[j]; + setupFiltering(link, 0, 0); + link->setActorFlag(PxActorFlag::eDISABLE_GRAVITY, false); + } + + // remove mine head + std::vector<Seamine*>::iterator mineIter = std::find(mSeamines.begin(), mSeamines.end(), mine); + if(mineIter != mSeamines.end()) + mSeamines.erase(mineIter); + removeActor(mine->mMineHead); + delete mine; + + // give damage to submarine + static const PxReal strength = 400.0f; + PxVec3 explosion = subMarinePos - explosionPos; + PxReal len = explosion.normalize(); + PxReal damage = strength * (1.0f/len); + explosion *= damage; + mSubmarineActor->addForce(explosion*300); + gSubmarineHealth = PxMax(gSubmarineHealth-PxI32(damage), 0); + if(gSubmarineHealth == 0) + { + mSubmarineCameraController->init(subMarinePos - getCamera().getViewDir()*10.0f, getCamera().getRot()); + explode(mSubmarineActor, subMarinePos /*- explosion*0.2f*/, damage); + mCameraAttachedToActor = NULL; + mSubmarineCameraController->setFollowingMode(false); + mSubmarineActor = NULL; + break; + } + } + mMinesToExplode.clear(); + } + + // respawn Crabs + const size_t nbCrabs = mCrabs.size(); + for(PxU32 i = 0; i < nbCrabs; i++) + { + Crab* crab = mCrabs[i]; + if(crab->needsRespawn()) + { + PxRigidDynamic* prevBody = crab->getCrabBody(); + PxVec3 prevPos = prevBody->getGlobalPose().p; + delete crab; + mCrabs[i] = SAMPLE_NEW(Crab)(*this, prevPos, mManagedMaterials[MATERIAL_RED]); + if(gCrab == crab) + gCrab = mCrabs[i]; + if(mCameraAttachedToActor == prevBody) + mCameraAttachedToActor = mCrabs[i]->getCrabBody(); + } + } + + // update camera + if(mCameraAttachedToActor) + mSubmarineCameraController->updateFollowingMode(getCamera(), dtime, mCameraAttachedToActor->getGlobalPose().p); + + mScene->unlockWrite(); + + // start the simulation + PhysXSample::onTickPreRender(dtime); +} + +/////////////////////////////////////////////////////////////////////////////// + +void SampleSubmarine::explode(PxRigidActor* actor, const PxVec3& explosionPos, const PxReal explosionStrength) +{ + size_t numRenderActors = mRenderActors.size(); + for(PxU32 i = 0; i < numRenderActors; i++) + { + if(mRenderActors[i]->getPhysicsActor() == actor) + { + PxShape* shape = mRenderActors[i]->getPhysicsShape(); + PxTransform pose = PxShapeExt::getGlobalPose(*shape, *actor); + + PxGeometryHolder geom = shape->getGeometry(); + + // create new actor from shape (to split compound) + PxRigidDynamic* newActor = mPhysics->createRigidDynamic(pose); + if(!newActor) fatalError("createRigidDynamic failed!"); + + PxShape* newShape = PxRigidActorExt::createExclusiveShape(*newActor, geom.any(), *mMaterial); + unlink(mRenderActors[i], shape, actor); + link(mRenderActors[i], newShape, newActor); + + newActor->setActorFlag(PxActorFlag::eVISUALIZATION, true); + newActor->setLinearDamping(10.5f); + newActor->setAngularDamping(0.5f); + PxRigidBodyExt::updateMassAndInertia(*newActor, 1.0f); + mScene->addActor(*newActor); + mPhysicsActors.push_back(newActor); + + PxVec3 explosion = pose.p - explosionPos; + PxReal len = explosion.normalize(); + explosion *= (explosionStrength / len); + newActor->setLinearVelocity(explosion); + newActor->setAngularVelocity(PxVec3(1,2,3)); + + } + } + + removeActor(actor); +} +/////////////////////////////////////////////////////////////////////////////// + + +PxFilterFlags SampleSubmarineFilterShader( + PxFilterObjectAttributes attributes0, PxFilterData filterData0, + PxFilterObjectAttributes attributes1, PxFilterData filterData1, + PxPairFlags& pairFlags, const void* constantBlock, PxU32 constantBlockSize) +{ + // let triggers through + if(PxFilterObjectIsTrigger(attributes0) || PxFilterObjectIsTrigger(attributes1)) + { + pairFlags = PxPairFlag::eTRIGGER_DEFAULT; + return PxFilterFlag::eDEFAULT; + } + // generate contacts for all that were not filtered above + pairFlags = PxPairFlag::eCONTACT_DEFAULT; + + // trigger the contact callback for pairs (A,B) where + // the filtermask of A contains the ID of B and vice versa. + if((filterData0.word0 & filterData1.word1) && (filterData1.word0 & filterData0.word1)) + pairFlags |= PxPairFlag::eNOTIFY_TOUCH_FOUND; + + return PxFilterFlag::eDEFAULT; +} + +/////////////////////////////////////////////////////////////////////////////// + +void SampleSubmarine::customizeSceneDesc(PxSceneDesc& sceneDesc) +{ + sceneDesc.filterShader = SampleSubmarineFilterShader; + sceneDesc.simulationEventCallback = this; + sceneDesc.flags |= PxSceneFlag::eREQUIRE_RW_LOCK; +} + +/////////////////////////////////////////////////////////////////////////////// + +void SampleSubmarine::onContact(const PxContactPairHeader& pairHeader, const PxContactPair* pairs, PxU32 nbPairs) +{ + for(PxU32 i=0; i < nbPairs; i++) + { + const PxContactPair& cp = pairs[i]; + + if(cp.events & PxPairFlag::eNOTIFY_TOUCH_FOUND) + { + if((pairHeader.actors[0] == mSubmarineActor) || (pairHeader.actors[1] == mSubmarineActor)) + { + PxActor* otherActor = (mSubmarineActor == pairHeader.actors[0]) ? pairHeader.actors[1] : pairHeader.actors[0]; + Seamine* mine = reinterpret_cast<Seamine*>(otherActor->userData); + // insert only once + if(std::find(mMinesToExplode.begin(), mMinesToExplode.end(), mine) == mMinesToExplode.end()) + mMinesToExplode.push_back(mine); + + break; + } + } + } +} + +/////////////////////////////////////////////////////////////////////////////// + +void SampleSubmarine::onTrigger(PxTriggerPair* pairs, PxU32 count) +{ + for(PxU32 i=0; i < count; i++) + { + // ignore pairs when shapes have been deleted + if (pairs[i].flags & (PxTriggerPairFlag::eREMOVED_SHAPE_TRIGGER | PxTriggerPairFlag::eREMOVED_SHAPE_OTHER)) + continue; + + if((pairs[i].otherActor == mSubmarineActor) && (pairs[i].triggerActor == gTreasureActor)) + { + gTreasureFound = true; + } + } +} + +/////////////////////////////////////////////////////////////////////////////// + +void SampleSubmarine::helpRender(PxU32 x, PxU32 y, PxU8 textAlpha) +{ + SampleRenderer::Renderer* renderer = getRenderer(); + const PxU32 yInc = 18; + const PxReal scale = 0.5f; + const PxReal shadowOffset = 6.0f; + const RendererColor textColor(255, 255, 255, textAlpha); + const bool isMouseSupported = getApplication().getPlatform()->getSampleUserInput()->mouseSupported(); + const bool isPadSupported = getApplication().getPlatform()->getSampleUserInput()->gamepadSupported(); + const char* msg; + + msg = mApplication.inputInfoMsg("Press "," to toggle various debug visualization", TOGGLE_VISUALIZATION, -1); + if(msg) + renderer->print(x, y += yInc, msg,scale, shadowOffset, textColor); + msg = mApplication.inputInfoMsg("Press "," to restart", SCENE_RESET,-1); + if(msg) + renderer->print(x, y += yInc, msg,scale, shadowOffset, textColor); + if (isMouseSupported && isPadSupported) + renderer->print(x, y += yInc, "Use mouse or right stick to rotate the camera", scale, shadowOffset, textColor); + else if (isMouseSupported) + renderer->print(x, y += yInc, "Use mouse to rotate the camera", scale, shadowOffset, textColor); + else if (isPadSupported) + renderer->print(x, y += yInc, "Use right stick to rotate the camera", scale, shadowOffset, textColor); + msg = mApplication.inputInfoMsg("Press "," to switch between submarine/crab/flyCam", CAMERA_SWITCH, -1); + if(msg) + renderer->print(x, y += yInc, msg,scale, shadowOffset, textColor); + + if(mCameraAttachedToActor == mSubmarineActor) + { + renderer->print(x, y += yInc, "Submarine Controller:", scale, shadowOffset, textColor); + const char* msg = mApplication.inputInfoMsg("Press "," to move along view direction", SUBMARINE_FORWARD, SUBMARINE_BACKWARD); + if(msg) + renderer->print(x, y += yInc, msg,scale, shadowOffset, textColor); + msg = mApplication.inputInfoMsg("Press "," to raise and dive", SUBMARINE_UP, SUBMARINE_DOWN); + if(msg) + renderer->print(x, y += yInc, msg,scale, shadowOffset, textColor); + } + else if(gCrab && (mCameraAttachedToActor == gCrab->getCrabBody())) + { + renderer->print(x, y += yInc, "Crab Controller:", scale, shadowOffset, textColor); + if (isPadSupported) + renderer->print(x, y += yInc, "Use left stick to move the crab", scale, shadowOffset, textColor); + const char* msg = mApplication.inputMoveInfoMsg("Press "," to move the crab", CRAB_FORWARD, CRAB_BACKWARD, CRAB_LEFT, CRAB_RIGHT); + if(msg) + renderer->print(x, y += yInc, msg,scale, shadowOffset, textColor); + } + else + { + renderer->print(x, y += yInc, "Fly Cam Controller:", scale, shadowOffset, textColor); + if (isPadSupported) + renderer->print(x, y += yInc, "Use left stick to move",scale, shadowOffset, textColor); + const char* msg = mApplication.inputMoveInfoMsg("Press "," to move", CAMERA_MOVE_FORWARD,CAMERA_MOVE_BACKWARD, CAMERA_MOVE_LEFT, CAMERA_MOVE_RIGHT); + if(msg) + renderer->print(x, y += yInc, msg,scale, shadowOffset, textColor); + msg = mApplication.inputInfoMsg("Press "," to move fast", CAMERA_SHIFT_SPEED, -1); + if(msg) + renderer->print(x, y += yInc, msg, scale, shadowOffset, textColor); + } +} + +void SampleSubmarine::descriptionRender(PxU32 x, PxU32 y, PxU8 textAlpha) +{ + bool print=(textAlpha!=0.0f); + + if(print) + { + Renderer* renderer = getRenderer(); + const PxU32 yInc = 24; + const PxReal scale = 0.5f; + const PxReal shadowOffset = 6.0f; + const RendererColor textColor(255, 255, 255, textAlpha); + + char line0[256]="This sample demonstrates the creation of jointed systems. In particular,"; + char line1[256]="a complex system of driven joints is introduced to model crab motion,"; + char line2[256]="while distance joints are used to model the tethering of exploding sea"; + char line3[256]="mines to the seabed. Trigger shapes are presented to detect the"; + char line4[256]="arrival of the submarine at a treasure chest on the ocean floor."; + char line5[256]="Similarly, contact notification is used to report the overlap of the"; + char line6[256]="submarine with the exploding sea mines. Crab logic is governed by sdk"; + char line7[256]="raycast results, and illustrates the application of the PhysX SDK task"; + char line8[256]="scheduler."; + + renderer->print(x, y+=yInc, line0, scale, shadowOffset, textColor); + renderer->print(x, y+=yInc, line1, scale, shadowOffset, textColor); + renderer->print(x, y+=yInc, line2, scale, shadowOffset, textColor); + renderer->print(x, y+=yInc, line3, scale, shadowOffset, textColor); + renderer->print(x, y+=yInc, line4, scale, shadowOffset, textColor); + renderer->print(x, y+=yInc, line5, scale, shadowOffset, textColor); + renderer->print(x, y+=yInc, line6, scale, shadowOffset, textColor); + renderer->print(x, y+=yInc, line7, scale, shadowOffset, textColor); + renderer->print(x, y+=yInc, line8, scale, shadowOffset, textColor); + } +} + +/////////////////////////////////////////////////////////////////////////////// + +void SampleSubmarine::customizeRender() +{ + SampleRenderer::Renderer* renderer = getRenderer(); + const PxU32 yInc = 18; + const RendererColor textColor(255, 255, 255, 255); + + PxU32 width, height; + renderer->getWindowSize(width, height); + char healthBar[20]; + PxU32 h = gSubmarineHealth; + sprintf(healthBar, "Health:%c%c%c%c%c%c%c%c%c%c", (h>90?'I':' '), (h>80?'I':' '), (h>70?'I':' '),(h>60?'I':' '),(h>50?'I':' '), + (h>40?'I':' '), (h>30?'I':' '), (h>20?'I':' '),(h>10?'I':' '),(h>0?'I':' ')); + renderer->print(width-130, height-yInc, healthBar); + if(gTreasureFound) + renderer->print(width-160, height-2*yInc, "Treasure Found!"); +} + +/////////////////////////////////////////////////////////////////////////////// + +static void setFlag(PxU32& flags, PxU32 flag, bool set) +{ + if(set) + flags |= flag; + else + flags &= ~flag; +} + +/////////////////////////////////////////////////////////////////////////////// + +void SampleSubmarine::onPointerInputEvent(const SampleFramework::InputEvent& ie, physx::PxU32 x, physx::PxU32 y, physx::PxReal dx, physx::PxReal dy, bool val) +{ + if(ie.m_Id== CAMERA_MOUSE_LOOK || !mSubmarineActor || mCameraAttachedToActor != mSubmarineActor) + PhysXSample::onPointerInputEvent(ie,x,y,dx,dy, val); + + switch (ie.m_Id) + { + case SUBMARINE_FORWARD: + { + setFlag(gKeyFlags, Movement::eSUBMAINE_FWD, val); + } + break; + case SUBMARINE_BACKWARD: + { + setFlag(gKeyFlags, Movement::eSUBMAINE_BCKWD, val); + } + break; + default: + break; + } +} + +////////////////////////////////////////////////////////////////////////// + +void SampleSubmarine::collectInputEvents(std::vector<const SampleFramework::InputEvent*>& inputEvents) +{ + PhysXSample::collectInputEvents(inputEvents); + + getApplication().getPlatform()->getSampleUserInput()->unregisterInputEvent(CAMERA_MOVE_UP); + getApplication().getPlatform()->getSampleUserInput()->unregisterInputEvent(CAMERA_MOVE_DOWN); + getApplication().getPlatform()->getSampleUserInput()->unregisterInputEvent(CAMERA_SPEED_INCREASE); + getApplication().getPlatform()->getSampleUserInput()->unregisterInputEvent(CAMERA_SPEED_DECREASE); + getApplication().getPlatform()->getSampleUserInput()->unregisterInputEvent(CAMERA_MOVE_BUTTON); + getApplication().getPlatform()->getSampleUserInput()->unregisterInputEvent(MOUSE_LOOK_BUTTON); + getApplication().getPlatform()->getSampleUserInput()->unregisterInputEvent(SPAWN_DEBUG_OBJECT); + + //digital mouse events + DIGITAL_INPUT_EVENT_DEF(SUBMARINE_FORWARD, MOUSE_BUTTON_LEFT, XKEY_UNKNOWN, X1KEY_UNKNOWN, PS3KEY_UNKNOWN, PS4KEY_UNKNOWN, AKEY_UNKNOWN, MOUSE_BUTTON_LEFT, IKEY_UNKNOWN, MOUSE_BUTTON_LEFT, WIIUKEY_UNKNOWN); + DIGITAL_INPUT_EVENT_DEF(SUBMARINE_BACKWARD, MOUSE_BUTTON_RIGHT, XKEY_UNKNOWN, X1KEY_UNKNOWN, PS3KEY_UNKNOWN, PS4KEY_UNKNOWN, AKEY_UNKNOWN, MOUSE_BUTTON_RIGHT, IKEY_UNKNOWN, MOUSE_BUTTON_RIGHT, WIIUKEY_UNKNOWN); + + //digital keyboard events + DIGITAL_INPUT_EVENT_DEF(CRAB_FORWARD, SCAN_CODE_FORWARD, XKEY_W, X1KEY_W, PS3KEY_W, PS4KEY_W, AKEY_UNKNOWN, SCAN_CODE_FORWARD, IKEY_UNKNOWN, SCAN_CODE_FORWARD, WIIUKEY_UNKNOWN); + DIGITAL_INPUT_EVENT_DEF(CRAB_BACKWARD, SCAN_CODE_BACKWARD, XKEY_S, X1KEY_S, PS3KEY_S, PS4KEY_S, AKEY_UNKNOWN, SCAN_CODE_BACKWARD, IKEY_UNKNOWN, SCAN_CODE_BACKWARD, WIIUKEY_UNKNOWN); + DIGITAL_INPUT_EVENT_DEF(CRAB_LEFT, SCAN_CODE_LEFT, XKEY_A, X1KEY_A, PS3KEY_A, PS4KEY_A, AKEY_UNKNOWN, SCAN_CODE_LEFT, IKEY_UNKNOWN, SCAN_CODE_LEFT, WIIUKEY_UNKNOWN); + DIGITAL_INPUT_EVENT_DEF(CRAB_RIGHT, SCAN_CODE_RIGHT, XKEY_D, X1KEY_D, PS3KEY_D, PS4KEY_D, AKEY_UNKNOWN, SCAN_CODE_RIGHT, IKEY_UNKNOWN, SCAN_CODE_RIGHT, WIIUKEY_UNKNOWN); + DIGITAL_INPUT_EVENT_DEF(SUBMARINE_UP, SCAN_CODE_FORWARD, XKEY_E, X1KEY_E, PS3KEY_E, PS4KEY_E, AKEY_UNKNOWN, SCAN_CODE_FORWARD, IKEY_UNKNOWN, SCAN_CODE_FORWARD, WIIUKEY_UNKNOWN); + DIGITAL_INPUT_EVENT_DEF(SUBMARINE_DOWN, SCAN_CODE_BACKWARD, XKEY_D, X1KEY_D, PS3KEY_D, PS4KEY_D, AKEY_UNKNOWN, SCAN_CODE_BACKWARD, IKEY_UNKNOWN, SCAN_CODE_BACKWARD, WIIUKEY_UNKNOWN); + DIGITAL_INPUT_EVENT_DEF(CAMERA_SWITCH, SCAN_CODE_DOWN, XKEY_C, X1KEY_C, PS3KEY_C, PS4KEY_C, AKEY_UNKNOWN, SCAN_CODE_DOWN, IKEY_UNKNOWN, SCAN_CODE_DOWN, WIIUKEY_UNKNOWN); + DIGITAL_INPUT_EVENT_DEF(SCENE_RESET, WKEY_R, XKEY_R, X1KEY_R, PS3KEY_R, PS4KEY_R, AKEY_UNKNOWN, OSXKEY_R, IKEY_UNKNOWN, LINUXKEY_R, WIIUKEY_UNKNOWN); + + //digital gamepad events + DIGITAL_INPUT_EVENT_DEF(SUBMARINE_FORWARD, GAMEPAD_RIGHT_SHOULDER_BOT, GAMEPAD_RIGHT_SHOULDER_BOT, GAMEPAD_RIGHT_SHOULDER_BOT, GAMEPAD_RIGHT_SHOULDER_BOT, GAMEPAD_RIGHT_SHOULDER_BOT, AKEY_UNKNOWN, GAMEPAD_RIGHT_SHOULDER_BOT, IKEY_UNKNOWN, LINUXKEY_UNKNOWN, GAMEPAD_RIGHT_SHOULDER_BOT); + DIGITAL_INPUT_EVENT_DEF(SUBMARINE_BACKWARD, GAMEPAD_LEFT_SHOULDER_BOT, GAMEPAD_LEFT_SHOULDER_BOT, GAMEPAD_LEFT_SHOULDER_BOT, GAMEPAD_LEFT_SHOULDER_BOT, GAMEPAD_LEFT_SHOULDER_BOT, AKEY_UNKNOWN, GAMEPAD_LEFT_SHOULDER_BOT, IKEY_UNKNOWN, LINUXKEY_UNKNOWN, GAMEPAD_LEFT_SHOULDER_BOT); + DIGITAL_INPUT_EVENT_DEF(SUBMARINE_UP, GAMEPAD_RIGHT_SHOULDER_TOP, GAMEPAD_RIGHT_SHOULDER_TOP, GAMEPAD_RIGHT_SHOULDER_TOP, GAMEPAD_RIGHT_SHOULDER_TOP, GAMEPAD_RIGHT_SHOULDER_TOP, AKEY_UNKNOWN, GAMEPAD_RIGHT_SHOULDER_TOP, IKEY_UNKNOWN, LINUXKEY_UNKNOWN, GAMEPAD_RIGHT_SHOULDER_TOP); + DIGITAL_INPUT_EVENT_DEF(SUBMARINE_DOWN, GAMEPAD_LEFT_SHOULDER_TOP, GAMEPAD_LEFT_SHOULDER_TOP, GAMEPAD_LEFT_SHOULDER_TOP, GAMEPAD_LEFT_SHOULDER_TOP, GAMEPAD_LEFT_SHOULDER_TOP, AKEY_UNKNOWN, GAMEPAD_LEFT_SHOULDER_TOP, IKEY_UNKNOWN, LINUXKEY_UNKNOWN, GAMEPAD_LEFT_SHOULDER_TOP); + DIGITAL_INPUT_EVENT_DEF(CAMERA_SWITCH, GAMEPAD_RIGHT_STICK, GAMEPAD_RIGHT_STICK, GAMEPAD_RIGHT_STICK, GAMEPAD_RIGHT_STICK, GAMEPAD_RIGHT_STICK, AKEY_UNKNOWN, GAMEPAD_RIGHT_STICK, IKEY_UNKNOWN, LINUXKEY_UNKNOWN, GAMEPAD_RIGHT_STICK); + DIGITAL_INPUT_EVENT_DEF(SCENE_RESET, GAMEPAD_LEFT_STICK, GAMEPAD_LEFT_STICK, GAMEPAD_LEFT_STICK, GAMEPAD_LEFT_STICK, GAMEPAD_LEFT_STICK, AKEY_UNKNOWN, GAMEPAD_LEFT_STICK, IKEY_UNKNOWN, LINUXKEY_UNKNOWN, GAMEPAD_LEFT_STICK); + + // analog gamepad events + ANALOG_INPUT_EVENT_DEF(CRAB_LEFT_RIGHT, GAMEPAD_DEFAULT_SENSITIVITY, GAMEPAD_LEFT_STICK_X, GAMEPAD_LEFT_STICK_X, GAMEPAD_LEFT_STICK_X, GAMEPAD_LEFT_STICK_X, GAMEPAD_LEFT_STICK_X, GAMEPAD_LEFT_STICK_X, GAMEPAD_LEFT_STICK_X, GAMEPAD_LEFT_STICK_X, LINUXKEY_UNKNOWN, GAMEPAD_LEFT_STICK_X); + ANALOG_INPUT_EVENT_DEF(CRAB_FORWARD_BACKWARD, GAMEPAD_DEFAULT_SENSITIVITY, GAMEPAD_LEFT_STICK_Y, GAMEPAD_LEFT_STICK_Y, GAMEPAD_LEFT_STICK_Y, GAMEPAD_LEFT_STICK_Y, GAMEPAD_LEFT_STICK_Y, GAMEPAD_LEFT_STICK_Y, GAMEPAD_LEFT_STICK_Y, GAMEPAD_LEFT_STICK_Y, LINUXKEY_UNKNOWN, GAMEPAD_LEFT_STICK_Y); + ANALOG_INPUT_EVENT_DEF(SUBMARINE_FORWARD_BACKWARD, GAMEPAD_DEFAULT_SENSITIVITY, GAMEPAD_LEFT_STICK_Y, XKEY_UNKNOWN, X1KEY_UNKNOWN, PS3KEY_UNKNOWN, PS4KEY_UNKNOWN, GAMEPAD_LEFT_STICK_Y, OSXKEY_UNKNOWN, GAMEPAD_LEFT_STICK_Y, LINUXKEY_UNKNOWN, WIIUKEY_UNKNOWN); + + //touch events + TOUCH_INPUT_EVENT_DEF(SCENE_RESET, "Reset", ABUTTON_5, IBUTTON_5); + TOUCH_INPUT_EVENT_DEF(CAMERA_SWITCH, "Switch Cam", ABUTTON_6, IBUTTON_6); + TOUCH_INPUT_EVENT_DEF(SUBMARINE_UP, "Rise", ABUTTON_7, IBUTTON_7); + TOUCH_INPUT_EVENT_DEF(SUBMARINE_DOWN, "Drop", ABUTTON_8, IBUTTON_8); +} + +/////////////////////////////////////////////////////////////////////////////// + +void SampleSubmarine::onDigitalInputEvent(const SampleFramework::InputEvent& ie, bool val) +{ + if(mSubmarineActor && mCameraAttachedToActor == mSubmarineActor) + { + switch (ie.m_Id) + { + case SUBMARINE_FORWARD: + setFlag(gKeyFlags, Movement::eSUBMAINE_FWD, val); + break; + case SUBMARINE_BACKWARD: + setFlag(gKeyFlags, Movement::eSUBMAINE_BCKWD, val); + break; + case SUBMARINE_UP: + setFlag(gKeyFlags, Movement::eSUBMAINE_UP, val); + break; + case SUBMARINE_DOWN: + setFlag(gKeyFlags, Movement::eSUBMAINE_DOWN, val); + break; + } + } + else if (gCrab && mCameraAttachedToActor == gCrab->getCrabBody()) + { + switch (ie.m_Id) + { + case CRAB_FORWARD: + setFlag(gKeyFlags, Movement::eCRAB_FWD, val); + break; + case CRAB_BACKWARD: + setFlag(gKeyFlags, Movement::eCRAB_BCKWD, val); + break; + case CRAB_LEFT: + setFlag(gKeyFlags, Movement::eCRAB_ROTATE_LEFT, val); + break; + case CRAB_RIGHT: + setFlag(gKeyFlags, Movement::eCRAB_ROTATE_RIGHT, val); + break; + } + } + + if (val) + { + switch (ie.m_Id) + { + case CAMERA_SWITCH: + { + // cycle camera + if(mSubmarineActor && mCameraAttachedToActor == NULL) + mCameraAttachedToActor = mSubmarineActor; + else if(gCrab && mCameraAttachedToActor != gCrab->getCrabBody()) + mCameraAttachedToActor = gCrab->getCrabBody(); + else + mCameraAttachedToActor = NULL; + + mSubmarineCameraController->init(getCamera().getPos(), getCamera().getRot()); + mSubmarineCameraController->setFollowingMode(mCameraAttachedToActor != NULL); + } + break; + case SCENE_RESET: + { + gResetScene = true; + } + break; + } + } + + PhysXSample::onDigitalInputEvent(ie,val); +} + +void SampleSubmarine::onAnalogInputEvent(const SampleFramework::InputEvent& ie, float val) +{ + if (mSubmarineActor && mCameraAttachedToActor == mSubmarineActor) + { + switch (ie.m_Id) + { + case SUBMARINE_FORWARD_BACKWARD: + { + setFlag(gKeyFlags, Movement::eSUBMAINE_FWD, val > 0.3f); + setFlag(gKeyFlags, Movement::eSUBMAINE_BCKWD, val < -0.3f); + } + break; + } + } + if(gCrab && mCameraAttachedToActor == gCrab->getCrabBody()) + { + switch (ie.m_Id) + { + case CRAB_FORWARD_BACKWARD: + { + setFlag(gKeyFlags, Movement::eCRAB_FWD, val > 0.3f); + setFlag(gKeyFlags, Movement::eCRAB_BCKWD, val < -0.3f); + } + break; + case CRAB_LEFT_RIGHT: + { + setFlag(gKeyFlags, Movement::eCRAB_ROTATE_LEFT, val > 0.3f); + setFlag(gKeyFlags, Movement::eCRAB_ROTATE_RIGHT, val < -0.3f); + } + break; + } + } +} + +/////////////////////////////////////////////////////////////////////////////// + +void SampleSubmarine::handleInput() +{ + if(gCrab && mCameraAttachedToActor == gCrab->getCrabBody()) + { + PxReal accFactor = 3.0f; + PxReal forward = 0, rot = 0; + if(gKeyFlags & Movement::eCRAB_FWD) + forward = 1.0f; + if(gKeyFlags & Movement::eCRAB_BCKWD) + forward = -1.0f; + if(gKeyFlags & Movement::eCRAB_ROTATE_LEFT) + rot = 1.0f; + if(gKeyFlags & Movement::eCRAB_ROTATE_RIGHT) + rot = -1.0f; + PxReal left = rot + forward; + PxReal right = -rot + forward; + gCrab->setAcceleration(left*accFactor, right*accFactor); + } + else if(mSubmarineActor && mCameraAttachedToActor == mSubmarineActor) + { + if(gKeyFlags & Movement::eSUBMAINE_FWD) + gForce.x -= gLinPower; + if(gKeyFlags & Movement::eSUBMAINE_BCKWD) + gForce.x += gLinPower; + if(gKeyFlags & Movement::eSUBMAINE_UP) + gForce.y += gLinPower; + if(gKeyFlags & Movement::eSUBMAINE_DOWN) + gForce.y -= gLinPower; + + if(gKeyFlags & (Movement::eSUBMAINE_FWD|Movement::eSUBMAINE_BCKWD)) + { + PxSceneReadLock scopedLock(*mScene); + + static const PxReal camEpsilon = 0.001f; + PxTransform subPose = mSubmarineActor->getGlobalPose(); + PxVec3 cameraDir = getCamera().getViewDir(); + PxVec3 cameraDirInSub = subPose.rotateInv(cameraDir).getNormalized(); + PxVec3 cameraUpInSub = subPose.rotateInv(PxVec3(0,1,0)).getNormalized(); + + if(PxAbs(cameraDirInSub.z) > camEpsilon) + gTorque.y += gAngPower*cameraDirInSub.z; + if(PxAbs(cameraDirInSub.y) > camEpsilon) + gTorque.z -= gAngPower*cameraDirInSub.y; + if(PxAbs(cameraUpInSub.z) > camEpsilon) + gTorque.x += gAngPower*cameraUpInSub.z; + } + } +} + +////////////////////////////////////////////////////////////////////////// + diff --git a/PhysX_3.4/Samples/SampleSubmarine/SampleSubmarine.h b/PhysX_3.4/Samples/SampleSubmarine/SampleSubmarine.h new file mode 100644 index 00000000..8761127a --- /dev/null +++ b/PhysX_3.4/Samples/SampleSubmarine/SampleSubmarine.h @@ -0,0 +1,157 @@ +// This code contains NVIDIA Confidential Information and is disclosed to you +// under a form of NVIDIA software license agreement provided separately to you. +// +// Notice +// NVIDIA Corporation and its licensors retain all intellectual property and +// proprietary rights in and to this software and related documentation and +// any modifications thereto. Any use, reproduction, disclosure, or +// distribution of this software and related documentation without an express +// license agreement from NVIDIA Corporation is strictly prohibited. +// +// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES +// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO +// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT, +// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE. +// +// Information and code furnished is believed to be accurate and reliable. +// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such +// information or for any infringement of patents or other rights of third parties that may +// result from its use. No license is granted by implication or otherwise under any patent +// or patent rights of NVIDIA Corporation. Details are subject to change without notice. +// This code supersedes and replaces all information previously supplied. +// NVIDIA Corporation products are not authorized for use as critical +// components in life support devices or systems without express written approval of +// NVIDIA Corporation. +// +// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved. +// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved. +// Copyright (c) 2001-2004 NovodeX AG. All rights reserved. + + +#ifndef SAMPLE_SUBMARINE_H +#define SAMPLE_SUBMARINE_H + +#include "PhysXSample.h" +#include "PxSimulationEventCallback.h" + +namespace physx +{ + class PxJoint; +} + +class Crab; +class ParticleSystem; +class SubmarineCameraController; + +struct ClassType +{ + enum Type + { + eSEA_MINE, + eCRAB, + }; + + ClassType(const PxU32 type): mType(type) {} + PxU32 getType() const { return mType; } + + const PxU32 mType; +private: + ClassType& operator=(const ClassType&); +}; + +struct FilterGroup +{ + enum Enum + { + eSUBMARINE = (1 << 0), + eMINE_HEAD = (1 << 1), + eMINE_LINK = (1 << 2), + eCRAB = (1 << 3), + eHEIGHTFIELD = (1 << 4), + }; +}; + +struct Seamine: public ClassType, public SampleAllocateable +{ + Seamine() : ClassType(ClassType::eSEA_MINE), mMineHead(NULL) {} + + std::vector<PxRigidDynamic*> mLinks; + PxRigidDynamic* mMineHead; + +}; + +class SampleSubmarine : public PhysXSample, public PxSimulationEventCallback +{ + friend class Crab; + public: + SampleSubmarine(PhysXSampleApplication& app); + virtual ~SampleSubmarine(); + + /////////////////////////////////////////////////////////////////////////////// + + // Implements PxSimulationEventCallback + virtual void onContact(const PxContactPairHeader& pairHeader, const PxContactPair* pairs, PxU32 nbPairs); + virtual void onTrigger(PxTriggerPair* pairs, PxU32 count); + virtual void onConstraintBreak(PxConstraintInfo*, PxU32) {} + virtual void onWake(PxActor** , PxU32 ) {} + virtual void onSleep(PxActor** , PxU32 ){} + virtual void onAdvance(const PxRigidBody*const*, const PxTransform*, const PxU32) {} + + /////////////////////////////////////////////////////////////////////////////// + + // Implements SampleApplication + virtual void onInit(); + virtual void onInit(bool restart) { onInit(); } + virtual void onShutdown(); + virtual void onTickPreRender(float dtime); + virtual void onDigitalInputEvent(const SampleFramework::InputEvent& , bool val); + virtual void onAnalogInputEvent(const SampleFramework::InputEvent& , float val); + virtual void onPointerInputEvent(const SampleFramework::InputEvent& ie, physx::PxU32 x, physx::PxU32 y, physx::PxReal dx, physx::PxReal dy, bool val); + + /////////////////////////////////////////////////////////////////////////////// + + // Implements PhysXSampleApplication + virtual void helpRender(PxU32 x, PxU32 y, PxU8 textAlpha); + virtual void descriptionRender(PxU32 x, PxU32 y, PxU8 textAlpha); + virtual void customizeSample(SampleSetup&); + virtual void customizeSceneDesc(PxSceneDesc&); + virtual void customizeRender(); + + // called at end of a simulation substep + virtual void onSubstep(float dtime); + // called before the simulation begins, useful for setting up + // tasks that need to finish before the completionTask can be called + virtual void onSubstepSetup(float dtime, PxBaseTask* completionTask); + // called once the simulation has begun running + virtual void onSubstepStart(float dtime); + + virtual void collectInputEvents(std::vector<const SampleFramework::InputEvent*>& inputEvents); + + /////////////////////////////////////////////////////////////////////////////// + + void createMaterials(); + Seamine* createSeamine(const PxVec3& position, PxReal height); + PxRigidDynamic* createSubmarine(const PxVec3& inPosition, const PxReal yRot); + void explode(PxRigidActor* actor, const PxVec3& explosionPos, const PxReal explosionStrength); + void handleInput(); + PxRigidActor* loadTerrain(const char* name, const PxReal heightScale, const PxReal rowScale, const PxReal columnScale); + + void createDynamicActors(); + void resetScene(); + + std::vector<void*>& getCrabsMemoryDeleteList() { return mCrabsMemoryDeleteList; } + + private: + std::vector<PxJoint*> mJoints; + std::vector<Seamine*> mMinesToExplode; + std::vector<Seamine*> mSeamines; + std::vector<Crab*> mCrabs; + std::vector<void*> mCrabsMemoryDeleteList; + PxRigidDynamic* mSubmarineActor; + RenderMaterial* mSeamineMaterial; + PxRigidDynamic* mCameraAttachedToActor; + + SubmarineCameraController* mSubmarineCameraController; +}; + +#endif diff --git a/PhysX_3.4/Samples/SampleSubmarine/SampleSubmarineInputEventIds.h b/PhysX_3.4/Samples/SampleSubmarine/SampleSubmarineInputEventIds.h new file mode 100644 index 00000000..c0bb36db --- /dev/null +++ b/PhysX_3.4/Samples/SampleSubmarine/SampleSubmarineInputEventIds.h @@ -0,0 +1,56 @@ +// This code contains NVIDIA Confidential Information and is disclosed to you +// under a form of NVIDIA software license agreement provided separately to you. +// +// Notice +// NVIDIA Corporation and its licensors retain all intellectual property and +// proprietary rights in and to this software and related documentation and +// any modifications thereto. Any use, reproduction, disclosure, or +// distribution of this software and related documentation without an express +// license agreement from NVIDIA Corporation is strictly prohibited. +// +// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES +// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO +// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT, +// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE. +// +// Information and code furnished is believed to be accurate and reliable. +// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such +// information or for any infringement of patents or other rights of third parties that may +// result from its use. No license is granted by implication or otherwise under any patent +// or patent rights of NVIDIA Corporation. Details are subject to change without notice. +// This code supersedes and replaces all information previously supplied. +// NVIDIA Corporation products are not authorized for use as critical +// components in life support devices or systems without express written approval of +// NVIDIA Corporation. +// +// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved. +#ifndef _SAMPLE_SUBMARINE_INPUT_EVENT_IDS_H +#define _SAMPLE_SUBMARINE_INPUT_EVENT_IDS_H + +#include <SampleBaseInputEventIds.h> + +// InputEvents used by SampleSubmarine +enum SampleSubmarineInputEventIds +{ + SAMPLE_SUBMARINE_FIRST = NUM_SAMPLE_BASE_INPUT_EVENT_IDS, + + SUBMARINE_FORWARD, + SUBMARINE_BACKWARD, + SUBMARINE_FORWARD_BACKWARD, + SUBMARINE_UP, + SUBMARINE_DOWN, + + CRAB_FORWARD, + CRAB_BACKWARD, + CRAB_LEFT, + CRAB_RIGHT, + CRAB_FORWARD_BACKWARD, + CRAB_LEFT_RIGHT, + + CAMERA_SWITCH , + SCENE_RESET , + + NUM_SAMPLE_SUBMARINE_INPUT_EVENT_IDS, +}; + +#endif diff --git a/PhysX_3.4/Samples/SampleSubmarine/SubmarineCameraController.h b/PhysX_3.4/Samples/SampleSubmarine/SubmarineCameraController.h new file mode 100644 index 00000000..2456d1be --- /dev/null +++ b/PhysX_3.4/Samples/SampleSubmarine/SubmarineCameraController.h @@ -0,0 +1,64 @@ +// This code contains NVIDIA Confidential Information and is disclosed to you +// under a form of NVIDIA software license agreement provided separately to you. +// +// Notice +// NVIDIA Corporation and its licensors retain all intellectual property and +// proprietary rights in and to this software and related documentation and +// any modifications thereto. Any use, reproduction, disclosure, or +// distribution of this software and related documentation without an express +// license agreement from NVIDIA Corporation is strictly prohibited. +// +// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES +// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO +// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT, +// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE. +// +// Information and code furnished is believed to be accurate and reliable. +// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such +// information or for any infringement of patents or other rights of third parties that may +// result from its use. No license is granted by implication or otherwise under any patent +// or patent rights of NVIDIA Corporation. Details are subject to change without notice. +// This code supersedes and replaces all information previously supplied. +// NVIDIA Corporation products are not authorized for use as critical +// components in life support devices or systems without express written approval of +// NVIDIA Corporation. +// +// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved. +// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved. +// Copyright (c) 2001-2004 NovodeX AG. All rights reserved. + + +#ifndef SUBMARINE_CAMERA_CONTROLLER_H +#define SUBMARINE_CAMERA_CONTROLLER_H + +#include "SampleCameraController.h" + +class SubmarineCameraController: public DefaultCameraController +{ +public: + SubmarineCameraController(): mFollowingMode(true) {} + ~SubmarineCameraController(){} + + virtual void update(Camera& camera, PxReal dtime) + { + if(!mFollowingMode) + DefaultCameraController::update(camera, dtime); + } + + void updateFollowingMode(Camera& camera, PxReal dtime, const PxVec3& targetPos) + { + PX_ASSERT(mFollowingMode); + // default update (orientation) + DefaultCameraController::update(camera, dtime); + + // put camera behind submarine/crab + camera.setPos(targetPos - camera.getViewDir()*15.0f); + } + + void setFollowingMode(bool follow) { mFollowingMode = follow;} + +private: + bool mFollowingMode; +}; + +#endif |