Files
PhysX4.1/physx/samples/samplesubmarine/SampleSubmarine.cpp
2025-11-28 23:13:44 +05:30

1273 lines
44 KiB
C++

//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of NVIDIA CORPORATION nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Copyright (c) 2008-2021 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, MOUSE_BUTTON_LEFT, MOUSE_BUTTON_LEFT );
DIGITAL_INPUT_EVENT_DEF(SUBMARINE_BACKWARD, MOUSE_BUTTON_RIGHT, MOUSE_BUTTON_RIGHT, MOUSE_BUTTON_RIGHT );
//digital keyboard events
DIGITAL_INPUT_EVENT_DEF(CRAB_FORWARD, SCAN_CODE_FORWARD, SCAN_CODE_FORWARD, SCAN_CODE_FORWARD );
DIGITAL_INPUT_EVENT_DEF(CRAB_BACKWARD, SCAN_CODE_BACKWARD, SCAN_CODE_BACKWARD, SCAN_CODE_BACKWARD );
DIGITAL_INPUT_EVENT_DEF(CRAB_LEFT, SCAN_CODE_LEFT, SCAN_CODE_LEFT, SCAN_CODE_LEFT );
DIGITAL_INPUT_EVENT_DEF(CRAB_RIGHT, SCAN_CODE_RIGHT, SCAN_CODE_RIGHT, SCAN_CODE_RIGHT );
DIGITAL_INPUT_EVENT_DEF(SUBMARINE_UP, SCAN_CODE_FORWARD, SCAN_CODE_FORWARD, SCAN_CODE_FORWARD );
DIGITAL_INPUT_EVENT_DEF(SUBMARINE_DOWN, SCAN_CODE_BACKWARD, SCAN_CODE_BACKWARD, SCAN_CODE_BACKWARD );
DIGITAL_INPUT_EVENT_DEF(CAMERA_SWITCH, SCAN_CODE_DOWN, SCAN_CODE_DOWN, SCAN_CODE_DOWN );
DIGITAL_INPUT_EVENT_DEF(SCENE_RESET, WKEY_R, OSXKEY_R, LINUXKEY_R );
//digital gamepad events
DIGITAL_INPUT_EVENT_DEF(SUBMARINE_FORWARD, GAMEPAD_RIGHT_SHOULDER_BOT, GAMEPAD_RIGHT_SHOULDER_BOT, LINUXKEY_UNKNOWN );
DIGITAL_INPUT_EVENT_DEF(SUBMARINE_BACKWARD, GAMEPAD_LEFT_SHOULDER_BOT, GAMEPAD_LEFT_SHOULDER_BOT, LINUXKEY_UNKNOWN );
DIGITAL_INPUT_EVENT_DEF(SUBMARINE_UP, GAMEPAD_RIGHT_SHOULDER_TOP, GAMEPAD_RIGHT_SHOULDER_TOP, LINUXKEY_UNKNOWN );
DIGITAL_INPUT_EVENT_DEF(SUBMARINE_DOWN, GAMEPAD_LEFT_SHOULDER_TOP, GAMEPAD_LEFT_SHOULDER_TOP, LINUXKEY_UNKNOWN );
DIGITAL_INPUT_EVENT_DEF(CAMERA_SWITCH, GAMEPAD_RIGHT_STICK, GAMEPAD_RIGHT_STICK, LINUXKEY_UNKNOWN );
DIGITAL_INPUT_EVENT_DEF(SCENE_RESET, GAMEPAD_LEFT_STICK, GAMEPAD_LEFT_STICK, LINUXKEY_UNKNOWN );
// analog gamepad events
ANALOG_INPUT_EVENT_DEF(CRAB_LEFT_RIGHT, GAMEPAD_DEFAULT_SENSITIVITY, GAMEPAD_LEFT_STICK_X, GAMEPAD_LEFT_STICK_X, LINUXKEY_UNKNOWN );
ANALOG_INPUT_EVENT_DEF(CRAB_FORWARD_BACKWARD, GAMEPAD_DEFAULT_SENSITIVITY, GAMEPAD_LEFT_STICK_Y, GAMEPAD_LEFT_STICK_Y, LINUXKEY_UNKNOWN );
ANALOG_INPUT_EVENT_DEF(SUBMARINE_FORWARD_BACKWARD, GAMEPAD_DEFAULT_SENSITIVITY, GAMEPAD_LEFT_STICK_Y, OSXKEY_UNKNOWN, LINUXKEY_UNKNOWN );
}
///////////////////////////////////////////////////////////////////////////////
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;
}
}
}
//////////////////////////////////////////////////////////////////////////