aboutsummaryrefslogtreecommitdiff
path: root/PhysX_3.4/Samples/SampleSubmarine
diff options
context:
space:
mode:
authorgit perforce import user <a@b>2016-10-25 12:29:14 -0600
committerSheikh Dawood Abdul Ajees <Sheikh Dawood Abdul Ajees>2016-10-25 18:56:37 -0500
commit3dfe2108cfab31ba3ee5527e217d0d8e99a51162 (patch)
treefa6485c169e50d7415a651bf838f5bcd0fd3bfbd /PhysX_3.4/Samples/SampleSubmarine
downloadphysx-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.cpp822
-rw-r--r--PhysX_3.4/Samples/SampleSubmarine/Crab.h163
-rw-r--r--PhysX_3.4/Samples/SampleSubmarine/SampleSubmarine.cpp1278
-rw-r--r--PhysX_3.4/Samples/SampleSubmarine/SampleSubmarine.h157
-rw-r--r--PhysX_3.4/Samples/SampleSubmarine/SampleSubmarineInputEventIds.h56
-rw-r--r--PhysX_3.4/Samples/SampleSubmarine/SubmarineCameraController.h64
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