1273 lines
44 KiB
C++
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;
|
|
}
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|