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

2272 lines
81 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 "SampleVehicle.h"
#include "RendererMemoryMacros.h"
#include "RenderMeshActor.h"
#include "SampleVehicle_VehicleCooking.h"
#include "SampleVehicle_SceneQuery.h"
#include "PxPhysicsAPI.h"
#include "extensions/PxExtensionsAPI.h"
#include "RenderPhysX3Debug.h"
#include "SampleVehicleInputEventIds.h"
#include <SampleFrameworkInputEventIds.h>
#include <SampleBaseInputEventIds.h>
#include <SamplePlatform.h>
#include <SampleUserInput.h>
#include <SampleUserInputIds.h>
#include <SampleUserInputDefines.h>
#include "PxTkFile.h"
#ifdef _MSC_VER
#pragma warning(disable:4305)
#endif
REGISTER_SAMPLE(SampleVehicle, "SampleVehicle")
enum
{
LOAD_TYPE_VEHICLE=0,
LOAD_TYPE_LOOPTHELOOP,
LOAD_TYPE_SKYDOME,
MAX_NUM_LOAD_TYPES
};
static PxU32 gLoadType = MAX_NUM_LOAD_TYPES;
using namespace physx;
using namespace SampleRenderer;
using namespace SampleFramework;
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////
//VEHICLE START PARAMETERS
///////////////////////////////////
#define NUM_PLAYER_CARS 1
static PxTransform gPlayerCarStartTransforms[NUM_PLAYER_CARS] =
{
PxTransform(PxVec3(-154.699753f, 9.863837f, 87.684113f), PxQuat(-0.000555f, -0.267015, 0.000155, -0.963692 ))
};
#define NUM_NONPLAYER_4W_VEHICLES 7
#if NUM_NONPLAYER_4W_VEHICLES
static PxTransform gVehicle4WStartTransforms[NUM_NONPLAYER_4W_VEHICLES] =
{
//Stack of 2 cars
PxTransform(PxVec3(-78.796158f,9.8764671f,155.47554f), PxQuat(0.00062184106f,0.97696519f,-0.0029967001f,0.21337670f)),
PxTransform(PxVec3(-78.796158f,11.7764671f,155.47554f), PxQuat(0.00062184106f,0.97696519f,-0.0029967001f,0.21337670f)),
//Stack of 2 cars
PxTransform(PxVec3(-80.391357f,9.8760214f,161.93578f), PxQuat(1.0251222e-005f, 0.98799443f, -6.0369461e-005f, 0.15448983f)),
PxTransform(PxVec3(-80.391357f,11.7760214f,161.93578f), PxQuat(1.0251222e-005f, 0.98799443f, -6.0369461e-005f, 0.15448983f)),
//Bookends to car stacks
PxTransform(PxVec3(-77.945328f,9.9765568f,151.78404f), PxQuat(0.0014836629f,-0.86193967f,0.0024594457f,0.50700283f)),
PxTransform(PxVec3(-80.395328f,9.8786600f,167.44662f), PxQuat(0.0014836629f,-0.86193967f,0.0024594457f,0.50700283f)),
//Car in-between two ramps
PxTransform(PxVec3(116.04498f,9.9760214f,139.02933f), PxQuat(7.5981094e-005f,-0.38262743f,-3.1461415e-005f,-0.92390275f)),
};
#endif
#define NUM_NONPLAYER_6W_VEHICLES 1
#if NUM_NONPLAYER_6W_VEHICLES
static PxTransform gVehicle6WStartTransforms[NUM_NONPLAYER_6W_VEHICLES]=
{
//6-wheeled car
PxTransform(PxVec3(-158.09471f,9.8649321f,80.359474f), PxQuat(-0.0017525638f,-0.24773766f,0.00040674198f,-0.96882552f))
};
#endif
#define NUM_NONPLAYER_4W_TANKS 0
#if NUM_NONPLAYER_4W_TANKS
static PxTransform gTank4WStartTransforms[NUM_NONPLAYER_4W_TANKS]=
{
//6-wheeled car
PxTransform(PxVec3(-158.09471f,9.8649321f,80.359474f), PxQuat(-0.0017525638f,-0.24773766f,0.00040674198f,-0.96882552f))
};
#endif
#define NUM_NONPLAYER_6W_TANKS 0
#if NUM_NONPLAYER_6W_TANKS
static PxTransform gTank6WStartTransforms[NUM_NONPLAYER_6W_TANKS]=
{
//6-wheeled car
PxTransform(PxVec3(-158.09471f,9.8649321f,80.359474f), PxQuat(-0.0017525638f,-0.24773766f,0.00040674198f,-0.96882552f))
};
#endif
PxU32 gNumVehicleAdded=0;
////////////////////////////////////////////////////////////////
//VEHICLE SETUP DATA
////////////////////////////////////////////////////////////////
PxF32 gChassisMass=1500.0f;
PxF32 gSuspensionShimHeight=0.125f;
////////////////////////////////////////////////////////////////
//RENDER USER DATA TO ASSOCIATE EACH RENDER MESH WITH A
//VEHICLE PHYSICS COMPONENT
////////////////////////////////////////////////////////////////
enum
{
CAR_PART_FRONT_LEFT_WHEEL=0,
CAR_PART_FRONT_RIGHT_WHEEL,
CAR_PART_REAR_LEFT_WHEEL,
CAR_PART_REAR_RIGHT_WHEEL,
CAR_PART_CHASSIS,
CAR_PART_WINDOWS,
NUM_CAR4W_RENDER_COMPONENTS,
CAR_PART_EXTRA_WHEEL0=NUM_CAR4W_RENDER_COMPONENTS,
CAR_PART_EXTRA_WHEEL1,
NUM_CAR6W_RENDER_COMPONENTS
};
static const char gCarPartNames[NUM_CAR4W_RENDER_COMPONENTS][64]=
{
"frontwheelleftshape",
"frontwheelrightshape",
"backwheelleftshape",
"backwheelrightshape",
"car_02_visshape",
"car_02_windowsshape"
};
struct CarRenderUserData
{
PxU8 carId;
PxU8 carPart;
PxU8 carPartDependency;
PxU8 pad;
};
static const CarRenderUserData gCar4WRenderUserData[NUM_CAR6W_RENDER_COMPONENTS] =
{
//wheel fl wheel fr wheel rl wheel rl chassis windows extra wheel0 extra wheel1
{0,0,255}, {0,1,255}, {0,2,255}, {0,3,255}, {0,4,255}, {0,4,4}, {255,255,255}, {255,255,255}
};
static const CarRenderUserData gCar6WRenderUserData[NUM_CAR6W_RENDER_COMPONENTS] =
{
//wheel fl wheel fr wheel rl wheel rl chassis windows extra wheel0 extra wheel1
{0,0,255}, {0,1,255}, {0,2,255}, {0,3,255}, {0,6,255}, {0,6,6}, {0,4,255}, {0,5,255}
};
CarRenderUserData gVehicleRenderUserData[NUM_PLAYER_CARS + NUM_NONPLAYER_4W_VEHICLES + NUM_NONPLAYER_6W_VEHICLES + NUM_NONPLAYER_4W_TANKS + NUM_NONPLAYER_6W_TANKS][NUM_CAR6W_RENDER_COMPONENTS];
RenderMeshActor* gRenderMeshActors[NUM_CAR6W_RENDER_COMPONENTS]={NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL};
////////////////////////////////////////////////////////////////
//TRANSFORM APPLIED TO CHASSIS RENDER MESH VERTS
//THAT IS REQUIRED TO PLACE AABB OF CHASSIS RENDER MESH AT ORIGIN
//AT CENTRE-POINT OF WHEELS.
////////////////////////////////////////////////////////////////
static PxVec3 gChassisMeshTransform(0,0,0);
////////////////////////////////////////////////////////////////
//WHEEL CENTRE OFFSETS FROM CENTRE OF CHASSIS RENDER MESH AABB
//OF 4-WHEELED VEHICLE
////////////////////////////////////////////////////////////////
static PxVec3 gWheelCentreOffsets4[4];
////////////////////////////////////////////////////////////////
//CONVEX HULL OF RENDER MESH FOR CHASSIS AND WHEELS OF
//4-WHEELED VEHICLE
////////////////////////////////////////////////////////////////
static PxConvexMesh* gChassisConvexMesh=NULL;
static PxConvexMesh* gWheelConvexMeshes4[4]={NULL,NULL,NULL,NULL};
////////////////////////////////////////////////////////////////
//Revolute joints and gian pendula
////////////////////////////////////////////////////////////////
#define MAX_NUM_PENDULA 4
PxTransform gPendulaBallStartTransforms[MAX_NUM_PENDULA]=
{
PxTransform(PxVec3( 151.867020 , 11.364232 , 97.350906 ), PxQuat( -0.000106 , -0.951955 , 0.000370 , -0.306239 ) ) ,
PxTransform(PxVec3( 163.001953 , 11.364203 , 77.854568 ), PxQuat( -0.000070 , -0.971984 , 0.000323 , -0.235048 ) ) ,
PxTransform(PxVec3( 173.971405 , 11.364145 , 45.944290 ), PxQuat( -0.000050 , -0.994988 , 0.000448 , -0.099990 ) ) ,
PxTransform(PxVec3( 179.876785 , 11.364090 , 3.679581 ), PxQuat( -0.000024 , -1.000000 , 0.000431 , -0.000193 ) )
};
PxF32 gPendulumBallRadius=2.0f;
PxF32 gPendulumBallMass=1000.0f;
PxF32 gPendulumShaftLength=10.0f;
PxF32 gPendulumShaftWidth=0.1f;
PxF32 gPendulumSuspensionStructureWidth=13.0f;
PxRevoluteJoint* gRevoluteJoints[MAX_NUM_PENDULA]={NULL,NULL,NULL,NULL};
PxF32 gRevoluteJointDriveSpeeds[MAX_NUM_PENDULA]={0.932f,1.0f,1.237f,0.876f};
PxF32 gRevoluteJointTimers[MAX_NUM_PENDULA]={0,0,0,0};
PxU32 gNumRevoluteJoints=0;
PxF32 gRevoluteJointMaxTheta=0;
////////////////////////////////////////////////////////////////
//Route
////////////////////////////////////////////////////////////////
PxTransform gWayPoints[35]=
{
PxTransform(PxVec3( -154.699753 , 9.863837 , 87.684113 ), PxQuat( -0.000555 , -0.267015 , 0.000155 , -0.963692 ) ) ,
PxTransform(PxVec3( -133.385757 , 9.863703 , 118.680717 ), PxQuat( -0.000620 , -0.334975 , 0.000219 , -0.942227 ) ) ,
PxTransform(PxVec3( -103.853020 , 9.863734 , 146.631256 ), PxQuat( -0.000560 , -0.474673 , 0.000301 , -0.880162 ) ) ,
PxTransform(PxVec3( -20.397881 , 9.862607 , 177.345657 ), PxQuat( -0.000938 , -0.674493 , 0.000867 , -0.738281 ) ) ,
PxTransform(PxVec3( 14.272619 , 9.863173 , 178.745789 ), PxQuat( -0.000736 , -0.723563 , 0.000740 , -0.690257 ) ) ,
PxTransform(PxVec3( 49.057743 , 9.862507 , 173.464539 ), PxQuat( -0.000387 , -0.794072 , 0.001316 , -0.607822 ) ) ,
PxTransform(PxVec3( 82.226036 , 9.862642 , 159.649200 ), PxQuat( -0.000670 , -0.853613 , 0.001099 , -0.520905 ) ) ,
PxTransform(PxVec3( 158.675018 , 9.864265 , 86.166740 ), PxQuat( -0.000052 , -0.973169 , 0.000286 , -0.230092 ) ) ,
PxTransform(PxVec3( 165.983170 , 9.857763 , 67.031097 ), PxQuat( -0.014701 , -0.979587 , 0.002133 , 0.200471 ) ) ,
PxTransform(PxVec3( 177.577393 , 9.864532 , 30.462427 ), PxQuat( 0.000022 , -0.998473 , -0.000423 , -0.055239 ) ) ,
PxTransform(PxVec3( 180.127686 , 9.864151 , -10.116920 ), PxQuat( 0.000011 , 0.999869 , 0.000295 , -0.016194 ) ) ,
PxTransform(PxVec3( 174.281616 , 9.863608 , -42.319435 ), PxQuat( 0.000168 , 0.989981 , -0.001008 , -0.141194 ) ) ,
PxTransform(PxVec3( 166.054413 , 9.864248 , -68.973045 ), PxQuat( -0.000052 , 0.985021 , -0.000213 , -0.172433 ) ) ,
PxTransform(PxVec3( 154.505814 , 9.864180 , -77.992622 ), PxQuat( -0.000098 , 0.754213 , -0.000129 , -0.656630 ) ) ,
PxTransform(PxVec3( 140.834076 , 9.863158 , -78.122841 ), PxQuat( -0.000730 , 0.709598 , -0.000737 , -0.704606 ) ) ,
PxTransform(PxVec3( 100.152573 , 9.853898 , -78.407364 ), PxQuat( 0.066651 , 0.683499 , 0.070412 , -0.723484 ) ) ,
PxTransform(PxVec3( 68.866241 , 10.293923 , -77.979095 ), PxQuat( -0.045687 , 0.703115 , -0.044258 , -0.708225 ) ),
PxTransform(PxVec3( 26.558704 , 10.495461 , -77.729164 ), PxQuat( -0.018349 , 0.708445 , -0.018563 , -0.705283 ) ) ,
PxTransform(PxVec3( -2.121686 , 9.860541 , -77.735886 ), PxQuat( -0.000792 , 0.706926 , -0.000792 , -0.707287 ) ) ,
PxTransform(PxVec3( -28.991186 , 9.867218 , -77.722122 ), PxQuat( -0.000251 , 0.706926 , -0.000251 , -0.707287 ) ) ,
PxTransform(PxVec3( -59.285870 , 9.861916 , -77.746246 ), PxQuat( -0.001042 , 0.708723 , -0.001048 , -0.705485 ) ) ,
PxTransform(PxVec3( -73.170433 , 9.863565 , -78.034157 ), PxQuat( -0.001567 , 0.736642 , -0.001323 , -0.676280 ) ) ,
PxTransform(PxVec3( -77.792152 , 9.864209 , -87.821510 ), PxQuat( 0.000006 , 0.999772 , -0.000294 , -0.021342 ) ) ,
PxTransform(PxVec3( -78.164032 , 9.862655 , -114.313690 ), PxQuat( -0.000010 , 0.999962 , -0.001280 , -0.008618 ) ),
PxTransform(PxVec3( -78.567627 , 9.862757 , -137.274292 ), PxQuat( -0.000010 , 0.999961 , -0.001146 , -0.008796 ) ) ,
PxTransform(PxVec3( -80.392769 , 9.863695 , -149.740082 ), PxQuat( -0.000149 , 0.987276 , -0.000512 , -0.159015 ) ) ,
PxTransform(PxVec3( -88.452507 , 9.864114 , -152.396698 ), PxQuat( -0.000355 , 0.622921 , -0.000278 , -0.782285 ) ) ,
PxTransform(PxVec3( -106.042450 , 9.863844 , -144.640076 ), PxQuat( -0.000485 , 0.459262 , -0.000133 , -0.888301 ) ) ,
PxTransform(PxVec3( -134.893997 , 15.093562 , -114.433586 ), PxQuat( 0.073759 , 0.354141 , 0.027569 , -0.931871 ) ) ,
PxTransform(PxVec3( -145.495453 , 9.864394 , -101.019417 ), PxQuat( -0.000351 , 0.305924 , -0.000104 , -0.952056 ) ) ,
PxTransform(PxVec3( -152.808212 , 9.864192 , -86.800613 ), PxQuat( -0.000099 , 0.206095 , -0.000015 , -0.978532 ) ) ,
PxTransform(PxVec3( -156.457855 , 9.864244 , -81.270035 ), PxQuat( -0.000420 , 0.201378 , -0.000086 , -0.979514 ) ) ,
PxTransform(PxVec3( -169.079376 , 10.192255 , -48.906967 ), PxQuat( 0.003633 , 0.179159 , 0.000892 , -0.983813 ) ) ,
PxTransform(PxVec3( -151.470123 , 7.783551 , -17.838057 ), PxQuat( 0.029215 , -0.077987 , -0.050732 , -0.995234 ) ) ,
PxTransform(PxVec3( -171.549225 , 9.864206 , 47.239426 ), PxQuat( -0.000319 , -0.159609 , 0.000039 , -0.987180 ) )
};
PxU32 gNumWayPoints=35;
///////////////////////////////////////////////////////////////////////////////
SampleVehicle::SampleVehicle(PhysXSampleApplication& app) :
PhysXSample (app),
mTerrainVB (NULL),
mNbTerrainVerts (0),
mNbIB (0),
mChassisMaterialDrivable (NULL),
mChassisMaterialNonDrivable (NULL),
mTerrainMaterial (NULL),
mRoadMaterial (NULL),
mRoadIceMaterial (NULL),
mRoadGravelMaterial (NULL),
mPlayerVehicle (0),
mPlayerVehicleType (ePLAYER_VEHICLE_TYPE_VEHICLE4W),
//mPlayerVehicleType (ePLAYER_VEHICLE_TYPE_VEHICLE6W),
//mPlayerVehicleType (ePLAYER_VEHICLE_TYPE_TANK4W),
//mPlayerVehicleType (ePLAYER_VEHICLE_TYPE_TANK6W),
//mTankDriveModel (PxVehicleDriveTankControlModel::eSPECIAL),
//mTankDriveModel (PxVehicleDriveTankControlModel::eSTANDARD),
mTerrainSize (256),
mTerrainWidth (2.0f),
mHFActor (NULL),
mHideScreenText (false),
mDebugRenderFlag (false),
mFixCar (false),
mBackToStart (false),
m3WModeIncremented (false),
m3WMode (0),
mForwardSpeedHud (0.0f)
{
mCreateGroundPlane = false;
//mStepperType = FIXED_STEPPER;
for(PxU32 i=0;i<MAX_NUM_INDEX_BUFFERS;i++)
mStandardMaterials[i] = NULL;
#if PX_DEBUG_VEHICLE_ON
mDebugRenderActiveGraphChannelWheel = 0;
mDebugRenderActiveGraphChannelEngine = 0;
mTelemetryData4W = NULL;
mTelemetryData6W = NULL;
#endif
}
SampleVehicle::~SampleVehicle()
{
}
///////////////////////////////////////////////////////////////////////////////
void SampleVehicle::customizeSample(SampleSetup& setup)
{
setup.mName = "SampleVehicle";
}
void SampleVehicle::setupTelemetryData()
{
#if PX_DEBUG_VEHICLE_ON
mDebugRenderActiveGraphChannelWheel=PxVehicleWheelGraphChannel::eWHEEL_OMEGA;
mDebugRenderActiveGraphChannelEngine=PxVehicleDriveGraphChannel::eENGINE_REVS;
{
const PxF32 graphSizeX=0.25f;
const PxF32 graphSizeY=0.25f;
const PxF32 engineGraphPosX=0.5f;
const PxF32 engineGraphPosY=0.5f;
const PxF32 wheelGraphPosX[4]={0.75f,0.25f,0.75f,0.25f};
const PxF32 wheelGraphPosY[4]={0.75f,0.75f,0.25f,0.25f};
const PxVec3 backgroundColor(255,255,255);
const PxVec3 lineColorHigh(255,0,0);
const PxVec3 lineColorLow(0,0,0);
mTelemetryData4W = PxVehicleTelemetryData::allocate(4);
mTelemetryData4W->setup
(graphSizeX,graphSizeY,
engineGraphPosX,engineGraphPosY,
wheelGraphPosX,wheelGraphPosY,
backgroundColor,lineColorHigh,lineColorLow);
}
{
const PxF32 graphSizeX=0.225f;
const PxF32 graphSizeY=0.225f;
const PxF32 engineGraphPosX=0.5f;
const PxF32 engineGraphPosY=0.5f;
const PxF32 wheelGraphPosX[6]={0.75f,0.25f,0.75f,0.25f,0.75f,0.25f};
const PxF32 wheelGraphPosY[8]={0.83f,0.83f,0.17f,0.17f,0.5f,0.5f};
const PxVec3 backgroundColor(255,255,255);
const PxVec3 lineColorHigh(255,0,0);
const PxVec3 lineColorLow(0,0,0);
mTelemetryData6W = PxVehicleTelemetryData::allocate(6);
mTelemetryData6W->setup
(graphSizeX,graphSizeY,
engineGraphPosX,engineGraphPosY,
wheelGraphPosX,wheelGraphPosY,
backgroundColor,lineColorHigh,lineColorLow);
}
#endif
}
///////////////////////////////////////////////////////////////////////////////
void SampleVehicle::onInit()
{
mNbThreads = PxMax(PxI32(shdfnd::Thread::getNbPhysicalCores())-1, 0);
PhysXSample::onInit();
PxSceneWriteLock scopedLock(*mScene);
#if defined(SERIALIZE_VEHICLE_BINARY)
mMemory = NULL;
#endif
//Create physx objects.
createStandardMaterials();
createVehicles();
createTrack(mTerrainSize, mTerrainWidth, mTerrainSize*4.0f);
createObstacles();
//Setup camera.
setCameraController(NULL);
//Setup debug render data.
setupTelemetryData();
//Setup the waypoint system.
mWayPoints.setWayPoints(gWayPoints,gNumWayPoints);
//Load the skydome.
gLoadType = LOAD_TYPE_SKYDOME;
importRAWFile("sky_mission_race1.raw", 1.0f);
//Set up the fog.
getRenderer()->setFog(SampleRenderer::RendererColor(40,40,40), 225.0f);
}
void SampleVehicle::newMesh(const RAWMesh& data)
{
if(LOAD_TYPE_LOOPTHELOOP==gLoadType)
{
PxMaterial* saved = mMaterial;
mMaterial = mStandardMaterials[SURFACE_TYPE_TARMAC];
PhysXSample::newMesh(data);
mMaterial = saved;
}
else if(LOAD_TYPE_VEHICLE==gLoadType)
{
PxU32 carPart=0xffffffff;
if(0==Ps::strcmp(data.mName,gCarPartNames[CAR_PART_CHASSIS]))
{
carPart=CAR_PART_CHASSIS;
//Find the min and max of the set of verts.
PxVec3 min(PX_MAX_F32,PX_MAX_F32,PX_MAX_F32);
PxVec3 max(-PX_MAX_F32,-PX_MAX_F32,-PX_MAX_F32);
for(PxU32 i=0;i<data.mNbVerts;i++)
{
min.x=PxMin(min.x,data.mVerts[i].x);
min.y=PxMin(min.y,data.mVerts[i].y);
min.z=PxMin(min.z,data.mVerts[i].z);
max.x=PxMax(max.x,data.mVerts[i].x);
max.y=PxMax(max.y,data.mVerts[i].y);
max.z=PxMax(max.z,data.mVerts[i].z);
}
//Make sure the chassis has an aabb that is centred at (0,0,0).
//This just makes it a lot easier to set the centre of mass offset relative to the centre of the actor.
gChassisMeshTransform=(min+max)*0.5f;
//Make sure wheel offsets are symmetric (they are not quite symmetric left to right or front to back).
gWheelCentreOffsets4[CAR_PART_FRONT_LEFT_WHEEL].x=-gWheelCentreOffsets4[CAR_PART_FRONT_RIGHT_WHEEL].x;
gWheelCentreOffsets4[CAR_PART_REAR_LEFT_WHEEL].x=-gWheelCentreOffsets4[CAR_PART_REAR_RIGHT_WHEEL].x;
gWheelCentreOffsets4[CAR_PART_FRONT_LEFT_WHEEL].y=gWheelCentreOffsets4[CAR_PART_REAR_LEFT_WHEEL].y;
gWheelCentreOffsets4[CAR_PART_FRONT_RIGHT_WHEEL].y=gWheelCentreOffsets4[CAR_PART_REAR_RIGHT_WHEEL].y;
//Make an adjustment so that the the centre of the four wheels is at the origin.
//Again, this just makes it a lot easier to set the centre of mass because we have a known point
//that represents the origin. Also, it kind of makes sense that the default centre of mass is at the
//centre point of the wheels.
PxF32 wheelOffsetZ=0;
for(PxU32 i=0;i<=CAR_PART_REAR_RIGHT_WHEEL;i++)
{
wheelOffsetZ+=gWheelCentreOffsets4[i].z;
}
wheelOffsetZ*=0.25f;
gChassisMeshTransform.z+=wheelOffsetZ;
//Reposition the mesh verts.
PxVec3* verts = const_cast<PxVec3*>(data.mVerts);
for(PxU32 i=0;i<data.mNbVerts;i++)
{
verts[i]-=gChassisMeshTransform;
}
//Need a convex mesh for the chassis.
gChassisConvexMesh=createChassisConvexMesh(data.mVerts,data.mNbVerts,getPhysics(),getCooking());
}
else if(0==Ps::strcmp(data.mName,gCarPartNames[CAR_PART_FRONT_LEFT_WHEEL]))
{
carPart=CAR_PART_FRONT_LEFT_WHEEL;
gWheelConvexMeshes4[CAR_PART_FRONT_LEFT_WHEEL]=createWheelConvexMesh(data.mVerts,data.mNbVerts,getPhysics(),getCooking());
}
else if(0==Ps::strcmp(data.mName,gCarPartNames[CAR_PART_FRONT_RIGHT_WHEEL]))
{
carPart=CAR_PART_FRONT_RIGHT_WHEEL;
gWheelConvexMeshes4[CAR_PART_FRONT_RIGHT_WHEEL]=createWheelConvexMesh(data.mVerts,data.mNbVerts,getPhysics(),getCooking());
}
else if(0==Ps::strcmp(data.mName,gCarPartNames[CAR_PART_REAR_LEFT_WHEEL]))
{
carPart=CAR_PART_REAR_LEFT_WHEEL;
gWheelConvexMeshes4[CAR_PART_REAR_LEFT_WHEEL]=createWheelConvexMesh(data.mVerts,data.mNbVerts,getPhysics(),getCooking());
}
else if(0==Ps::strcmp(data.mName,gCarPartNames[CAR_PART_REAR_RIGHT_WHEEL]))
{
carPart=CAR_PART_REAR_RIGHT_WHEEL;
gWheelConvexMeshes4[CAR_PART_REAR_RIGHT_WHEEL]=createWheelConvexMesh(data.mVerts,data.mNbVerts,getPhysics(),getCooking());
}
else if(0==Ps::strcmp(data.mName,gCarPartNames[CAR_PART_WINDOWS]))
{
carPart=CAR_PART_WINDOWS;
//Take the offset that was required to centre the chassis and apply it to everything that is dependent on the chassis transform.
PxVec3* verts = const_cast<PxVec3*>(data.mVerts);
for(PxU32 i=0;i<data.mNbVerts;i++)
{
verts[i]-=gChassisMeshTransform;
}
for(PxU32 i=0;i<=CAR_PART_REAR_RIGHT_WHEEL;i++)
{
gWheelCentreOffsets4[i]-=gChassisMeshTransform;
}
}
RenderMeshActor* meshActor = createRenderMeshFromRawMesh(data);
PX_ASSERT(carPart!=0xffffffff);
gRenderMeshActors[carPart]=meshActor;
//Store the wheel offsets from the centre.
for(PxU32 i=0;i<=CAR_PART_REAR_RIGHT_WHEEL;i++)
{
if(0==Ps::strcmp(data.mName,gCarPartNames[i]))
{
gWheelCentreOffsets4[i]=meshActor->getTransform().p;
gWheelCentreOffsets4[i].y-=gSuspensionShimHeight;
//The left and right wheels seem to be mixed up.
//Swap them to correct this.
gWheelCentreOffsets4[i].x*=-1.0f;
}
}
}
else if(LOAD_TYPE_SKYDOME==gLoadType)
{
createRenderMeshFromRawMesh(data);
}
else
{
getSampleErrorCallback().reportError(PxErrorCode::eINTERNAL_ERROR, "Unknown mesh type", __FILE__, __LINE__);
}
}
void SampleVehicle::onShutdown()
{
{
PxSceneWriteLock scopedLock(*mScene);
for(PxU32 i=0;i<mNbIB;i++)
SAMPLE_FREE(mIB[i]);
SAMPLE_FREE(mTerrainVB);
#if PX_DEBUG_VEHICLE_ON
mTelemetryData4W->free();
mTelemetryData6W->free();
#endif
mVehicleManager.shutdown();
}
PhysXSample::onShutdown();
#if defined(SERIALIZE_VEHICLE_BINARY)
if(mMemory)
SAMPLE_FREE(mMemory);
#endif
}
void SampleVehicle::onTickPreRender(PxF32 dtime)
{
mScene->lockWrite();
if(mFixCar)
{
//Get the transform of the last crossed waypoint and reset the player car
//at this transform.
resetFocusVehicleAtWaypoint();
mFixCar=false;
//Reset the control logic driving the car back to start state to avoid mismatch
//between vehicle gears and state stored in vehicle controller.
mVehicleController.clear();
#if PX_DEBUG_VEHICLE_ON
//Clear all the graph data because the discontinuity in car position makes the stored data redundant.
clearTelemetryData();
#endif
}
else if(mBackToStart)
{
//Set the progress back to zero.
mWayPoints.setBackAtStart();
//Get the transform of the last crossed waypoint (this will now be the start
//waypoint) and reset the player car at this transform.
resetFocusVehicleAtWaypoint();
mBackToStart=false;
//Reset the control logic driving the car back to start state to avoid mismatch
//between vehicle gears and state stored in vehicle controller.
mVehicleController.clear();
#if PX_DEBUG_VEHICLE_ON
//Clear all the graph data because the discontinuity in car position makes the stored data redundant.
clearTelemetryData();
#endif
}
//Only switch to 3-wheeled if driving a 4-wheeled car.
if(ePLAYER_VEHICLE_TYPE_VEHICLE4W==mPlayerVehicleType)
{
if(m3WModeIncremented)
{
const PxU32 old3WMode=m3WMode;
const PxU32 new3WMode=(m3WMode+1)%3;
if(0==old3WMode && 1==new3WMode)
{
mVehicleManager.switchTo3WDeltaMode(mPlayerVehicle);
}
else if(1==old3WMode && 2==new3WMode)
{
mVehicleManager.switchTo3WTadpoleMode(mPlayerVehicle);
}
else if(2==old3WMode && 0==new3WMode)
{
mVehicleManager.switchTo4WMode(mPlayerVehicle);
}
m3WModeIncremented=false;
m3WMode=new3WMode;
}
}
//Make sure we can still update the camera in pause model.
if(mPause)
{
mCameraController.setInputs(
mControlInputs.getRotateY(),
mControlInputs.getRotateZ());
updateCameraController(dtime, getActiveScene());
}
//Set the global transforms of all actors that have user data.
const size_t nbVehicleGraphicsMeshes = mVehicleGraphics.size();
for(PxU32 i=0;i<nbVehicleGraphicsMeshes;i++)
{
//Get the mesh actor that represents a vehicle render component.
RenderMeshActor* actor = mVehicleGraphics[i];
//Get the data that associates the render component with a physics vehicle component.
const CarRenderUserData* carRenderUserData=(CarRenderUserData*)actor->mUserData;
const PxU8 carId=carRenderUserData->carId;
const PxU8 carPart=carRenderUserData->carPart;
const PxU8 carPartDependency=carRenderUserData->carPartDependency;
//Get the physics shapes of the vehicle.
//The transform of these shapes will be applied to the render meshes.
PxShape* carShapes[PX_MAX_NB_WHEELS+1];
const PxVehicleWheels& vehicle=*mVehicleManager.getVehicle(carId);
const PxU32 numShapes=vehicle.getRigidDynamicActor()->getNbShapes();
const PxRigidDynamic& vehicleActor = *vehicle.getRigidDynamicActor();
vehicleActor.getShapes(carShapes,numShapes);
//Set the transform of the render component from the associated physics shape transform.
if(255==carPartDependency)
{
//The transform of this car component has been computed by the vehicle physics
//and stored in the composite bound of the car (chassis + wheels).
actor->setTransform(PxShapeExt::getGlobalPose(*carShapes[carPart], vehicleActor));
//update bounds of render actor, for camera cull
actor->setWorldBounds(PxShapeExt::getWorldBounds(*carShapes[carPart], vehicleActor));
}
else
{
//The transform of this car component hasn't been computed by the vehicle physics.
//The transform is just an offset from another vehicle physics component.
//(This is kind of like a very,very simple skeleton of hierarchical transforms that would normally
//be used to render a vehicle).
actor->setTransform(PxShapeExt::getGlobalPose(*carShapes[carPartDependency], vehicleActor));
//update bounds of render actor, for camera cull
actor->setWorldBounds(PxShapeExt::getWorldBounds(*carShapes[carPartDependency], vehicleActor));
}
}
getCamera().lookAt(mCameraController.getCameraPos(), mCameraController.getCameraTar());
mScene->unlockWrite();
// Update the physics
PhysXSample::onTickPreRender(dtime);
}
void SampleVehicle::onTickPostRender(PxF32 dtime)
{
// Fetch results
PhysXSample::onTickPostRender(dtime);
if(mDebugRenderFlag)
{
drawWheels();
drawVehicleDebug();
}
//Draw the next three way-points.
const RendererColor colors[3]={RendererColor(255,0,0),RendererColor(0,255,0),RendererColor(0,0,255)};
PxVec3 v[3];
PxVec3 w[3];
PxU32 numPoints=0;
mWayPoints.getNextWayPointsAndLineDirs(numPoints,v[0],v[1],v[2],w[0],w[1],w[2]);
for(PxU32 i=0;i<numPoints;i++)
{
getDebugRenderer()->addLine(v[i],v[i]+PxVec3(0,5,0),colors[i]);
getDebugRenderer()->addLine(v[i]-w[i],v[i]+w[i],colors[i]);
}
}
void SampleVehicle::onSubstep(PxF32 dtime)
{
//Update the vehicle controls.
switch(mPlayerVehicleType)
{
case ePLAYER_VEHICLE_TYPE_VEHICLE4W:
case ePLAYER_VEHICLE_TYPE_VEHICLE6W:
mVehicleController.setCarKeyboardInputs(
mControlInputs.getAccelKeyPressed(),
mControlInputs.getBrakeKeyPressed(),
mControlInputs.getHandbrakeKeyPressed(),
mControlInputs.getSteerLeftKeyPressed(),
mControlInputs.getSteerRightKeyPressed(),
mControlInputs.getGearUpKeyPressed(),
mControlInputs.getGearDownKeyPressed());
mVehicleController.setCarGamepadInputs(
mControlInputs.getAccel(),
mControlInputs.getBrake(),
mControlInputs.getSteer(),
mControlInputs.getGearUp(),
mControlInputs.getGearDown(),
mControlInputs.getHandbrake());
break;
case ePLAYER_VEHICLE_TYPE_TANK4W:
case ePLAYER_VEHICLE_TYPE_TANK6W:
mVehicleController.setTankKeyboardInputs(
mControlInputs.getAccelKeyPressed(),
mControlInputs.getThrustLeftKeyPressed(),
mControlInputs.getThrustRightKeyPressed(),
mControlInputs.getBrakeLeftKeyPressed(),
mControlInputs.getBrakeRightKeyPressed(),
mControlInputs.getGearUpKeyPressed(),
mControlInputs.getGearDownKeyPressed());
mVehicleController.setTankGamepadInputs(
mControlInputs.getAccel(),
mControlInputs.getThrustLeft(),
mControlInputs.getThrustRight(),
mControlInputs.getBrakeLeft(),
mControlInputs.getBrakeRight(),
mControlInputs.getGearUp(),
mControlInputs.getGearDown());
break;
default:
PX_ASSERT(false);
break;
}
updateVehicleController(dtime);
//Update the vehicles.
mVehicleManager.suspensionRaycasts(&getActiveScene());
if (dtime > 0.0f)
{
PxSceneWriteLock scopedLock(*mScene);
#if PX_DEBUG_VEHICLE_ON
updateVehicleManager(dtime,getActiveScene().getGravity());
#else
mVehicleManager.update(dtime,getActiveScene().getGravity());
#endif
}
//Update the camera.
mCameraController.setInputs(
mControlInputs.getRotateY(),
mControlInputs.getRotateZ());
updateCameraController(dtime,getActiveScene());
//Update the revolute joints.
//If the joint has exceeded the rotation limit then reverse the drive velocity
//to make the joint rotate in the opposite direction.
for(PxU32 i=0;i<gNumRevoluteJoints;i++)
{
PxSceneWriteLock scopedLock(*mScene);
//Get the two actors of the joint.
PxRigidActor* actor0=NULL;
PxRigidActor* actor1=NULL;
gRevoluteJoints[i]->getActors(actor0,actor1);
//Work out the rotation angle of the joint.
const PxF32 cosTheta=PxAbs(actor1->is<PxRigidDynamic>()->getGlobalPose().q.getBasisVector1().y);
const PxF32 theta=PxAcos(cosTheta);
//If the joint rotation limit has been exceeded then reverse the drive direction.
//It's possible to reverse the direction but then after a timestep or two for it to still be beyond the rotation limit.
//To avoid switching back and forth don't switch drive direction until a minimum time has passed since the last drive direction change.
//Its possible that the pendulum has hit the car and is unable to reach the limit. A nice fix for this is to keep a track of the time
//passed since the last direction change and reverse the joint drive direction if a time limit has been reached. This gives the car
//a chance to escape the pendulum.
if((theta > gRevoluteJointMaxTheta && gRevoluteJointTimers[i]>4*dtime) || gRevoluteJointTimers[i] > 4*gRevoluteJointMaxTheta/gRevoluteJointDriveSpeeds[i])
{
//Help the joint by setting the actor momenta to zero.
((PxRigidDynamic*)actor1)->setLinearVelocity(PxVec3(0,0,0));
((PxRigidDynamic*)actor1)->setAngularVelocity(PxVec3(0,0,0));
//Switch the joint drive direction.
const PxF32 currDriveVel=gRevoluteJoints[i]->getDriveVelocity();
const PxF32 newDriveVel=-currDriveVel;
gRevoluteJoints[i]->setDriveVelocity(newDriveVel);
//Reset the timer.
gRevoluteJointTimers[i]=0;
}
//Increment the joint timer.
gRevoluteJointTimers[i]+=dtime;
}
{
PxSceneReadLock scopedLock(*mScene);
//Update the progress around the track with the latest vehicle transform.
PxRigidDynamic* actor=getFocusVehicleRigidDynamicActor();
mWayPoints.update(actor->getGlobalPose(),dtime);
//Cache forward speed for the HUD to avoid making API calls while vehicle update is running
const PxVehicleWheels& focusVehicle = *mVehicleManager.getVehicle(mPlayerVehicle);
mForwardSpeedHud = focusVehicle.computeForwardSpeed();
}
}
void SampleVehicle::helpRender(PxU32 x, PxU32 y, PxU8 textAlpha)
{
Renderer* renderer = getRenderer();
const PxU32 yInc=18;
const PxF32 scale=0.5f;
const PxF32 shadowOffset=6.0f;
const RendererColor textColor(255, 255, 255, textAlpha);
const bool isKeyboardSupported = getApplication().getPlatform()->getSampleUserInput()->keyboardSupported();
const bool isPadSupported = getApplication().getPlatform()->getSampleUserInput()->gamepadSupported();
const char* msg;
if(ePLAYER_VEHICLE_TYPE_TANK4W==mPlayerVehicleType || ePLAYER_VEHICLE_TYPE_TANK6W==mPlayerVehicleType)
{
renderer->print(x, y += yInc, "TODO: document inputs for ePLAYER_VEHICLE_TYPE_TANK4W, ePLAYER_VEHICLE_TYPE_TANK6W", scale, shadowOffset, textColor);
if(PxVehicleDriveTankControlModel::eSPECIAL==mTankDriveModel)
{
}
else
{
}
}
else
{
if (isPadSupported && isKeyboardSupported)
renderer->print(x, y += yInc, "Use right stick or numpad keys 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);
else if (isKeyboardSupported)
renderer->print(x, y += yInc, "Use numpad keys to rotate the camera", scale, shadowOffset, textColor);
if (isPadSupported)
renderer->print(x, y += yInc, "Use left stick to steer", scale, shadowOffset, textColor);
msg = mApplication.inputInfoMsg("Press "," for accelerate", VEH_ACCELERATE_PAD, VEH_ACCELERATE_KBD);
if(msg)
renderer->print(x, y += yInc, msg, scale, shadowOffset, textColor);
msg = mApplication.inputInfoMsg("Press "," for brake", CAR_BRAKE_PAD, CAR_BRAKE_KBD);
if(msg)
renderer->print(x, y += yInc, msg, scale, shadowOffset, textColor);
msg = mApplication.inputInfoMsg("Press "," to steer", CAR_STEER_LEFT_KBD, CAR_STEER_RIGHT_KBD);
if(msg)
renderer->print(x, y += yInc, msg, scale, shadowOffset, textColor);
}
msg = mApplication.inputInfoMsg("Press "," for handbrake", CAR_HANDBRAKE_PAD, CAR_HANDBRAKE_KBD);
if(msg)
renderer->print(x, y += yInc, msg, scale, shadowOffset, textColor);
if(!getFocusVehicleUsesAutoGears())
{
msg = mApplication.inputInfoMsg("Press "," to gear up", VEH_GEAR_UP_PAD, VEH_GEAR_UP_KBD);
if(msg)
renderer->print(x, y += yInc, msg, scale, shadowOffset, textColor);
msg = mApplication.inputInfoMsg("Press "," to gear down", VEH_GEAR_DOWN_PAD, VEH_GEAR_DOWN_KBD);
if(msg)
renderer->print(x, y += yInc, msg, scale, shadowOffset, textColor);
}
msg = mApplication.inputInfoMsg("Press "," to toggle car debug render",DEBUG_RENDER_FLAG , -1);
if(msg)
renderer->print(x, y += yInc, msg, scale, shadowOffset, textColor);
msg = mApplication.inputInfoMsg("Press "," to go back to start",RETRY, -1);
if(msg)
renderer->print(x, y += yInc, msg, scale, shadowOffset, textColor);
msg = mApplication.inputInfoMsg("Press "," to go back to last waypoint",FIX_CAR, -1);
if(msg)
renderer->print(x, y += yInc, msg, scale, shadowOffset, textColor);
#if PX_DEBUG_VEHICLE_ON
if(mDebugRenderFlag)
{
msg = mApplication.inputInfoMsg("Press "," to increment wheel graphs", DEBUG_RENDER_WHEEL,-1);
if(msg)
renderer->print(x, y += yInc, msg, scale, shadowOffset, textColor);
msg = mApplication.inputInfoMsg("Press "," to increment central graphs", DEBUG_RENDER_ENGINE,-1);
if(msg)
renderer->print(x, y += yInc, msg, scale, shadowOffset, textColor);
}
#endif
}
void SampleVehicle::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 vehicle simulation using PhysX. In particular,";
char line1[256]="vehicle instantiation, the setup of vehicle description data, and";
char line2[256]="integration with the PhysX SDK are all presented. Key concepts such";
char line3[256]="as raycast and simulation filtering are illustrated as a means to";
char line4[256]="tailor vehicle interaction with the scene. The setup and rendering";
char line5[256]="of vehicle telemetry data is also shown. Finally, physics obstacles";
char line6[256]="such as swinging pendula exemplify the configuration and run-time ";
char line7[256]="control of driven joints using PhysX.";
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);
}
}
void SampleVehicle::customizeRender()
{
drawHud();
if(mDebugRenderFlag)
{
drawFocusVehicleGraphsAndPrintTireSurfaces();
}
const PxU32 width=getCamera().getScreenWidth();
const PxU32 height=getCamera().getScreenHeight();
const PxU32 xCentre=280*width/800;
const PxU32 xRight=570*width/800;
const PxU32 yBottom=600*height/600;
const PxU32 yInc=18;
Renderer* renderer = getRenderer();
char time[64];
sprintf(time, "Curr Lap Time: %1.1f \n", mWayPoints.getTimeElapsed());
renderer->print(xRight, yBottom - yInc*2, time);
sprintf(time, "Best Lap Time: %1.1f \n", mWayPoints.getMinTimeElapsed());
renderer->print(xRight, yBottom - yInc*3, time);
if(!mCameraController.getIsLockedOnVehicleTransform())
{
renderer->print(xCentre, yBottom - yInc*4, "Camera decoupled from car");
}
}
///////////////////////////////////////////////////////////////////////////////
PxFilterFlags SampleVehicleFilterShader(
PxFilterObjectAttributes attributes0, PxFilterData filterData0,
PxFilterObjectAttributes attributes1, PxFilterData filterData1,
PxPairFlags& pairFlags, const void* constantBlock, PxU32 constantBlockSize)
{
PX_UNUSED(constantBlock);
PX_UNUSED(constantBlockSize);
// let triggers through
if(PxFilterObjectIsTrigger(attributes0) || PxFilterObjectIsTrigger(attributes1))
{
pairFlags = PxPairFlag::eTRIGGER_DEFAULT;
return PxFilterFlags();
}
// use a group-based mechanism for all other pairs:
// - Objects within the default group (mask 0) always collide
// - By default, objects of the default group do not collide
// with any other group. If they should collide with another
// group then this can only be specified through the filter
// data of the default group objects (objects of a different
// group can not choose to do so)
// - For objects that are not in the default group, a bitmask
// is used to define the groups they should collide with
if ((filterData0.word0 != 0 || filterData1.word0 != 0) &&
!(filterData0.word0&filterData1.word1 || filterData1.word0&filterData0.word1))
return PxFilterFlag::eSUPPRESS;
pairFlags = PxPairFlag::eCONTACT_DEFAULT;
// The pairFlags for each object are stored in word2 of the filter data. Combine them.
pairFlags |= PxPairFlags(PxU16(filterData0.word2 | filterData1.word2));
return PxFilterFlags();
}
void SampleVehicle::customizeSceneDesc(PxSceneDesc& sceneDesc)
{
sceneDesc.filterShader = SampleVehicleFilterShader;
sceneDesc.flags |= PxSceneFlag::eREQUIRE_RW_LOCK;
}
///////////////////////////////////////////////////////////////////////////////
void SampleVehicle::createStandardMaterials()
{
const PxF32 restitutions[MAX_NUM_SURFACE_TYPES] = {0.2f, 0.2f, 0.2f, 0.2f};
const PxF32 staticFrictions[MAX_NUM_SURFACE_TYPES] = {0.5f, 0.5f, 0.5f, 0.5f};
const PxF32 dynamicFrictions[MAX_NUM_SURFACE_TYPES] = {0.5f, 0.5f, 0.5f, 0.5f};
for(PxU32 i=0;i<MAX_NUM_SURFACE_TYPES;i++)
{
//Create a new material.
mStandardMaterials[i] = getPhysics().createMaterial(staticFrictions[i], dynamicFrictions[i], restitutions[i]);
if(!mStandardMaterials[i])
{
getSampleErrorCallback().reportError(PxErrorCode::eINTERNAL_ERROR, "createMaterial failed", __FILE__, __LINE__);
}
//Set up the drivable surface type that will be used for the new material.
mVehicleDrivableSurfaceTypes[i].mType = i;
}
mChassisMaterialDrivable = getPhysics().createMaterial(0.0f, 0.0f, 0.0f);
if(!mChassisMaterialDrivable)
{
getSampleErrorCallback().reportError(PxErrorCode::eINTERNAL_ERROR, "createMaterial failed", __FILE__, __LINE__);
}
mChassisMaterialNonDrivable = getPhysics().createMaterial(1.0f, 1.0f, 0.0f);
if(!mChassisMaterialNonDrivable)
{
getSampleErrorCallback().reportError(PxErrorCode::eINTERNAL_ERROR, "createMaterial failed", __FILE__, __LINE__);
}
}
///////////////////////////////////////////////////////////////////////////////
static const char* getPlatformName()
{
#if PX_X86
return "PC32";
#elif PX_X64
return "PC64";
#elif PX_ARM_FAMILY
return "ARM";
#else
return "";
#endif
}
const char* SampleVehicle::getFocusVehicleName()
{
switch(mPlayerVehicleType)
{
case ePLAYER_VEHICLE_TYPE_VEHICLE4W:
return "VEHICLE4W";
case ePLAYER_VEHICLE_TYPE_TANK4W:
return "TANK4W";
case ePLAYER_VEHICLE_TYPE_VEHICLE6W:
return "VEHICLE6W";
case ePLAYER_VEHICLE_TYPE_TANK6W:
return "TANK6W";
default:
return NULL;
}
}
static PxU32 GetFileSize(const char* name)
{
if(!name) return 0;
#ifndef SEEK_END
#define SEEK_END 2
#endif
SampleFramework::File* fp;
if (PxToolkit::fopen_s(&fp, name, "rb"))
return 0;
fseek(fp, 0, SEEK_END);
PxU32 eof_ftell = (PxU32)ftell(fp);
fclose(fp);
return eof_ftell;
}
void SampleVehicle::createVehicles()
{
bool hasFocusVehicle = false;
//Make sure that we set the foundation before doing anything.
mVehicleManager.init(getPhysics(),(const PxMaterial**)mStandardMaterials,mVehicleDrivableSurfaceTypes);
//Not added any vehicles yet.
gNumVehicleAdded=0;
//Load the vehicle model (this will add the render actors for the chassis, 4 wheels, and windows).
gLoadType = LOAD_TYPE_VEHICLE;
importRAWFile("car2.raw", 1.0f);
//The extra wheels of an 8-wheeled vehicle are instanced from the 4 wheels of the 4-wheeled car.
gRenderMeshActors[CAR_PART_EXTRA_WHEEL0]=gRenderMeshActors[CAR_PART_FRONT_LEFT_WHEEL];
gRenderMeshActors[CAR_PART_EXTRA_WHEEL1]=gRenderMeshActors[CAR_PART_FRONT_RIGHT_WHEEL];
//Clear the array of render actors before adding the actors for each vehicle.
for(PxU32 i=0;i<mRenderActors.size();i++)
{
RenderBaseActor* renderActor=mRenderActors[i];
renderActor->setRendering(false);
}
//Load the player car.
switch(mPlayerVehicleType)
{
case ePLAYER_VEHICLE_TYPE_VEHICLE4W:
case ePLAYER_VEHICLE_TYPE_TANK4W:
{
for(PxU32 i=0;i<NUM_CAR4W_RENDER_COMPONENTS;i++)
{
gVehicleRenderUserData[gNumVehicleAdded][i]=gCar4WRenderUserData[i];
gVehicleRenderUserData[gNumVehicleAdded][i].carId=PxU8(gNumVehicleAdded);
RenderMeshActor* clone=SAMPLE_NEW(RenderMeshActor)(*gRenderMeshActors[i]);
clone->setRendering(true);
clone->mUserData=&gVehicleRenderUserData[gNumVehicleAdded][i];
clone->setEnableCameraCull(true);
mVehicleGraphics.push_back(clone);
mRenderActors.push_back(clone);
}
mPlayerVehicle=0;
if(!hasFocusVehicle)
{
if(ePLAYER_VEHICLE_TYPE_VEHICLE4W==mPlayerVehicleType)
{
mVehicleManager.create4WVehicle(getActiveScene(),getPhysics(),getCooking(),*mChassisMaterialDrivable,gChassisMass,gWheelCentreOffsets4,gChassisConvexMesh,gWheelConvexMeshes4,gPlayerCarStartTransforms[0],true);
}
else
{
mVehicleManager.create4WTank(getActiveScene(),getPhysics(),getCooking(),*mChassisMaterialDrivable,gChassisMass,gWheelCentreOffsets4,gChassisConvexMesh,gWheelConvexMeshes4,gPlayerCarStartTransforms[0],true,mTankDriveModel);
}
}
gNumVehicleAdded++;
}
break;
case ePLAYER_VEHICLE_TYPE_VEHICLE6W:
case ePLAYER_VEHICLE_TYPE_TANK6W:
{
for(PxU32 i=0;i<NUM_CAR4W_RENDER_COMPONENTS;i++)
{
gVehicleRenderUserData[gNumVehicleAdded][i]=gCar6WRenderUserData[i];
gVehicleRenderUserData[gNumVehicleAdded][i].carId=PxU8(gNumVehicleAdded);
RenderMeshActor* clone=SAMPLE_NEW(RenderMeshActor)(*gRenderMeshActors[i]);
clone->setRendering(true);
clone->mUserData=&gVehicleRenderUserData[gNumVehicleAdded][i];
clone->setEnableCameraCull(true);
mVehicleGraphics.push_back(clone);
mRenderActors.push_back(clone);
}
gVehicleRenderUserData[gNumVehicleAdded][CAR_PART_EXTRA_WHEEL0]=gCar6WRenderUserData[CAR_PART_EXTRA_WHEEL0];
gVehicleRenderUserData[gNumVehicleAdded][CAR_PART_EXTRA_WHEEL1]=gCar6WRenderUserData[CAR_PART_EXTRA_WHEEL1];
gVehicleRenderUserData[gNumVehicleAdded][CAR_PART_EXTRA_WHEEL0].carId = PxU8(gNumVehicleAdded);
gVehicleRenderUserData[gNumVehicleAdded][CAR_PART_EXTRA_WHEEL1].carId = PxU8(gNumVehicleAdded);
//Add the extra wheels.
RenderMeshActor* clone;
clone = SAMPLE_NEW(RenderMeshActor)(*gRenderMeshActors[CAR_PART_EXTRA_WHEEL0]);
clone->setRendering(true);
clone->mUserData=&gVehicleRenderUserData[gNumVehicleAdded][CAR_PART_EXTRA_WHEEL0];
clone->setEnableCameraCull(true);
mVehicleGraphics.push_back(clone);
mRenderActors.push_back(clone);
clone = SAMPLE_NEW(RenderMeshActor)(*gRenderMeshActors[CAR_PART_EXTRA_WHEEL1]);
clone->setRendering(true);
clone->mUserData=&gVehicleRenderUserData[gNumVehicleAdded][CAR_PART_EXTRA_WHEEL1];
clone->setEnableCameraCull(true);
mVehicleGraphics.push_back(clone);
mRenderActors.push_back(clone);
mPlayerVehicle=0;
if(!hasFocusVehicle)
{
if(ePLAYER_VEHICLE_TYPE_VEHICLE6W==mPlayerVehicleType)
{
mVehicleManager.create6WVehicle(getActiveScene(),getPhysics(),getCooking(),*mChassisMaterialDrivable,gChassisMass,gWheelCentreOffsets4,gChassisConvexMesh,gWheelConvexMeshes4,gPlayerCarStartTransforms[0],true);
}
else
{
mVehicleManager.create6WTank(getActiveScene(),getPhysics(),getCooking(),*mChassisMaterialDrivable,gChassisMass,gWheelCentreOffsets4,gChassisConvexMesh,gWheelConvexMeshes4,gPlayerCarStartTransforms[0],true,mTankDriveModel);
}
}
gNumVehicleAdded++;
}
break;
default:
PX_ASSERT(false);
break;
}
#if NUM_NONPLAYER_4W_VEHICLES
for(PxU32 i=0;i<NUM_NONPLAYER_4W_VEHICLES;i++)
{
//Clone the meshes from the instanced meshes.
for(PxU32 j=0;j<NUM_CAR4W_RENDER_COMPONENTS;j++)
{
gVehicleRenderUserData[gNumVehicleAdded][j]=gCar4WRenderUserData[j];
gVehicleRenderUserData[gNumVehicleAdded][j].carId=PxU8(gNumVehicleAdded);
RenderMeshActor* clone = SAMPLE_NEW(RenderMeshActor)(*gRenderMeshActors[j]);
clone->setRendering(true);
clone->mUserData=&gVehicleRenderUserData[gNumVehicleAdded][j];
clone->setEnableCameraCull(true);
mVehicleGraphics.push_back(clone);
mRenderActors.push_back(clone);
}
//Add the next vehicle.
mVehicleManager.create4WVehicle(getActiveScene(),getPhysics(),getCooking(),*mChassisMaterialNonDrivable,gChassisMass,gWheelCentreOffsets4,gChassisConvexMesh,gWheelConvexMeshes4,gVehicle4WStartTransforms[i],true);
gNumVehicleAdded++;
}
#endif
#if NUM_NONPLAYER_6W_VEHICLES
for(PxU32 i=0;i<NUM_NONPLAYER_6W_VEHICLES;i++)
{
//Clone the meshes from the instanced meshes.
for(PxU32 j=0;j<NUM_CAR4W_RENDER_COMPONENTS;j++)
{
gVehicleRenderUserData[gNumVehicleAdded][j]=gCar6WRenderUserData[j];
gVehicleRenderUserData[gNumVehicleAdded][j].carId=PxU8(gNumVehicleAdded);
RenderMeshActor* clone = SAMPLE_NEW(RenderMeshActor)(*gRenderMeshActors[j]);
clone->setRendering(true);
clone->mUserData=&gVehicleRenderUserData[gNumVehicleAdded][j];
clone->setEnableCameraCull(true);
mVehicleGraphics.push_back(clone);
mRenderActors.push_back(clone);
}
//Add the extra wheels.
gVehicleRenderUserData[gNumVehicleAdded][CAR_PART_EXTRA_WHEEL0]=gCar6WRenderUserData[CAR_PART_EXTRA_WHEEL0];
gVehicleRenderUserData[gNumVehicleAdded][CAR_PART_EXTRA_WHEEL1]=gCar6WRenderUserData[CAR_PART_EXTRA_WHEEL1];
gVehicleRenderUserData[gNumVehicleAdded][CAR_PART_EXTRA_WHEEL0].carId = PxU8(gNumVehicleAdded);
gVehicleRenderUserData[gNumVehicleAdded][CAR_PART_EXTRA_WHEEL1].carId = PxU8(gNumVehicleAdded);
RenderMeshActor* clone;
clone = SAMPLE_NEW(RenderMeshActor)(*gRenderMeshActors[CAR_PART_EXTRA_WHEEL0]);
clone->setRendering(true);
clone->mUserData=&gVehicleRenderUserData[gNumVehicleAdded][CAR_PART_EXTRA_WHEEL0];
clone->setEnableCameraCull(true);
mVehicleGraphics.push_back(clone);
mRenderActors.push_back(clone);
clone = SAMPLE_NEW(RenderMeshActor)(*gRenderMeshActors[CAR_PART_EXTRA_WHEEL1]);
clone->setRendering(true);
clone->mUserData=&gVehicleRenderUserData[gNumVehicleAdded][CAR_PART_EXTRA_WHEEL1];
clone->setEnableCameraCull(true);
mVehicleGraphics.push_back(clone);
mRenderActors.push_back(clone);
//Add the next vehicle.
mVehicleManager.create6WVehicle(getActiveScene(),getPhysics(),getCooking(),*mChassisMaterialNonDrivable,gChassisMass,gWheelCentreOffsets4,gChassisConvexMesh,gWheelConvexMeshes4,gVehicle6WStartTransforms[i],true);
gNumVehicleAdded++;
}
#endif
#if NUM_NONPLAYER_4W_TANKS
for(PxU32 i=0;i<NUM_NONPLAYER_4W_TANKS;i++)
{
//Clone the meshes from the instanced meshes.
for(PxU32 j=0;j<NUM_CAR4W_RENDER_COMPONENTS;j++)
{
gVehicleRenderUserData[gNumVehicleAdded][j]=gCar4WRenderUserData[j];
gVehicleRenderUserData[gNumVehicleAdded][j].carId=PxU8(gNumVehicleAdded);
RenderMeshActor* clone = SAMPLE_NEW(RenderMeshActor)(*gRenderMeshActors[j]);
clone->setRendering(true);
clone->mUserData=&gVehicleRenderUserData[gNumVehicleAdded][j];
clone->setEnableCameraCull(true);
mVehicleGraphics.push_back(clone);
mRenderActors.push_back(clone);
}
mPlayerVehicle=0;
//Add the next vehicle.
mVehicleManager.create4WTank(getActiveScene(),getPhysics(),getCooking(),*mChassisMaterial,gChassisMass,gWheelCentreOffsets4,gChassisConvexMesh,gWheelConvexMeshes4,gTank4WStartTransforms[i],true, PxVehicleDriveTank::eDRIVE_MODEL_SPECIAL);
gNumVehicleAdded++;
}
#endif
#if NUM_NONPLAYER_6W_TANKS
for(PxU32 i=0;i<NUM_NONPLAYER_6W_TANKS;i++)
{
//Clone the meshes from the instanced meshes.
for(PxU32 j=0;j<NUM_CAR4W_RENDER_COMPONENTS;j++)
{
gVehicleRenderUserData[gNumVehicleAdded][j]=gTank6WRenderUserData[j];
gVehicleRenderUserData[gNumVehicleAdded][j].carId=PxU8(gNumVehicleAdded);
RenderMeshActor* clone = SAMPLE_NEW(RenderMeshActor)(*gRenderMeshActors[j]);
clone->setRendering(true);
clone->mUserData=&gVehicleRenderUserData[gNumVehicleAdded][j];
clone->setEnableCameraCull(true);
mVehicleGraphics.push_back(clone);
mRenderActors.push_back(clone);
}
//Add the extra wheels.
gVehicleRenderUserData[gNumVehicleAdded][CAR_PART_EXTRA_WHEEL0]=gTank6WRenderUserData[CAR_PART_EXTRA_WHEEL0];
gVehicleRenderUserData[gNumVehicleAdded][CAR_PART_EXTRA_WHEEL1]=gTank6WRenderUserData[CAR_PART_EXTRA_WHEEL1];
gVehicleRenderUserData[gNumVehicleAdded][CAR_PART_EXTRA_WHEEL0].carId = PxU8(gNumVehicleAdded);
gVehicleRenderUserData[gNumVehicleAdded][CAR_PART_EXTRA_WHEEL1].carId = PxU8(gNumVehicleAdded);
RenderMeshActor* clone;
clone = SAMPLE_NEW(RenderMeshActor)(*gRenderMeshActors[CAR_PART_EXTRA_WHEEL0]);
clone->setRendering(true);
clone->mUserData=&gVehicleRenderUserData[gNumVehicleAdded][CAR_PART_EXTRA_WHEEL0];
clone->setEnableCameraCull(true);
mVehicleGraphics.push_back(clone);
mRenderActors.push_back(clone);
clone = SAMPLE_NEW(RenderMeshActor)(*gRenderMeshActors[CAR_PART_EXTRA_WHEEL1]);
clone->setRendering(true);
clone->mUserData=&gVehicleRenderUserData[gNumVehicleAdded][CAR_PART_EXTRA_WHEEL1];
clone->setEnableCameraCull(true);
mVehicleGraphics.push_back(clone);
mRenderActors.push_back(clone);
//Add the next vehicle.
mVehicleManager.create6WTank(getActiveScene(),getPhysics(),getCooking(),*mChassisMaterial,gChassisMass,gWheelCentreOffsets4,gChassisConvexMesh,gWheelConvexMeshes4,gTank6WStartTransforms[i],true);
gNumVehicleAdded++;
}
#endif
}
PxRigidStatic* SampleVehicle::addStaticObstacle
(const PxTransform& transform, const PxU32 numShapes, PxTransform* shapeTransforms, PxGeometry** shapeGeometries, PxMaterial** shapeMaterials)
{
PxFilterData simFilterData;
simFilterData.word0=COLLISION_FLAG_GROUND;
simFilterData.word1=COLLISION_FLAG_GROUND_AGAINST;
PxFilterData qryFilterData;
SampleVehicleSetupDrivableShapeQueryFilterData(&qryFilterData);
PxRigidStatic* actor=getPhysics().createRigidStatic(transform);
for(PxU32 i=0;i<numShapes;i++)
{
PxShape* shape=PxRigidActorExt::createExclusiveShape(*actor, *shapeGeometries[i], *shapeMaterials[i]);
shape->setLocalPose(shapeTransforms[i]);
shape->setSimulationFilterData(simFilterData);
shape->setQueryFilterData(qryFilterData);
}
getActiveScene().addActor(*actor);
createRenderObjectsFromActor(actor);
return actor;
}
PxRigidDynamic* SampleVehicle::addDynamicObstacle
(const PxTransform& transform, const PxF32 mass, const PxU32 numShapes, PxTransform* shapeTransforms, PxGeometry** shapeGeometries, PxMaterial** shapeMaterials)
{
PxFilterData simFilterData;
simFilterData.word0=COLLISION_FLAG_OBSTACLE;
simFilterData.word1=COLLISION_FLAG_OBSTACLE_AGAINST;
PxFilterData qryFilterData;
SampleVehicleSetupNonDrivableShapeQueryFilterData(&qryFilterData);
PxRigidDynamic* actor = getPhysics().createRigidDynamic(transform);
for(PxU32 i=0;i<numShapes;i++)
{
PxShape* shape = PxRigidActorExt::createExclusiveShape(*actor, *shapeGeometries[i], *shapeMaterials[i]);
shape->setLocalPose(shapeTransforms[i]);
shape->setSimulationFilterData(simFilterData);
shape->setQueryFilterData(qryFilterData);
}
PxRigidBodyExt::setMassAndUpdateInertia(*actor,mass);
getActiveScene().addActor(*actor);
createRenderObjectsFromActor(actor);
return actor;
}
PxRigidDynamic* SampleVehicle::addDynamicDrivableObstacle
(const PxTransform& transform, const PxF32 mass, const PxU32 numShapes, PxTransform* shapeTransforms, PxGeometry** shapeGeometries, PxMaterial** shapeMaterials)
{
PxFilterData simFilterData;
simFilterData.word0=COLLISION_FLAG_DRIVABLE_OBSTACLE;
simFilterData.word1=COLLISION_FLAG_DRIVABLE_OBSTACLE_AGAINST;
PxFilterData qryFilterData;
SampleVehicleSetupDrivableShapeQueryFilterData(&qryFilterData);
PxRigidDynamic* actor = getPhysics().createRigidDynamic(transform);
for(PxU32 i=0;i<numShapes;i++)
{
PxShape* shape = PxRigidActorExt::createExclusiveShape(*actor, *shapeGeometries[i], *shapeMaterials[i]);
shape->setLocalPose(shapeTransforms[i]);
shape->setSimulationFilterData(simFilterData);
shape->setQueryFilterData(qryFilterData);
}
PxRigidBodyExt::setMassAndUpdateInertia(*actor,mass);
getActiveScene().addActor(*actor);
createRenderObjectsFromActor(actor);
return actor;
}
void SampleVehicle::createStack(PxU32 numBaseBoxes, PxF32 boxSize, const PxVec3& pos, const PxQuat& quat)
{
const PxF32 density=50.0f;
const PxF32 sizeX = boxSize;
const PxF32 sizeY = boxSize;
const PxF32 sizeZ = boxSize;
const PxF32 mass = boxSize*boxSize*boxSize*density;
const PxVec3 halfExtents(sizeX*0.5f,sizeY*0.5f,sizeZ*0.5f);
PxBoxGeometry geometry(halfExtents);
PxTransform shapeTransforms[1]={PxTransform(PxIdentity)};
PxGeometry* shapeGeometries[1]={&geometry};
PxMaterial* shapeMaterials[1]={mStandardMaterials[SURFACE_TYPE_TARMAC]};
const PxF32 spacing = 0.0001f;
PxVec3 relPos(0.0f, sizeY/2, 0.0f);
PxF32 offsetX = -(numBaseBoxes * (sizeX + spacing) * 0.5f);
PxF32 offsetZ = 0.0f;
while(numBaseBoxes)
{
for(PxU32 i=0;i<numBaseBoxes ;i++)
{
relPos.x = offsetX + (PxF32)i * (sizeX + spacing);
relPos.z = offsetZ;
PxTransform transform(pos + quat.rotate(relPos),quat);
addDynamicObstacle(transform,mass,1,shapeTransforms,shapeGeometries,shapeMaterials);
}
offsetX += sizeX/2;
relPos.y += (sizeY + spacing);
numBaseBoxes--;
}
}
void SampleVehicle::createWall(const PxU32 numHorizontalBoxes, const PxU32 numVerticalBoxes, const PxF32 boxSize, const PxVec3& pos, const PxQuat& quat)
{
const PxF32 density=50.0f;
const PxF32 sizeX = boxSize;
const PxF32 sizeY = boxSize;
const PxF32 sizeZ = boxSize;
const PxF32 mass = sizeX*sizeY*sizeZ*density;
const PxVec3 halfExtents(sizeX*0.5f,sizeY*0.5f,sizeZ*0.5f);
PxBoxGeometry geometry(halfExtents);
PxTransform shapeTransforms[1] = {PxTransform(PxIdentity)};
PxGeometry* shapeGeometries[1] = {&geometry};
PxMaterial* shapeMaterials[1] = {mStandardMaterials[SURFACE_TYPE_TARMAC]};
const PxF32 spacing = 0.0001f;
PxVec3 relPos(0.0f, sizeY/2, 0.0f);
PxF32 offsetX = -(numHorizontalBoxes * (sizeX + spacing) * 0.5f);
PxF32 offsetZ = 0.0f;
for(PxU32 k=0;k<numVerticalBoxes;k++)
{
for(PxU32 i=0;i<numHorizontalBoxes;i++)
{
relPos.x = offsetX + (sizeX + spacing)*i;
relPos.z = offsetZ;
PxTransform transform(pos + quat.rotate(relPos),quat);
addDynamicObstacle(transform,mass,1,shapeTransforms,shapeGeometries,shapeMaterials);
}
if(0==(k%2))
{
offsetX += sizeX/2;
}
else
{
offsetX -= sizeX/2;
}
relPos.y += (sizeY + spacing);
}
}
void SampleVehicle::createObstacles()
{
PxSceneWriteLock scopedLock(*mScene);
//Create some giant pendula
{
PxTransform shapeTransforms[3]={PxTransform(PxIdentity),PxTransform(PxIdentity),PxTransform(PxIdentity)};
PxMaterial* shapeMaterials[3]={NULL,NULL,NULL};
PxGeometry* shapeGeometries[3]={NULL,NULL,NULL};
PxShape* shapes[3]={NULL,NULL,NULL};
gNumRevoluteJoints=0;
for(PxU32 i=0;i<MAX_NUM_PENDULA;i++)
{
//Get the transform to position the next pendulum ball.
const PxTransform& ballStartTransform=gPendulaBallStartTransforms[i];
//Pendulum made of two shapes : a sphere for the ball and a cylinder for the shaft.
//In the absence of a special material for pendula just use the tarmac material.
PxSphereGeometry geomBall(gPendulumBallRadius);
shapeGeometries[0]=&geomBall;
shapeTransforms[0]=PxTransform(PxIdentity);
shapeMaterials[0]=mStandardMaterials[SURFACE_TYPE_TARMAC];
PxConvexMeshGeometry geomShaft(createCylinderConvexMesh(gPendulumShaftLength, gPendulumShaftWidth, 8, getPhysics(), getCooking()));
shapeGeometries[1]=&geomShaft;
shapeTransforms[1]=PxTransform(PxVec3(0, 0.5f*gPendulumShaftLength, 0), PxQuat(PxHalfPi, PxVec3(0,0,1))),
shapeMaterials[1]=mStandardMaterials[SURFACE_TYPE_TARMAC];
//Ready to add the pendulum as a dynamic object.
PxRigidDynamic* actor=addDynamicObstacle(ballStartTransform,gPendulumBallMass,2,shapeTransforms,shapeGeometries,shapeMaterials);
//As an optimization we don't want pendulum to intersect with static geometry because the position and
//limits on joint rotation will ensure that this is already impossible.
actor->getShapes(shapes,2);
PxFilterData simFilterData=shapes[0]->getSimulationFilterData();
simFilterData.word1 &= ~COLLISION_FLAG_GROUND;
shapes[0]->setSimulationFilterData(simFilterData);
shapes[1]->setSimulationFilterData(simFilterData);
//As a further optimization lets set the pendulum shapes to be non-drivable surfaces.
PxFilterData qryFilterData;
SampleVehicleSetupNonDrivableShapeQueryFilterData(&qryFilterData);
shapes[0]->setQueryFilterData(qryFilterData);
shapes[1]->setQueryFilterData(qryFilterData);
//Add static geometry to give the appearance that something is physically supporting the pendulum.
//This supporting geometry is just a vertical bar and two horizontal bars.
const PxF32 groundClearance=3.0f;
PxConvexMeshGeometry geomHorizontalBar(createCylinderConvexMesh(gPendulumSuspensionStructureWidth, gPendulumShaftWidth, 8, getPhysics(), getCooking()));
PxConvexMeshGeometry geomVerticalBar(createCylinderConvexMesh(gPendulumShaftLength+groundClearance, gPendulumShaftWidth, 8, getPhysics(), getCooking()));
shapeGeometries[0]=&geomHorizontalBar;
shapeMaterials[0]=mStandardMaterials[SURFACE_TYPE_TARMAC];
shapeTransforms[0]=PxTransform(PxVec3(0, gPendulumShaftLength, 0), PxQuat(PxIdentity));
shapeGeometries[1]=&geomVerticalBar;
shapeMaterials[1]=mStandardMaterials[SURFACE_TYPE_TARMAC];
shapeTransforms[1]=PxTransform(PxVec3(0.5f*gPendulumSuspensionStructureWidth, 0.5f*(gPendulumShaftLength-groundClearance), 0), PxQuat(PxHalfPi, PxVec3(0,0,1)));
shapeGeometries[2]=&geomVerticalBar;
shapeMaterials[2]=mStandardMaterials[SURFACE_TYPE_TARMAC];
shapeTransforms[2]=PxTransform(PxVec3(-0.5f*gPendulumSuspensionStructureWidth, 0.5f*(gPendulumShaftLength-groundClearance), 0), PxQuat(PxHalfPi, PxVec3(0,0,1)));
//Ready to add the support geometry as a static object.
PxRigidStatic* staticActor=addStaticObstacle(ballStartTransform,3,shapeTransforms,shapeGeometries,shapeMaterials);
//As an optimization lets disable collision with the dynamic pendulum because the joint limits will make
//collision impossible.
staticActor->getShapes(shapes,3);
simFilterData=shapes[0]->getSimulationFilterData();
simFilterData.word1 &= ~COLLISION_FLAG_OBSTACLE;
shapes[0]->setSimulationFilterData(simFilterData);
shapes[1]->setSimulationFilterData(simFilterData);
shapes[2]->setSimulationFilterData(simFilterData);
//Now finally add the joint that will create the pendulum behaviour : rotation around a single axis.
const PxVec3 pendulumPos=ballStartTransform.p + PxVec3(0, gPendulumShaftLength, 0);
PxQuat pendulumRotation=PxQuat(PxHalfPi,PxVec3(0,1,0));
PxRevoluteJoint* joint=PxRevoluteJointCreate
(getPhysics(),
NULL, PxTransform(pendulumPos, ballStartTransform.q*pendulumRotation),
actor, PxTransform(PxVec3(0,gPendulumShaftLength,0), pendulumRotation));
joint->setDriveVelocity(gRevoluteJointDriveSpeeds[i]);
joint->setRevoluteJointFlag(PxRevoluteJointFlag::eDRIVE_ENABLED, true);
gRevoluteJoints[gNumRevoluteJoints]=joint;
gNumRevoluteJoints++;
}
//Work out the maximum angle of rotation allowed before the pendulum hits the support geometry.
//We're going to monitor the pendulum's progress at each update and reverse the pendulum drive speed
//if the limit is exceed.
const PxF32 sinTheta=(gPendulumSuspensionStructureWidth*0.5f - gPendulumBallRadius)/gPendulumShaftLength;
gRevoluteJointMaxTheta=PxAsin(sinTheta);
}
//Create a see-saw
{
//See-saw made of two separate objects : a static prism-shaped base and a ramp that balances on top of the prism.
//In the absence of a special material for see-saws just reuse the tarmac material.
PxTransform shapeTransforms[1]={PxTransform(PxIdentity)};
PxMaterial* shapeMaterials[1]={mStandardMaterials[SURFACE_TYPE_TARMAC]};
PxGeometry* shapeGeometries[1]={NULL};
//Add the static prism-shaped object.
PxTransform tBase(PxVec3( -132.940292 , 8.664189 , -116.392891 ), PxQuat( -0.000319 , 0.348920 , -0.000129 , -0.937153 ) );
PxConvexMesh* meshBase=createPrismConvexMesh(12,3.0f,4.5f,getPhysics(), getCooking());
PxConvexMeshGeometry geomBase(meshBase);
shapeGeometries[0]=&geomBase;
addStaticObstacle(tBase,1,shapeTransforms,shapeGeometries,shapeMaterials);
//Add the dynamic ramp that balances on the prism.
PxTransform tRamp(PxVec3( -130.357010 , 12.584847 , -119.381256 ), PxQuat( 0.088919 , 0.347436 , 0.033112 , -0.932891 ) ) ;
PxConvexMesh* meshRamp=createSquashedCuboidMesh(6.0f, 40.0f, 0.25f, 0.065f, getPhysics(), getCooking());
PxConvexMeshGeometry geomRamp(meshRamp);
shapeGeometries[0]=&geomRamp;
addDynamicDrivableObstacle(tRamp,1000.0f,1,shapeTransforms,shapeGeometries,shapeMaterials);
}
//Add a really big ramp to jump over the car stack.
{
PxVec3 halfExtentsRamp(5.0f,1.9f,7.0f);
PxConvexMeshGeometry geomRamp(createWedgeConvexMesh(halfExtentsRamp,getPhysics(),getCooking()));
PxTransform shapeTransforms[1]={PxTransform(PxIdentity)};
PxMaterial* shapeMaterials[1]={mStandardMaterials[SURFACE_TYPE_TARMAC]};
PxGeometry* shapeGeometries[1]={&geomRamp};
PxTransform tRamp(PxVec3( -89.849564 , 9.950000 , 154.516617 ), PxQuat( -0.000002 , -0.837118 , -0.000004 , 0.547022 ) );
addStaticObstacle(tRamp,1,shapeTransforms,shapeGeometries,shapeMaterials);
}
//Add two ramps side by side with a gap in between
{
PxVec3 halfExtents(3.0f,1.5f,3.5f);
PxConvexMeshGeometry geometry(createWedgeConvexMesh(halfExtents,getPhysics(),getCooking()));
PxTransform shapeTransforms[1]={PxTransform(PxIdentity)};
PxMaterial* shapeMaterials[1]={mStandardMaterials[SURFACE_TYPE_TARMAC]};
PxGeometry* shapeGeometries[1]={&geometry};
PxTransform t1(PxVec3( 112.797081 , 10.086022 , 134.419052 ), PxQuat( 0.000013 , -0.406322 , 0.000006 , 0.913730 ) );
addStaticObstacle(t1,1,shapeTransforms,shapeGeometries,shapeMaterials);
PxTransform t2(PxVec3( 120.135361 , 10.086023 , 140.594055 ), PxQuat( 0.000013 , -0.406322 , 0.000006 , 0.913730 ) );
addStaticObstacle(t2,1,shapeTransforms,shapeGeometries,shapeMaterials);
}
//Add a wall made of dynamic objects with cuboid shapes for bricks.
{
PxTransform t(PxVec3( -37.525650 , 9.864201 , -77.926567 ), PxQuat( -0.000286 , 0.728016 , -0.000290 , -0.685561 ) ) ;
createWall(12,4,1.0f,t.p,t.q);
}
//Create a kind of cattle grid of cylindrical rods.
{
//Cattle grid made out of 128 identical cylindrical rods.
//Need to instantiate geometry used for the rods.
const PxF32 logRadius=0.125f;
PxConvexMesh* mesh=createCylinderConvexMesh(10.0f,logRadius,8,getPhysics(),getCooking());
PxConvexMeshGeometry geom(mesh);
//Set up transform, geometry, and material of each cylindrical rod shape.
PxGeometry* shapeGeometries[128];
PxMaterial* shapeMaterials[128];
PxTransform shapeTransforms[128];
PxTransform shapeTransform=PxTransform(PxVec3(0,0,0),PxQuat(PxIdentity));
for(PxU32 i=0;i<128;i++)
{
shapeTransforms[i]=shapeTransform;
shapeGeometries[i]=&geom;
shapeMaterials[i]=mStandardMaterials[SURFACE_TYPE_TARMAC];
//Work out the position of the next cylindrical rod.
shapeTransform.p.z += (2.40f*logRadius);
shapeTransform.p.y += 0.0025f;
}
//Ready to add the cattle grid as a static object with a composite bound of 128 cylindrical rods.
PxTransform t(PxVec3( -160.972595 , 8.739249 , -74.141998 ), PxQuat( 0.000407 , -0.165312 , 0.000060 , 0.986241 ) ) ;
addStaticObstacle(t,128,shapeTransforms,shapeGeometries,shapeMaterials);
}
//Add three static walls
{
PxBoxGeometry box(8,2,1);
PxTransform shapeTransforms[1]={PxTransform(PxIdentity)};
PxGeometry* shapeGeometries[1]={&box};
PxMaterial* shapeMaterials[1]={mStandardMaterials[SURFACE_TYPE_TARMAC]};
PxTransform t1(PxVec3( -175.981186 , 9.864196 , -25.040220 ), PxQuat( -0.000417 , 0.042262 , -0.000009 , -0.999106 ) );
addStaticObstacle(t1,1,shapeTransforms,shapeGeometries,shapeMaterials);
PxTransform t2(PxVec3( -174.972122 , 9.864214 , 32.517246 ), PxQuat( -0.000384 , -0.080625 , 0.000019 , -0.996744 ) ) ;
addStaticObstacle(t2,1,shapeTransforms,shapeGeometries,shapeMaterials);
PxTransform t3(PxVec3( 157.825897 , 9.864218 , -83.961632 ), PxQuat( -0.000124 , 0.997806 , -0.000358 , -0.066201 ) );
addStaticObstacle(t3,1,shapeTransforms,shapeGeometries,shapeMaterials);
}
}
void SampleVehicle::collectInputEvents(std::vector<const SampleFramework::InputEvent*>& inputEvents)
{
PhysXSample::collectInputEvents(inputEvents);
getApplication().getPlatform()->getSampleUserInput()->unregisterInputEvent(CAMERA_GAMEPAD_MOVE_LEFT_RIGHT);
getApplication().getPlatform()->getSampleUserInput()->unregisterInputEvent(CAMERA_GAMEPAD_MOVE_FORWARD_BACK);
getApplication().getPlatform()->getSampleUserInput()->unregisterInputEvent(SPAWN_DEBUG_OBJECT);
getApplication().getPlatform()->getSampleUserInput()->unregisterInputEvent(MENU_VISUALIZATIONS);
getApplication().getPlatform()->getSampleUserInput()->unregisterInputEvent(HIDE_GRAPHICS);
getApplication().getPlatform()->getSampleUserInput()->unregisterInputEvent(VARIABLE_TIMESTEP);
DIGITAL_INPUT_EVENT_DEF(VEH_SAVE_KBD, WKEY_I, SCAN_CODE_FORWARD, SCAN_CODE_FORWARD );
//Driving keyboard controls.
if(ePLAYER_VEHICLE_TYPE_TANK4W==mPlayerVehicleType || ePLAYER_VEHICLE_TYPE_TANK6W==mPlayerVehicleType)
{
DIGITAL_INPUT_EVENT_DEF(VEH_GEAR_DOWN_KBD, SCAN_CODE_9, SCAN_CODE_9, SCAN_CODE_9 );
DIGITAL_INPUT_EVENT_DEF(VEH_GEAR_UP_KBD, SCAN_CODE_0, SCAN_CODE_0, SCAN_CODE_0 );
DIGITAL_INPUT_EVENT_DEF(TANK_THRUST_LEFT_KBD, WKEY_Q, SCAN_CODE_BACKWARD, SCAN_CODE_BACKWARD );
DIGITAL_INPUT_EVENT_DEF(TANK_THRUST_RIGHT_KBD, WKEY_I, SCAN_CODE_LEFT, SCAN_CODE_LEFT );
DIGITAL_INPUT_EVENT_DEF(TANK_BRAKE_LEFT_KBD, WKEY_A, SCAN_CODE_RIGHT, SCAN_CODE_RIGHT );
DIGITAL_INPUT_EVENT_DEF(TANK_BRAKE_RIGHT_KBD, WKEY_J, SCAN_CODE_L, SCAN_CODE_L );
}
else
{
DIGITAL_INPUT_EVENT_DEF(VEH_ACCELERATE_KBD, SCAN_CODE_FORWARD, SCAN_CODE_FORWARD, SCAN_CODE_FORWARD );
DIGITAL_INPUT_EVENT_DEF(VEH_GEAR_DOWN_KBD, SCAN_CODE_9, SCAN_CODE_9, SCAN_CODE_9 );
DIGITAL_INPUT_EVENT_DEF(VEH_GEAR_UP_KBD, SCAN_CODE_0, SCAN_CODE_0, SCAN_CODE_0 );
DIGITAL_INPUT_EVENT_DEF(CAR_BRAKE_KBD, SCAN_CODE_BACKWARD, SCAN_CODE_BACKWARD, SCAN_CODE_BACKWARD );
DIGITAL_INPUT_EVENT_DEF(CAR_HANDBRAKE_KBD, SCAN_CODE_L, SCAN_CODE_L, SCAN_CODE_L );
DIGITAL_INPUT_EVENT_DEF(CAR_STEER_LEFT_KBD, SCAN_CODE_LEFT, SCAN_CODE_LEFT, SCAN_CODE_LEFT );
DIGITAL_INPUT_EVENT_DEF(CAR_STEER_RIGHT_KBD, SCAN_CODE_RIGHT, SCAN_CODE_RIGHT, SCAN_CODE_RIGHT );
}
//Driving gamepad controls
if(ePLAYER_VEHICLE_TYPE_TANK4W==mPlayerVehicleType || ePLAYER_VEHICLE_TYPE_TANK6W==mPlayerVehicleType)
{
DIGITAL_INPUT_EVENT_DEF(VEH_GEAR_DOWN_PAD, GAMEPAD_EAST, OSXKEY_UNKNOWN, LINUXKEY_UNKNOWN );
DIGITAL_INPUT_EVENT_DEF(VEH_GEAR_UP_PAD, GAMEPAD_NORTH, OSXKEY_UNKNOWN, LINUXKEY_UNKNOWN );
if(PxVehicleDriveTankControlModel::eSPECIAL==mTankDriveModel)
{
ANALOG_INPUT_EVENT_DEF(TANK_THRUST_LEFT_PAD, GAMEPAD_DEFAULT_SENSITIVITY, GAMEPAD_LEFT_STICK_Y, OSXKEY_UNKNOWN, LINUXKEY_UNKNOWN );
ANALOG_INPUT_EVENT_DEF(TANK_THRUST_RIGHT_PAD, GAMEPAD_DEFAULT_SENSITIVITY, GAMEPAD_RIGHT_STICK_Y, OSXKEY_UNKNOWN, LINUXKEY_UNKNOWN );
ANALOG_INPUT_EVENT_DEF(TANK_BRAKE_LEFT_PAD, GAMEPAD_DEFAULT_SENSITIVITY, GAMEPAD_LEFT_SHOULDER_BOT, OSXKEY_UNKNOWN, LINUXKEY_UNKNOWN );
ANALOG_INPUT_EVENT_DEF(TANK_BRAKE_RIGHT_PAD, GAMEPAD_DEFAULT_SENSITIVITY, GAMEPAD_RIGHT_SHOULDER_BOT, OSXKEY_UNKNOWN, LINUXKEY_UNKNOWN );
}
else
{
ANALOG_INPUT_EVENT_DEF(VEH_ACCELERATE_PAD, GAMEPAD_DEFAULT_SENSITIVITY, GAMEPAD_RIGHT_SHOULDER_BOT, OSXKEY_UNKNOWN, LINUXKEY_UNKNOWN );
ANALOG_INPUT_EVENT_DEF(TANK_THRUST_LEFT_PAD , GAMEPAD_DEFAULT_SENSITIVITY, GAMEPAD_LEFT_STICK_Y, OSXKEY_UNKNOWN, LINUXKEY_UNKNOWN );
ANALOG_INPUT_EVENT_DEF(TANK_THRUST_RIGHT_PAD, GAMEPAD_DEFAULT_SENSITIVITY, GAMEPAD_RIGHT_STICK_Y, OSXKEY_UNKNOWN, LINUXKEY_UNKNOWN );
}
ANALOG_INPUT_EVENT_DEF(CAMERA_ROTATE_LEFT_RIGHT_PAD,GAMEPAD_ROTATE_SENSITIVITY, GAMEPAD_RIGHT_STICK_X, OSXKEY_UNKNOWN, LINUXKEY_UNKNOWN );
}
else
{
DIGITAL_INPUT_EVENT_DEF(VEH_GEAR_DOWN_PAD, GAMEPAD_EAST, OSXKEY_UNKNOWN, LINUXKEY_UNKNOWN );
DIGITAL_INPUT_EVENT_DEF(VEH_GEAR_UP_PAD, GAMEPAD_NORTH, OSXKEY_UNKNOWN, LINUXKEY_UNKNOWN );
DIGITAL_INPUT_EVENT_DEF(CAR_HANDBRAKE_PAD, GAMEPAD_SOUTH, OSXKEY_UNKNOWN, LINUXKEY_UNKNOWN );
ANALOG_INPUT_EVENT_DEF(VEH_ACCELERATE_PAD, GAMEPAD_DEFAULT_SENSITIVITY, GAMEPAD_RIGHT_SHOULDER_BOT, OSXKEY_UNKNOWN, LINUXKEY_UNKNOWN );
ANALOG_INPUT_EVENT_DEF(CAR_BRAKE_PAD , GAMEPAD_DEFAULT_SENSITIVITY, GAMEPAD_LEFT_SHOULDER_BOT, OSXKEY_UNKNOWN, LINUXKEY_UNKNOWN );
ANALOG_INPUT_EVENT_DEF(CAR_STEER_PAD, GAMEPAD_DEFAULT_SENSITIVITY, GAMEPAD_LEFT_STICK_X, OSXKEY_UNKNOWN, LINUXKEY_UNKNOWN );
ANALOG_INPUT_EVENT_DEF(CAR_ACCELERATE_BRAKE, GAMEPAD_DEFAULT_SENSITIVITY, GAMEPAD_LEFT_STICK_Y, OSXKEY_UNKNOWN, LINUXKEY_UNKNOWN );
ANALOG_INPUT_EVENT_DEF(CAMERA_ROTATE_LEFT_RIGHT_PAD,GAMEPAD_ROTATE_SENSITIVITY, GAMEPAD_RIGHT_STICK_X, OSXKEY_UNKNOWN, LINUXKEY_UNKNOWN );
ANALOG_INPUT_EVENT_DEF(CAMERA_ROTATE_UP_DOWN_PAD, GAMEPAD_ROTATE_SENSITIVITY, GAMEPAD_RIGHT_STICK_Y, OSXKEY_UNKNOWN, LINUXKEY_UNKNOWN );
}
//Camera keyboard control on keybord
DIGITAL_INPUT_EVENT_DEF(CAMERA_ROTATE_LEFT_KBD, WKEY_NUMPAD4, OSXKEY_NUMPAD4, LINUXKEY_NUMPAD4 );
DIGITAL_INPUT_EVENT_DEF(CAMERA_ROTATE_RIGHT_KBD, WKEY_NUMPAD6, OSXKEY_NUMPAD6, LINUXKEY_NUMPAD6 );
DIGITAL_INPUT_EVENT_DEF(CAMERA_ROTATE_UP_KBD, WKEY_NUMPAD8, OSXKEY_NUMPAD8, LINUXKEY_NUMPAD8 );
DIGITAL_INPUT_EVENT_DEF(CAMERA_ROTATE_DOWN_KBD, WKEY_NUMPAD2, OSXKEY_NUMPAD2, LINUXKEY_NUMPAD2 );
//General control events on keyboard.
DIGITAL_INPUT_EVENT_DEF(DEBUG_RENDER_FLAG, WKEY_F9, OSXKEY_T, LINUXKEY_F9 );
DIGITAL_INPUT_EVENT_DEF(DEBUG_RENDER_ENGINE, WKEY_2, OSXKEY_2, LINUXKEY_2 );
DIGITAL_INPUT_EVENT_DEF(DEBUG_RENDER_WHEEL, WKEY_1, OSXKEY_1, LINUXKEY_1 );
DIGITAL_INPUT_EVENT_DEF(FIX_CAR, WKEY_K, OSXKEY_K, LINUXKEY_K );
//General control events on gamepad.
DIGITAL_INPUT_EVENT_DEF(DEBUG_RENDER_FLAG, GAMEPAD_WEST, OSXKEY_UNKNOWN, LINUXKEY_UNKNOWN );
DIGITAL_INPUT_EVENT_DEF(DEBUG_RENDER_ENGINE, GAMEPAD_LEFT_SHOULDER_TOP, OSXKEY_UNKNOWN, LINUXKEY_UNKNOWN );
DIGITAL_INPUT_EVENT_DEF(DEBUG_RENDER_WHEEL, GAMEPAD_RIGHT_SHOULDER_TOP, OSXKEY_UNKNOWN, LINUXKEY_UNKNOWN );
DIGITAL_INPUT_EVENT_DEF(FIX_CAR, GAMEPAD_RIGHT_STICK, OSXKEY_UNKNOWN, LINUXKEY_UNKNOWN );
}
void SampleVehicle::onDigitalInputEvent(const SampleFramework::InputEvent& ie, bool val)
{
switch (ie.m_Id)
{
case VEH_SAVE_KBD:
{
if(val)
{
#if defined(SERIALIZE_VEHICLE_RPEX) || defined(SERIALIZE_VEHICLE_BINARY)
PxSerializationRegistry* sr = mVehicleManager.getSerializationRegistry();
PxVehicleWheels& focusVehicle = *mVehicleManager.getVehicle(mPlayerVehicle);
PxCollection* c = PxCreateCollection();
c->add( focusVehicle, 1 );
PxSerialization::complete(*c, *sr, NULL);
PxDefaultFileOutputStream theStream(mVehicleFilePath);
#if defined(SERIALIZE_VEHICLE_RPEX)
PxSerialization::serializeCollectionToXml(theStream, *c, *sr, &getCooking());
#elif defined(SERIALIZE_VEHICLE_BINARY)
PxSerialization::serializeCollectionToBinary(theStream, *c, *sr);
#endif
c->release();
#endif
}
}
break;
case VEH_ACCELERATE_KBD:
{
mControlInputs.setAccelKeyPressed(val);
}
break;
case VEH_GEAR_DOWN_KBD:
{
mControlInputs.setGearDownKeyPressed(val);
}
break;
case VEH_GEAR_UP_KBD:
{
mControlInputs.setGearUpKeyPressed(val);
}
break;
case CAR_BRAKE_KBD:
{
mControlInputs.setBrakeKeyPressed(val);
}
break;
case CAR_STEER_LEFT_KBD:
{
mControlInputs.setSteerRightKeyPressed(val);
}
break;
case CAR_STEER_RIGHT_KBD:
{
mControlInputs.setSteerLeftKeyPressed(val);
}
break;
case CAR_HANDBRAKE_KBD:
{
mControlInputs.setHandbrakeKeyPressed(val);
}
break;
case TANK_THRUST_LEFT_KBD:
{
if(PxVehicleDriveTankControlModel::eSPECIAL==mTankDriveModel)
{
mControlInputs.setThrustLeftKeyPressed(val);
mControlInputs.setAccelKeyPressed(val);
}
else if(val)
{
mControlInputs.setThrustLeftKeyPressed(val);
mControlInputs.setAccelKeyPressed(val);
}
else
{
mControlInputs.setThrustLeftKeyPressed(val);
}
}
break;
case TANK_THRUST_RIGHT_KBD:
{
if(PxVehicleDriveTankControlModel::eSPECIAL==mTankDriveModel)
{
mControlInputs.setThrustRightKeyPressed(val);
mControlInputs.setAccelKeyPressed(val);
}
else if(val)
{
mControlInputs.setThrustRightKeyPressed(val);
mControlInputs.setAccelKeyPressed(val);
}
else
{
mControlInputs.setThrustRightKeyPressed(val);
}
}
break;
case TANK_BRAKE_LEFT_KBD:
{
if(PxVehicleDriveTankControlModel::eSPECIAL==mTankDriveModel)
{
mControlInputs.setBrakeLeftKeyPressed(val);
mControlInputs.setAccelKeyPressed(val);
}
else if(val)
{
mControlInputs.setBrakeLeftKeyPressed(val);
}
else
{
mControlInputs.setBrakeLeftKeyPressed(val);
}
}
break;
case TANK_BRAKE_RIGHT_KBD:
{
if(PxVehicleDriveTankControlModel::eSPECIAL==mTankDriveModel)
{
mControlInputs.setBrakeRightKeyPressed(val);
mControlInputs.setAccelKeyPressed(val);
}
else if(val)
{
mControlInputs.setBrakeRightKeyPressed(val);
}
else
{
mControlInputs.setBrakeRightKeyPressed(val);
}
}
break;
case VEH_GEAR_DOWN_PAD:
{
mControlInputs.setGearDown(val);
}
break;
case VEH_GEAR_UP_PAD:
{
mControlInputs.setGearUp(val);
}
break;
case CAR_HANDBRAKE_PAD:
{
mControlInputs.setHandbrake(val);
}
break;
case AUTOMATIC_GEAR:
{
if(val)
{
mVehicleController.toggleAutoGearFlag();
}
}
break;
case DEBUG_RENDER_FLAG:
{
if(val)
{
mDebugRenderFlag = !mDebugRenderFlag;
}
}
break;
case DEBUG_RENDER_WHEEL:
{
if(val)
{
#if PX_DEBUG_VEHICLE_ON
mDebugRenderActiveGraphChannelWheel++;
if(mDebugRenderActiveGraphChannelWheel==PxVehicleWheelGraphChannel::eMAX_NB_WHEEL_CHANNELS)
{
mDebugRenderActiveGraphChannelWheel=0;
}
#endif
}
}
break;
case DEBUG_RENDER_ENGINE:
{
if(val)
{
#if PX_DEBUG_VEHICLE_ON
mDebugRenderActiveGraphChannelEngine++;
if(mDebugRenderActiveGraphChannelEngine==PxVehicleDriveGraphChannel::eMAX_NB_DRIVE_CHANNELS)
{
mDebugRenderActiveGraphChannelEngine=0;
}
#endif
}
}
break;
case RETRY:
{
if(val)
mBackToStart=true;
}
break;
case FIX_CAR:
{
if(val)
mFixCar = true;
}
break;
case CAMERA_ROTATE_LEFT_KBD:
{
mControlInputs.setRotateY(val ? -0.5f : 0.0f);
}
break;
case CAMERA_ROTATE_RIGHT_KBD:
{
mControlInputs.setRotateY(val ? 0.5f : 0.0f);
}
break;
case CAMERA_ROTATE_UP_KBD:
{
mControlInputs.setRotateZ(val ? 0.5f : 0.0f);
}
break;
case CAMERA_ROTATE_DOWN_KBD:
{
mControlInputs.setRotateZ(val ? -0.5f : 0.0f);
}
break;
case W3MODE:
{
if(val)
{
m3WModeIncremented=true;
}
}
break;
default:
break;
}
PhysXSample::onDigitalInputEvent(ie,val);
}
void SampleVehicle::onAnalogInputEvent(const SampleFramework::InputEvent& ie, float val)
{
switch(mPlayerVehicleType)
{
case ePLAYER_VEHICLE_TYPE_VEHICLE4W:
case ePLAYER_VEHICLE_TYPE_VEHICLE6W:
switch (ie.m_Id)
{
case VEH_ACCELERATE_PAD:
{
mControlInputs.setAccel(val);
}
break;
case CAR_BRAKE_PAD:
{
mControlInputs.setBrake(val);
}
break;
case CAR_ACCELERATE_BRAKE:
{
if (val >= 0.0f)
{
mControlInputs.setAccel(val);
mControlInputs.setBrake(0.0f);
}
else
{
mControlInputs.setBrake(-val);
mControlInputs.setAccel(0.0f);
}
}
break;
case CAR_STEER_PAD:
{
mControlInputs.setSteer(-val);
}
break;
case CAMERA_ROTATE_LEFT_RIGHT_PAD:
{
mControlInputs.setRotateY(-val);
}
break;
case CAMERA_ROTATE_UP_DOWN_PAD:
{
mControlInputs.setRotateZ(-val);
}
break;
default:
break;
}
break;
case ePLAYER_VEHICLE_TYPE_TANK4W:
case ePLAYER_VEHICLE_TYPE_TANK6W:
switch (ie.m_Id)
{
case VEH_ACCELERATE_PAD:
{
PX_ASSERT(PxVehicleDriveTankControlModel::eSTANDARD==mTankDriveModel);
mControlInputs.setAccel(val);
}
break;
case TANK_THRUST_RIGHT_PAD:
{
if(PxVehicleDriveTankControlModel::eSPECIAL==mTankDriveModel)
{
mControlInputs.setThrustLeft(val);
mControlInputs.setAccel(val ? 1.0f : 0.0f);
}
else if(val>0)
{
mControlInputs.setThrustLeft(val);
mControlInputs.setBrakeLeft(0.0f);
}
else
{
mControlInputs.setThrustLeft(0.0f);
mControlInputs.setBrakeLeft(-val);
}
}
break;
case TANK_THRUST_LEFT_PAD:
{
if(PxVehicleDriveTankControlModel::eSPECIAL==mTankDriveModel)
{
mControlInputs.setThrustRight(val);
mControlInputs.setAccel(val ? 1.0f : 0.0f);
}
else if(val>0)
{
mControlInputs.setThrustRight(val);
mControlInputs.setBrakeRight(0.0f);
}
else
{
mControlInputs.setThrustRight(0.0f);
mControlInputs.setBrakeRight(-val);
}
}
break;
case TANK_BRAKE_LEFT_PAD:
{
PX_ASSERT(PxVehicleDriveTankControlModel::eSPECIAL==mTankDriveModel);
mControlInputs.setBrakeLeft(val);
}
break;
case TANK_BRAKE_RIGHT_PAD:
{
PX_ASSERT(PxVehicleDriveTankControlModel::eSPECIAL==mTankDriveModel);
mControlInputs.setBrakeRight(val);
}
break;
case CAMERA_ROTATE_LEFT_RIGHT_PAD:
{
mControlInputs.setRotateY(-val);
}
break;
default:
break;
}
break;
default:
PX_ASSERT(false);
break;
}
}
///////////////////////////////////////////////////////////////////////////////
#if PX_DEBUG_VEHICLE_ON
void SampleVehicle::clearTelemetryData()
{
mTelemetryData4W->clear();
mTelemetryData6W->clear();
}
#endif
void SampleVehicle::updateCameraController(const PxF32 dtime, PxScene& scene)
{
mCameraController.update(dtime,*mVehicleManager.getVehicle(mPlayerVehicle),scene);
}
void SampleVehicle::updateVehicleController(const PxF32 dtime)
{
PxSceneReadLock scopedLock(*mScene);
mVehicleController.update(dtime, mVehicleManager.getVehicleWheelQueryResults(mPlayerVehicle), *mVehicleManager.getVehicle(mPlayerVehicle));
}
void SampleVehicle::updateVehicleManager(const PxF32 dtime, const PxVec3& gravity)
{
switch(mPlayerVehicleType)
{
case ePLAYER_VEHICLE_TYPE_VEHICLE4W:
case ePLAYER_VEHICLE_TYPE_TANK4W:
#if PX_DEBUG_VEHICLE_ON
mVehicleManager.updateAndRecordTelemetryData(dtime,gravity,mVehicleManager.getVehicle(mPlayerVehicle),mTelemetryData4W);
#else
mVehicleManager.update(dtime,gravity);
#endif
break;
case ePLAYER_VEHICLE_TYPE_VEHICLE6W:
case ePLAYER_VEHICLE_TYPE_TANK6W:
#if PX_DEBUG_VEHICLE_ON
mVehicleManager.updateAndRecordTelemetryData(dtime,gravity,mVehicleManager.getVehicle(mPlayerVehicle),mTelemetryData6W);
#else
mVehicleManager.update(dtime,gravity);
#endif
break;
default:
PX_ASSERT(false);
break;
}
}
void SampleVehicle::resetFocusVehicleAtWaypoint()
{
mVehicleManager.resetNWCar(mWayPoints.getResetTransform(),mPlayerVehicle);
}
PxRigidDynamic* SampleVehicle::getFocusVehicleRigidDynamicActor()
{
return mVehicleManager.getVehicle(mPlayerVehicle)->getRigidDynamicActor();
}
void SampleVehicle::drawFocusVehicleGraphsAndPrintTireSurfaces()
{
drawGraphsAndPrintTireSurfaceTypes(*mVehicleManager.getVehicle(mPlayerVehicle), mVehicleManager.getVehicleWheelQueryResults(mPlayerVehicle));
}
bool SampleVehicle::getFocusVehicleUsesAutoGears()
{
PxVehicleWheels* vehWheels=mVehicleManager.getVehicle(mPlayerVehicle);
PxVehicleDriveDynData* driveDynData=NULL;
switch(vehWheels->getVehicleType())
{
case PxVehicleTypes::eDRIVE4W:
{
PxVehicleDrive4W* vehDrive4W=(PxVehicleDrive4W*)vehWheels;
driveDynData=&vehDrive4W->mDriveDynData;
}
break;
case PxVehicleTypes::eDRIVENW:
{
PxVehicleDriveNW* vehDriveNW=(PxVehicleDriveNW*)vehWheels;
driveDynData=&vehDriveNW->mDriveDynData;
}
break;
case PxVehicleTypes::eDRIVETANK:
{
PxVehicleDriveTank* vehDriveTank=(PxVehicleDriveTank*)vehWheels;
driveDynData=&vehDriveTank->mDriveDynData;
}
break;
default:
PX_ASSERT(false);
break;
}
return driveDynData->getUseAutoGears();
}