diff options
| author | git perforce import user <a@b> | 2016-10-25 12:29:14 -0600 |
|---|---|---|
| committer | Sheikh Dawood Abdul Ajees <Sheikh Dawood Abdul Ajees> | 2016-10-25 18:56:37 -0500 |
| commit | 3dfe2108cfab31ba3ee5527e217d0d8e99a51162 (patch) | |
| tree | fa6485c169e50d7415a651bf838f5bcd0fd3bfbd /PhysX_3.4/Samples/SampleSubmarine/SampleSubmarine.cpp | |
| download | physx-3.4-3dfe2108cfab31ba3ee5527e217d0d8e99a51162.tar.xz physx-3.4-3dfe2108cfab31ba3ee5527e217d0d8e99a51162.zip | |
Initial commit:
PhysX 3.4.0 Update @ 21294896
APEX 1.4.0 Update @ 21275617
[CL 21300167]
Diffstat (limited to 'PhysX_3.4/Samples/SampleSubmarine/SampleSubmarine.cpp')
| -rw-r--r-- | PhysX_3.4/Samples/SampleSubmarine/SampleSubmarine.cpp | 1278 |
1 files changed, 1278 insertions, 0 deletions
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; + } + } +} + +////////////////////////////////////////////////////////////////////////// + |