aboutsummaryrefslogtreecommitdiff
path: root/PhysX_3.4/Samples/SampleVehicle
diff options
context:
space:
mode:
authorgit perforce import user <a@b>2016-10-25 12:29:14 -0600
committerSheikh Dawood Abdul Ajees <Sheikh Dawood Abdul Ajees>2016-10-25 18:56:37 -0500
commit3dfe2108cfab31ba3ee5527e217d0d8e99a51162 (patch)
treefa6485c169e50d7415a651bf838f5bcd0fd3bfbd /PhysX_3.4/Samples/SampleVehicle
downloadphysx-3.4-3dfe2108cfab31ba3ee5527e217d0d8e99a51162.tar.xz
physx-3.4-3dfe2108cfab31ba3ee5527e217d0d8e99a51162.zip
Initial commit:
PhysX 3.4.0 Update @ 21294896 APEX 1.4.0 Update @ 21275617 [CL 21300167]
Diffstat (limited to 'PhysX_3.4/Samples/SampleVehicle')
-rw-r--r--PhysX_3.4/Samples/SampleVehicle/SampleVehicle.cpp2271
-rw-r--r--PhysX_3.4/Samples/SampleVehicle/SampleVehicle.h198
-rw-r--r--PhysX_3.4/Samples/SampleVehicle/SampleVehicleDebugRender.cpp367
-rw-r--r--PhysX_3.4/Samples/SampleVehicle/SampleVehicleInputEventIds.h98
-rw-r--r--PhysX_3.4/Samples/SampleVehicle/SampleVehicleTerrain.cpp547
-rw-r--r--PhysX_3.4/Samples/SampleVehicle/SampleVehicle_CameraController.cpp164
-rw-r--r--PhysX_3.4/Samples/SampleVehicle/SampleVehicle_CameraController.h92
-rw-r--r--PhysX_3.4/Samples/SampleVehicle/SampleVehicle_ControlInputs.cpp68
-rw-r--r--PhysX_3.4/Samples/SampleVehicle/SampleVehicle_ControlInputs.h145
-rw-r--r--PhysX_3.4/Samples/SampleVehicle/SampleVehicle_GameLogic.cpp91
-rw-r--r--PhysX_3.4/Samples/SampleVehicle/SampleVehicle_GameLogic.h97
-rw-r--r--PhysX_3.4/Samples/SampleVehicle/SampleVehicle_SceneQuery.cpp90
-rw-r--r--PhysX_3.4/Samples/SampleVehicle/SampleVehicle_SceneQuery.h132
-rw-r--r--PhysX_3.4/Samples/SampleVehicle/SampleVehicle_VehicleController.cpp840
-rw-r--r--PhysX_3.4/Samples/SampleVehicle/SampleVehicle_VehicleController.h226
-rw-r--r--PhysX_3.4/Samples/SampleVehicle/SampleVehicle_VehicleCooking.cpp171
-rw-r--r--PhysX_3.4/Samples/SampleVehicle/SampleVehicle_VehicleCooking.h48
-rw-r--r--PhysX_3.4/Samples/SampleVehicle/SampleVehicle_VehicleManager.cpp1171
-rw-r--r--PhysX_3.4/Samples/SampleVehicle/SampleVehicle_VehicleManager.h226
-rw-r--r--PhysX_3.4/Samples/SampleVehicle/SampleVehicle_WheelQueryResults.cpp73
-rw-r--r--PhysX_3.4/Samples/SampleVehicle/SampleVehicle_WheelQueryResults.h82
21 files changed, 7197 insertions, 0 deletions
diff --git a/PhysX_3.4/Samples/SampleVehicle/SampleVehicle.cpp b/PhysX_3.4/Samples/SampleVehicle/SampleVehicle.cpp
new file mode 100644
index 00000000..52f86b8c
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleVehicle/SampleVehicle.cpp
@@ -0,0 +1,2271 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+
+#include "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"
+
+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, XKEY_I, X1KEY_I, PS3KEY_I, PS4KEY_I, AKEY_UNKNOWN, SCAN_CODE_FORWARD, IKEY_UNKNOWN, SCAN_CODE_FORWARD, WIIUKEY_UNKNOWN);
+
+
+ //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, XKEY_9, X1KEY_9, PS3KEY_9, PS4KEY_9, AKEY_UNKNOWN, SCAN_CODE_9, IKEY_UNKNOWN, SCAN_CODE_9, WIIUKEY_UNKNOWN);
+ DIGITAL_INPUT_EVENT_DEF(VEH_GEAR_UP_KBD, SCAN_CODE_0, XKEY_0, X1KEY_0, PS3KEY_0, PS4KEY_0, AKEY_UNKNOWN, SCAN_CODE_0, IKEY_UNKNOWN, SCAN_CODE_0, WIIUKEY_UNKNOWN);
+
+ DIGITAL_INPUT_EVENT_DEF(TANK_THRUST_LEFT_KBD, WKEY_Q, XKEY_S, X1KEY_S, PS3KEY_S, PS4KEY_S, AKEY_UNKNOWN, SCAN_CODE_BACKWARD, IKEY_UNKNOWN, SCAN_CODE_BACKWARD, WIIUKEY_UNKNOWN);
+ DIGITAL_INPUT_EVENT_DEF(TANK_THRUST_RIGHT_KBD, WKEY_I, XKEY_A, X1KEY_A, PS3KEY_A, PS4KEY_A, AKEY_UNKNOWN, SCAN_CODE_LEFT, IKEY_UNKNOWN, SCAN_CODE_LEFT, WIIUKEY_UNKNOWN);
+ DIGITAL_INPUT_EVENT_DEF(TANK_BRAKE_LEFT_KBD, WKEY_A, XKEY_D, X1KEY_D, PS3KEY_D, PS4KEY_D, AKEY_UNKNOWN, SCAN_CODE_RIGHT, IKEY_UNKNOWN, SCAN_CODE_RIGHT, GAMEPAD_LEFT_SHOULDER_BOT);
+ DIGITAL_INPUT_EVENT_DEF(TANK_BRAKE_RIGHT_KBD, WKEY_J, XKEY_L, X1KEY_L, PS3KEY_L, PS4KEY_L, AKEY_UNKNOWN, SCAN_CODE_L, IKEY_UNKNOWN, SCAN_CODE_L, GAMEPAD_RIGHT_SHOULDER_BOT);
+ }
+ else
+ {
+ DIGITAL_INPUT_EVENT_DEF(VEH_ACCELERATE_KBD, SCAN_CODE_FORWARD, XKEY_W, X1KEY_W, PS3KEY_W, PS4KEY_W, AKEY_UNKNOWN, SCAN_CODE_FORWARD, IKEY_UNKNOWN, SCAN_CODE_FORWARD, GAMEPAD_RIGHT_SHOULDER_BOT);
+ DIGITAL_INPUT_EVENT_DEF(VEH_GEAR_DOWN_KBD, SCAN_CODE_9, XKEY_9, X1KEY_9, PS3KEY_9, PS4KEY_9, AKEY_UNKNOWN, SCAN_CODE_9, IKEY_UNKNOWN, SCAN_CODE_9, WIIUKEY_UNKNOWN);
+ DIGITAL_INPUT_EVENT_DEF(VEH_GEAR_UP_KBD, SCAN_CODE_0, XKEY_0, X1KEY_0, PS3KEY_0, PS4KEY_0, AKEY_UNKNOWN, SCAN_CODE_0, IKEY_UNKNOWN, SCAN_CODE_0, WIIUKEY_UNKNOWN);
+
+ DIGITAL_INPUT_EVENT_DEF(CAR_BRAKE_KBD, SCAN_CODE_BACKWARD, XKEY_S, X1KEY_S, PS3KEY_S, PS4KEY_S, AKEY_UNKNOWN, SCAN_CODE_BACKWARD, IKEY_UNKNOWN, SCAN_CODE_BACKWARD, GAMEPAD_LEFT_SHOULDER_BOT);
+ DIGITAL_INPUT_EVENT_DEF(CAR_HANDBRAKE_KBD, SCAN_CODE_L, XKEY_L, X1KEY_L, PS3KEY_L, PS4KEY_L, AKEY_UNKNOWN, SCAN_CODE_L, IKEY_UNKNOWN, SCAN_CODE_L, WIIUKEY_UNKNOWN);
+ DIGITAL_INPUT_EVENT_DEF(CAR_STEER_LEFT_KBD, SCAN_CODE_LEFT, XKEY_A, X1KEY_A, PS3KEY_A, PS4KEY_A, AKEY_UNKNOWN, SCAN_CODE_LEFT, IKEY_UNKNOWN, SCAN_CODE_LEFT, WIIUKEY_UNKNOWN);
+ DIGITAL_INPUT_EVENT_DEF(CAR_STEER_RIGHT_KBD, SCAN_CODE_RIGHT, XKEY_D, X1KEY_D, PS3KEY_D, PS4KEY_D, AKEY_UNKNOWN, SCAN_CODE_RIGHT, IKEY_UNKNOWN, SCAN_CODE_RIGHT, WIIUKEY_UNKNOWN);
+ }
+
+ //Driving gamepad controls
+ if(ePLAYER_VEHICLE_TYPE_TANK4W==mPlayerVehicleType || ePLAYER_VEHICLE_TYPE_TANK6W==mPlayerVehicleType)
+ {
+ DIGITAL_INPUT_EVENT_DEF(VEH_GEAR_DOWN_PAD, GAMEPAD_EAST, GAMEPAD_EAST, GAMEPAD_EAST, GAMEPAD_EAST, GAMEPAD_EAST, AKEY_UNKNOWN, OSXKEY_UNKNOWN, IKEY_UNKNOWN, LINUXKEY_UNKNOWN, GAMEPAD_EAST);
+ DIGITAL_INPUT_EVENT_DEF(VEH_GEAR_UP_PAD, GAMEPAD_NORTH, GAMEPAD_NORTH, GAMEPAD_NORTH, GAMEPAD_NORTH, GAMEPAD_NORTH, AKEY_UNKNOWN, OSXKEY_UNKNOWN, IKEY_UNKNOWN, LINUXKEY_UNKNOWN, GAMEPAD_NORTH);
+
+ if(PxVehicleDriveTankControlModel::eSPECIAL==mTankDriveModel)
+ {
+ ANALOG_INPUT_EVENT_DEF(TANK_THRUST_LEFT_PAD, GAMEPAD_DEFAULT_SENSITIVITY, GAMEPAD_LEFT_STICK_Y, GAMEPAD_LEFT_STICK_Y, GAMEPAD_LEFT_STICK_Y, GAMEPAD_LEFT_STICK_Y, GAMEPAD_LEFT_STICK_Y, GAMEPAD_LEFT_STICK_Y, OSXKEY_UNKNOWN, GAMEPAD_LEFT_STICK_Y, LINUXKEY_UNKNOWN, GAMEPAD_LEFT_STICK_Y);
+ ANALOG_INPUT_EVENT_DEF(TANK_THRUST_RIGHT_PAD, GAMEPAD_DEFAULT_SENSITIVITY, GAMEPAD_RIGHT_STICK_Y, GAMEPAD_RIGHT_STICK_Y, GAMEPAD_RIGHT_STICK_Y, GAMEPAD_RIGHT_STICK_Y, GAMEPAD_RIGHT_STICK_Y, GAMEPAD_RIGHT_STICK_Y, OSXKEY_UNKNOWN, GAMEPAD_RIGHT_STICK_Y, LINUXKEY_UNKNOWN, GAMEPAD_RIGHT_STICK_Y);
+ ANALOG_INPUT_EVENT_DEF(TANK_BRAKE_LEFT_PAD, GAMEPAD_DEFAULT_SENSITIVITY, GAMEPAD_LEFT_SHOULDER_BOT, GAMEPAD_LEFT_SHOULDER_BOT, GAMEPAD_LEFT_SHOULDER_BOT, GAMEPAD_LEFT_SHOULDER_BOT, GAMEPAD_LEFT_SHOULDER_BOT, AKEY_UNKNOWN, OSXKEY_UNKNOWN, IKEY_UNKNOWN, LINUXKEY_UNKNOWN, WIIUKEY_UNKNOWN);
+ ANALOG_INPUT_EVENT_DEF(TANK_BRAKE_RIGHT_PAD, GAMEPAD_DEFAULT_SENSITIVITY, GAMEPAD_RIGHT_SHOULDER_BOT, GAMEPAD_RIGHT_SHOULDER_BOT, GAMEPAD_RIGHT_SHOULDER_BOT, GAMEPAD_RIGHT_SHOULDER_BOT, GAMEPAD_RIGHT_SHOULDER_BOT, AKEY_UNKNOWN, OSXKEY_UNKNOWN, IKEY_UNKNOWN, LINUXKEY_UNKNOWN, WIIUKEY_UNKNOWN);
+ }
+ else
+ {
+ ANALOG_INPUT_EVENT_DEF(VEH_ACCELERATE_PAD, GAMEPAD_DEFAULT_SENSITIVITY, GAMEPAD_RIGHT_SHOULDER_BOT, GAMEPAD_RIGHT_SHOULDER_BOT, GAMEPAD_RIGHT_SHOULDER_BOT, GAMEPAD_RIGHT_SHOULDER_BOT, GAMEPAD_RIGHT_SHOULDER_BOT, AKEY_UNKNOWN, OSXKEY_UNKNOWN, IKEY_UNKNOWN, LINUXKEY_UNKNOWN, WIIUKEY_UNKNOWN);
+ ANALOG_INPUT_EVENT_DEF(TANK_THRUST_LEFT_PAD , GAMEPAD_DEFAULT_SENSITIVITY, GAMEPAD_LEFT_STICK_Y, GAMEPAD_LEFT_STICK_Y, GAMEPAD_LEFT_STICK_Y, GAMEPAD_LEFT_STICK_Y, GAMEPAD_LEFT_STICK_Y, GAMEPAD_LEFT_STICK_Y, OSXKEY_UNKNOWN, GAMEPAD_LEFT_STICK_Y, LINUXKEY_UNKNOWN, GAMEPAD_LEFT_STICK_Y);
+ ANALOG_INPUT_EVENT_DEF(TANK_THRUST_RIGHT_PAD, GAMEPAD_DEFAULT_SENSITIVITY, GAMEPAD_RIGHT_STICK_Y, GAMEPAD_RIGHT_STICK_Y, GAMEPAD_RIGHT_STICK_Y, GAMEPAD_RIGHT_STICK_Y, GAMEPAD_RIGHT_STICK_Y, GAMEPAD_RIGHT_STICK_Y, OSXKEY_UNKNOWN, GAMEPAD_RIGHT_STICK_Y, LINUXKEY_UNKNOWN, GAMEPAD_RIGHT_STICK_Y);
+ }
+
+ ANALOG_INPUT_EVENT_DEF(CAMERA_ROTATE_LEFT_RIGHT_PAD,GAMEPAD_ROTATE_SENSITIVITY, GAMEPAD_RIGHT_STICK_X, GAMEPAD_RIGHT_STICK_X, GAMEPAD_RIGHT_STICK_X, GAMEPAD_RIGHT_STICK_X, GAMEPAD_RIGHT_STICK_X, GAMEPAD_RIGHT_STICK_X, OSXKEY_UNKNOWN, GAMEPAD_RIGHT_STICK_X, LINUXKEY_UNKNOWN, GAMEPAD_RIGHT_STICK_X);
+ }
+ else
+ {
+ DIGITAL_INPUT_EVENT_DEF(VEH_GEAR_DOWN_PAD, GAMEPAD_EAST, GAMEPAD_EAST, GAMEPAD_EAST, GAMEPAD_EAST, GAMEPAD_EAST, AKEY_UNKNOWN, OSXKEY_UNKNOWN, IKEY_UNKNOWN, LINUXKEY_UNKNOWN, GAMEPAD_EAST);
+ DIGITAL_INPUT_EVENT_DEF(VEH_GEAR_UP_PAD, GAMEPAD_NORTH, GAMEPAD_NORTH, GAMEPAD_NORTH, GAMEPAD_NORTH, GAMEPAD_NORTH, AKEY_UNKNOWN, OSXKEY_UNKNOWN, IKEY_UNKNOWN, LINUXKEY_UNKNOWN, GAMEPAD_NORTH);
+ DIGITAL_INPUT_EVENT_DEF(CAR_HANDBRAKE_PAD, GAMEPAD_SOUTH, GAMEPAD_SOUTH, GAMEPAD_SOUTH, GAMEPAD_SOUTH, GAMEPAD_SOUTH, AKEY_UNKNOWN, OSXKEY_UNKNOWN, IKEY_UNKNOWN, LINUXKEY_UNKNOWN, GAMEPAD_SOUTH);
+
+ ANALOG_INPUT_EVENT_DEF(VEH_ACCELERATE_PAD, GAMEPAD_DEFAULT_SENSITIVITY, GAMEPAD_RIGHT_SHOULDER_BOT, GAMEPAD_RIGHT_SHOULDER_BOT, GAMEPAD_RIGHT_SHOULDER_BOT, GAMEPAD_RIGHT_SHOULDER_BOT, GAMEPAD_RIGHT_SHOULDER_BOT, AKEY_UNKNOWN, OSXKEY_UNKNOWN, IKEY_UNKNOWN, LINUXKEY_UNKNOWN, WIIUKEY_UNKNOWN);
+ ANALOG_INPUT_EVENT_DEF(CAR_BRAKE_PAD , GAMEPAD_DEFAULT_SENSITIVITY, GAMEPAD_LEFT_SHOULDER_BOT, GAMEPAD_LEFT_SHOULDER_BOT, GAMEPAD_LEFT_SHOULDER_BOT, GAMEPAD_LEFT_SHOULDER_BOT, GAMEPAD_LEFT_SHOULDER_BOT, AKEY_UNKNOWN, OSXKEY_UNKNOWN, IKEY_UNKNOWN, LINUXKEY_UNKNOWN, WIIUKEY_UNKNOWN);
+ ANALOG_INPUT_EVENT_DEF(CAR_STEER_PAD, GAMEPAD_DEFAULT_SENSITIVITY, GAMEPAD_LEFT_STICK_X, GAMEPAD_LEFT_STICK_X, GAMEPAD_LEFT_STICK_X, GAMEPAD_LEFT_STICK_X, GAMEPAD_LEFT_STICK_X, GAMEPAD_LEFT_STICK_X, OSXKEY_UNKNOWN, GAMEPAD_LEFT_STICK_X, LINUXKEY_UNKNOWN, GAMEPAD_LEFT_STICK_X);
+
+ ANALOG_INPUT_EVENT_DEF(CAR_ACCELERATE_BRAKE, GAMEPAD_DEFAULT_SENSITIVITY, GAMEPAD_LEFT_STICK_Y, XKEY_UNKNOWN, X1KEY_UNKNOWN, PS3KEY_UNKNOWN, PS4KEY_UNKNOWN, GAMEPAD_LEFT_STICK_Y, OSXKEY_UNKNOWN, GAMEPAD_LEFT_STICK_Y, LINUXKEY_UNKNOWN, WIIUKEY_UNKNOWN);
+
+ ANALOG_INPUT_EVENT_DEF(CAMERA_ROTATE_LEFT_RIGHT_PAD,GAMEPAD_ROTATE_SENSITIVITY, GAMEPAD_RIGHT_STICK_X, GAMEPAD_RIGHT_STICK_X, GAMEPAD_RIGHT_STICK_X, GAMEPAD_RIGHT_STICK_X, GAMEPAD_RIGHT_STICK_X, GAMEPAD_RIGHT_STICK_X, OSXKEY_UNKNOWN, GAMEPAD_RIGHT_STICK_X, LINUXKEY_UNKNOWN, GAMEPAD_RIGHT_STICK_X);
+ ANALOG_INPUT_EVENT_DEF(CAMERA_ROTATE_UP_DOWN_PAD, GAMEPAD_ROTATE_SENSITIVITY, GAMEPAD_RIGHT_STICK_Y, GAMEPAD_RIGHT_STICK_Y, GAMEPAD_RIGHT_STICK_Y, GAMEPAD_RIGHT_STICK_Y, GAMEPAD_RIGHT_STICK_Y, GAMEPAD_RIGHT_STICK_Y, OSXKEY_UNKNOWN, GAMEPAD_RIGHT_STICK_Y, LINUXKEY_UNKNOWN, GAMEPAD_RIGHT_STICK_Y);
+ }
+
+ //Camera keyboard control on keybord
+ DIGITAL_INPUT_EVENT_DEF(CAMERA_ROTATE_LEFT_KBD, WKEY_NUMPAD4, XKEY_NUMPAD4, X1KEY_NUMPAD4, PS3KEY_NUMPAD4, PS4KEY_NUMPAD4, AKEY_UNKNOWN, OSXKEY_NUMPAD4, IKEY_UNKNOWN, LINUXKEY_NUMPAD4, WIIUKEY_UNKNOWN);
+ DIGITAL_INPUT_EVENT_DEF(CAMERA_ROTATE_RIGHT_KBD, WKEY_NUMPAD6, XKEY_NUMPAD6, X1KEY_NUMPAD6, PS3KEY_NUMPAD6, PS4KEY_NUMPAD6, AKEY_UNKNOWN, OSXKEY_NUMPAD6, IKEY_UNKNOWN, LINUXKEY_NUMPAD6, WIIUKEY_UNKNOWN);
+ DIGITAL_INPUT_EVENT_DEF(CAMERA_ROTATE_UP_KBD, WKEY_NUMPAD8, XKEY_NUMPAD8, X1KEY_NUMPAD8, PS3KEY_NUMPAD8, PS4KEY_NUMPAD8, AKEY_UNKNOWN, OSXKEY_NUMPAD8, IKEY_UNKNOWN, LINUXKEY_NUMPAD8, WIIUKEY_UNKNOWN);
+ DIGITAL_INPUT_EVENT_DEF(CAMERA_ROTATE_DOWN_KBD, WKEY_NUMPAD2, XKEY_NUMPAD2, X1KEY_NUMPAD2, PS3KEY_NUMPAD2, PS4KEY_NUMPAD2, AKEY_UNKNOWN, OSXKEY_NUMPAD2, IKEY_UNKNOWN, LINUXKEY_NUMPAD2, WIIUKEY_UNKNOWN);
+
+ //General control events on keyboard.
+ DIGITAL_INPUT_EVENT_DEF(DEBUG_RENDER_FLAG, WKEY_F9, XKEY_F9, X1KEY_F9, PS3KEY_F9, PS4KEY_F9, AKEY_UNKNOWN, OSXKEY_T, IKEY_UNKNOWN, LINUXKEY_F9, WIIUKEY_UNKNOWN);
+ DIGITAL_INPUT_EVENT_DEF(DEBUG_RENDER_ENGINE, WKEY_2, XKEY_2, X1KEY_2, PS3KEY_2, PS4KEY_2, AKEY_UNKNOWN, OSXKEY_2, IKEY_UNKNOWN, LINUXKEY_2, WIIUKEY_UNKNOWN);
+ DIGITAL_INPUT_EVENT_DEF(DEBUG_RENDER_WHEEL, WKEY_1, XKEY_1, X1KEY_1, PS3KEY_1, PS4KEY_1, AKEY_UNKNOWN, OSXKEY_1, IKEY_UNKNOWN, LINUXKEY_1, WIIUKEY_UNKNOWN);
+ DIGITAL_INPUT_EVENT_DEF(FIX_CAR, WKEY_K, XKEY_K, X1KEY_K, PS3KEY_K, PS4KEY_K, AKEY_UNKNOWN, OSXKEY_K, IKEY_UNKNOWN, LINUXKEY_K, WIIUKEY_UNKNOWN);
+
+ //General control events on gamepad.
+ DIGITAL_INPUT_EVENT_DEF(DEBUG_RENDER_FLAG, GAMEPAD_WEST, GAMEPAD_WEST, GAMEPAD_WEST, GAMEPAD_WEST, GAMEPAD_WEST, AKEY_UNKNOWN, OSXKEY_UNKNOWN, IKEY_UNKNOWN, LINUXKEY_UNKNOWN, GAMEPAD_WEST);
+ DIGITAL_INPUT_EVENT_DEF(DEBUG_RENDER_ENGINE, GAMEPAD_LEFT_SHOULDER_TOP, GAMEPAD_LEFT_SHOULDER_TOP, GAMEPAD_LEFT_SHOULDER_TOP, GAMEPAD_LEFT_SHOULDER_TOP, GAMEPAD_LEFT_SHOULDER_TOP, AKEY_UNKNOWN, OSXKEY_UNKNOWN, IKEY_UNKNOWN, LINUXKEY_UNKNOWN, GAMEPAD_LEFT_SHOULDER_TOP);
+ DIGITAL_INPUT_EVENT_DEF(DEBUG_RENDER_WHEEL, GAMEPAD_RIGHT_SHOULDER_TOP, GAMEPAD_RIGHT_SHOULDER_TOP, GAMEPAD_RIGHT_SHOULDER_TOP, GAMEPAD_RIGHT_SHOULDER_TOP, GAMEPAD_RIGHT_SHOULDER_TOP, AKEY_UNKNOWN, OSXKEY_UNKNOWN, IKEY_UNKNOWN, LINUXKEY_UNKNOWN, GAMEPAD_RIGHT_SHOULDER_TOP);
+ DIGITAL_INPUT_EVENT_DEF(FIX_CAR, GAMEPAD_RIGHT_STICK, GAMEPAD_RIGHT_STICK, GAMEPAD_RIGHT_STICK, GAMEPAD_RIGHT_STICK, GAMEPAD_RIGHT_STICK, AKEY_UNKNOWN, OSXKEY_UNKNOWN, IKEY_UNKNOWN, LINUXKEY_UNKNOWN, GAMEPAD_RIGHT_STICK);
+
+ //General control events on touch
+ TOUCH_INPUT_EVENT_DEF(FIX_CAR, "Reset Car", ABUTTON_5, IBUTTON_5);
+ TOUCH_INPUT_EVENT_DEF(CAR_HANDBRAKE_PAD, "Handbrake", AQUICK_BUTTON_1, IQUICK_BUTTON_1);
+}
+
+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();
+}
diff --git a/PhysX_3.4/Samples/SampleVehicle/SampleVehicle.h b/PhysX_3.4/Samples/SampleVehicle/SampleVehicle.h
new file mode 100644
index 00000000..e77a116f
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleVehicle/SampleVehicle.h
@@ -0,0 +1,198 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+
+#ifndef SAMPLE_VEHICLE_H
+#define SAMPLE_VEHICLE_H
+
+#include "PhysXSample.h"
+#include "SampleVehicle_ControlInputs.h"
+#include "SampleVehicle_CameraController.h"
+#include "SampleVehicle_VehicleController.h"
+#include "SampleVehicle_VehicleManager.h"
+#include "SampleVehicle_GameLogic.h"
+#include "vehicle/PxVehicleTireFriction.h"
+
+class SampleVehicle : public PhysXSample
+{
+
+public:
+
+ SampleVehicle(PhysXSampleApplication& app);
+ virtual ~SampleVehicle();
+
+
+ ///////////////////////////////////////////////////////////////////////////////
+
+ // Implements RAWImportCallback
+ virtual void newMesh(const RAWMesh&);
+
+ ///////////////////////////////////////////////////////////////////////////////
+
+ // Implements SampleApplication
+ virtual void onInit();
+ virtual void onInit(bool restart) { onInit(); }
+ virtual void onShutdown();
+
+ virtual void onTickPreRender(PxF32 dtime);
+ virtual void onTickPostRender(PxF32 dtime);
+
+ virtual void onDigitalInputEvent(const SampleFramework::InputEvent& , bool val);
+ virtual void onAnalogInputEvent(const SampleFramework::InputEvent& , float val);
+
+ ///////////////////////////////////////////////////////////////////////////////
+
+ // Implements PhysXSampleApplication
+ virtual void helpRender(PxU32 x, PxU32 y, PxU8 textAlpha);
+ virtual void descriptionRender(PxU32 x, PxU32 y, PxU8 textAlpha);
+ virtual void customizeSample(SampleSetup&);
+ virtual void customizeSceneDesc(PxSceneDesc&);
+ virtual void customizeRender();
+ virtual void onSubstep(PxF32 dtime);
+ virtual void collectInputEvents(std::vector<const SampleFramework::InputEvent*>& inputEvents);
+
+private:
+
+ SampleVehicle_ControlInputs mControlInputs;
+ SampleVehicle_CameraController mCameraController;
+ SampleVehicle_VehicleController mVehicleController;
+
+
+ //Terrain
+
+ PxF32* mTerrainVB;
+ PxU32 mNbTerrainVerts;
+
+ enum
+ {
+ MAX_NUM_INDEX_BUFFERS = 16
+ };
+ PxU32 mNbIB;
+ PxU32* mIB[MAX_NUM_INDEX_BUFFERS];
+ PxU32 mNbTriangles[MAX_NUM_INDEX_BUFFERS];
+ PxU32 mRenderMaterial[MAX_NUM_INDEX_BUFFERS];
+
+ //Materials
+
+ PxVehicleDrivableSurfaceType mVehicleDrivableSurfaceTypes[MAX_NUM_INDEX_BUFFERS];
+ PxMaterial* mStandardMaterials[MAX_NUM_INDEX_BUFFERS];
+ PxMaterial* mChassisMaterialDrivable;
+ PxMaterial* mChassisMaterialNonDrivable;
+
+
+ RenderMaterial* mTerrainMaterial;
+ RenderMaterial* mRoadMaterial;
+ RenderMaterial* mRoadIceMaterial;
+ RenderMaterial* mRoadGravelMaterial;
+
+ void createStandardMaterials();
+
+ enum eFocusVehicleType
+ {
+ ePLAYER_VEHICLE_TYPE_VEHICLE4W=0,
+ ePLAYER_VEHICLE_TYPE_VEHICLE6W,
+ ePLAYER_VEHICLE_TYPE_TANK4W,
+ ePLAYER_VEHICLE_TYPE_TANK6W,
+ eMAX_NUM_FOCUS_VEHICLE_TYPES
+ };
+
+ // Vehicles
+ SampleVehicle_VehicleManager mVehicleManager;
+ std::vector<RenderMeshActor*> mVehicleGraphics;
+ PxU32 mPlayerVehicle;
+ eFocusVehicleType mPlayerVehicleType;
+ PxVehicleDriveTankControlModel::Enum mTankDriveModel;
+
+ const char* getFocusVehicleName();
+ void createVehicles();
+
+ PxU32 mTerrainSize;
+ PxF32 mTerrainWidth;
+ PxRigidActor* mHFActor;
+
+ void createTrack(PxU32 size, PxF32 width, PxF32 chaos);
+ void createTerrain(PxU32 size, PxF32 width, PxF32 chaos);
+ void addRenderMesh(PxF32* verts, PxU32 nVerts, PxU32* indices, PxU32 mIndices, PxU32 matID);
+ void addMesh(PxRigidActor* actor, PxF32* verts, PxU32 nVerts, PxU32* indices, PxU32 mIndices, PxU32 materialIndex, const char* filename);
+ void createLandscapeMesh();
+
+ //Obstacles
+
+ void createObstacles();
+ PxRigidStatic* addStaticObstacle(const PxTransform& transform, const PxU32 numShapes, PxTransform* shapeTransforms, PxGeometry** shapeGeometries, PxMaterial** shapeMaterials);
+ PxRigidDynamic* addDynamicObstacle(const PxTransform& transform, const PxF32 mass, const PxU32 numShapes, PxTransform* transforms, PxGeometry** geometries, PxMaterial** materials);
+ PxRigidDynamic* addDynamicDrivableObstacle(const PxTransform& transform, const PxF32 mass, const PxU32 numShapes, PxTransform* transforms, PxGeometry** geometries, PxMaterial** materials);
+ void createStack(PxU32 size, PxF32 boxSize, const PxVec3& pos, const PxQuat& quat);
+ void createWall(const PxU32 numHorizontalBoxes, const PxU32 numVerticalBoxes, const PxF32 boxSize, const PxVec3& pos, const PxQuat& quat);
+
+ //Debug render
+
+ bool mHideScreenText;
+ bool mDebugRenderFlag;
+#if PX_DEBUG_VEHICLE_ON
+ PxU32 mDebugRenderActiveGraphChannelWheel;
+ PxU32 mDebugRenderActiveGraphChannelEngine;
+ PxVehicleTelemetryData* mTelemetryData4W;
+ PxVehicleTelemetryData* mTelemetryData6W;
+#endif
+ void setupTelemetryData();
+ void clearTelemetryData();
+
+ void drawWheels();
+ void drawVehicleDebug();
+ void drawHud();
+ void drawGraphsAndPrintTireSurfaceTypes(const PxVehicleWheels& focusVehicle, const PxVehicleWheelQueryResult& focusVehicleWheelQueryResults);
+ void drawFocusVehicleGraphsAndPrintTireSurfaces();
+
+ //Waypoints
+ SampleVehicleWayPoints mWayPoints;
+ bool mFixCar;
+ bool mBackToStart;
+
+ //3W and 4W modes
+ bool m3WModeIncremented;
+ PxU32 m3WMode;
+
+ PxF32 mForwardSpeedHud;
+
+#if defined(SERIALIZE_VEHICLE_BINARY)
+ void* mMemory;
+#endif
+
+ void updateCameraController(const PxF32 dtime, PxScene& scene);
+ void updateVehicleController(const PxF32 dtime);
+ void updateVehicleManager(const PxF32 dtime, const PxVec3& gravity);
+
+ void resetFocusVehicleAtWaypoint();
+ PxRigidDynamic* getFocusVehicleRigidDynamicActor();
+ bool getFocusVehicleUsesAutoGears();
+ char mVehicleFilePath[256];
+};
+
+#endif
diff --git a/PhysX_3.4/Samples/SampleVehicle/SampleVehicleDebugRender.cpp b/PhysX_3.4/Samples/SampleVehicle/SampleVehicleDebugRender.cpp
new file mode 100644
index 00000000..233bad36
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleVehicle/SampleVehicleDebugRender.cpp
@@ -0,0 +1,367 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#include "SampleVehicle.h"
+#include "RenderPhysX3Debug.h"
+#include "PxRigidDynamic.h"
+#include "SampleVehicle_VehicleManager.h"
+
+using namespace SampleRenderer;
+
+// PT: this file contains the part of SampleVehicle dealing with cars' debug rendering
+
+void SampleVehicle::drawWheels()
+{
+ PxSceneReadLock scopedLock(*mScene);
+ const RendererColor colorPurple(255, 0, 255);
+
+ for(PxU32 i=0;i<mVehicleManager.getNbVehicles();i++)
+ {
+ //Draw a rotating arrow to get an idea of the wheel rotation speed.
+ PxVehicleWheels* veh=mVehicleManager.getVehicle(i);
+ const PxRigidDynamic* actor=veh->getRigidDynamicActor();
+ PxShape* shapeBuffer[PX_MAX_NB_WHEELS];
+ actor->getShapes(shapeBuffer,veh->mWheelsSimData.getNbWheels());
+ const PxTransform vehGlobalPose=actor->getGlobalPose();
+ const PxU32 numWheels=veh->mWheelsSimData.getNbWheels();
+ for(PxU32 j=0;j<numWheels;j++)
+ {
+ const PxTransform wheelTransform=vehGlobalPose.transform(shapeBuffer[j]->getLocalPose());
+ const PxF32 wheelRadius=veh->mWheelsSimData.getWheelData(j).mRadius;
+ const PxF32 wheelHalfWidth=veh->mWheelsSimData.getWheelData(j).mWidth*0.5f;
+ PxVec3 offset=wheelTransform.q.getBasisVector0()*wheelHalfWidth;
+ offset*= (veh->mWheelsSimData.getWheelCentreOffset(j).x > 0) ? 1.0f : -1.0f;
+ const PxVec3 arrow=wheelTransform.rotate(PxVec3(0,0,1));
+ getDebugRenderer()->addLine(wheelTransform.p+offset, wheelTransform.p+offset+arrow*wheelRadius, colorPurple);
+ }
+ }
+}
+
+void SampleVehicle::drawVehicleDebug()
+{
+ PxSceneReadLock scopedLock(*mScene);
+ const RendererColor colorColl(255, 0, 0);
+ const RendererColor colorCol2(0, 255, 0);
+ const RendererColor colorCol3(0, 0, 255);
+
+#if PX_DEBUG_VEHICLE_ON
+ const PxVec3* tireForceAppPoints=NULL;
+ const PxVec3* suspForceAppPoints=NULL;
+ switch(mPlayerVehicleType)
+ {
+ case ePLAYER_VEHICLE_TYPE_VEHICLE4W:
+ case ePLAYER_VEHICLE_TYPE_TANK4W:
+ tireForceAppPoints=mTelemetryData4W->getTireforceAppPoints();
+ suspForceAppPoints=mTelemetryData4W->getSuspforceAppPoints();
+ break;
+ case ePLAYER_VEHICLE_TYPE_VEHICLE6W:
+ case ePLAYER_VEHICLE_TYPE_TANK6W:
+ tireForceAppPoints=mTelemetryData6W->getTireforceAppPoints();
+ suspForceAppPoints=mTelemetryData6W->getSuspforceAppPoints();
+ break;
+ default:
+ PX_ASSERT(false);
+ break;
+ }
+#endif
+
+ const PxVehicleWheels& vehicle4W=*mVehicleManager.getVehicle(mPlayerVehicle);
+ const PxVehicleWheelQueryResult& vehicleWheelQueryResults=mVehicleManager.getVehicleWheelQueryResults(mPlayerVehicle);
+ const PxRigidDynamic* actor=vehicle4W.getRigidDynamicActor();
+ const PxU32 numWheels=vehicle4W.mWheelsSimData.getNbWheels();
+ PxVec3 v[8];
+ PxVec3 w[8];
+ PxF32 l[8];
+ for(PxU32 i=0;i<numWheels;i++)
+ {
+ v[i] = vehicleWheelQueryResults.wheelQueryResults[i].suspLineStart;
+ w[i] = vehicleWheelQueryResults.wheelQueryResults[i].suspLineDir;
+ l[i] = vehicleWheelQueryResults.wheelQueryResults[i].suspLineLength;
+ }
+
+
+ const PxTransform t=actor->getGlobalPose().transform(actor->getCMassLocalPose());
+ const PxVec3 dirs[3]={t.rotate(PxVec3(1,0,0)),t.rotate(PxVec3(0,1,0)),t.rotate(PxVec3(0,0,1))};
+ getDebugRenderer()->addLine(t.p, t.p + dirs[0]*4.0f, colorColl);
+ getDebugRenderer()->addLine(t.p, t.p + dirs[1]*4.0f, colorColl);
+ getDebugRenderer()->addLine(t.p, t.p + dirs[2]*4.0f, colorColl);
+
+ for(PxU32 j=0;j<numWheels;j++)
+ {
+ getDebugRenderer()->addLine(v[j], v[j]+w[j]*l[j], colorColl);
+
+#if PX_DEBUG_VEHICLE_ON
+ //Draw all tire force app points.
+ const PxVec3& appPoint = tireForceAppPoints[j];
+ getDebugRenderer()->addLine(appPoint - dirs[0], appPoint + dirs[0], colorCol2);
+ getDebugRenderer()->addLine(appPoint - dirs[2], appPoint + dirs[2], colorCol2);
+
+ //Draw all susp force app points.
+ const PxVec3& appPoint2 = suspForceAppPoints[j];
+ getDebugRenderer()->addLine(appPoint2 - dirs[0], appPoint2 + dirs[0], colorCol3);
+ getDebugRenderer()->addLine(appPoint2 - dirs[2], appPoint2 + dirs[2], colorCol3);
+#endif
+ }
+}
+
+static void drawBox2D(Renderer* renderer, PxF32 minX, PxF32 maxX, PxF32 minY, PxF32 maxY, const RendererColor& color, PxF32 alpha)
+{
+ ScreenQuad sq;
+ sq.mX0 = minX;
+ sq.mY0 = 1.0f - minY;
+ sq.mX1 = maxX;
+ sq.mY1 = 1.0f - maxY;
+ sq.mLeftUpColor = color;
+ sq.mRightUpColor = color;
+ sq.mLeftDownColor = color;
+ sq.mRightDownColor = color;
+ sq.mAlpha = alpha;
+
+ renderer->drawScreenQuad(sq);
+}
+
+static void print(Renderer* renderer, PxF32 x, PxF32 y, PxF32 scale_, const char* text)
+{
+ PxU32 width, height;
+ renderer->getWindowSize(width, height);
+
+ y = 1.0f - y;
+
+ const PxReal scale = scale_*20.0f;
+ const PxReal shadowOffset = 6.0f;
+ const RendererColor textColor(255, 255, 255, 255);
+
+ renderer->print(PxU32(x*PxF32(width)), PxU32(y*PxF32(height)), text, scale, shadowOffset, textColor);
+}
+
+void SampleVehicle::drawHud()
+{
+ const PxVehicleWheels& focusVehicle = *mVehicleManager.getVehicle(mPlayerVehicle);
+ PxVehicleDriveDynData* driveDynData=NULL;
+ PxVehicleDriveSimData* driveSimData=NULL;
+ switch(focusVehicle.getVehicleType())
+ {
+ case PxVehicleTypes::eDRIVE4W:
+ {
+ PxVehicleDrive4W& vehDrive4W=(PxVehicleDrive4W&)focusVehicle;
+ driveDynData=&vehDrive4W.mDriveDynData;
+ driveSimData=&vehDrive4W.mDriveSimData;
+ }
+ break;
+ case PxVehicleTypes::eDRIVENW:
+ {
+ PxVehicleDriveNW& vehDriveNW=(PxVehicleDriveNW&)focusVehicle;
+ driveDynData=&vehDriveNW.mDriveDynData;
+ driveSimData=&vehDriveNW.mDriveSimData;
+ }
+ break;
+ case PxVehicleTypes::eDRIVETANK:
+ {
+ PxVehicleDriveTank& vehDriveTank=(PxVehicleDriveTank&)focusVehicle;
+ driveDynData=&vehDriveTank.mDriveDynData;
+ driveSimData=&vehDriveTank.mDriveSimData;
+ }
+ break;
+ default:
+ PX_ASSERT(false);
+ break;
+ }
+
+ const PxU32 currentGear=driveDynData->getCurrentGear();
+ const PxF32 vz=mForwardSpeedHud*3.6f;
+ const PxF32 revs=driveDynData->getEngineRotationSpeed();
+ const PxF32 maxRevs=driveSimData->getEngineData().mMaxOmega*60*0.5f/PxPi;//Convert from radians per second to rpm
+ const PxF32 invMaxRevs=driveSimData->getEngineData().getRecipMaxOmega();
+
+ //Draw gears and speed.
+
+ const PxF32 x=0.5f;
+ const PxF32 y=0.18f;
+ const PxF32 length=0.1f;
+ const PxF32 textheight=0.02f;
+
+ Renderer* renderer = getRenderer();
+ drawBox2D(renderer, x-length-textheight, x+length+textheight, y, y+length+textheight, RendererColor(255, 255, 255), 0.5f);
+
+ //Gear
+ char gear[PxVehicleGearsData::eGEARSRATIO_COUNT][64]=
+ {
+ "R","N","1","2","3","4","5"
+ };
+ print(renderer, x-0.25f*textheight, y+0.02f, 0.02f, gear[currentGear]);
+
+ //Speed
+ char speed[64];
+ sprintf(speed, "%1.0f %s", PxAbs(vz), "kmph");
+ print(renderer, x-textheight, y+length-textheight, textheight, speed);
+
+ //Revs
+ {
+ const PxF32 xy[4]={x, 1.0f-y, x-length, 1.0f-(y+length)};
+ renderer->drawLines2D(2, xy, RendererColor(0, 0, 255));
+
+ char buffer[64];
+ sprintf(buffer, "%d \n", 0);
+ print(renderer, x-length, y+length, textheight, buffer);
+ }
+ {
+ const PxF32 xy[4]={x, 1.0f-y, x+length, 1.0f-(y+length)};
+ renderer->drawLines2D(2, xy, RendererColor(0, 0, 255));
+
+ char buffer[64];
+ sprintf(buffer, "%1.0f \n", maxRevs);
+ print(renderer, x+length-2*textheight, y+length, textheight, buffer);
+ }
+ {
+ const PxF32 alpha=revs*invMaxRevs;
+ const PxF32 dx=-(1.0f-alpha)*length + alpha*length;
+ const PxF32 xy[4]={x, 1.0f-y, x+dx, 1.0f-(y+length)};
+ renderer->drawLines2D(2, xy, RendererColor(255, 0, 0));
+ }
+}
+
+#if PX_DEBUG_VEHICLE_ON
+
+static PX_FORCE_INLINE RendererColor getColor(const PxVec3& c)
+{
+ return RendererColor(PxU8(c.x), PxU8(c.y), PxU8(c.z));
+}
+
+static PX_FORCE_INLINE void convertColors(const PxVec3* src, RendererColor* dst)
+{
+ for(PxU32 i=0;i<PxVehicleGraph::eMAX_NB_SAMPLES;i++)
+ *dst++ = getColor(src[i]);
+}
+
+static void convertY(PxF32* xy)
+{
+ for(PxU32 i=0;i<PxVehicleGraph::eMAX_NB_SAMPLES;i++)
+ xy[2*i+1]=1.0f-xy[2*i+1];
+}
+
+#endif //PX_DEBUG_VEHICLE_ON
+
+#if PX_DEBUG_VEHICLE_ON
+
+void drawGraphsAndPrintTireSurfaceTypesN
+(const PxVehicleTelemetryData& telemetryData, const PxU32* tireTypes, const PxU32* surfaceTypes,
+ const PxU32 activeEngineGraphChannel, const PxU32 activeWheelGraphChannel,
+ SampleRenderer::Renderer* renderer)
+{
+
+ PxF32 xy[2*PxVehicleGraph::eMAX_NB_SAMPLES];
+ PxVec3 color[PxVehicleGraph::eMAX_NB_SAMPLES];
+ RendererColor rendererColor[PxVehicleGraph::eMAX_NB_SAMPLES];
+ char title[PxVehicleGraph::eMAX_NB_TITLE_CHARS];
+
+ const PxU32 numWheelGraphs=telemetryData.getNbWheelGraphs();
+
+ for(PxU32 i=0;i<numWheelGraphs;i++)
+ {
+ PxF32 xMin,xMax,yMin,yMax;
+ telemetryData.getWheelGraph(i).getBackgroundCoords(xMin,yMin,xMax,yMax);
+ const PxVec3& backgroundColor=telemetryData.getWheelGraph(i).getBackgroundColor();
+ const PxF32 alpha=telemetryData.getWheelGraph(i).getBackgroundAlpha();
+ drawBox2D(renderer, xMin,xMax,yMin,yMax, getColor(backgroundColor),alpha);
+
+ telemetryData.getWheelGraph(i).computeGraphChannel(activeWheelGraphChannel,xy,color,title);
+ convertY(xy);
+ convertColors(color, rendererColor);
+ renderer->drawLines2D(PxVehicleGraph::eMAX_NB_SAMPLES, xy, rendererColor);
+
+ print(renderer, xMin,yMax-0.02f, 0.02f, title);
+
+ const PxU32 tireType=tireTypes[i];
+ const PxU32 tireSurfaceType=surfaceTypes[i];
+
+ if (PxVehicleDrivableSurfaceType::eSURFACE_TYPE_UNKNOWN!=tireSurfaceType)
+ {
+ const char* surfaceType= SurfaceTypeNames::getName(tireSurfaceType);
+ const PxF32 friction=TireFrictionMultipliers::getValue(tireSurfaceType, tireType);
+ char surfaceDetails[64];
+ sprintf(surfaceDetails, "%s %1.2f \n", surfaceType, friction);
+ print(renderer, xMin+0.1f, yMax-0.12f, 0.02f, surfaceDetails);
+ }
+ }
+
+ PxF32 xMin,xMax,yMin,yMax;
+ telemetryData.getEngineGraph().getBackgroundCoords(xMin,yMin,xMax,yMax);
+ const PxVec3& backgroundColor=telemetryData.getEngineGraph().getBackgroundColor();
+ const PxF32 alpha=telemetryData.getEngineGraph().getBackgroundAlpha();
+ drawBox2D(renderer, xMin,xMax,yMin,yMax, getColor(backgroundColor),alpha);
+
+ telemetryData.getEngineGraph().computeGraphChannel(activeEngineGraphChannel,xy,color,title);
+ convertY(xy);
+ convertColors(color, rendererColor);
+ renderer->drawLines2D(PxVehicleGraph::eMAX_NB_SAMPLES, xy, rendererColor);
+
+ print(renderer, xMin,yMax-0.02f,0.02f,title);
+}
+
+#endif //PX_DEBUG_VEHICLE_GRAPH_ON
+
+void SampleVehicle::drawGraphsAndPrintTireSurfaceTypes(const PxVehicleWheels& focusVehicle, const PxVehicleWheelQueryResult& focusVehicleWheelQueryResults)
+{
+#if PX_DEBUG_VEHICLE_ON
+
+ PxU32 tireTypes[8];
+ PxU32 surfaceTypes[8];
+ const PxU32 numWheels=focusVehicle.mWheelsSimData.getNbWheels();
+ PX_ASSERT(numWheels<=8);
+ for(PxU32 i=0;i<numWheels;i++)
+ {
+ tireTypes[i]=focusVehicle.mWheelsSimData.getTireData(i).mType;
+ surfaceTypes[i]=focusVehicleWheelQueryResults.wheelQueryResults[i].tireSurfaceType;
+ }
+
+ PxVehicleTelemetryData* vehTelData=NULL;
+ switch(mPlayerVehicleType)
+ {
+ case ePLAYER_VEHICLE_TYPE_VEHICLE4W:
+ case ePLAYER_VEHICLE_TYPE_TANK4W:
+ vehTelData=mTelemetryData4W;
+ break;
+ case ePLAYER_VEHICLE_TYPE_VEHICLE6W:
+ case ePLAYER_VEHICLE_TYPE_TANK6W:
+ vehTelData=mTelemetryData6W;
+ break;
+ default:
+ PX_ASSERT(false);
+ break;
+ }
+
+ drawGraphsAndPrintTireSurfaceTypesN(
+ *vehTelData,tireTypes,surfaceTypes,
+ mDebugRenderActiveGraphChannelEngine,mDebugRenderActiveGraphChannelWheel,
+ getRenderer());
+
+#endif
+}
+
+
diff --git a/PhysX_3.4/Samples/SampleVehicle/SampleVehicleInputEventIds.h b/PhysX_3.4/Samples/SampleVehicle/SampleVehicleInputEventIds.h
new file mode 100644
index 00000000..29781d77
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleVehicle/SampleVehicleInputEventIds.h
@@ -0,0 +1,98 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved.
+#ifndef _SAMPLE_VEHICLE_INPUT_EVENT_IDS_H
+#define _SAMPLE_VEHICLE_INPUT_EVENT_IDS_H
+
+#include <SampleBaseInputEventIds.h>
+
+// InputEvents used by SampleVehicle
+enum SampleVehicleInputEventIds
+{
+ SAMPLE_VEHICLE_FIRST_ID = NUM_SAMPLE_BASE_INPUT_EVENT_IDS,
+
+ CAR_ACCELERATE_BRAKE,
+
+ //KEYBOARD (car+tank)
+ VEH_ACCELERATE_KBD,
+ VEH_GEAR_UP_KBD,
+ VEH_GEAR_DOWN_KBD,
+
+ VEH_SAVE_KBD,
+
+ //KEYBOARD (car)
+ CAR_BRAKE_KBD,
+ CAR_HANDBRAKE_KBD,
+ CAR_STEER_LEFT_KBD,
+ CAR_STEER_RIGHT_KBD,
+
+ //KEYBOARD (tank)
+ TANK_THRUST_LEFT_KBD,
+ TANK_THRUST_RIGHT_KBD,
+ TANK_BRAKE_LEFT_KBD,
+ TANK_BRAKE_RIGHT_KBD,
+
+ //KEYBOARD (camera)
+ CAMERA_ROTATE_LEFT_KBD,
+ CAMERA_ROTATE_RIGHT_KBD,
+ CAMERA_ROTATE_UP_KBD,
+ CAMERA_ROTATE_DOWN_KBD,
+
+ //GAMEPAD (car+tank)
+ VEH_ACCELERATE_PAD,
+ VEH_GEAR_UP_PAD,
+ VEH_GEAR_DOWN_PAD,
+
+ //GAMEPAD (car)
+ CAR_BRAKE_PAD,
+ CAR_HANDBRAKE_PAD,
+ CAR_STEER_PAD,
+
+ //GAMEPAD (tank)
+ TANK_THRUST_LEFT_PAD,
+ TANK_THRUST_RIGHT_PAD,
+ TANK_BRAKE_LEFT_PAD,
+ TANK_BRAKE_RIGHT_PAD,
+
+ //GAMEPAD (camera)
+ CAMERA_ROTATE_LEFT_RIGHT_PAD,
+ CAMERA_ROTATE_UP_DOWN_PAD,
+
+ //
+ AUTOMATIC_GEAR,
+ DEBUG_RENDER_FLAG,
+ DEBUG_RENDER_WHEEL ,
+ DEBUG_RENDER_ENGINE,
+ RETRY,
+ FIX_CAR,
+ CAMERA_LOCK,
+ W3MODE,
+
+
+ NUM_SAMPLE_VEHICLE_INPUT_EVENT_IDS,
+};
+
+#endif
diff --git a/PhysX_3.4/Samples/SampleVehicle/SampleVehicleTerrain.cpp b/PhysX_3.4/Samples/SampleVehicle/SampleVehicleTerrain.cpp
new file mode 100644
index 00000000..e5d57c3a
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleVehicle/SampleVehicleTerrain.cpp
@@ -0,0 +1,547 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#include "SampleVehicle.h"
+#include "SampleVehicle_SceneQuery.h"
+#include "SampleRandomPrecomputed.h"
+#include "SampleAllocatorSDKClasses.h"
+#include "RendererMemoryMacros.h"
+#include "RenderMaterial.h"
+#include "RenderMeshActor.h"
+#include "cooking/PxTriangleMeshDesc.h"
+#include "geometry/PxHeightFieldGeometry.h"
+#include "geometry/PxHeightFieldSample.h"
+#include "geometry/PxHeightFieldDesc.h"
+#include "cooking/PxCooking.h"
+#include "PxScene.h"
+#include "PxRigidStatic.h"
+#include "PxTkStream.h"
+#include "PxTkFile.h"
+
+//using namespace physx;
+using namespace PxToolkit;
+
+//Use a mesh (instead of a height field)
+static bool gRecook = false;
+
+enum MaterialID
+{
+ MATERIAL_TERRAIN_MUD = 1000,
+ MATERIAL_ROAD_TARMAC = 1001,
+ MATERIAL_ROAD_SNOW = 1002,
+ MATERIAL_ROAD_GRASS = 1003,
+};
+
+static void computeTerrain(bool* done, float* pVB, PxU32 x0, PxU32 y0, PxU32 currentSize, float value, PxU32 initSize, SampleRandomPrecomputed& randomPrecomputed)
+{
+ // Compute new size
+ currentSize>>=1;
+ if(currentSize > 0)
+ {
+ const PxU32 x1 = (x0+currentSize) % initSize;
+ const PxU32 x2 = (x0+currentSize+currentSize) % initSize;
+ const PxU32 y1 = (y0+currentSize) % initSize;
+ const PxU32 y2 = (y0+currentSize+currentSize) % initSize;
+
+ if(!done[x1 + y0*initSize]) pVB[(x1 + y0*initSize)*9+1] = randomPrecomputed.getRandomInRange(-0.5f*value, 0.5f*value) + 0.5f * (pVB[(x0 + y0*initSize)*9+1] + pVB[(x2 + y0*initSize)*9+1]);
+ if(!done[x0 + y1*initSize]) pVB[(x0 + y1*initSize)*9+1] = randomPrecomputed.getRandomInRange(-0.5f*value, 0.5f*value) + 0.5f * (pVB[(x0 + y0*initSize)*9+1] + pVB[(x0 + y2*initSize)*9+1]);
+ if(!done[x2 + y1*initSize]) pVB[(x2 + y1*initSize)*9+1] = randomPrecomputed.getRandomInRange(-0.5f*value, 0.5f*value) + 0.5f * (pVB[(x2 + y0*initSize)*9+1] + pVB[(x2 + y2*initSize)*9+1]);
+ if(!done[x1 + y2*initSize]) pVB[(x1 + y2*initSize)*9+1] = randomPrecomputed.getRandomInRange(-0.5f*value, 0.5f*value) + 0.5f * (pVB[(x0 + y2*initSize)*9+1] + pVB[(x2 + y2*initSize)*9+1]);
+ if(!done[x1 + y1*initSize]) pVB[(x1 + y1*initSize)*9+1] = randomPrecomputed.getRandomInRange(-0.5f*value, 0.5f*value) + 0.5f * (pVB[(x0 + y1*initSize)*9+1] + pVB[(x2 + y1*initSize)*9+1]);
+
+ done[x1 + y0*initSize] = true;
+ done[x0 + y1*initSize] = true;
+ done[x2 + y1*initSize] = true;
+ done[x1 + y2*initSize] = true;
+ done[x1 + y1*initSize] = true;
+
+ // Recurse through 4 corners
+ value *= 0.5f;
+ computeTerrain(done, pVB, x0, y0, currentSize, value, initSize, randomPrecomputed);
+ computeTerrain(done, pVB, x0, y1, currentSize, value, initSize, randomPrecomputed);
+ computeTerrain(done, pVB, x1, y0, currentSize, value, initSize, randomPrecomputed);
+ computeTerrain(done, pVB, x1, y1, currentSize, value, initSize, randomPrecomputed);
+ }
+}
+
+void SampleVehicle::createTerrain(PxU32 size, float width, float chaos)
+{
+ mNbTerrainVerts = size*size;
+
+ // Vertex buffer
+ mTerrainVB = (float*)SAMPLE_ALLOC(sizeof(float)*mNbTerrainVerts*3*3);
+ for(PxU32 y=0;y<size;y++)
+ {
+ for(PxU32 x=0;x<size;x++)
+ {
+ mTerrainVB[(x+y*size)*9+0] = (float(x)-(float(size-1)*0.5f))* width;
+ mTerrainVB[(x+y*size)*9+1] = 0.0f;
+ mTerrainVB[(x+y*size)*9+2] = (float(y)-(float(size-1)*0.5f))* width;
+ mTerrainVB[(x+y*size)*9+3] = 0.0f; mTerrainVB[(x+y*size)*9+4] = 1.0f; mTerrainVB[(x+y*size)*9+5] = 0.0f;
+ mTerrainVB[(x+y*size)*9+6] = 0.5f; mTerrainVB[(x+y*size)*9+7] = 0.4f; mTerrainVB[(x+y*size)*9+8] = 0.2f;
+ }
+ }
+
+ // Fractalize
+ bool* doneBuffer = (bool*)SAMPLE_ALLOC(sizeof(bool)*mNbTerrainVerts);
+ PxU32* tagBuffer = (PxU32*)SAMPLE_ALLOC(sizeof(PxU32)*mNbTerrainVerts);
+ for(PxU32 i=0;i<mNbTerrainVerts;i++)
+ {
+ doneBuffer[i] = false;
+ tagBuffer[i] = 0;
+ }
+ mTerrainVB[1] = 10.0f;
+ mTerrainVB[(size-1)*9+1] = 10.0f;
+ mTerrainVB[(size*(size-1))*9+1] = 10.0f;
+ mTerrainVB[(mNbTerrainVerts-1)*9+1] = 10.0f;
+
+ SampleRandomPrecomputed randomPrecomputed(*this);
+ computeTerrain(doneBuffer, mTerrainVB, 0, 0, size, chaos/16.0f, size, randomPrecomputed);
+
+ const PxU32 street0 = (PxU32)(size/3.0f);
+ const PxU32 streetSize = (PxU32)(size/30.0f);
+ float ay = 0.0f;
+
+ for(PxU32 y=0;y<size;y++)
+ {
+ for(PxU32 x=street0;x<street0+streetSize;x++)
+ {
+ ay+=mTerrainVB[(x+y*size)*9+1];
+ ay+=mTerrainVB[(y+x*size)*9+1];
+ }
+ }
+
+ const float cx = size/2.0f;
+ const float cy = size/2.0f;
+ const float r = size/3.0f;
+ const float g = streetSize/2.0f;
+
+ for(PxU32 i=0;i<mNbTerrainVerts;i++)
+ tagBuffer[i] = false;
+
+ ay/=streetSize*size;
+ ay-=streetSize;
+ for(PxU32 y=15;y<size-15;y++)
+ {
+ bool smoothBorder = true;
+
+ for(PxU32 x=street0;x<street0+streetSize;x++)
+ {
+ if(y > size*0.5f && y < size*0.7f)
+ {
+ mTerrainVB[(x+y*size)*9+1]=ay+sinf(((float)y)*12.0f+4.0f)*2.0f;
+ smoothBorder = false;
+ }
+ else
+ {
+ mTerrainVB[(x+y*size)*9+1]=ay;
+ }
+
+ if(y > size*0.55f && y < size*0.75f)
+ {
+ mTerrainVB[(y+x*size)*9+1]=ay+sinf(y*12.0f)*0.75f;
+ //mTerrainVB[(y+x*size)*9+1]=ay;
+ tagBuffer[y+x*size] = 3;
+ tagBuffer[x+y*size] = 3;
+ smoothBorder = false;
+ }
+ else if(y < size*0.15f)
+ {
+ const float s = size*0.15f-(float)y;
+ mTerrainVB[(y+x*size)*9+1]=ay+s*0.25f;
+ smoothBorder = false;
+ }
+ else if(y > size*0.85f)
+ {
+ const float s = (float)y-size*0.85f;
+ mTerrainVB[(y+x*size)*9+1]=ay+s*0.7f;
+ smoothBorder = false;
+ }
+ else
+ {
+ mTerrainVB[(y+x*size)*9+1]=ay;
+ tagBuffer[y+x*size] = 1;
+ tagBuffer[x+y*size] = 1;
+ }
+
+ }
+ if(smoothBorder)
+ {
+ mTerrainVB[((street0-1)+y*size)*9+1]=ay*0.5f+mTerrainVB[((street0-1)+y*size)*9+1]*0.5f;
+ mTerrainVB[(y+(street0-1)*size)*9+1]=ay*0.5f+mTerrainVB[(y+(street0-1)*size)*9+1]*0.5f;
+ mTerrainVB[((street0+1)+y*size)*9+1]=ay*0.5f+mTerrainVB[((street0+1)+y*size)*9+1]*0.5f;
+ mTerrainVB[(y+(street0+1)*size)*9+1]=ay*0.5f+mTerrainVB[(y+(street0+1)*size)*9+1]*0.5f;
+ }
+ }
+
+ // Circle street
+ for(PxU32 y=0;y<size;y++)
+ {
+ for(PxU32 x=0;x<size;x++)
+ {
+ const float x0 = x-cx;
+ const float y0 = y-cy;
+ const float d = sqrtf(x0*x0+y0*y0);
+ if(d >= r && d < r+streetSize)
+ {
+ mTerrainVB[(y+x*size)*9+1]=ay;
+
+ if(y > size*0.55f && y < size*0.75f)
+ tagBuffer[y+x*size] = 2;
+ else
+ tagBuffer[y+x*size] = 1;
+
+ }
+ else if(d >= r+streetSize && d < r+streetSize+g)
+ {
+ const float a = (d-(r+streetSize))/g;
+ mTerrainVB[(y+x*size)*9+1]=ay*(1.0f-a) + mTerrainVB[(y+x*size)*9+1]*a;
+ }
+ else if(d >= r-g && d < r)
+ {
+ const float a = (d-(r-g))/g;
+ mTerrainVB[(y+x*size)*9+1]=ay*a+mTerrainVB[(y+x*size)*9+1]*(1.0f-a);
+ }
+ }
+ }
+
+ // Borders
+ const float b = size/25.0f;
+ const float bd = size/2.0f-b;
+ for(PxU32 y=0;y<size;y++)
+ {
+ for(PxU32 x=0;x<size;x++)
+ {
+ const float x0 = fabsf(x-cx);
+ const float y0 = fabsf(y-cy);
+ if(x0 > bd || y0 > bd)
+ {
+ float a0 = (x0-bd)/b;
+ float a1 = (y0-bd)/b;
+ if(a1 > a0)
+ a0 = a1;
+ mTerrainVB[(y+x*size)*9+1]=20.0f*a0 + mTerrainVB[(y+x*size)*9+1]*(1-a0);
+ }
+ }
+ }
+
+ // Sobel filter
+ for(PxU32 y=1;y<size-1;y++)
+ {
+ for(PxU32 x=1;x<size-1;x++)
+ {
+ // 1 0 -1
+ // 2 0 -2
+ // 1 0 -1
+ float dx;
+ dx = mTerrainVB[((x-1)+(y-1)*size)*9+1];
+ dx -= mTerrainVB[((x+1)+(y-1)*size)*9+1];
+ dx += 2.0f*mTerrainVB[((x-1)+(y+0)*size)*9+1];
+ dx -= 2.0f*mTerrainVB[((x+1)+(y+0)*size)*9+1];
+ dx += mTerrainVB[((x-1)+(y+1)*size)*9+1];
+ dx -= mTerrainVB[((x+1)+(y+1)*size)*9+1];
+
+ // 1 2 1
+ // 0 0 0
+ // -1 -2 -1
+ float dy;
+ dy = mTerrainVB[((x-1)+(y-1)*size)*9+1];
+ dy += 2.0f*mTerrainVB[((x+0)+(y-1)*size)*9+1];
+ dy += mTerrainVB[((x+1)+(y-1)*size)*9+1];
+ dy -= mTerrainVB[((x-1)+(y+1)*size)*9+1];
+ dy -= 2.0f*mTerrainVB[((x+0)+(y+1)*size)*9+1];
+ dy -= mTerrainVB[((x+1)+(y+1)*size)*9+1];
+
+ const float nx = dx/width*0.15f;
+ const float ny = 1.0f;
+ const float nz = dy/width*0.15f;
+
+ const float len = sqrtf(nx*nx+ny*ny+nz*nz);
+
+ mTerrainVB[(x+y*size)*9+3] = nx/len;
+ mTerrainVB[(x+y*size)*9+4] = ny/len;
+ mTerrainVB[(x+y*size)*9+5] = nz/len;
+ }
+ }
+
+ // Static lighting (two directional lights)
+ const float l0[3] = {0.25f/0.8292f, 0.75f/0.8292f, 0.25f/0.8292f};
+ const float l1[3] = {0.65f/0.963f, 0.55f/0.963f, 0.45f/0.963f};
+ //const float len = sqrtf(l1[0]*l1[0]+l1[1]*l1[1]+l1[2]*l1[2]);
+ for(PxU32 y=0;y<size;y++)
+ {
+ for(PxU32 x=0;x<size;x++)
+ {
+ const float nx = mTerrainVB[(x+y*size)*9+3], ny = mTerrainVB[(x+y*size)*9+4], nz = mTerrainVB[(x+y*size)*9+5];
+
+ const float a = 0.3f;
+ float dot0 = l0[0]*nx + l0[1]*ny + l0[2]*nz;
+ float dot1 = l1[0]*nx + l1[1]*ny + l1[2]*nz;
+ if(dot0 < 0.0f) { dot0 = 0.0f; }
+ if(dot1 < 0.0f) { dot1 = 0.0f; }
+
+ const float l = dot0*0.7f + dot1*0.3f;
+
+ mTerrainVB[(x+y*size)*9+6] = mTerrainVB[(x+y*size)*9+6]*(l + a);
+ mTerrainVB[(x+y*size)*9+7] = mTerrainVB[(x+y*size)*9+7]*(l + a);
+ mTerrainVB[(x+y*size)*9+8] = mTerrainVB[(x+y*size)*9+8]*(l + a);
+
+ /*mTerrainVB[(x+y*size)*9+3] = 0.0f;
+ mTerrainVB[(x+y*size)*9+4] = -1.0f;
+ mTerrainVB[(x+y*size)*9+5] = 0.0f;*/
+ }
+ }
+
+ // Index buffers
+ const PxU32 maxNbTerrainTriangles = (size-1)*(size-1)*2;
+
+ mNbIB = 4;
+ mRenderMaterial[0] = MATERIAL_TERRAIN_MUD;
+ mRenderMaterial[1] = MATERIAL_ROAD_TARMAC;
+ mRenderMaterial[2] = MATERIAL_ROAD_SNOW;
+ mRenderMaterial[3] = MATERIAL_ROAD_GRASS;
+
+ for(PxU32 i=0;i<mNbIB;i++)
+ {
+ mIB[i] = (PxU32*)SAMPLE_ALLOC(sizeof(PxU32)*maxNbTerrainTriangles*3);
+ mNbTriangles[i] = 0;
+ }
+
+ for(PxU32 j=0;j<size-1;j++)
+ {
+ for(PxU32 i=0;i<size-1;i++)
+ {
+ PxU32 tris[6];
+ tris[0] = i + j*size; tris[1] = i + (j+1)*size; tris[2] = i+1 + (j+1)*size;
+ tris[3] = i + j*size; tris[4] = i+1 + (j+1)*size; tris[5] = i+1 + j*size;
+
+ for(PxU32 t=0;t<2;t++)
+ {
+ const PxU32 vt0 = tagBuffer[tris[t*3+0]];
+ const PxU32 vt1 = tagBuffer[tris[t*3+1]];
+ const PxU32 vt2 = tagBuffer[tris[t*3+2]];
+
+ PxU32 buffer = 0;
+ if(vt0 == vt1 && vt0 == vt2)
+ buffer = vt0;
+
+ mIB[buffer][mNbTriangles[buffer]*3+0] = tris[t*3+0];
+ mIB[buffer][mNbTriangles[buffer]*3+1] = tris[t*3+1];
+ mIB[buffer][mNbTriangles[buffer]*3+2] = tris[t*3+2];
+ mNbTriangles[buffer]++;
+ }
+ }
+ }
+
+ SAMPLE_FREE(tagBuffer);
+ SAMPLE_FREE(doneBuffer);
+}
+
+void SampleVehicle::addMesh(PxRigidActor* actor, float* verts, PxU32 nVerts, PxU32* indices, PxU32 mIndices, PxU32 materialIndex, const char* filename)
+{
+ const char* filenameCooked = getSampleOutputFilePath(filename, "");
+ PX_ASSERT(NULL != filenameCooked);
+
+ bool ok = false;
+ if(!gRecook)
+ {
+ SampleFramework::File* fp = NULL;
+ PxToolkit::fopen_s(&fp, filenameCooked, "rb");
+ if(fp)
+ {
+ fseek(fp, 0, SEEK_END);
+ PxU32 filesize = (PxU32)ftell(fp);
+
+ fclose(fp);
+
+
+ ok = (filesize != 0);
+ }
+ }
+
+ if(!ok)
+ {
+ PxTriangleMeshDesc meshDesc;
+ meshDesc.points.count = nVerts;
+ meshDesc.triangles.count = mIndices;
+ meshDesc.points.stride = sizeof(float)*3*3;
+ meshDesc.triangles.stride = sizeof(PxU32)*3;
+ meshDesc.points.data = verts;
+ meshDesc.triangles.data = indices;
+ meshDesc.flags = PxMeshFlags(0);
+
+ //
+ shdfnd::printFormatted("Cooking object... %s", filenameCooked);
+ PxDefaultFileOutputStream stream(filenameCooked);
+ ok = getCooking().cookTriangleMesh(meshDesc, stream);
+ shdfnd::printFormatted(" - Done\n");
+ }
+
+ {
+ PxDefaultFileInputData stream(filenameCooked);
+ PxTriangleMesh* triangleMesh = getPhysics().createTriangleMesh(stream);
+
+ if(triangleMesh)
+ {
+ PxRigidActorExt::createExclusiveShape(*actor, PxTriangleMeshGeometry(triangleMesh), *mStandardMaterials[materialIndex] /**mStandardMaterial*/);
+ }
+ }
+}
+
+// PT: the renderer also expects 16bit indices so we still have to cut a big mesh to pieces
+void SampleVehicle::addRenderMesh(float* verts, PxU32 nVerts, PxU32* indices, PxU32 mIndices, PxU32 matID)
+{
+ float minX=1000000.0f;
+ float minZ=1000000.0f;
+ float maxX=-1000000.0f;
+ float maxZ=-1000000.0f;
+
+ // PT: the VB uses interleaved data so we need a temp buffer
+ PxVec3Alloc* v = SAMPLE_NEW(PxVec3Alloc)[nVerts];
+ float* curVerts = verts;
+ PxBounds3 meshBound = PxBounds3::empty();
+ for(PxU32 i=0;i<nVerts;i++)
+ {
+ v[i].x = curVerts[0];
+ v[i].y = curVerts[1];
+ v[i].z = curVerts[2];
+ if (v[i].x < minX) { minX = v[i].x; }
+ if (v[i].z < minZ) { minZ = v[i].z; }
+ if (v[i].x > maxX) { maxX = v[i].x; }
+ if (v[i].z > maxZ) { maxZ = v[i].z; }
+ curVerts += 3*3;
+
+ meshBound.include(v[i]);
+ }
+
+ PxReal* uv = (PxReal*)SAMPLE_ALLOC(sizeof(PxReal)*nVerts*2);
+ curVerts = verts;
+ const float scaleX = (maxX-minX)/64.0f;
+ const float scaleZ = (maxZ-minZ)/64.0f;
+ for(PxU32 i=0;i<nVerts;i++)
+ {
+ uv[i*2+0] = (curVerts[0]-minX)/scaleX;
+ uv[i*2+1] = (curVerts[2]-minZ)/scaleZ;
+ curVerts += 3*3;
+ }
+
+ RAWMesh data;
+ data.mMaterialID = matID;
+ data.mNbVerts = nVerts;
+ data.mNbFaces = mIndices;
+ data.mVerts = v;
+ data.mUVs = uv;
+ data.mIndices = indices;
+ RenderMeshActor* renderActor = createRenderMeshFromRawMesh(data);
+ if( renderActor != NULL )
+ {
+ renderActor->setWorldBounds(meshBound);
+ renderActor->setEnableCameraCull(true);
+ }
+
+ SAMPLE_FREE(uv);
+ DELETEARRAY(v);
+}
+
+void SampleVehicle::createTrack(PxU32 size, float width, float chaos)
+{
+ createTerrain(size, width, chaos);
+ createLandscapeMesh();
+}
+
+void SampleVehicle::createLandscapeMesh()
+{
+ RAWTexture data;
+ data.mName = "gravel_diffuse.dds";
+ RenderTexture* gravelTexture = createRenderTextureFromRawTexture(data);
+
+ mTerrainMaterial = SAMPLE_NEW(RenderMaterial)(*getRenderer(), PxVec3(0.5f, 0.25f, 0.125f), 1.0f, false, MATERIAL_TERRAIN_MUD, gravelTexture);
+ mRenderMaterials.push_back(mTerrainMaterial);
+
+ data.mName = "asphalt_diffuse.dds";
+ RenderTexture* asphaltTexture = createRenderTextureFromRawTexture(data);
+
+ mRoadMaterial = SAMPLE_NEW(RenderMaterial)(*getRenderer(), PxVec3(1.0f, 1.0f, 1.0f), 1.0f, false, MATERIAL_ROAD_TARMAC, asphaltTexture);
+ mRenderMaterials.push_back(mRoadMaterial);
+
+ data.mName = "ice_diffuse.dds";
+ RenderTexture* snowTexture = createRenderTextureFromRawTexture(data);
+
+ mRoadIceMaterial = SAMPLE_NEW(RenderMaterial)(*getRenderer(), PxVec3(0.05f, 0.05f, 0.75f), 1.0f, false, MATERIAL_ROAD_SNOW, snowTexture);
+ mRenderMaterials.push_back(mRoadIceMaterial);
+
+ data.mName = "grass_diffuse.dds";
+ RenderTexture* grassTexture = createRenderTextureFromRawTexture(data);
+
+ mRoadGravelMaterial = SAMPLE_NEW(RenderMaterial)(*getRenderer(), PxVec3(1.0f, 1.0f, 1.0f), 1.0f, false, MATERIAL_ROAD_GRASS, grassTexture);
+ mRenderMaterials.push_back(mRoadGravelMaterial);
+
+ PxTransform pose;
+ pose = PxTransform(PxIdentity);
+// pose.p.y -= 10.0f;
+ mHFActor = getPhysics().createRigidStatic(pose);
+
+ for(PxU32 i=0;i<mNbIB;i++)
+ {
+ if(mNbTriangles[i] > 0)
+ {
+ char filename[512];
+ sprintf(filename, "SampleVehicleGroundMeshes_Part%d", i);
+ addMesh(mHFActor, mTerrainVB, mNbTerrainVerts, mIB[i], mNbTriangles[i], i, filename);
+ if (mNbTriangles[i] > (1<<16))
+ {
+ PxU32 firstBatch = mNbTriangles[i]/2;
+ addRenderMesh(mTerrainVB, mNbTerrainVerts, mIB[i], firstBatch, MATERIAL_TERRAIN_MUD);
+ addRenderMesh(mTerrainVB, mNbTerrainVerts, mIB[i]+(firstBatch*3), mNbTriangles[i]-firstBatch, mRenderMaterial[i]);
+ }
+ else
+ {
+ addRenderMesh(mTerrainVB, mNbTerrainVerts, mIB[i], mNbTriangles[i], mRenderMaterial[i]);
+ }
+ }
+ }
+
+ PxSceneWriteLock scopedLock(*mScene);
+ mScene->addActor(*mHFActor);
+
+ PxShape* shapeBuffer[MAX_NUM_INDEX_BUFFERS];
+ mHFActor->getShapes(shapeBuffer, MAX_NUM_INDEX_BUFFERS);
+ PxFilterData simulationFilterData;
+ simulationFilterData.word0=COLLISION_FLAG_GROUND;
+ simulationFilterData.word1=COLLISION_FLAG_GROUND_AGAINST;
+ PxFilterData queryFilterData;
+ SampleVehicleSetupDrivableShapeQueryFilterData(&queryFilterData);
+
+ for(PxU32 i=0;i<mNbIB;i++)
+ {
+ shapeBuffer[i]->setSimulationFilterData(simulationFilterData);
+ shapeBuffer[i]->setQueryFilterData(queryFilterData);
+ shapeBuffer[i]->setFlag(PxShapeFlag::eVISUALIZATION,false);
+ }
+}
diff --git a/PhysX_3.4/Samples/SampleVehicle/SampleVehicle_CameraController.cpp b/PhysX_3.4/Samples/SampleVehicle/SampleVehicle_CameraController.cpp
new file mode 100644
index 00000000..2bd6691d
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleVehicle/SampleVehicle_CameraController.cpp
@@ -0,0 +1,164 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#include "SampleVehicle_CameraController.h"
+#include "PhysXSampleApplication.h"
+#include "PxRigidDynamic.h"
+#include "PxQueryFiltering.h"
+#include "PxScene.h"
+#include "PxSceneLock.h"
+#include "vehicle/PxVehicleWheels.h"
+
+using namespace SampleRenderer;
+using namespace SampleFramework;
+
+///////////////////////////////////////////////////////////////////////////////
+
+
+
+SampleVehicle_CameraController::SampleVehicle_CameraController()
+: mRotateInputY (0.0f),
+ mRotateInputZ (0.0f),
+ mMaxCameraRotateSpeed (5.0f),
+ mCameraRotateAngleY (0.0f),
+ mCameraRotateAngleZ (0.33f),
+ mCameraPos (PxVec3(0,0,0)),
+ mCameraTargetPos (PxVec3(0,0,0)),
+ mLastCarPos (PxVec3(0,0,0)),
+ mLastCarVelocity (PxVec3(0,0,0)),
+ mCameraInit (false),
+ mLockOnFocusVehTransform (true),
+ mLastFocusVehTransform (PxTransform(PxIdentity))
+{
+}
+
+SampleVehicle_CameraController::~SampleVehicle_CameraController()
+{
+}
+
+static void dampVec3(const PxVec3& oldPosition, PxVec3& newPosition, PxF32 timestep)
+{
+ PxF32 t = 0.7f * timestep * 8.0f;
+ t = PxMin(t, 1.0f);
+ newPosition = oldPosition * (1 - t) + newPosition * t;
+}
+
+void SampleVehicle_CameraController::update(const PxReal dtime, const PxRigidDynamic* actor, PxScene& scene)
+{
+ PxSceneReadLock scopedLock(scene);
+ PxTransform carChassisTransfm;
+ if(mLockOnFocusVehTransform)
+ {
+ carChassisTransfm = actor->getGlobalPose();
+ mLastFocusVehTransform = carChassisTransfm;
+ }
+ else
+ {
+ carChassisTransfm = mLastFocusVehTransform;
+ }
+
+ PxF32 camDist = 15.0f;
+ PxF32 cameraYRotExtra = 0.0f;
+
+ PxVec3 velocity = mLastCarPos-carChassisTransfm.p;
+
+ if (mCameraInit)
+ {
+ //Work out the forward and sideways directions.
+ PxVec3 unitZ(0,0,1);
+ PxVec3 carDirection = carChassisTransfm.q.rotate(unitZ);
+ PxVec3 unitX(1,0,0);
+ PxVec3 carSideDirection = carChassisTransfm.q.rotate(unitX);
+
+ //Acceleration (note that is not scaled by time).
+ PxVec3 acclVec = mLastCarVelocity-velocity;
+
+ //Higher forward accelerations allow the car to speed away from the camera.
+ PxF32 acclZ = carDirection.dot(acclVec);
+ camDist = PxMax(camDist+acclZ*400.0f, 5.0f);
+
+ //Higher sideways accelerations allow the car's rotation to speed away from the camera's rotation.
+ PxF32 acclX = carSideDirection.dot(acclVec);
+ cameraYRotExtra = -acclX*10.0f;
+ //At very small sideways speeds the camera greatly amplifies any numeric error in the body and leads to a slight jitter.
+ //Scale cameraYRotExtra by a value in range (0,1) for side speeds in range (0.1,1.0) and by zero for side speeds less than 0.1.
+ PxFixedSizeLookupTable<4> table;
+ table.addPair(0.0f, 0.0f);
+ table.addPair(0.1f*dtime, 0);
+ table.addPair(1.0f*dtime, 1);
+ PxF32 velX = carSideDirection.dot(velocity);
+ cameraYRotExtra *= table.getYVal(PxAbs(velX));
+ }
+
+ mCameraRotateAngleY+=mRotateInputY*mMaxCameraRotateSpeed*dtime;
+ mCameraRotateAngleY=physx::intrinsics::fsel(mCameraRotateAngleY-10*PxPi, mCameraRotateAngleY-10*PxPi, physx::intrinsics::fsel(-mCameraRotateAngleY-10*PxPi, mCameraRotateAngleY + 10*PxPi, mCameraRotateAngleY));
+ mCameraRotateAngleZ+=mRotateInputZ*mMaxCameraRotateSpeed*dtime;
+ mCameraRotateAngleZ=PxClamp(mCameraRotateAngleZ,-PxPi*0.05f,PxPi*0.45f);
+
+ PxVec3 cameraDir=PxVec3(0,0,1)*PxCos(mCameraRotateAngleY+cameraYRotExtra) + PxVec3(1,0,0)*PxSin(mCameraRotateAngleY+cameraYRotExtra);
+
+ cameraDir=cameraDir*PxCos(mCameraRotateAngleZ)-PxVec3(0,1,0)*PxSin(mCameraRotateAngleZ);
+
+ const PxVec3 direction = carChassisTransfm.q.rotate(cameraDir);
+ PxVec3 target = carChassisTransfm.p;
+ target.y+=0.5f;
+
+ PxRaycastBuffer hit;
+ PxQueryFilterData filterData(PxQueryFlag::eSTATIC);
+ scene.raycast(target, -direction, camDist, hit, PxHitFlag::eDISTANCE, filterData);
+ if (hit.hasBlock && hit.block.shape != NULL)
+ {
+ camDist = hit.block.distance-0.25f;
+ }
+
+ camDist = PxMax(5.0f, PxMin(camDist, 50.0f));
+
+ PxVec3 position = target-direction*camDist;
+
+ if (mCameraInit)
+ {
+ dampVec3(mCameraPos, position, dtime);
+ dampVec3(mCameraTargetPos, target, dtime);
+ }
+
+ mCameraPos = position;
+ mCameraTargetPos = target;
+ mCameraInit = true;
+
+ mLastCarVelocity = velocity;
+ mLastCarPos = carChassisTransfm.p;
+}
+
+void SampleVehicle_CameraController::update(const PxReal dtime, const PxVehicleWheels& focusVehicle, PxScene& scene)
+{
+ const PxRigidDynamic* actor=focusVehicle.getRigidDynamicActor();
+ update(dtime,actor,scene);
+}
+
+
diff --git a/PhysX_3.4/Samples/SampleVehicle/SampleVehicle_CameraController.h b/PhysX_3.4/Samples/SampleVehicle/SampleVehicle_CameraController.h
new file mode 100644
index 00000000..fb00d0e7
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleVehicle/SampleVehicle_CameraController.h
@@ -0,0 +1,92 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+
+#ifndef SAMPLE_VEHICLE_CAMERA_CONTROLLER_H
+#define SAMPLE_VEHICLE_CAMERA_CONTROLLER_H
+
+#include "common/PxPhysXCommonConfig.h"
+#include "foundation/PxVec3.h"
+#include "foundation/PxTransform.h"
+
+using namespace physx;
+
+namespace physx
+{
+ class PxScene;
+ class PxVehicleWheels;
+ class PxRigidDynamic;
+}
+
+class Camera;
+
+class SampleVehicle_CameraController
+{
+public:
+
+ SampleVehicle_CameraController();
+ ~SampleVehicle_CameraController();
+
+ void setInputs(const PxF32 rotateInputY, const PxF32 rotateInputZ)
+ {
+ mRotateInputY=rotateInputY;
+ mRotateInputZ=rotateInputZ;
+ }
+
+ void update(const PxF32 dtime, const PxVehicleWheels& focusVehicle, PxScene& scene);
+
+ void restart() {}
+
+ bool getIsLockedOnVehicleTransform() const {return mLockOnFocusVehTransform;}
+ void toggleLockOnVehTransform() {mLockOnFocusVehTransform = !mLockOnFocusVehTransform;}
+
+ const PxVec3& getCameraPos() const {return mCameraPos;}
+ const PxVec3& getCameraTar() const {return mCameraTargetPos;}
+
+private:
+
+ PxF32 mRotateInputY;
+ PxF32 mRotateInputZ;
+
+ PxF32 mMaxCameraRotateSpeed;
+ PxF32 mCameraRotateAngleY;
+ PxF32 mCameraRotateAngleZ;
+ PxVec3 mCameraPos;
+ PxVec3 mCameraTargetPos;
+ PxVec3 mLastCarPos;
+ PxVec3 mLastCarVelocity;
+ bool mCameraInit;
+
+ bool mLockOnFocusVehTransform;
+ PxTransform mLastFocusVehTransform;
+
+ void update(const PxReal dtime, const PxRigidDynamic* actor, PxScene& scene);
+};
+
+#endif //SAMPLE_VEHICLE_CAMERA_CONTROLLER_H \ No newline at end of file
diff --git a/PhysX_3.4/Samples/SampleVehicle/SampleVehicle_ControlInputs.cpp b/PhysX_3.4/Samples/SampleVehicle/SampleVehicle_ControlInputs.cpp
new file mode 100644
index 00000000..648db019
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleVehicle/SampleVehicle_ControlInputs.cpp
@@ -0,0 +1,68 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#include "SampleVehicle_ControlInputs.h"
+#include "PhysXSampleApplication.h"
+
+using namespace SampleRenderer;
+using namespace SampleFramework;
+
+///////////////////////////////////////////////////////////////////////////////
+
+SampleVehicle_ControlInputs::SampleVehicle_ControlInputs()
+: mCameraRotateInputY (0.0f),
+ mCameraRotateInputZ (0.0f),
+ mAccelKeyPressed (false),
+ mGearUpKeyPressed (false),
+ mGearDownKeyPressed (false),
+ mBrakeKeyPressed (false),
+ mHandbrakeKeyPressed (false),
+ mSteerLeftKeyPressed (false),
+ mSteerRightKeyPressed (false),
+ mBrakeLeftKeyPressed (false),
+ mBrakeRightKeyPressed (false),
+ mThrustLeftKeyPressed (false),
+ mThrustRightKeyPressed (false),
+ mAccel (0.0f),
+ mGearup (false),
+ mGeardown (false),
+ mBrake (0.0f),
+ mSteer (0.0f),
+ mHandbrake (false),
+ mThrustLeft (0.0f),
+ mThrustRight (0.0f),
+ mBrakeLeft (0.0f),
+ mBrakeRight (0.0f)
+{
+}
+
+SampleVehicle_ControlInputs::~SampleVehicle_ControlInputs()
+{
+}
+
diff --git a/PhysX_3.4/Samples/SampleVehicle/SampleVehicle_ControlInputs.h b/PhysX_3.4/Samples/SampleVehicle/SampleVehicle_ControlInputs.h
new file mode 100644
index 00000000..3327cc8b
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleVehicle/SampleVehicle_ControlInputs.h
@@ -0,0 +1,145 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+
+#ifndef SAMPLE_VEHICLE_CONTROL_INPUTS_H
+#define SAMPLE_VEHICLE_CONTROL_INPUTS_H
+
+#include "common/PxPhysXCommonConfig.h"
+
+using namespace physx;
+
+class SampleVehicle_ControlInputs
+{
+public:
+
+ SampleVehicle_ControlInputs();
+ ~SampleVehicle_ControlInputs();
+
+ //Camera inputs
+ void setRotateY(const PxF32 f) {mCameraRotateInputY=f;}
+ void setRotateZ(const PxF32 f) {mCameraRotateInputZ=f;}
+ PxF32 getRotateY() const {return mCameraRotateInputY;}
+ PxF32 getRotateZ() const {return mCameraRotateInputZ;}
+
+ //Keyboard driving inputs - (car + tank)
+ void setAccelKeyPressed(const bool b) {mAccelKeyPressed=b;}
+ void setGearUpKeyPressed(const bool b) {mGearUpKeyPressed=b;}
+ void setGearDownKeyPressed(const bool b) {mGearDownKeyPressed=b;}
+ bool getAccelKeyPressed() const {return mAccelKeyPressed;}
+ bool getGearUpKeyPressed() const {return mGearUpKeyPressed;}
+ bool getGearDownKeyPressed() const {return mGearDownKeyPressed;}
+
+ //Keyboard driving inputs - (car only)
+ void setBrakeKeyPressed(const bool b) {mBrakeKeyPressed=b;}
+ void setHandbrakeKeyPressed(const bool b) {mHandbrakeKeyPressed=b;}
+ void setSteerLeftKeyPressed(const bool b) {mSteerLeftKeyPressed=b;}
+ void setSteerRightKeyPressed(const bool b) {mSteerRightKeyPressed=b;}
+ bool getBrakeKeyPressed() const {return mBrakeKeyPressed;}
+ bool getHandbrakeKeyPressed() const {return mHandbrakeKeyPressed;}
+ bool getSteerLeftKeyPressed() const {return mSteerLeftKeyPressed;}
+ bool getSteerRightKeyPressed() const {return mSteerRightKeyPressed;}
+
+ //Keyboard driving inputs - (tank only)
+ void setBrakeLeftKeyPressed(const bool b) {mBrakeLeftKeyPressed=b;}
+ void setBrakeRightKeyPressed(const bool b) {mBrakeRightKeyPressed=b;}
+ void setThrustLeftKeyPressed(const bool b) {mThrustLeftKeyPressed=b;}
+ void setThrustRightKeyPressed(const bool b) {mThrustRightKeyPressed=b;}
+ bool getBrakeLeftKeyPressed() const {return mBrakeLeftKeyPressed;}
+ bool getBrakeRightKeyPressed() const {return mBrakeRightKeyPressed;}
+ bool getThrustLeftKeyPressed() const {return mThrustLeftKeyPressed;}
+ bool getThrustRightKeyPressed() const {return mThrustRightKeyPressed;}
+
+ //Gamepad driving inputs (car + tank)
+ void setAccel(const PxF32 f) {mAccel=f;}
+ void setGearUp(const bool b) {mGearup=b;}
+ void setGearDown(const bool b) {mGeardown=b;}
+ PxF32 getAccel() const {return mAccel;}
+ bool getGearUp() const {return mGearup;}
+ bool getGearDown() const {return mGeardown;}
+
+ //Gamepad driving inputs (car only)
+ void setBrake(const PxF32 f) {mBrake=f;}
+ void setSteer(const PxF32 f) {mSteer=f;}
+ void setHandbrake(const bool b) {mHandbrake=b;}
+ PxF32 getBrake() const {return mBrake;}
+ PxF32 getSteer() const {return mSteer;}
+ bool getHandbrake() const {return mHandbrake;}
+
+ //Gamepad driving inputs (tank only)
+ void setThrustLeft(const PxF32 f) {mThrustLeft=f;}
+ void setThrustRight(const PxF32 f) {mThrustRight=f;}
+ PxF32 getThrustLeft() const {return mThrustLeft;}
+ PxF32 getThrustRight() const {return mThrustRight;}
+ void setBrakeLeft(const PxF32 f) {mBrakeLeft=f;}
+ void setBrakeRight(const PxF32 f) {mBrakeRight=f;}
+ PxF32 getBrakeLeft() const {return mBrakeLeft;}
+ PxF32 getBrakeRight() const {return mBrakeRight;}
+
+private:
+
+ //Camera inputs.
+ PxF32 mCameraRotateInputY;
+ PxF32 mCameraRotateInputZ;
+
+ //keyboard inputs (car and tank)
+ bool mAccelKeyPressed;
+ bool mGearUpKeyPressed;
+ bool mGearDownKeyPressed;
+
+ //keyboard inputs (car only)
+ bool mBrakeKeyPressed;
+ bool mHandbrakeKeyPressed;
+ bool mSteerLeftKeyPressed;
+ bool mSteerRightKeyPressed;
+
+ //keyboard inputs (tank only)
+ bool mBrakeLeftKeyPressed;
+ bool mBrakeRightKeyPressed;
+ bool mThrustLeftKeyPressed;
+ bool mThrustRightKeyPressed;
+
+ //gamepad inputs (car and tank)
+ PxF32 mAccel;
+ bool mGearup;
+ bool mGeardown;
+
+ //gamepad inputs (car only)
+ PxF32 mBrake;
+ PxF32 mSteer;
+ bool mHandbrake;
+
+ //gamepad inputs (tank only)
+ PxF32 mThrustLeft;
+ PxF32 mThrustRight;
+ PxF32 mBrakeLeft;
+ PxF32 mBrakeRight;
+};
+
+#endif //SAMPLE_VEHICLE_CONTROL_INPUTS_H \ No newline at end of file
diff --git a/PhysX_3.4/Samples/SampleVehicle/SampleVehicle_GameLogic.cpp b/PhysX_3.4/Samples/SampleVehicle/SampleVehicle_GameLogic.cpp
new file mode 100644
index 00000000..60864b4e
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleVehicle/SampleVehicle_GameLogic.cpp
@@ -0,0 +1,91 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#include "SampleVehicle_GameLogic.h"
+
+void SampleVehicleWayPoints::getNextWayPointsAndLineDirs(PxU32& numPoints, PxVec3& v0, PxVec3& v1, PxVec3& v2, PxVec3& w0, PxVec3& w1, PxVec3& w2) const
+{
+ numPoints=0;
+ if((mProgress+1) < mNumWayPoints)
+ {
+ v0=mWayPoints[mProgress+1].p;
+ w0=mWayPoints[mProgress+1].q.getBasisVector0();
+ numPoints++;
+
+ if((mProgress+2) < mNumWayPoints)
+ {
+ v1=mWayPoints[mProgress+2].p;
+ w1=mWayPoints[mProgress+2].q.getBasisVector0();
+ numPoints++;
+
+ if((mProgress+3) < mNumWayPoints)
+ {
+ v2=mWayPoints[mProgress+3].p;
+ w2=mWayPoints[mProgress+3].q.getBasisVector0();
+ numPoints++;
+ }
+ }
+ }
+}
+
+#define LINEWIDTH 8
+#define LINEDISTANCE2 3*3
+void SampleVehicleWayPoints::update(const PxTransform& playerTransform, const PxF32 timestep)
+{
+ //Increment the elapsed time
+ mTimeElapsed+=timestep;
+
+ //Work out the point on the crossing line of the next way-point that is closest to the player.
+ const PxTransform& nextWayPoint=mWayPoints[mProgress+1];
+ const PxVec3 v=nextWayPoint.p;
+ const PxVec3 w=nextWayPoint.q.getBasisVector0();
+ const PxVec3 p=playerTransform.p;
+ const PxVec3 pv=p-v;
+ const PxF32 t=pv.dot(w);
+
+ //Test if the player's position is inside the width of the line crossing the next way-point.
+ if(PxAbs(t) < LINEWIDTH)
+ {
+ //Now test if the shortest distance to the next crossing line is smaller than a threshold.
+ const PxVec3 linePos=v+w*t;
+ const PxVec3 diff=p-linePos;
+ const PxF32 dist2=diff.magnitudeSquared();
+ if(dist2<LINEDISTANCE2)
+ {
+ mProgress++;
+ }
+ }
+
+ if(mProgress == mNumWayPoints-1)
+ {
+ mMinTimeElapsed=PxMin(mTimeElapsed, mMinTimeElapsed);
+ mTimeElapsed=0;
+ mProgress=0;
+ }
+}
diff --git a/PhysX_3.4/Samples/SampleVehicle/SampleVehicle_GameLogic.h b/PhysX_3.4/Samples/SampleVehicle/SampleVehicle_GameLogic.h
new file mode 100644
index 00000000..c7870ce5
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleVehicle/SampleVehicle_GameLogic.h
@@ -0,0 +1,97 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+
+#ifndef SAMPLE_VEHICLE_GAME_LOGIC_H
+#define SAMPLE_VEHICLE_GAME_LOGIC_H
+
+#include "common/PxPhysXCommonConfig.h"
+#include "foundation/PxTransform.h"
+
+using namespace physx;
+
+class SampleVehicleWayPoints
+{
+public:
+
+ SampleVehicleWayPoints()
+ : mWayPoints(NULL),
+ mNumWayPoints(0),
+ mProgress(0),
+ mTimeElapsed(0),
+ mMinTimeElapsed(100000)
+ {
+ }
+
+ ~SampleVehicleWayPoints()
+ {
+ }
+
+ //Setup.
+ void setWayPoints(const PxTransform* wayPoints, const PxU32 numWayPoints)
+ {
+ mWayPoints=wayPoints;
+ mNumWayPoints=numWayPoints;
+ }
+
+ //Update.
+ void update(const PxTransform& playerTransform, const PxF32 timestep);
+
+ //Imagine we are starting the lap again.
+ PxTransform setBackAtStart()
+ {
+ mTimeElapsed=0;
+ mProgress=0;
+ return mWayPoints[0];
+ }
+
+ //Get the next three points and the crossing line of each way-point.
+ void getNextWayPointsAndLineDirs(PxU32& numPoints, PxVec3& v0, PxVec3& v1, PxVec3& v2, PxVec3& w0, PxVec3& w1, PxVec3& w2) const;
+
+ //Get lap time and best lap time.
+ PxF32 getTimeElapsed() const {return mTimeElapsed;}
+ PxF32 getMinTimeElapsed() const {return mMinTimeElapsed;}
+
+ //Get the transform to reset the car at the last passed way-point.
+ PxTransform getResetTransform() const {return mWayPoints[mProgress];}
+
+private:
+
+ //Array of way points.
+ const PxTransform* mWayPoints;
+ PxU32 mNumWayPoints;
+
+ //Progress and time elapsed.
+ PxU32 mProgress;
+ PxF32 mTimeElapsed;
+ PxF32 mMinTimeElapsed;
+};
+
+
+#endif //SAMPLE_VEHICLE_GAME_LOGIC_H \ No newline at end of file
diff --git a/PhysX_3.4/Samples/SampleVehicle/SampleVehicle_SceneQuery.cpp b/PhysX_3.4/Samples/SampleVehicle/SampleVehicle_SceneQuery.cpp
new file mode 100644
index 00000000..bd3a6896
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleVehicle/SampleVehicle_SceneQuery.cpp
@@ -0,0 +1,90 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#include "SampleVehicle_SceneQuery.h"
+#include "vehicle/PxVehicleSDK.h"
+#include "PxFiltering.h"
+#include "PsFoundation.h"
+#include "PsUtilities.h"
+
+#define CHECK_MSG(exp, msg) (!!(exp) || (physx::shdfnd::getFoundation().error(physx::PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__, msg), 0) )
+#define SIZEALIGN16(size) (((unsigned)(size)+15)&((unsigned)(~15)));
+
+void SampleVehicleSetupDrivableShapeQueryFilterData(PxFilterData* qryFilterData)
+{
+ CHECK_MSG(0==qryFilterData->word3, "word3 is reserved for filter data for vehicle raycast queries");
+ qryFilterData->word3 = (PxU32)SAMPLEVEHICLE_DRIVABLE_SURFACE;
+}
+
+void SampleVehicleSetupNonDrivableShapeQueryFilterData(PxFilterData* qryFilterData)
+{
+ CHECK_MSG(0==qryFilterData->word3, "word3 is reserved for filter data for vehicle raycast queries");
+ qryFilterData->word3 = (PxU32)SAMPLEVEHICLE_UNDRIVABLE_SURFACE;
+}
+
+void SampleVehicleSetupVehicleShapeQueryFilterData(PxFilterData* qryFilterData)
+{
+ CHECK_MSG(0==qryFilterData->word3, "word3 is reserved for filter data for vehicle raycast queries");
+ qryFilterData->word3 = (PxU32)SAMPLEVEHICLE_UNDRIVABLE_SURFACE;
+}
+
+SampleVehicleSceneQueryData* SampleVehicleSceneQueryData::allocate(const PxU32 maxNumWheels)
+{
+ const PxU32 size0 = SIZEALIGN16(sizeof(SampleVehicleSceneQueryData));
+ const PxU32 size1 = SIZEALIGN16(sizeof(PxRaycastQueryResult)*maxNumWheels);
+ const PxU32 size2 = SIZEALIGN16(sizeof(PxRaycastHit)*maxNumWheels);
+ const PxU32 size = size0 + size1 + size2;
+ SampleVehicleSceneQueryData* sqData = (SampleVehicleSceneQueryData*)PX_ALLOC(size, "PxVehicleNWSceneQueryData");
+ sqData->init();
+ PxU8* ptr = (PxU8*) sqData;
+ ptr += size0;
+ sqData->mSqResults = (PxRaycastQueryResult*)ptr;
+ sqData->mNbSqResults = maxNumWheels;
+ ptr += size1;
+ sqData->mSqHitBuffer = (PxRaycastHit*)ptr;
+ ptr += size2;
+ sqData->mNumQueries = maxNumWheels;
+ return sqData;
+}
+
+void SampleVehicleSceneQueryData::free()
+{
+ PX_FREE(this);
+}
+
+PxBatchQuery* SampleVehicleSceneQueryData::setUpBatchedSceneQuery(PxScene* scene)
+{
+ PxBatchQueryDesc sqDesc(mNbSqResults, 0, 0);
+ sqDesc.queryMemory.userRaycastResultBuffer = mSqResults;
+ sqDesc.queryMemory.userRaycastTouchBuffer = mSqHitBuffer;
+ sqDesc.queryMemory.raycastTouchBufferSize = mNumQueries;
+ sqDesc.preFilterShader = mPreFilterShader;
+ return scene->createBatchQuery(sqDesc);
+}
+
diff --git a/PhysX_3.4/Samples/SampleVehicle/SampleVehicle_SceneQuery.h b/PhysX_3.4/Samples/SampleVehicle/SampleVehicle_SceneQuery.h
new file mode 100644
index 00000000..a13f3c41
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleVehicle/SampleVehicle_SceneQuery.h
@@ -0,0 +1,132 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#ifndef SAMPLEVEHICLE_UTILSCENEQUERY_H
+#define SAMPLEVEHICLE_UTILSCENEQUERY_H
+
+#include "common/PxPhysXCommonConfig.h"
+#include "vehicle/PxVehicleSDK.h"
+#include "foundation/PxPreprocessor.h"
+#include "PxScene.h"
+#include "PxBatchQueryDesc.h"
+
+using namespace physx;
+
+//Make sure that suspension raycasts only consider shapes flagged as drivable that don't belong to the owner vehicle.
+enum
+{
+ SAMPLEVEHICLE_DRIVABLE_SURFACE = 0xffff0000,
+ SAMPLEVEHICLE_UNDRIVABLE_SURFACE = 0x0000ffff
+};
+
+static PxQueryHitType::Enum SampleVehicleWheelRaycastPreFilter(
+ PxFilterData filterData0,
+ PxFilterData filterData1,
+ const void* constantBlock, PxU32 constantBlockSize,
+ PxHitFlags& queryFlags)
+{
+ //filterData0 is the vehicle suspension raycast.
+ //filterData1 is the shape potentially hit by the raycast.
+ PX_UNUSED(queryFlags);
+ PX_UNUSED(constantBlockSize);
+ PX_UNUSED(constantBlock);
+ PX_UNUSED(filterData0);
+ return ((0 == (filterData1.word3 & SAMPLEVEHICLE_DRIVABLE_SURFACE)) ? PxQueryHitType::eNONE : PxQueryHitType::eBLOCK);
+}
+
+
+//Set up query filter data so that vehicles can drive on shapes with this filter data.
+//Note that we have reserved word3 of the PxFilterData for vehicle raycast query filtering.
+void SampleVehicleSetupDrivableShapeQueryFilterData(PxFilterData* qryFilterData);
+
+//Set up query filter data so that vehicles cannot drive on shapes with this filter data.
+//Note that we have reserved word3 of the PxFilterData for vehicle raycast query filtering.
+void SampleVehicleSetupNonDrivableShapeQueryFilterData(PxFilterData* qryFilterData);
+
+//Set up query filter data for the shapes of a vehicle to ensure that vehicles cannot drive on themselves
+//but can drive on the shapes of other vehicles.
+//Note that we have reserved word3 of the PxFilterData for vehicle raycast query filtering.
+void SampleVehicleSetupVehicleShapeQueryFilterData(PxFilterData* qryFilterData);
+
+//Data structure for quick setup of scene queries for suspension raycasts.
+class SampleVehicleSceneQueryData
+{
+public:
+
+ //Allocate scene query data for up to maxNumWheels suspension raycasts.
+ static SampleVehicleSceneQueryData* allocate(const PxU32 maxNumWheels);
+
+ //Free allocated buffer for scene queries of suspension raycasts.
+ void free();
+
+ //Create a PxBatchQuery instance that will be used as a single batched raycast of multiple suspension lines of multiple vehicles
+ PxBatchQuery* setUpBatchedSceneQuery(PxScene* scene);
+
+ //Get the buffer of scene query results that will be used by PxVehicleNWSuspensionRaycasts
+ PxRaycastQueryResult* getRaycastQueryResultBuffer() {return mSqResults;}
+
+ //Get the number of scene query results that have been allocated for use by PxVehicleNWSuspensionRaycasts
+ PxU32 getRaycastQueryResultBufferSize() const {return mNumQueries;}
+
+ //Set the pre-filter shader
+ void setPreFilterShader(PxBatchQueryPreFilterShader preFilterShader) {mPreFilterShader=preFilterShader;}
+
+private:
+
+ //One result for each wheel.
+ PxRaycastQueryResult* mSqResults;
+ PxU32 mNbSqResults;
+
+ //One hit for each wheel.
+ PxRaycastHit* mSqHitBuffer;
+
+ //Filter shader used to filter drivable and non-drivable surfaces
+ PxBatchQueryPreFilterShader mPreFilterShader;
+
+ //Maximum number of suspension raycasts that can be supported by the allocated buffers
+ //assuming a single query and hit per suspension line.
+ PxU32 mNumQueries;
+
+ void init()
+ {
+ mPreFilterShader=SampleVehicleWheelRaycastPreFilter;
+ }
+
+ SampleVehicleSceneQueryData()
+ {
+ init();
+ }
+
+ ~SampleVehicleSceneQueryData()
+ {
+ }
+};
+
+
+#endif //SAMPLEVEHICLE_UTILSCENEQUERY_H
diff --git a/PhysX_3.4/Samples/SampleVehicle/SampleVehicle_VehicleController.cpp b/PhysX_3.4/Samples/SampleVehicle/SampleVehicle_VehicleController.cpp
new file mode 100644
index 00000000..469b824c
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleVehicle/SampleVehicle_VehicleController.cpp
@@ -0,0 +1,840 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#include "SampleVehicle_VehicleController.h"
+#include "PhysXSample.h"
+#include "vehicle/PxVehicleDrive4W.h"
+#include "vehicle/PxVehicleDriveNW.h"
+#include "vehicle/PxVehicleUtilControl.h"
+#include "vehicle/PxVehicleUtil.h"
+
+using namespace SampleRenderer;
+using namespace SampleFramework;
+
+PxVehicleKeySmoothingData gKeySmoothingData=
+{
+ {
+ 3.0f, //rise rate eANALOG_INPUT_ACCEL
+ 3.0f, //rise rate eANALOG_INPUT_BRAKE
+ 10.0f, //rise rate eANALOG_INPUT_HANDBRAKE
+ 2.5f, //rise rate eANALOG_INPUT_STEER_LEFT
+ 2.5f, //rise rate eANALOG_INPUT_STEER_RIGHT
+ },
+ {
+ 5.0f, //fall rate eANALOG_INPUT__ACCEL
+ 5.0f, //fall rate eANALOG_INPUT__BRAKE
+ 10.0f, //fall rate eANALOG_INPUT__HANDBRAKE
+ 5.0f, //fall rate eANALOG_INPUT_STEER_LEFT
+ 5.0f //fall rate eANALOG_INPUT_STEER_RIGHT
+ }
+};
+
+PxVehiclePadSmoothingData gCarPadSmoothingData=
+{
+ {
+ 6.0f, //rise rate eANALOG_INPUT_ACCEL
+ 6.0f, //rise rate eANALOG_INPUT_BRAKE
+ 12.0f, //rise rate eANALOG_INPUT_HANDBRAKE
+ 2.5f, //rise rate eANALOG_INPUT_STEER_LEFT
+ 2.5f, //rise rate eANALOG_INPUT_STEER_RIGHT
+ },
+ {
+ 10.0f, //fall rate eANALOG_INPUT_ACCEL
+ 10.0f, //fall rate eANALOG_INPUT_BRAKE
+ 12.0f, //fall rate eANALOG_INPUT_HANDBRAKE
+ 5.0f, //fall rate eANALOG_INPUT_STEER_LEFT
+ 5.0f //fall rate eANALOG_INPUT_STEER_RIGHT
+ }
+};
+
+PxF32 gSteerVsForwardSpeedData[2*8]=
+{
+ 0.0f, 0.75f,
+ 5.0f, 0.75f,
+ 30.0f, 0.125f,
+ 120.0f, 0.1f,
+ PX_MAX_F32, PX_MAX_F32,
+ PX_MAX_F32, PX_MAX_F32,
+ PX_MAX_F32, PX_MAX_F32,
+ PX_MAX_F32, PX_MAX_F32
+};
+PxFixedSizeLookupTable<8> gSteerVsForwardSpeedTable(gSteerVsForwardSpeedData,4);
+
+//Tank smoothing data.
+PxVehiclePadSmoothingData gTankPadSmoothingData=
+{
+ {
+ 6.0f, //rise rate eTANK_ANALOG_INPUT_ACCEL
+ 6.0f, //rise rate eTANK_ANALOG_INPUT_BRAKE_LEFT
+ 6.0f, //rise rate eTANK_ANALOG_INPUT_BRAKE_RIGHT
+ 2.5f, //rise rate eTANK_ANALOG_INPUT_THRUST_LEFT
+ 2.5f, //rise rate eTANK_ANALOG_INPUT_THRUST_RIGHT
+ },
+ {
+ 10.0f, //fall rate eTANK_ANALOG_INPUT_ACCEL
+ 10.0f, //fall rate eTANK_ANALOG_INPUT_BRAKE_LEFT
+ 10.0f, //fall rate eTANK_ANALOG_INPUT_BRAKE_RIGHT
+ 5.0f, //fall rate eTANK_ANALOG_INPUT_THRUST_LEFT
+ 5.0f //fall rate eTANK_ANALOG_INPUT_THRUST_RIGHT
+ }
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+
+SampleVehicle_VehicleController::SampleVehicle_VehicleController()
+{
+ clear();
+}
+
+SampleVehicle_VehicleController::~SampleVehicle_VehicleController()
+{
+}
+
+void SampleVehicle_VehicleController::clear()
+{
+ mKeyPressedAccel = false;
+ mKeyPressedGearUp = false;
+ mKeyPressedGearDown = false;
+
+ mKeyPressedBrake = false;
+ mKeyPressedHandbrake = false;
+ mKeyPressedSteerLeft = false;
+ mKeyPressedSteerRight = false;
+
+ mKeyPressedThrustLeft = false;
+ mKeyPressedThrustRight = false;
+ mKeyPressedBrakeLeft = false;
+ mKeyPressedBrakeRight = false;
+
+ mGamepadAccel = 0.0f;
+ mGamepadGearup = false;
+ mGamepadGeardown = false;
+
+ mGamepadCarBrake = 0.0f;
+ mGamepadCarSteer = 0.0f;
+ mGamepadCarHandbrake = false;
+
+ mTankThrustLeft = 0.0f;
+ mTankThrustRight = 0.0f;
+ mTankBrakeLeft = 0.0f;
+ mTankBrakeRight = 0.0f;
+
+ mRecord = false;
+ mReplay = false;
+ mNumSamples = 0;
+ mNumRecordedSamples = 0;
+ mUseKeyInputs = true;
+ mToggleAutoGears = false;
+ mIsMovingForwardSlowly = true;
+ mInReverseMode = false;
+}
+
+
+/*
+bool SampleVehicle_VehicleController::processAutoReverse
+(const PxF32 timestep, const bool isInAir, const PxF32 forwardSpeed, const PxF32 sidewaysSpeed, const PxVehicleDriveTankRawInputData& rawInputData)
+{
+ //Keyboard controls for tank not implemented yet.
+ bool brakeLeft,brakeRight,accelLeft,accelRight;
+ if(mUseKeyInputs)
+ {
+ //Keyboard controls for tank not implemented yet.
+ brakeLeft=false;
+ brakeRight=false;
+ accelLeft=false;
+ accelRight=false;
+ }
+ else if(PxVehicleDriveTank::eDRIVE_MODEL_STANDARD==rawInputData.getDriveModel())
+ {
+ brakeLeft = mInReverseMode ? rawInputData.getAnalogLeftThrust() > 0 : rawInputData.getAnalogLeftBrake() > 0.0f;
+ brakeRight = mInReverseMode ? rawInputData.getAnalogRightThrust() > 0 : rawInputData.getAnalogRightBrake() > 0.0f;
+ accelLeft = mInReverseMode ? rawInputData.getAnalogLeftBrake() > 0 : rawInputData.getAnalogLeftThrust() > 0.0f;
+ accelRight = mInReverseMode ? rawInputData.getAnalogRightBrake() > 0 : rawInputData.getAnalogRightThrust() > 0.0f;
+ }
+ else
+ {
+ //Not much point in auto-reverse for tanks that can just spin both wheels backwards.
+ return false;
+ }
+
+ //If the car has been brought to rest by pressing the brake then raise a flag.
+ bool justRaisedFlag=false;
+ if(brakeLeft && brakeRight && !mAtRestUnderBraking)
+ {
+ if(!isInAir && forwardSpeed < THRESHOLD_FORWARD_SPEED && sidewaysSpeed < THRESHOLD_SIDEWAYS_SPEED)
+ {
+ justRaisedFlag=true;
+ mAtRestUnderBraking = true;
+ mTimeElapsedSinceAtRestUnderBraking = 0.0f;
+ }
+ }
+
+ //If the flag is raised and the player pressed accelerate then lower the flag.
+ if(mAtRestUnderBraking && (accelLeft || accelRight))
+ {
+ mAtRestUnderBraking = false;
+ mTimeElapsedSinceAtRestUnderBraking = 0.0f;
+ }
+
+ //If the flag is raised and the player doesn't press brake then increment the timer.
+ if(!brakeLeft && !brakeRight && mAtRestUnderBraking && !justRaisedFlag)
+ {
+ mTimeElapsedSinceAtRestUnderBraking += timestep;
+ }
+
+ //If the flag is raised and the player pressed brake again then switch auto-reverse.
+ if(brakeLeft && brakeRight && mAtRestUnderBraking && !justRaisedFlag && mTimeElapsedSinceAtRestUnderBraking > 0.0f)
+ {
+ mAtRestUnderBraking = false;
+ mTimeElapsedSinceAtRestUnderBraking = 0.0f;
+ return true;
+ }
+
+ return false;
+}
+*/
+
+void SampleVehicle_VehicleController::processRawInputs
+(const PxF32 dtime, const bool useAutoGears, PxVehicleDrive4WRawInputData& rawInputData)
+{
+ // Keyboard
+ {
+ if(mRecord)
+ {
+ if(mNumSamples<MAX_NUM_RECORD_REPLAY_SAMPLES)
+ {
+ mKeyboardAccelValues[mNumSamples] = mKeyPressedAccel;
+ mKeyboardBrakeValues[mNumSamples] = mKeyPressedBrake;
+ mKeyboardHandbrakeValues[mNumSamples] = mKeyPressedHandbrake;
+ mKeyboardSteerLeftValues[mNumSamples] = mKeyPressedSteerLeft;
+ mKeyboardSteerRightValues[mNumSamples] = mKeyPressedSteerRight;
+ mKeyboardGearupValues[mNumSamples] = mKeyPressedGearUp;
+ mKeyboardGeardownValues[mNumSamples] = mKeyPressedGearDown;
+ }
+ }
+ else if(mReplay)
+ {
+ if(mNumSamples<mNumRecordedSamples)
+ {
+ mKeyPressedAccel = mKeyboardAccelValues[mNumSamples];
+ mKeyPressedBrake = mKeyboardBrakeValues[mNumSamples];
+ mKeyPressedHandbrake = mKeyboardHandbrakeValues[mNumSamples];
+ mKeyPressedSteerLeft = mKeyboardSteerLeftValues[mNumSamples];
+ mKeyPressedSteerRight = mKeyboardSteerRightValues[mNumSamples];
+ mKeyPressedGearUp = mKeyboardGearupValues[mNumSamples];
+ mKeyPressedGearDown = mKeyboardGeardownValues[mNumSamples];
+ }
+ }
+
+ rawInputData.setDigitalAccel(mKeyPressedAccel);
+ rawInputData.setDigitalBrake(mKeyPressedBrake);
+ rawInputData.setDigitalHandbrake(mKeyPressedHandbrake);
+ rawInputData.setDigitalSteerLeft(mKeyPressedSteerLeft);
+ rawInputData.setDigitalSteerRight(mKeyPressedSteerRight);
+ rawInputData.setGearUp(mKeyPressedGearUp);
+ rawInputData.setGearDown(mKeyPressedGearDown);
+
+ mUseKeyInputs=
+ (mKeyPressedAccel || mKeyPressedBrake || mKeyPressedHandbrake ||
+ mKeyPressedSteerLeft || mKeyPressedSteerRight ||
+ mKeyPressedGearUp || mKeyPressedGearDown);
+ }
+
+ // Gamepad
+ {
+ if(mRecord)
+ {
+ if(mNumSamples<MAX_NUM_RECORD_REPLAY_SAMPLES)
+ {
+ mGamepadAccelValues[mNumSamples] = mGamepadAccel;
+ mGamepadCarBrakeValues[mNumSamples] = mGamepadCarBrake;
+ mGamepadCarSteerValues[mNumSamples] = mGamepadCarSteer;
+ mGamepadGearupValues[mNumSamples] = mGamepadGearup;
+ mGamepadGeardownValues[mNumSamples] = mGamepadGeardown;
+ mGamepadCarHandbrakeValues[mNumSamples] = mGamepadCarHandbrake;
+ }
+ }
+ else if(mReplay)
+ {
+ if(mNumSamples<mNumRecordedSamples)
+ {
+ mGamepadAccel = mGamepadAccelValues[mNumSamples];
+ mGamepadCarBrake = mGamepadCarBrakeValues[mNumSamples];
+ mGamepadCarSteer = mGamepadCarSteerValues[mNumSamples];
+ mGamepadGearup = mGamepadGearupValues[mNumSamples];
+ mGamepadGeardown = mGamepadGeardownValues[mNumSamples];
+ mGamepadCarHandbrake = mGamepadCarHandbrakeValues[mNumSamples];
+ }
+ }
+
+ if(mGamepadAccel<0.0f || mGamepadAccel>1.01f)
+ getSampleErrorCallback().reportError(PxErrorCode::eINTERNAL_ERROR, "Illegal accel value from gamepad", __FILE__, __LINE__);
+
+ if(mGamepadCarBrake<0.0f || mGamepadCarBrake>1.01f)
+ getSampleErrorCallback().reportError(PxErrorCode::eINTERNAL_ERROR, "Illegal brake value from gamepad", __FILE__, __LINE__);
+
+ if(PxAbs(mGamepadCarSteer)>1.01f)
+ getSampleErrorCallback().reportError(PxErrorCode::eINTERNAL_ERROR, "Illegal steer value from gamepad", __FILE__, __LINE__);
+
+ if(mUseKeyInputs && ((mGamepadAccel+mGamepadCarBrake+mGamepadCarSteer)!=0.0f || mGamepadGearup || mGamepadGeardown || mGamepadCarHandbrake))
+ {
+ mUseKeyInputs=false;
+ }
+
+ if(!mUseKeyInputs)
+ {
+ rawInputData.setAnalogAccel(mGamepadAccel);
+ rawInputData.setAnalogBrake(mGamepadCarBrake);
+ rawInputData.setAnalogHandbrake(mGamepadCarHandbrake ? 1.0f : 0.0f);
+ rawInputData.setAnalogSteer(mGamepadCarSteer);
+ rawInputData.setGearUp(mGamepadGearup);
+ rawInputData.setGearDown(mGamepadGeardown);
+ }
+ }
+
+ if(useAutoGears && (rawInputData.getGearDown() || rawInputData.getGearUp()))
+ {
+ rawInputData.setGearDown(false);
+ rawInputData.setGearUp(false);
+ }
+
+ mNumSamples++;
+}
+
+void SampleVehicle_VehicleController::processRawInputs
+(const PxF32 dtime, const bool useAutoGears, PxVehicleDriveTankRawInputData& rawInputData)
+{
+ // Keyboard
+ //Keyboard controls for tank not implemented yet.
+ {
+ /*
+ if(mRecord)
+ {
+ if(mNumSamples<MAX_NUM_RECORD_REPLAY_SAMPLES)
+ {
+ mKeyboardAccelValues[mNumSamples] = mAccelKeyPressed;
+ mKeyboardBrakeValues[mNumSamples] = mBrakeKeyPressed;
+ mKeyboardHandbrakeValues[mNumSamples] = mHandbrakeKeyPressed;
+ mKeyboardSteerLeftValues[mNumSamples] = mSteerLeftKeyPressed;
+ mKeyboardSteerRightValues[mNumSamples] = mSteerRightKeyPressed;
+ mKeyboardGearupValues[mNumSamples] = mGearUpKeyPressed;
+ mKeyboardGeardownValues[mNumSamples] = mGearDownKeyPressed;
+ }
+ }
+ else if(mReplay)
+ {
+ if(mNumSamples<mNumRecordedSamples)
+ {
+ mAccelKeyPressed = mKeyboardAccelValues[mNumSamples];
+ mBrakeKeyPressed = mKeyboardBrakeValues[mNumSamples];
+ mHandbrakeKeyPressed = mKeyboardHandbrakeValues[mNumSamples];
+ mSteerLeftKeyPressed = mKeyboardSteerLeftValues[mNumSamples];
+ mSteerRightKeyPressed = mKeyboardSteerRightValues[mNumSamples];
+ mGearUpKeyPressed = mKeyboardGearupValues[mNumSamples];
+ mGearDownKeyPressed = mKeyboardGeardownValues[mNumSamples];
+ }
+ }
+ */
+
+ rawInputData.setDigitalAccel(mKeyPressedAccel);
+ rawInputData.setDigitalLeftThrust(mKeyPressedThrustLeft);
+ rawInputData.setDigitalRightThrust(mKeyPressedThrustRight);
+ rawInputData.setDigitalLeftBrake(mKeyPressedBrakeLeft);
+ rawInputData.setDigitalRightBrake(mKeyPressedBrakeRight);
+ rawInputData.setGearUp(mKeyPressedGearUp);
+ rawInputData.setGearDown(mKeyPressedGearDown);
+
+ mUseKeyInputs=
+ (mKeyPressedAccel || mKeyPressedThrustLeft || mKeyPressedThrustRight ||
+ mKeyPressedBrakeLeft || mKeyPressedBrakeRight ||
+ mKeyPressedGearUp || mKeyPressedGearDown);
+ }
+
+
+ // Gamepad
+ {
+ if(mRecord)
+ {
+ if(mNumSamples<MAX_NUM_RECORD_REPLAY_SAMPLES)
+ {
+ mGamepadAccelValues[mNumSamples] = mGamepadAccel;
+ mGamepadTankThrustLeftValues[mNumSamples] = mTankThrustLeft;
+ mGamepadTankThrustRightValues[mNumSamples] = mTankThrustRight;
+ mGamepadGearupValues[mNumSamples] = mGamepadGearup;
+ mGamepadGeardownValues[mNumSamples] = mGamepadGeardown;
+ }
+ }
+ else if(mReplay)
+ {
+ if(mNumSamples<mNumRecordedSamples)
+ {
+ mGamepadAccel = mGamepadAccelValues[mNumSamples];
+ mTankThrustLeft = mGamepadTankThrustLeftValues[mNumSamples];
+ mTankThrustRight= mGamepadTankThrustRightValues[mNumSamples];
+ mGamepadGearup = mGamepadGearupValues[mNumSamples];
+ mGamepadGeardown = mGamepadGeardownValues[mNumSamples];
+ }
+ }
+
+ if(mGamepadAccel<0.0f || mGamepadAccel>1.01f)
+ getSampleErrorCallback().reportError(PxErrorCode::eINTERNAL_ERROR, "Illegal accel value from gamepad", __FILE__, __LINE__);
+
+ if(mTankThrustLeft<-1.01f || mTankThrustLeft>1.01f)
+ getSampleErrorCallback().reportError(PxErrorCode::eINTERNAL_ERROR, "Illegal brake value from gamepad", __FILE__, __LINE__);
+
+ if(mTankThrustRight<-1.01f || mTankThrustRight>1.01f)
+ getSampleErrorCallback().reportError(PxErrorCode::eINTERNAL_ERROR, "Illegal steer value from gamepad", __FILE__, __LINE__);
+
+ if(mUseKeyInputs && ((mGamepadAccel+mTankThrustLeft+mTankThrustRight)!=0.0f || mGamepadGearup || mGamepadGeardown))
+ {
+ mUseKeyInputs=false;
+ }
+
+ if(!mUseKeyInputs)
+ {
+ rawInputData.setAnalogAccel(mGamepadAccel);
+ rawInputData.setAnalogLeftThrust(mTankThrustLeft);
+ rawInputData.setAnalogRightThrust(mTankThrustRight);
+ rawInputData.setAnalogLeftBrake(mTankBrakeLeft);
+ rawInputData.setAnalogRightBrake(mTankBrakeRight);
+ rawInputData.setGearUp(mGamepadGearup);
+ rawInputData.setGearDown(mGamepadGeardown);
+ }
+ }
+
+ if(useAutoGears && (rawInputData.getGearDown() || rawInputData.getGearUp()))
+ {
+ rawInputData.setGearDown(false);
+ rawInputData.setGearUp(false);
+ }
+
+ mNumSamples++;
+}
+
+#define THRESHOLD_FORWARD_SPEED (0.1f)
+#define THRESHOLD_SIDEWAYS_SPEED (0.2f)
+#define THRESHOLD_ROLLING_BACKWARDS_SPEED (0.1f)
+
+void SampleVehicle_VehicleController::processAutoReverse
+(const PxVehicleWheels& focusVehicle, const PxVehicleDriveDynData& driveDynData, const PxVehicleWheelQueryResult& vehicleWheelQueryResults,
+ const PxVehicleDrive4WRawInputData& carRawInputs,
+ bool& toggleAutoReverse, bool& newIsMovingForwardSlowly) const
+{
+ newIsMovingForwardSlowly = false;
+ toggleAutoReverse = false;
+
+ if(driveDynData.getUseAutoGears())
+ {
+ //If the car is travelling very slowly in forward gear without player input and the player subsequently presses the brake then we want the car to go into reverse gear
+ //If the car is travelling very slowly in reverse gear without player input and the player subsequently presses the accel then we want the car to go into forward gear
+ //If the car is in forward gear and is travelling backwards then we want to automatically put the car into reverse gear.
+ //If the car is in reverse gear and is travelling forwards then we want to automatically put the car into forward gear.
+ //(If the player brings the car to rest with the brake the player needs to release the brake then reapply it
+ //to indicate they want to toggle between forward and reverse.)
+
+ const bool prevIsMovingForwardSlowly=mIsMovingForwardSlowly;
+ bool isMovingForwardSlowly=false;
+ bool isMovingBackwards=false;
+ const bool isInAir = PxVehicleIsInAir(vehicleWheelQueryResults);
+ if(!isInAir)
+ {
+ bool accelRaw,brakeRaw,handbrakeRaw;
+ if(mUseKeyInputs)
+ {
+ accelRaw=carRawInputs.getDigitalAccel();
+ brakeRaw=carRawInputs.getDigitalBrake();
+ handbrakeRaw=carRawInputs.getDigitalHandbrake();
+ }
+ else
+ {
+ accelRaw=carRawInputs.getAnalogAccel() > 0 ? true : false;
+ brakeRaw=carRawInputs.getAnalogBrake() > 0 ? true : false;
+ handbrakeRaw=carRawInputs.getAnalogHandbrake() > 0 ? true : false;
+ }
+
+ const PxF32 forwardSpeed = focusVehicle.computeForwardSpeed();
+ const PxF32 forwardSpeedAbs = PxAbs(forwardSpeed);
+ const PxF32 sidewaysSpeedAbs = PxAbs(focusVehicle.computeSidewaysSpeed());
+ const PxU32 currentGear = driveDynData.getCurrentGear();
+ const PxU32 targetGear = driveDynData.getTargetGear();
+
+ //Check if the car is rolling against the gear (backwards in forward gear or forwards in reverse gear).
+ if(PxVehicleGearsData::eFIRST == currentGear && forwardSpeed < -THRESHOLD_ROLLING_BACKWARDS_SPEED)
+ {
+ isMovingBackwards = true;
+ }
+ else if(PxVehicleGearsData::eREVERSE == currentGear && forwardSpeed > THRESHOLD_ROLLING_BACKWARDS_SPEED)
+ {
+ isMovingBackwards = true;
+ }
+
+ //Check if the car is moving slowly.
+ if(forwardSpeedAbs < THRESHOLD_FORWARD_SPEED && sidewaysSpeedAbs < THRESHOLD_SIDEWAYS_SPEED)
+ {
+ isMovingForwardSlowly=true;
+ }
+
+ //Now work if we need to toggle from forwards gear to reverse gear or vice versa.
+ if(isMovingBackwards)
+ {
+ if(!accelRaw && !brakeRaw && !handbrakeRaw && (currentGear == targetGear))
+ {
+ //The car is rolling against the gear and the player is doing nothing to stop this.
+ toggleAutoReverse = true;
+ }
+ }
+ else if(prevIsMovingForwardSlowly && isMovingForwardSlowly)
+ {
+ if((currentGear > PxVehicleGearsData::eNEUTRAL) && brakeRaw && !accelRaw && (currentGear == targetGear))
+ {
+ //The car was moving slowly in forward gear without player input and is now moving slowly with player input that indicates the
+ //player wants to switch to reverse gear.
+ toggleAutoReverse = true;
+ }
+ else if(currentGear == PxVehicleGearsData::eREVERSE && accelRaw && !brakeRaw && (currentGear == targetGear))
+ {
+ //The car was moving slowly in reverse gear without player input and is now moving slowly with player input that indicates the
+ //player wants to switch to forward gear.
+ toggleAutoReverse = true;
+ }
+ }
+
+ //If the car was brought to rest through braking then the player needs to release the brake then reapply
+ //to indicate that the gears should toggle between reverse and forward.
+ if(isMovingForwardSlowly && !brakeRaw && !accelRaw && !handbrakeRaw)
+ {
+ newIsMovingForwardSlowly = true;
+ }
+ }
+ }
+}
+
+void SampleVehicle_VehicleController::processAutoReverse
+(const PxVehicleWheels& focusVehicle, const PxVehicleDriveDynData& driveDynData, const PxVehicleWheelQueryResult& vehicleWheelQueryResults,
+ const PxVehicleDriveTankRawInputData& tankRawInputs,
+ bool& toggleAutoReverse, bool& newIsMovingForwardSlowly) const
+{
+ newIsMovingForwardSlowly = false;
+ toggleAutoReverse = false;
+
+ if(driveDynData.getUseAutoGears())
+ {
+ //If the car is travelling very slowly in forward gear without player input and the player subsequently presses the brake then we want the car to go into reverse gear
+ //If the car is travelling very slowly in reverse gear without player input and the player subsequently presses the accel then we want the car to go into forward gear
+ //If the car is in forward gear and is travelling backwards then we want to automatically put the car into reverse gear.
+ //If the car is in reverse gear and is travelling forwards then we want to automatically put the car into forward gear.
+ //(If the player brings the car to rest with the brake the player needs to release the brake then reapply it
+ //to indicate they want to toggle between forward and reverse.)
+
+ const bool prevIsMovingForwardSlowly=mIsMovingForwardSlowly;
+ bool isMovingForwardSlowly=false;
+ bool isMovingBackwards=false;
+ const bool isInAir = PxVehicleIsInAir(vehicleWheelQueryResults);
+ if(!isInAir)
+ {
+ bool accelLeft,accelRight,brakeLeft,brakeRight;
+ if(mUseKeyInputs)
+ {
+ accelLeft=tankRawInputs.getDigitalLeftThrust();
+ accelRight=tankRawInputs.getDigitalRightThrust();
+ brakeLeft=tankRawInputs.getDigitalLeftBrake();
+ brakeRight=tankRawInputs.getDigitalRightBrake();
+ }
+ else
+ {
+ accelLeft = tankRawInputs.getAnalogLeftThrust() > 0 ? true : false;
+ accelRight = tankRawInputs.getAnalogRightThrust() > 0 ? true : false;
+ brakeLeft = tankRawInputs.getAnalogLeftBrake() > 0 ? true : false;
+ brakeRight = tankRawInputs.getAnalogRightBrake() > 0 ? true : false;
+
+ /*
+ if(accelLeft && accelLeft==accelRight && !brakeLeft && !brakeRight)
+ {
+ shdfnd::printFormatted("aligned accel\n");
+ }
+
+ if(brakeLeft && brakeLeft==brakeRight && !accelLeft && !accelRight)
+ {
+ shdfnd::printFormatted("aligned brake\n");
+ }
+ */
+
+ }
+
+ const PxF32 forwardSpeed = focusVehicle.computeForwardSpeed();
+ const PxF32 forwardSpeedAbs = PxAbs(forwardSpeed);
+ const PxF32 sidewaysSpeedAbs = PxAbs(focusVehicle.computeSidewaysSpeed());
+ const PxU32 currentGear = driveDynData.getCurrentGear();
+ const PxU32 targetGear = driveDynData.getTargetGear();
+
+ //Check if the car is rolling against the gear (backwards in forward gear or forwards in reverse gear).
+ if(PxVehicleGearsData::eFIRST == currentGear && forwardSpeed < -THRESHOLD_ROLLING_BACKWARDS_SPEED)
+ {
+ isMovingBackwards = true;
+ }
+ else if(PxVehicleGearsData::eREVERSE == currentGear && forwardSpeed > THRESHOLD_ROLLING_BACKWARDS_SPEED)
+ {
+ isMovingBackwards = true;
+ }
+
+ //Check if the car is moving slowly.
+ if(forwardSpeedAbs < THRESHOLD_FORWARD_SPEED && sidewaysSpeedAbs < THRESHOLD_SIDEWAYS_SPEED)
+ {
+ isMovingForwardSlowly=true;
+ }
+
+ //Now work if we need to toggle from forwards gear to reverse gear or vice versa.
+ if(isMovingBackwards)
+ {
+ if(!accelLeft && !accelRight && !brakeLeft && !brakeRight && (currentGear == targetGear))
+ {
+ //The car is rolling against the gear and the player is doing nothing to stop this.
+ toggleAutoReverse = true;
+ }
+ }
+ else if(prevIsMovingForwardSlowly && isMovingForwardSlowly)
+ {
+ if((currentGear > PxVehicleGearsData::eNEUTRAL) && brakeLeft && brakeRight && !accelLeft && !accelRight && (currentGear == targetGear))
+ {
+ //The car was moving slowly in forward gear without player input and is now moving slowly with player input that indicates the
+ //player wants to switch to reverse gear.
+ toggleAutoReverse = true;
+ }
+ else if(currentGear == PxVehicleGearsData::eREVERSE && accelLeft && accelRight && !brakeLeft && !brakeRight && (currentGear == targetGear))
+ {
+ //The car was moving slowly in reverse gear without player input and is now moving slowly with player input that indicates the
+ //player wants to switch to forward gear.
+ toggleAutoReverse = true;
+ }
+ }
+
+ //If the car was brought to rest through braking then the player needs to release the brake then reapply
+ //to indicate that the gears should toggle between reverse and forward.
+ if(isMovingForwardSlowly && (!brakeLeft || !brakeRight) && (!accelLeft || !accelRight))
+ {
+ newIsMovingForwardSlowly = true;
+ }
+ }
+ }
+}
+
+void SampleVehicle_VehicleController::update(const PxF32 timestep, const PxVehicleWheelQueryResult& vehicleWheelQueryResults, PxVehicleWheels& focusVehicle)
+{
+ PxVehicleDriveDynData* driveDynData=NULL;
+ bool isTank=false;
+ PxVehicleDriveTankControlModel::Enum tankDriveModel=PxVehicleDriveTankControlModel::eSTANDARD;
+ switch(focusVehicle.getVehicleType())
+ {
+ case PxVehicleTypes::eDRIVE4W:
+ {
+ PxVehicleDrive4W& vehDrive4W=(PxVehicleDrive4W&)focusVehicle;
+ driveDynData=&vehDrive4W.mDriveDynData;
+ isTank=false;
+ }
+ break;
+ case PxVehicleTypes::eDRIVENW:
+ {
+ PxVehicleDriveNW& vehDriveNW=(PxVehicleDriveNW&)focusVehicle;
+ driveDynData=&vehDriveNW.mDriveDynData;
+ isTank=false;
+ }
+ break;
+ case PxVehicleTypes::eDRIVETANK:
+ {
+ PxVehicleDriveTank& vehDriveTank=(PxVehicleDriveTank&)focusVehicle;
+ driveDynData=&vehDriveTank.mDriveDynData;
+ isTank=true;
+ tankDriveModel=vehDriveTank.getDriveModel();
+ }
+ break;
+ default:
+ PX_ASSERT(false);
+ break;
+ }
+
+ //Toggle autogear flag
+ if(mToggleAutoGears)
+ {
+ driveDynData->toggleAutoGears();
+ mToggleAutoGears = false;
+ }
+
+ //Store raw inputs in replay stream if in recording mode.
+ //Set raw inputs from replay stream if in replay mode.
+ //Store raw inputs from active stream in handy arrays so we don't need to worry
+ //about which stream (live input or replay) is active.
+ //Work out if we are using keys or gamepad controls depending on which is being used
+ //(gamepad selected if both are being used).
+ PxVehicleDrive4WRawInputData carRawInputs;
+ PxVehicleDriveTankRawInputData tankRawInputs(tankDriveModel);
+ if(!isTank)
+ {
+ processRawInputs(timestep,driveDynData->getUseAutoGears(),carRawInputs);
+ }
+ else
+ {
+ processRawInputs(timestep,driveDynData->getUseAutoGears(),tankRawInputs);
+ }
+
+ //Work out if the car is to flip from reverse to forward gear or from forward gear to reverse.
+ bool toggleAutoReverse = false;
+ bool newIsMovingForwardSlowly = false;
+ if(!isTank)
+ {
+ processAutoReverse(focusVehicle, *driveDynData, vehicleWheelQueryResults, carRawInputs, toggleAutoReverse, newIsMovingForwardSlowly);
+ }
+ else
+ {
+ processAutoReverse(focusVehicle, *driveDynData, vehicleWheelQueryResults, tankRawInputs, toggleAutoReverse, newIsMovingForwardSlowly);
+ }
+ mIsMovingForwardSlowly = newIsMovingForwardSlowly;
+
+
+ //If the car is to flip gear direction then switch gear as appropriate.
+ if(toggleAutoReverse)
+ {
+ mInReverseMode = !mInReverseMode;
+
+ if(mInReverseMode)
+ {
+ driveDynData->forceGearChange(PxVehicleGearsData::eREVERSE);
+ }
+ else
+ {
+ driveDynData->forceGearChange(PxVehicleGearsData::eFIRST);
+ }
+ }
+
+ //If in reverse mode then swap the accel and brake.
+ if(mInReverseMode)
+ {
+ if(mUseKeyInputs)
+ {
+ if(!isTank)
+ {
+ const bool accel=carRawInputs.getDigitalAccel();
+ const bool brake=carRawInputs.getDigitalBrake();
+ carRawInputs.setDigitalAccel(brake);
+ carRawInputs.setDigitalBrake(accel);
+ }
+ else
+ {
+ //Keyboard controls for tank not implemented yet.
+ const bool accelLeft=tankRawInputs.getDigitalLeftThrust();
+ const bool accelRight=tankRawInputs.getDigitalRightThrust();
+ const bool brakeLeft=tankRawInputs.getDigitalLeftBrake();
+ const bool brakeRight=tankRawInputs.getDigitalRightBrake();
+ tankRawInputs.setDigitalLeftThrust(brakeLeft);
+ tankRawInputs.setDigitalRightThrust(brakeRight);
+ tankRawInputs.setDigitalLeftBrake(accelLeft);
+ tankRawInputs.setDigitalRightBrake(accelRight);
+ }
+ }
+ else
+ {
+ if(!isTank)
+ {
+ const PxF32 accel=carRawInputs.getAnalogAccel();
+ const PxF32 brake=carRawInputs.getAnalogBrake();
+ carRawInputs.setAnalogAccel(brake);
+ carRawInputs.setAnalogBrake(accel);
+ }
+ else if(PxVehicleDriveTankControlModel::eSPECIAL==tankDriveModel)
+ {
+ const PxF32 thrustLeft=tankRawInputs.getAnalogLeftThrust();
+ const PxF32 thrustRight=tankRawInputs.getAnalogRightThrust();
+ tankRawInputs.setAnalogLeftThrust(-thrustLeft);
+ tankRawInputs.setAnalogRightThrust(-thrustRight);
+ }
+ else
+ {
+ const PxF32 thrustLeft=tankRawInputs.getAnalogLeftThrust();
+ const PxF32 thrustRight=tankRawInputs.getAnalogRightThrust();
+ const PxF32 brakeLeft=tankRawInputs.getAnalogLeftBrake();
+ const PxF32 brakeRight=tankRawInputs.getAnalogRightBrake();
+ tankRawInputs.setAnalogLeftThrust(brakeLeft);
+ tankRawInputs.setAnalogLeftBrake(thrustLeft);
+ tankRawInputs.setAnalogRightThrust(brakeRight);
+ tankRawInputs.setAnalogRightBrake(thrustRight);
+ }
+ }
+ }
+
+ // Now filter the raw input values and apply them to focus vehicle
+ // as floats for brake,accel,handbrake,steer and bools for gearup,geardown.
+ if(mUseKeyInputs)
+ {
+ if(!isTank)
+ {
+ const bool isInAir = PxVehicleIsInAir(vehicleWheelQueryResults);
+ PxVehicleDrive4WSmoothDigitalRawInputsAndSetAnalogInputs
+ (gKeySmoothingData,gSteerVsForwardSpeedTable,carRawInputs,timestep,isInAir,(PxVehicleDrive4W&)focusVehicle);
+ }
+ else
+ {
+ PxVehicleDriveTankSmoothDigitalRawInputsAndSetAnalogInputs
+ (gKeySmoothingData,tankRawInputs,timestep,(PxVehicleDriveTank&)focusVehicle);
+ }
+ }
+ else
+ {
+ if(!isTank)
+ {
+ const bool isInAir = PxVehicleIsInAir(vehicleWheelQueryResults);
+ PxVehicleDrive4WSmoothAnalogRawInputsAndSetAnalogInputs
+ (gCarPadSmoothingData,gSteerVsForwardSpeedTable,carRawInputs,timestep,isInAir,(PxVehicleDrive4W&)focusVehicle);
+ }
+ else
+ {
+ PxVehicleDriveTankSmoothAnalogRawInputsAndSetAnalogInputs
+ (gTankPadSmoothingData,tankRawInputs,timestep,(PxVehicleDriveTank&)focusVehicle);
+ }
+ }
+}
+
+void SampleVehicle_VehicleController::restart()
+{
+ const bool record=mRecord;
+ const bool replay=mReplay;
+ const PxU32 numSamples=mNumSamples;
+ const PxU32 numRecordedSamples=mNumRecordedSamples;
+ clear();
+ mRecord=record;
+ mReplay=replay;
+ mNumRecordedSamples=numRecordedSamples;
+
+ if(record)
+ {
+ PX_ASSERT(!replay);
+ mNumRecordedSamples = numSamples;
+ mRecord = false;
+ mReplay = true;
+ }
+}
diff --git a/PhysX_3.4/Samples/SampleVehicle/SampleVehicle_VehicleController.h b/PhysX_3.4/Samples/SampleVehicle/SampleVehicle_VehicleController.h
new file mode 100644
index 00000000..d823ad5e
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleVehicle/SampleVehicle_VehicleController.h
@@ -0,0 +1,226 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+
+#ifndef SAMPLE_VEHICLE_VEHICLE_CONTROLLER_H
+#define SAMPLE_VEHICLE_VEHICLE_CONTROLLER_H
+
+#include "common/PxPhysXCommonConfig.h"
+#include "foundation/PxVec3.h"
+#include "vehicle/PxVehicleSDK.h"
+#include "vehicle/PxVehicleUpdate.h"
+#include "vehicle/PxVehicleUtilControl.h"
+
+using namespace physx;
+
+class SampleVehicle_VehicleController
+{
+public:
+
+ SampleVehicle_VehicleController();
+ ~SampleVehicle_VehicleController();
+
+ void setCarKeyboardInputs
+ (const bool accel, const bool brake, const bool handbrake,
+ const bool steerleft, const bool steerright,
+ const bool gearup, const bool geardown)
+ {
+ mKeyPressedAccel=accel;
+ mKeyPressedBrake=brake;
+ mKeyPressedHandbrake=handbrake;
+ mKeyPressedSteerLeft=steerleft;
+ mKeyPressedSteerRight=steerright;
+ mKeyPressedGearUp=gearup;
+ mKeyPressedGearDown=geardown;
+ }
+
+ void setCarGamepadInputs
+ (const PxF32 accel, const PxF32 brake,
+ const PxF32 steer,
+ const bool gearup, const bool geardown,
+ const bool handbrake)
+ {
+ mGamepadAccel=accel;
+ mGamepadCarBrake=brake;
+ mGamepadCarSteer=steer;
+ mGamepadGearup=gearup;
+ mGamepadGeardown=geardown;
+ mGamepadCarHandbrake=handbrake;
+ }
+
+ void setTankKeyboardInputs
+ (const bool accel, const bool thrustLeft, const bool thrustRight, const bool brakeLeft, const bool brakeRight, const bool gearUp, const bool gearDown)
+ {
+ mKeyPressedAccel=accel;
+ mKeyPressedThrustLeft=thrustLeft;
+ mKeyPressedThrustRight=thrustRight;
+ mKeyPressedBrakeLeft=brakeLeft;
+ mKeyPressedBrakeRight=brakeRight;
+ mKeyPressedGearUp=gearUp;
+ mKeyPressedGearDown=gearDown;
+ }
+
+ void setTankGamepadInputs
+ (const PxF32 accel, const PxF32 thrustLeft, const PxF32 thrustRight, const PxF32 brakeLeft, const PxF32 brakeRight, const bool gearUp, const bool gearDown)
+ {
+ mGamepadAccel=accel;
+ mTankThrustLeft=thrustLeft;
+ mTankThrustRight=thrustRight;
+ mTankBrakeLeft=brakeLeft;
+ mTankBrakeRight=brakeRight;
+ mGamepadGearup=gearUp;
+ mGamepadGeardown=gearDown;
+ }
+
+ void toggleAutoGearFlag()
+ {
+ mToggleAutoGears = true;
+ }
+
+ void update(const PxF32 dtime, const PxVehicleWheelQueryResult& vehicleWheelQueryResults, PxVehicleWheels& focusVehicle);
+
+ void clear();
+
+private:
+
+ //Raw driving inputs - keys (car + tank)
+ bool mKeyPressedAccel;
+ bool mKeyPressedGearUp;
+ bool mKeyPressedGearDown;
+
+ //Raw driving inputs - keys (car only)
+ bool mKeyPressedBrake;
+ bool mKeyPressedHandbrake;
+ bool mKeyPressedSteerLeft;
+ bool mKeyPressedSteerRight;
+
+ //Raw driving inputs - keys (tank only)
+ bool mKeyPressedThrustLeft;
+ bool mKeyPressedThrustRight;
+ bool mKeyPressedBrakeLeft;
+ bool mKeyPressedBrakeRight;
+
+ //Raw driving inputs - gamepad (car + tank)
+ PxF32 mGamepadAccel;
+ bool mGamepadGearup;
+ bool mGamepadGeardown;
+
+ //Raw driving inputs - gamepad (car only)
+ PxF32 mGamepadCarBrake;
+ PxF32 mGamepadCarSteer;
+ bool mGamepadCarHandbrake;
+
+ //Raw driving inputs - (tank only)
+ PxF32 mTankThrustLeft;
+ PxF32 mTankThrustRight;
+ PxF32 mTankBrakeLeft;
+ PxF32 mTankBrakeRight;
+
+ //Record and replay using raw driving inputs.
+ bool mRecord;
+ bool mReplay;
+ enum
+ {
+ MAX_NUM_RECORD_REPLAY_SAMPLES=8192
+ };
+ // Keyboard
+ bool mKeyboardAccelValues[MAX_NUM_RECORD_REPLAY_SAMPLES];
+ bool mKeyboardBrakeValues[MAX_NUM_RECORD_REPLAY_SAMPLES];
+ bool mKeyboardHandbrakeValues[MAX_NUM_RECORD_REPLAY_SAMPLES];
+ bool mKeyboardSteerLeftValues[MAX_NUM_RECORD_REPLAY_SAMPLES];
+ bool mKeyboardSteerRightValues[MAX_NUM_RECORD_REPLAY_SAMPLES];
+ bool mKeyboardGearupValues[MAX_NUM_RECORD_REPLAY_SAMPLES];
+ bool mKeyboardGeardownValues[MAX_NUM_RECORD_REPLAY_SAMPLES];
+ // Gamepad - (tank + car)
+ PxF32 mGamepadAccelValues[MAX_NUM_RECORD_REPLAY_SAMPLES];
+ bool mGamepadGearupValues[MAX_NUM_RECORD_REPLAY_SAMPLES];
+ bool mGamepadGeardownValues[MAX_NUM_RECORD_REPLAY_SAMPLES];
+ // Gamepad - car only
+ PxF32 mGamepadCarBrakeValues[MAX_NUM_RECORD_REPLAY_SAMPLES];
+ PxF32 mGamepadCarSteerValues[MAX_NUM_RECORD_REPLAY_SAMPLES];
+ bool mGamepadCarHandbrakeValues[MAX_NUM_RECORD_REPLAY_SAMPLES];
+ //Gamepad - tank only.
+ PxF32 mGamepadTankThrustLeftValues[MAX_NUM_RECORD_REPLAY_SAMPLES];
+ PxF32 mGamepadTankThrustRightValues[MAX_NUM_RECORD_REPLAY_SAMPLES];
+
+ PxU32 mNumSamples;
+ PxU32 mNumRecordedSamples;
+
+ // Raw data taken from the correct stream (live input stream or replay stream)
+ bool mUseKeyInputs;
+
+ // Toggle autogears flag on focus vehicle
+ bool mToggleAutoGears;
+
+ //Auto-reverse mode.
+ bool mIsMovingForwardSlowly;
+ bool mInReverseMode;
+
+ //Update
+ void processRawInputs(const PxF32 timestep, const bool useAutoGears, PxVehicleDrive4WRawInputData& rawInputData);
+ void processRawInputs(const PxF32 timestep, const bool useAutoGears, PxVehicleDriveTankRawInputData& rawInputData);
+ void processAutoReverse(
+ const PxVehicleWheels& focusVehicle, const PxVehicleDriveDynData& driveDynData, const PxVehicleWheelQueryResult& vehicleWheelQueryResults,
+ const PxVehicleDrive4WRawInputData& rawInputData,
+ bool& toggleAutoReverse, bool& newIsMovingForwardSlowly) const;
+ void processAutoReverse(
+ const PxVehicleWheels& focusVehicle, const PxVehicleDriveDynData& driveDynData, const PxVehicleWheelQueryResult& vehicleWheelQueryResults,
+ const PxVehicleDriveTankRawInputData& rawInputData,
+ bool& toggleAutoReverse, bool& newIsMovingForwardSlowly) const;
+
+ ////////////////////////////////
+ //Record and replay deprecated at the moment.
+ //Setting functions as private to avoid them being used.
+ ///////////////////////////////
+ bool getIsInRecordReplayMode() const {return (mRecord || mReplay);}
+ bool getIsRecording() const {return mRecord;}
+ bool getIsReplaying() const {return mReplay;}
+
+ void enableRecordReplayMode()
+ {
+ PX_ASSERT(!getIsInRecordReplayMode());
+ mRecord=true;
+ mReplay=false;
+ mNumRecordedSamples=0;
+ }
+
+ void disableRecordReplayMode()
+ {
+ PX_ASSERT(getIsInRecordReplayMode());
+ mRecord=false;
+ mReplay=false;
+ mNumRecordedSamples=0;
+ }
+
+ void restart();
+ ////////////////////////////
+
+};
+
+#endif //SAMPLE_VEHICLE_VEHICLE_CONTROLLER_H \ No newline at end of file
diff --git a/PhysX_3.4/Samples/SampleVehicle/SampleVehicle_VehicleCooking.cpp b/PhysX_3.4/Samples/SampleVehicle/SampleVehicle_VehicleCooking.cpp
new file mode 100644
index 00000000..3eacceaf
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleVehicle/SampleVehicle_VehicleCooking.cpp
@@ -0,0 +1,171 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#include "SampleVehicle_VehicleCooking.h"
+#include "PxTkStream.h"
+#include "extensions/PxDefaultStreams.h"
+
+
+PxConvexMesh* createConvexMesh(const PxVec3* verts, const PxU32 numVerts, PxPhysics& physics, PxCooking& cooking)
+{
+ // Create descriptor for convex mesh
+ PxConvexMeshDesc convexDesc;
+ convexDesc.points.count = numVerts;
+ convexDesc.points.stride = sizeof(PxVec3);
+ convexDesc.points.data = verts;
+ convexDesc.flags = PxConvexFlag::eCOMPUTE_CONVEX;
+
+ PxConvexMesh* convexMesh = NULL;
+ PxDefaultMemoryOutputStream buf;
+ if(cooking.cookConvexMesh(convexDesc, buf))
+ {
+ PxDefaultMemoryInputData id(buf.getData(), buf.getSize());
+ convexMesh = physics.createConvexMesh(id);
+ }
+
+ return convexMesh;
+}
+
+PxConvexMesh* createCuboidConvexMesh(const PxVec3& halfExtents, PxPhysics& physics, PxCooking& cooking)
+{
+ PxVec3 verts[8]=
+ {
+ PxVec3(-halfExtents.x, -halfExtents.y, -halfExtents.z),
+ PxVec3(-halfExtents.x, -halfExtents.y, +halfExtents.z),
+ PxVec3(-halfExtents.x, +halfExtents.y, -halfExtents.z),
+ PxVec3(-halfExtents.x, +halfExtents.y, +halfExtents.z),
+ PxVec3(+halfExtents.x, -halfExtents.y, -halfExtents.z),
+ PxVec3(+halfExtents.x, -halfExtents.y, +halfExtents.z),
+ PxVec3(+halfExtents.x, +halfExtents.y, -halfExtents.z),
+ PxVec3(+halfExtents.x, +halfExtents.y, +halfExtents.z)
+ };
+ PxU32 numVerts=8;
+
+ return createConvexMesh(verts,numVerts,physics,cooking);
+}
+
+PxConvexMesh* createWedgeConvexMesh(const PxVec3& halfExtents, PxPhysics& physics, PxCooking& cooking)
+{
+ PxVec3 verts[6]=
+ {
+ PxVec3(-halfExtents.x, -halfExtents.y, -halfExtents.z),
+ PxVec3(-halfExtents.x, -halfExtents.y, +halfExtents.z),
+ PxVec3(-halfExtents.x, +halfExtents.y, -halfExtents.z),
+ PxVec3(+halfExtents.x, -halfExtents.y, -halfExtents.z),
+ PxVec3(+halfExtents.x, -halfExtents.y, +halfExtents.z),
+ PxVec3(+halfExtents.x, +halfExtents.y, -halfExtents.z)
+ };
+ PxU32 numVerts=6;
+
+ return createConvexMesh(verts,numVerts,physics,cooking);
+}
+
+PxConvexMesh* createCylinderConvexMesh(const PxF32 width, const PxF32 radius, const PxU32 numCirclePoints, PxPhysics& physics, PxCooking& cooking)
+{
+#define MAX_NUM_VERTS_IN_CIRCLE 16
+ PX_ASSERT(numCirclePoints<MAX_NUM_VERTS_IN_CIRCLE);
+ PxVec3 verts[2*MAX_NUM_VERTS_IN_CIRCLE];
+ PxU32 numVerts=2*numCirclePoints;
+ const PxF32 dtheta=2*PxPi/(1.0f*numCirclePoints);
+ for(PxU32 i=0;i<MAX_NUM_VERTS_IN_CIRCLE;i++)
+ {
+ const PxF32 theta=dtheta*i;
+ const PxF32 cosTheta=radius*PxCos(theta);
+ const PxF32 sinTheta=radius*PxSin(theta);
+ verts[2*i+0]=PxVec3(-0.5f*width, cosTheta, sinTheta);
+ verts[2*i+1]=PxVec3(+0.5f*width, cosTheta, sinTheta);
+ }
+
+ return createConvexMesh(verts,numVerts,physics,cooking);
+}
+
+PxConvexMesh* createSquashedCuboidMesh(const PxF32 baseLength, const PxF32 baseDepth, const PxF32 height1, const PxF32 height2, PxPhysics& physics, PxCooking& cooking)
+{
+ const PxF32 x=baseLength*0.5f;
+ const PxF32 z=baseDepth*0.5f;
+ PxVec3 verts[8]=
+ {
+ PxVec3(-x,-0.5f*height1,-z),
+ PxVec3(-x,-0.5f*height1,+z),
+ PxVec3(+x,-0.5f*height1,-z),
+ PxVec3(+x,-0.5f*height1,+z),
+ PxVec3(-x,-0.5f*height1+height2,-z),
+ PxVec3(-x,+0.5f*height1,+z),
+ PxVec3(+x,-0.5f*height1+height2,-z),
+ PxVec3(+x,+0.5f*height1,+z)
+ };
+ PxU32 numVerts=8;
+
+ return createConvexMesh(verts,numVerts,physics,cooking);
+}
+
+
+PxConvexMesh* createPrismConvexMesh(const PxF32 baseLength, const PxF32 baseDepth, const PxF32 height, PxPhysics& physics, PxCooking& cooking)
+{
+ const PxF32 x=baseLength*0.5f;
+ const PxF32 z=baseDepth*0.5f;
+
+ PxVec3 verts[6]=
+ {
+ PxVec3(-x, 0, -z),
+ PxVec3(-x, 0, +z),
+ PxVec3(+x, 0, -z),
+ PxVec3(+x, 0, +z),
+ PxVec3(-x, height, 0),
+ PxVec3(+x, height, 0),
+ };
+ PxU32 numVerts=6;
+
+ return createConvexMesh(verts,numVerts,physics,cooking);
+}
+
+PxConvexMesh* createChassisConvexMesh(const PxVec3* verts, const PxU32 numVerts, PxPhysics& physics, PxCooking& cooking)
+{
+ return createConvexMesh(verts,numVerts,physics,cooking);
+}
+
+PxConvexMesh* createWheelConvexMesh(const PxVec3* verts, const PxU32 numVerts, PxPhysics& physics, PxCooking& cooking)
+{
+ //Extract the wheel radius and width from the aabb of the wheel convex mesh.
+ PxVec3 wheelMin(PX_MAX_F32,PX_MAX_F32,PX_MAX_F32);
+ PxVec3 wheelMax(-PX_MAX_F32,-PX_MAX_F32,-PX_MAX_F32);
+ for(PxU32 i=0;i<numVerts;i++)
+ {
+ wheelMin.x=PxMin(wheelMin.x,verts[i].x);
+ wheelMin.y=PxMin(wheelMin.y,verts[i].y);
+ wheelMin.z=PxMin(wheelMin.z,verts[i].z);
+ wheelMax.x=PxMax(wheelMax.x,verts[i].x);
+ wheelMax.y=PxMax(wheelMax.y,verts[i].y);
+ wheelMax.z=PxMax(wheelMax.z,verts[i].z);
+ }
+ const PxF32 wheelWidth=wheelMax.x-wheelMin.x;
+ const PxF32 wheelRadius=PxMax(wheelMax.y,wheelMax.z);
+
+ return createCylinderConvexMesh(wheelWidth,wheelRadius,8,physics,cooking);
+}
diff --git a/PhysX_3.4/Samples/SampleVehicle/SampleVehicle_VehicleCooking.h b/PhysX_3.4/Samples/SampleVehicle/SampleVehicle_VehicleCooking.h
new file mode 100644
index 00000000..053909c2
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleVehicle/SampleVehicle_VehicleCooking.h
@@ -0,0 +1,48 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#ifndef VEHICLE_COOKING_H
+#define VEHICLE_COOKING_H
+
+#include "PxPhysicsAPI.h"
+
+using namespace physx;
+
+
+PxConvexMesh* createConvexMesh(const PxVec3* verts, const PxU32 numVerts, PxPhysics& physics, PxCooking& cooking);
+PxConvexMesh* createCuboidConvexMesh(const PxVec3& halfExtents, PxPhysics& physics, PxCooking& cooking);
+PxConvexMesh* createWedgeConvexMesh(const PxVec3& halfExtents, PxPhysics& physics, PxCooking& cooking);
+PxConvexMesh* createCylinderConvexMesh(const PxF32 width, const PxF32 radius, const PxU32 numCirclePoints, PxPhysics& physics, PxCooking& cooking);
+PxConvexMesh* createSquashedCuboidMesh(const PxF32 baseLength, const PxF32 baseDepth, const PxF32 height1, const PxF32 height2, PxPhysics& physics, PxCooking& cooking);
+PxConvexMesh* createPrismConvexMesh(const PxF32 baseLength, const PxF32 baseDepth, const PxF32 height, PxPhysics& physics, PxCooking& cooking);
+PxConvexMesh* createWheelConvexMesh(const PxVec3* verts, const PxU32 numVerts, PxPhysics& physics, PxCooking& cooking);
+PxConvexMesh* createChassisConvexMesh(const PxVec3* verts, const PxU32 numVerts, PxPhysics& physics, PxCooking& cooking);
+
+
+#endif //VEHICLE_COOKING_H
diff --git a/PhysX_3.4/Samples/SampleVehicle/SampleVehicle_VehicleManager.cpp b/PhysX_3.4/Samples/SampleVehicle/SampleVehicle_VehicleManager.cpp
new file mode 100644
index 00000000..930804c8
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleVehicle/SampleVehicle_VehicleManager.cpp
@@ -0,0 +1,1171 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#include "SampleVehicle.h"
+#include "SampleVehicle_VehicleManager.h"
+#include "SampleVehicle_VehicleCooking.h"
+#include "SampleVehicle_SceneQuery.h"
+#include "SampleVehicle_WheelQueryResults.h"
+#include "RendererMemoryMacros.h"
+#include "vehicle/PxVehicleSDK.h"
+#include "vehicle/PxVehicleDrive4W.h"
+#include "vehicle/PxVehicleDriveNW.h"
+#include "vehicle/PxVehicleDriveTank.h"
+#include "vehicle/PxVehicleUpdate.h"
+#include "vehicle/PxVehicleTireFriction.h"
+#include "vehicle/PxVehicleUtilSetup.h"
+#include "PxRigidDynamic.h"
+#include "PxScene.h"
+#include "geometry/PxConvexMesh.h"
+#include "geometry/PxConvexMeshGeometry.h"
+#include "SampleAllocatorSDKClasses.h"
+
+#include "PxVehicleSerialization.h"
+
+///////////////////////////////////
+
+SampleVehicle_VehicleManager::SampleVehicle_VehicleManager()
+: mNumVehicles(0),
+ mSqWheelRaycastBatchQuery(NULL),
+ mIsIn3WMode(false),
+ mSerializationRegistry(NULL)
+{
+}
+
+SampleVehicle_VehicleManager::~SampleVehicle_VehicleManager()
+{
+}
+
+void SampleVehicle_VehicleManager::init(PxPhysics& physics, const PxMaterial** drivableSurfaceMaterials, const PxVehicleDrivableSurfaceType* drivableSurfaceTypes)
+{
+#if defined(SERIALIZE_VEHICLE_RPEX) || defined(SERIALIZE_VEHICLE_BINARY)
+ mSerializationRegistry = PxSerialization::createSerializationRegistry(physics);
+#endif
+
+ //Initialise the sdk.
+ PxInitVehicleSDK(physics, mSerializationRegistry);
+
+ //Set the basis vectors.
+ PxVec3 up(0,1,0);
+ PxVec3 forward(0,0,1);
+ PxVehicleSetBasisVectors(up,forward);
+
+ //Set the vehicle update mode to be immediate velocity changes.
+ PxVehicleSetUpdateMode(PxVehicleUpdateMode::eVELOCITY_CHANGE);
+
+ //Initialise all vehicle ptrs to null.
+ for(PxU32 i=0;i<MAX_NUM_4W_VEHICLES+MAX_NUM_6W_VEHICLES;i++)
+ {
+ mVehicles[i]=NULL;
+ }
+
+ //Allocate simulation data so we can switch from 3-wheeled to 4-wheeled cars by switching simulation data.
+ mWheelsSimData4W = PxVehicleWheelsSimData::allocate(4);
+
+ //Scene query data for to allow raycasts for all suspensions of all vehicles.
+ mSqData = SampleVehicleSceneQueryData::allocate(MAX_NUM_4W_VEHICLES*4 + MAX_NUM_6W_VEHICLES*6);
+
+ //Data to store reports for each wheel.
+ mWheelQueryResults = SampleVehicleWheelQueryResults::allocate(MAX_NUM_4W_VEHICLES*4 + MAX_NUM_6W_VEHICLES*6);
+
+ //Set up the friction values arising from combinations of tire type and surface type.
+ mSurfaceTirePairs=PxVehicleDrivableSurfaceToTireFrictionPairs::allocate(MAX_NUM_TIRE_TYPES,MAX_NUM_SURFACE_TYPES);
+ mSurfaceTirePairs->setup(MAX_NUM_TIRE_TYPES,MAX_NUM_SURFACE_TYPES,drivableSurfaceMaterials,drivableSurfaceTypes);
+ for(PxU32 i=0;i<MAX_NUM_SURFACE_TYPES;i++)
+ {
+ for(PxU32 j=0;j<MAX_NUM_TIRE_TYPES;j++)
+ {
+ mSurfaceTirePairs->setTypePairFriction(i,j,TireFrictionMultipliers::getValue(i, j));
+ }
+ }
+}
+
+void SampleVehicle_VehicleManager::shutdown()
+{
+ //Remove the N-wheeled vehicles.
+ for(PxU32 i=0;i<mNumVehicles;i++)
+ {
+ switch(mVehicles[i]->getVehicleType())
+ {
+ case PxVehicleTypes::eDRIVE4W:
+ {
+ PxVehicleDrive4W* veh=(PxVehicleDrive4W*)mVehicles[i];
+ veh->free();
+ }
+ break;
+ case PxVehicleTypes::eDRIVENW:
+ {
+ PxVehicleDriveNW* veh=(PxVehicleDriveNW*)mVehicles[i];
+ veh->free();
+ }
+ break;
+ case PxVehicleTypes::eDRIVETANK:
+ {
+ PxVehicleDriveTank* veh=(PxVehicleDriveTank*)mVehicles[i];
+ veh->free();
+ }
+ break;
+ default:
+ PX_ASSERT(false);
+ break;
+ }
+ }
+
+ //Deallocate simulation data that was used to switch from 3-wheeled to 4-wheeled cars by switching simulation data.
+ mWheelsSimData4W->free();
+
+ //Deallocate scene query data that was used for suspension raycasts.
+ mSqData->free();
+
+ //Deallocate buffers that store wheel reports.
+ mWheelQueryResults->free();
+
+ //Release the friction values used for combinations of tire type and surface type.
+ mSurfaceTirePairs->release();
+
+ //Scene query.
+ if(mSqWheelRaycastBatchQuery)
+ {
+ mSqWheelRaycastBatchQuery=NULL;
+ }
+
+ PxCloseVehicleSDK(mSerializationRegistry);
+
+ if(mSerializationRegistry)
+ mSerializationRegistry->release();
+}
+
+void SampleVehicle_VehicleManager::addVehicle(const PxU32 i, PxVehicleWheels* vehicle)
+{
+ mVehicles[i] = vehicle;
+
+ const PxU32 numWheels = vehicle->mWheelsSimData.getNbWheels();
+ mVehicleWheelQueryResults[i].nbWheelQueryResults = numWheels;
+ mVehicleWheelQueryResults[i].wheelQueryResults = mWheelQueryResults->addVehicle(numWheels);
+
+ mNumVehicles++;
+}
+
+
+void SampleVehicle_VehicleManager::resetNWCar(const PxTransform& transform, const PxU32 vehicleId)
+{
+ PX_ASSERT(vehicleId<mNumVehicles);
+ resetNWCar(transform,mVehicles[vehicleId]);
+}
+
+void SampleVehicle_VehicleManager::suspensionRaycasts(PxScene* scene)
+{
+ //Create a scene query if we haven't already done so.
+ if(NULL==mSqWheelRaycastBatchQuery)
+ {
+ mSqWheelRaycastBatchQuery=mSqData->setUpBatchedSceneQuery(scene);
+ }
+ //Raycasts.
+ PxSceneReadLock scopedLock(*scene);
+ PxVehicleSuspensionRaycasts(mSqWheelRaycastBatchQuery,mNumVehicles,mVehicles,mSqData->getRaycastQueryResultBufferSize(),mSqData->getRaycastQueryResultBuffer());
+}
+
+
+#if PX_DEBUG_VEHICLE_ON
+
+void SampleVehicle_VehicleManager::updateAndRecordTelemetryData
+(const PxF32 timestep, const PxVec3& gravity, PxVehicleWheels* focusVehicle, PxVehicleTelemetryData* telemetryData)
+{
+ PX_ASSERT(focusVehicle && telemetryData);
+
+ //Update all vehicles except for focusVehicle.
+ PxVehicleWheels* vehicles[MAX_NUM_4W_VEHICLES+MAX_NUM_6W_VEHICLES];
+ PxVehicleWheelQueryResult vehicleWheelQueryResults[MAX_NUM_4W_VEHICLES+MAX_NUM_6W_VEHICLES];
+ PxVehicleWheelQueryResult focusVehicleWheelQueryResults[1];
+ PxU32 numVehicles=0;
+ for(PxU32 i=0;i<mNumVehicles;i++)
+ {
+ if(focusVehicle!=mVehicles[i])
+ {
+ vehicles[numVehicles]=mVehicles[i];
+ vehicleWheelQueryResults[numVehicles]=mVehicleWheelQueryResults[i];
+ numVehicles++;
+ }
+ else
+ {
+ focusVehicleWheelQueryResults[0]=mVehicleWheelQueryResults[i];
+ }
+ }
+ PxVehicleUpdates(timestep,gravity,*mSurfaceTirePairs,numVehicles,vehicles,vehicleWheelQueryResults);
+
+
+ //Update the vehicle for which we want to record debug data.
+ PxVehicleUpdateSingleVehicleAndStoreTelemetryData(timestep,gravity,*mSurfaceTirePairs,focusVehicle,focusVehicleWheelQueryResults,*telemetryData);
+}
+
+#else
+
+void SampleVehicle_VehicleManager::update(const PxF32 timestep, const PxVec3& gravity)
+{
+ PxVehicleUpdates(timestep,gravity,*mSurfaceTirePairs,mNumVehicles,mVehicles,mVehicleWheelQueryResults);
+}
+
+#endif //PX_DEBUG_VEHICLE_ON
+
+void SampleVehicle_VehicleManager::resetNWCar(const PxTransform& startTransform, PxVehicleWheels* vehWheels)
+{
+ switch(vehWheels->getVehicleType())
+ {
+ case PxVehicleTypes::eDRIVE4W:
+ {
+ PxVehicleDrive4W* vehDrive4W=(PxVehicleDrive4W*)vehWheels;
+ //Set the car back to its rest state.
+ vehDrive4W->setToRestState();
+ //Set the car to first gear.
+ vehDrive4W->mDriveDynData.forceGearChange(PxVehicleGearsData::eFIRST);
+ }
+ break;
+ case PxVehicleTypes::eDRIVENW:
+ {
+ PxVehicleDriveNW* vehDriveNW=(PxVehicleDriveNW*)vehWheels;
+ //Set the car back to its rest state.
+ vehDriveNW->setToRestState();
+ //Set the car to first gear.
+ vehDriveNW->mDriveDynData.forceGearChange(PxVehicleGearsData::eFIRST);
+ }
+ break;
+ case PxVehicleTypes::eDRIVETANK:
+ {
+ PxVehicleDriveTank* vehDriveTank=(PxVehicleDriveTank*)vehWheels;
+ //Set the car back to its rest state.
+ vehDriveTank->setToRestState();
+ //Set the car to first gear.
+ vehDriveTank->mDriveDynData.forceGearChange(PxVehicleGearsData::eFIRST);
+ }
+ break;
+ default:
+ PX_ASSERT(false);
+ break;
+ }
+
+ //Set the car's transform to be the start transform.
+ PxRigidDynamic* actor=vehWheels->getRigidDynamicActor();
+ PxSceneWriteLock scopedLock(*actor->getScene());
+ actor->setGlobalPose(startTransform);
+}
+
+void setupActor
+(PxRigidDynamic* vehActor,
+ const PxFilterData& vehQryFilterData,
+ const PxGeometry** wheelGeometries, const PxTransform* wheelLocalPoses, const PxU32 numWheelGeometries, const PxMaterial* wheelMaterial, const PxFilterData& wheelCollFilterData,
+ const PxGeometry** chassisGeometries, const PxTransform* chassisLocalPoses, const PxU32 numChassisGeometries, const PxMaterial* chassisMaterial, const PxFilterData& chassisCollFilterData,
+ const PxVehicleChassisData& chassisData,
+ PxPhysics* physics)
+{
+ //Add all the wheel shapes to the actor.
+ for(PxU32 i=0;i<numWheelGeometries;i++)
+ {
+ PxShape* wheelShape=PxRigidActorExt::createExclusiveShape(*vehActor, *wheelGeometries[i],*wheelMaterial);
+ wheelShape->setQueryFilterData(vehQryFilterData);
+ wheelShape->setSimulationFilterData(wheelCollFilterData);
+ wheelShape->setLocalPose(wheelLocalPoses[i]);
+ }
+
+ //Add the chassis shapes to the actor.
+ for(PxU32 i=0;i<numChassisGeometries;i++)
+ {
+ PxShape* chassisShape=PxRigidActorExt::createExclusiveShape(*vehActor, *chassisGeometries[i],*chassisMaterial);
+ chassisShape->setQueryFilterData(vehQryFilterData);
+ chassisShape->setSimulationFilterData(chassisCollFilterData);
+ chassisShape->setLocalPose(chassisLocalPoses[i]);
+ }
+
+ vehActor->setMass(chassisData.mMass);
+ vehActor->setMassSpaceInertiaTensor(chassisData.mMOI);
+ vehActor->setCMassLocalPose(PxTransform(chassisData.mCMOffset,PxQuat(PxIdentity)));
+}
+
+PxRigidDynamic* createVehicleActor4W
+(const PxVehicleChassisData& chassisData,
+ PxConvexMesh** wheelConvexMeshes, PxConvexMesh* chassisConvexMesh,
+ PxScene& scene, PxPhysics& physics, const PxMaterial& material)
+{
+ //We need a rigid body actor for the vehicle.
+ //Don't forget to add the actor the scene after setting up the associated vehicle.
+ PxRigidDynamic* vehActor=physics.createRigidDynamic(PxTransform(PxIdentity));
+
+ //We need to add wheel collision shapes, their local poses, a material for the wheels, and a simulation filter for the wheels.
+ PxConvexMeshGeometry frontLeftWheelGeom(wheelConvexMeshes[0]);
+ PxConvexMeshGeometry frontRightWheelGeom(wheelConvexMeshes[1]);
+ PxConvexMeshGeometry rearLeftWheelGeom(wheelConvexMeshes[2]);
+ PxConvexMeshGeometry rearRightWheelGeom(wheelConvexMeshes[3]);
+ const PxGeometry* wheelGeometries[4]={&frontLeftWheelGeom,&frontRightWheelGeom,&rearLeftWheelGeom,&rearRightWheelGeom};
+ const PxTransform wheelLocalPoses[4]={PxTransform(PxIdentity),PxTransform(PxIdentity),PxTransform(PxIdentity),PxTransform(PxIdentity)};
+ const PxMaterial& wheelMaterial=material;
+ PxFilterData wheelCollFilterData;
+ wheelCollFilterData.word0=COLLISION_FLAG_WHEEL;
+ wheelCollFilterData.word1=COLLISION_FLAG_WHEEL_AGAINST;
+
+ //We need to add chassis collision shapes, their local poses, a material for the chassis, and a simulation filter for the chassis.
+ PxConvexMeshGeometry chassisConvexGeom(chassisConvexMesh);
+ const PxGeometry* chassisGeoms[1]={&chassisConvexGeom};
+ const PxTransform chassisLocalPoses[1]={PxTransform(PxIdentity)};
+ const PxMaterial& chassisMaterial=material;
+ PxFilterData chassisCollFilterData;
+ chassisCollFilterData.word0=COLLISION_FLAG_CHASSIS;
+ chassisCollFilterData.word1=COLLISION_FLAG_CHASSIS_AGAINST;
+
+ //Create a query filter data for the car to ensure that cars
+ //do not attempt to drive on themselves.
+ PxFilterData vehQryFilterData;
+ SampleVehicleSetupVehicleShapeQueryFilterData(&vehQryFilterData);
+
+ //Set up the physx rigid body actor with shapes, local poses, and filters.
+ setupActor
+ (vehActor,
+ vehQryFilterData,
+ wheelGeometries,wheelLocalPoses,4,&wheelMaterial,wheelCollFilterData,
+ chassisGeoms,chassisLocalPoses,1,&chassisMaterial,chassisCollFilterData,
+ chassisData,
+ &physics);
+
+ return vehActor;
+}
+
+void computeWheelWidthsAndRadii(PxConvexMesh** wheelConvexMeshes, PxF32* wheelWidths, PxF32* wheelRadii)
+{
+ for(PxU32 i=0;i<4;i++)
+ {
+ const PxU32 numWheelVerts=wheelConvexMeshes[i]->getNbVertices();
+ const PxVec3* wheelVerts=wheelConvexMeshes[i]->getVertices();
+ PxVec3 wheelMin(PX_MAX_F32,PX_MAX_F32,PX_MAX_F32);
+ PxVec3 wheelMax(-PX_MAX_F32,-PX_MAX_F32,-PX_MAX_F32);
+ for(PxU32 j=0;j<numWheelVerts;j++)
+ {
+ wheelMin.x=PxMin(wheelMin.x,wheelVerts[j].x);
+ wheelMin.y=PxMin(wheelMin.y,wheelVerts[j].y);
+ wheelMin.z=PxMin(wheelMin.z,wheelVerts[j].z);
+ wheelMax.x=PxMax(wheelMax.x,wheelVerts[j].x);
+ wheelMax.y=PxMax(wheelMax.y,wheelVerts[j].y);
+ wheelMax.z=PxMax(wheelMax.z,wheelVerts[j].z);
+ }
+ wheelWidths[i]=wheelMax.x-wheelMin.x;
+ wheelRadii[i]=PxMax(wheelMax.y,wheelMax.z)*0.975f;
+ }
+}
+
+PxVec3 computeChassisAABBDimensions(const PxConvexMesh* chassisConvexMesh)
+{
+ const PxU32 numChassisVerts=chassisConvexMesh->getNbVertices();
+ const PxVec3* chassisVerts=chassisConvexMesh->getVertices();
+ PxVec3 chassisMin(PX_MAX_F32,PX_MAX_F32,PX_MAX_F32);
+ PxVec3 chassisMax(-PX_MAX_F32,-PX_MAX_F32,-PX_MAX_F32);
+ for(PxU32 i=0;i<numChassisVerts;i++)
+ {
+ chassisMin.x=PxMin(chassisMin.x,chassisVerts[i].x);
+ chassisMin.y=PxMin(chassisMin.y,chassisVerts[i].y);
+ chassisMin.z=PxMin(chassisMin.z,chassisVerts[i].z);
+ chassisMax.x=PxMax(chassisMax.x,chassisVerts[i].x);
+ chassisMax.y=PxMax(chassisMax.y,chassisVerts[i].y);
+ chassisMax.z=PxMax(chassisMax.z,chassisVerts[i].z);
+ }
+ const PxVec3 chassisDims=chassisMax-chassisMin;
+ return chassisDims;
+}
+
+void createVehicle4WSimulationData
+(const PxF32 chassisMass, PxConvexMesh* chassisConvexMesh,
+ const PxF32 wheelMass, PxConvexMesh** wheelConvexMeshes, const PxVec3* wheelCentreOffsets,
+ PxVehicleWheelsSimData& wheelsData, PxVehicleDriveSimData4W& driveData, PxVehicleChassisData& chassisData)
+{
+ //Extract the chassis AABB dimensions from the chassis convex mesh.
+ const PxVec3 chassisDims=computeChassisAABBDimensions(chassisConvexMesh);
+
+ //The origin is at the center of the chassis mesh.
+ //Set the center of mass to be below this point and a little towards the front.
+ const PxVec3 chassisCMOffset=PxVec3(0.0f,-chassisDims.y*0.5f+0.65f,0.25f);
+
+ //Now compute the chassis mass and moment of inertia.
+ //Use the moment of inertia of a cuboid as an approximate value for the chassis moi.
+ PxVec3 chassisMOI
+ ((chassisDims.y*chassisDims.y + chassisDims.z*chassisDims.z)*chassisMass/12.0f,
+ (chassisDims.x*chassisDims.x + chassisDims.z*chassisDims.z)*chassisMass/12.0f,
+ (chassisDims.x*chassisDims.x + chassisDims.y*chassisDims.y)*chassisMass/12.0f);
+ //A bit of tweaking here. The car will have more responsive turning if we reduce the
+ //y-component of the chassis moment of inertia.
+ chassisMOI.y*=0.8f;
+
+ //Let's set up the chassis data structure now.
+ chassisData.mMass=chassisMass;
+ chassisData.mMOI=chassisMOI;
+ chassisData.mCMOffset=chassisCMOffset;
+
+ //Compute the sprung masses of each suspension spring using a helper function.
+ PxF32 suspSprungMasses[4];
+ PxVehicleComputeSprungMasses(4,wheelCentreOffsets,chassisCMOffset,chassisMass,1,suspSprungMasses);
+
+ //Extract the wheel radius and width from the wheel convex meshes.
+ PxF32 wheelWidths[4];
+ PxF32 wheelRadii[4];
+ computeWheelWidthsAndRadii(wheelConvexMeshes,wheelWidths,wheelRadii);
+
+ //Now compute the wheel masses and inertias components around the axle's axis.
+ //http://en.wikipedia.org/wiki/List_of_moments_of_inertia
+ PxF32 wheelMOIs[4];
+ for(PxU32 i=0;i<4;i++)
+ {
+ wheelMOIs[i]=0.5f*wheelMass*wheelRadii[i]*wheelRadii[i];
+ }
+ //Let's set up the wheel data structures now with radius, mass, and moi.
+ PxVehicleWheelData wheels[4];
+ for(PxU32 i=0;i<4;i++)
+ {
+ wheels[i].mRadius=wheelRadii[i];
+ wheels[i].mMass=wheelMass;
+ wheels[i].mMOI=wheelMOIs[i];
+ wheels[i].mWidth=wheelWidths[i];
+ }
+ //Disable the handbrake from the front wheels and enable for the rear wheels
+ wheels[PxVehicleDrive4WWheelOrder::eFRONT_LEFT].mMaxHandBrakeTorque=0.0f;
+ wheels[PxVehicleDrive4WWheelOrder::eFRONT_RIGHT].mMaxHandBrakeTorque=0.0f;
+ wheels[PxVehicleDrive4WWheelOrder::eREAR_LEFT].mMaxHandBrakeTorque=4000.0f;
+ wheels[PxVehicleDrive4WWheelOrder::eREAR_RIGHT].mMaxHandBrakeTorque=4000.0f;
+ //Enable steering for the front wheels and disable for the front wheels.
+ wheels[PxVehicleDrive4WWheelOrder::eFRONT_LEFT].mMaxSteer=PxPi*0.3333f;
+ wheels[PxVehicleDrive4WWheelOrder::eFRONT_RIGHT].mMaxSteer=PxPi*0.3333f;
+ wheels[PxVehicleDrive4WWheelOrder::eREAR_LEFT].mMaxSteer=0.0f;
+ wheels[PxVehicleDrive4WWheelOrder::eREAR_RIGHT].mMaxSteer=0.0f;
+
+ //Let's set up the tire data structures now.
+ //Put slicks on the front tires and wets on the rear tires.
+ PxVehicleTireData tires[4];
+ tires[PxVehicleDrive4WWheelOrder::eFRONT_LEFT].mType=TIRE_TYPE_SLICKS;
+ tires[PxVehicleDrive4WWheelOrder::eFRONT_RIGHT].mType=TIRE_TYPE_SLICKS;
+ tires[PxVehicleDrive4WWheelOrder::eREAR_LEFT].mType=TIRE_TYPE_WETS;
+ tires[PxVehicleDrive4WWheelOrder::eREAR_RIGHT].mType=TIRE_TYPE_WETS;
+
+ //Let's set up the suspension data structures now.
+ PxVehicleSuspensionData susps[4];
+ for(PxU32 i=0;i<4;i++)
+ {
+ susps[i].mMaxCompression=0.3f;
+ susps[i].mMaxDroop=0.1f;
+ susps[i].mSpringStrength=35000.0f;
+ susps[i].mSpringDamperRate=4500.0f;
+ }
+ susps[PxVehicleDrive4WWheelOrder::eFRONT_LEFT].mSprungMass=suspSprungMasses[PxVehicleDrive4WWheelOrder::eFRONT_LEFT];
+ susps[PxVehicleDrive4WWheelOrder::eFRONT_RIGHT].mSprungMass=suspSprungMasses[PxVehicleDrive4WWheelOrder::eFRONT_RIGHT];
+ susps[PxVehicleDrive4WWheelOrder::eREAR_LEFT].mSprungMass=suspSprungMasses[PxVehicleDrive4WWheelOrder::eREAR_LEFT];
+ susps[PxVehicleDrive4WWheelOrder::eREAR_RIGHT].mSprungMass=suspSprungMasses[PxVehicleDrive4WWheelOrder::eREAR_RIGHT];
+
+ //Set up the camber.
+ //Remember that the left and right wheels need opposite camber so that the car preserves symmetry about the forward direction.
+ //Set the camber to 0.0f when the spring is neither compressed or elongated.
+ const PxF32 camberAngleAtRest=0.0;
+ susps[PxVehicleDrive4WWheelOrder::eFRONT_LEFT].mCamberAtRest=camberAngleAtRest;
+ susps[PxVehicleDrive4WWheelOrder::eFRONT_RIGHT].mCamberAtRest=-camberAngleAtRest;
+ susps[PxVehicleDrive4WWheelOrder::eREAR_LEFT].mCamberAtRest=camberAngleAtRest;
+ susps[PxVehicleDrive4WWheelOrder::eREAR_RIGHT].mCamberAtRest=-camberAngleAtRest;
+ //Set the wheels to camber inwards at maximum droop (the left and right wheels almost form a V shape)
+ const PxF32 camberAngleAtMaxDroop=0.001f;
+ susps[PxVehicleDrive4WWheelOrder::eFRONT_LEFT].mCamberAtMaxDroop=camberAngleAtMaxDroop;
+ susps[PxVehicleDrive4WWheelOrder::eFRONT_RIGHT].mCamberAtMaxDroop=-camberAngleAtMaxDroop;
+ susps[PxVehicleDrive4WWheelOrder::eREAR_LEFT].mCamberAtMaxDroop=camberAngleAtMaxDroop;
+ susps[PxVehicleDrive4WWheelOrder::eREAR_RIGHT].mCamberAtMaxDroop=-camberAngleAtMaxDroop;
+ //Set the wheels to camber outwards at maximum compression (the left and right wheels almost form a A shape).
+ const PxF32 camberAngleAtMaxCompression=-0.001f;
+ susps[PxVehicleDrive4WWheelOrder::eFRONT_LEFT].mCamberAtMaxCompression=camberAngleAtMaxCompression;
+ susps[PxVehicleDrive4WWheelOrder::eFRONT_RIGHT].mCamberAtMaxCompression=-camberAngleAtMaxCompression;
+ susps[PxVehicleDrive4WWheelOrder::eREAR_LEFT].mCamberAtMaxCompression=camberAngleAtMaxCompression;
+ susps[PxVehicleDrive4WWheelOrder::eREAR_RIGHT].mCamberAtMaxCompression=-camberAngleAtMaxCompression;
+
+ //We need to set up geometry data for the suspension, wheels, and tires.
+ //We already know the wheel centers described as offsets from the actor center and the center of mass offset from actor center.
+ //From here we can approximate application points for the tire and suspension forces.
+ //Lets assume that the suspension travel directions are absolutely vertical.
+ //Also assume that we apply the tire and suspension forces 30cm below the center of mass.
+ PxVec3 suspTravelDirections[4]={PxVec3(0,-1,0),PxVec3(0,-1,0),PxVec3(0,-1,0),PxVec3(0,-1,0)};
+ PxVec3 wheelCentreCMOffsets[4];
+ PxVec3 suspForceAppCMOffsets[4];
+ PxVec3 tireForceAppCMOffsets[4];
+ for(PxU32 i=0;i<4;i++)
+ {
+ wheelCentreCMOffsets[i]=wheelCentreOffsets[i]-chassisCMOffset;
+ suspForceAppCMOffsets[i]=PxVec3(wheelCentreCMOffsets[i].x,-0.3f,wheelCentreCMOffsets[i].z);
+ tireForceAppCMOffsets[i]=PxVec3(wheelCentreCMOffsets[i].x,-0.3f,wheelCentreCMOffsets[i].z);
+ }
+
+ //Now add the wheel, tire and suspension data.
+ for(PxU32 i=0;i<4;i++)
+ {
+ wheelsData.setWheelData(i,wheels[i]);
+ wheelsData.setTireData(i,tires[i]);
+ wheelsData.setSuspensionData(i,susps[i]);
+ wheelsData.setSuspTravelDirection(i,suspTravelDirections[i]);
+ wheelsData.setWheelCentreOffset(i,wheelCentreCMOffsets[i]);
+ wheelsData.setSuspForceAppPointOffset(i,suspForceAppCMOffsets[i]);
+ wheelsData.setTireForceAppPointOffset(i,tireForceAppCMOffsets[i]);
+ }
+
+ //Set the car to perform 3 sub-steps when it moves with a forwards speed of less than 5.0
+ //and with a single step when it moves at speed greater than or equal to 5.0.
+ wheelsData.setSubStepCount(5.0f, 3, 1);
+
+
+ //Now set up the differential, engine, gears, clutch, and ackermann steering.
+
+ //Diff
+ PxVehicleDifferential4WData diff;
+ diff.mType=PxVehicleDifferential4WData::eDIFF_TYPE_LS_4WD;
+ driveData.setDiffData(diff);
+
+ //Engine
+ PxVehicleEngineData engine;
+ engine.mPeakTorque=500.0f;
+ engine.mMaxOmega=600.0f;//approx 6000 rpm
+ driveData.setEngineData(engine);
+
+ //Gears
+ PxVehicleGearsData gears;
+ gears.mSwitchTime=0.5f;
+ driveData.setGearsData(gears);
+
+ //Clutch
+ PxVehicleClutchData clutch;
+ clutch.mStrength=10.0f;
+ driveData.setClutchData(clutch);
+
+ //Ackermann steer accuracy
+ PxVehicleAckermannGeometryData ackermann;
+ ackermann.mAccuracy=1.0f;
+ ackermann.mAxleSeparation=wheelCentreOffsets[PxVehicleDrive4WWheelOrder::eFRONT_LEFT].z-wheelCentreOffsets[PxVehicleDrive4WWheelOrder::eREAR_LEFT].z;
+ ackermann.mFrontWidth=wheelCentreOffsets[PxVehicleDrive4WWheelOrder::eFRONT_RIGHT].x-wheelCentreOffsets[PxVehicleDrive4WWheelOrder::eFRONT_LEFT].x;
+ ackermann.mRearWidth=wheelCentreOffsets[PxVehicleDrive4WWheelOrder::eREAR_RIGHT].x-wheelCentreOffsets[PxVehicleDrive4WWheelOrder::eREAR_LEFT].x;
+ driveData.setAckermannGeometryData(ackermann);
+}
+
+void SampleVehicle_VehicleManager::create4WVehicle
+(PxScene& scene, PxPhysics& physics, PxCooking& cooking, const PxMaterial& material,
+ const PxF32 chassisMass, const PxVec3* wheelCentreOffsets4, PxConvexMesh* chassisConvexMesh, PxConvexMesh** wheelConvexMeshes4,
+ const PxTransform& startTransform, const bool useAutoGearFlag)
+{
+ PX_ASSERT(mNumVehicles<MAX_NUM_4W_VEHICLES);
+
+ PxVehicleWheelsSimData* wheelsSimData=PxVehicleWheelsSimData::allocate(4);
+ PxVehicleDriveSimData4W driveSimData;
+ PxVehicleChassisData chassisData;
+ createVehicle4WSimulationData
+ (chassisMass,chassisConvexMesh,
+ 20.0f,wheelConvexMeshes4,wheelCentreOffsets4,
+ *wheelsSimData,driveSimData,chassisData);
+
+ //Instantiate and finalize the vehicle using physx.
+ PxRigidDynamic* vehActor=createVehicleActor4W(chassisData,wheelConvexMeshes4,chassisConvexMesh,scene,physics,material);
+
+ //Create a car.
+ PxVehicleDrive4W* car = PxVehicleDrive4W::allocate(4);
+ car->setup(&physics,vehActor,*wheelsSimData,driveSimData,0);
+
+ //Free the sim data because we don't need that any more.
+ wheelsSimData->free();
+
+ //Don't forget to add the actor to the scene.
+ {
+ PxSceneWriteLock scopedLock(scene);
+ scene.addActor(*vehActor);
+ }
+
+
+ //Set up the mapping between wheel and actor shape.
+ car->mWheelsSimData.setWheelShapeMapping(0,0);
+ car->mWheelsSimData.setWheelShapeMapping(1,1);
+ car->mWheelsSimData.setWheelShapeMapping(2,2);
+ car->mWheelsSimData.setWheelShapeMapping(3,3);
+
+ //Set up the scene query filter data for each suspension line.
+ PxFilterData vehQryFilterData;
+ SampleVehicleSetupVehicleShapeQueryFilterData(&vehQryFilterData);
+ car->mWheelsSimData.setSceneQueryFilterData(0, vehQryFilterData);
+ car->mWheelsSimData.setSceneQueryFilterData(1, vehQryFilterData);
+ car->mWheelsSimData.setSceneQueryFilterData(2, vehQryFilterData);
+ car->mWheelsSimData.setSceneQueryFilterData(3, vehQryFilterData);
+
+ //Set the transform and the instantiated car and set it be to be at rest.
+ resetNWCar(startTransform,car);
+ //Set the autogear mode of the instantiate car.
+ car->mDriveDynData.setUseAutoGears(useAutoGearFlag);
+
+ //Increment the number of vehicles
+ mVehicles[mNumVehicles]=car;
+ mVehicleWheelQueryResults[mNumVehicles].nbWheelQueryResults=4;
+ mVehicleWheelQueryResults[mNumVehicles].wheelQueryResults=mWheelQueryResults->addVehicle(4);
+ mNumVehicles++;
+}
+
+PxRigidDynamic* createVehicleActor6W
+(const PxVehicleChassisData& chassisData,
+ PxConvexMesh** wheelConvexMeshes, PxConvexMesh* chassisConvexMesh,
+ PxScene& scene, PxPhysics& physics, const PxMaterial& material)
+{
+ PxTransform ident=PxTransform(PxIdentity);
+
+ //We need a rigid body actor for the vehicle.
+ //Don't forget to add the actor the scene after setting up the associated vehicle.
+ PxRigidDynamic* vehActor=physics.createRigidDynamic(PxTransform(PxIdentity));
+
+ //We need to add wheel collision shapes, their local poses, a material for the wheels, and a simulation filter for the wheels.
+ PxConvexMeshGeometry frontLeftWheelGeom(wheelConvexMeshes[0]);
+ PxConvexMeshGeometry frontRightWheelGeom(wheelConvexMeshes[1]);
+ PxConvexMeshGeometry rearLeftWheelGeom(wheelConvexMeshes[2]);
+ PxConvexMeshGeometry rearRightWheelGeom(wheelConvexMeshes[3]);
+ PxConvexMeshGeometry extraWheel0(wheelConvexMeshes[0]);
+ PxConvexMeshGeometry extraWheel1(wheelConvexMeshes[1]);
+ const PxGeometry* wheelGeoms[6]={&frontLeftWheelGeom,&frontRightWheelGeom,&rearLeftWheelGeom,&rearRightWheelGeom,&extraWheel0,&extraWheel1};
+ const PxTransform wheelLocalPoses[6]={ident,ident,ident,ident,ident,ident};
+ const PxMaterial& wheelMaterial=material;
+ PxFilterData wheelCollFilterData;
+ wheelCollFilterData.word0=COLLISION_FLAG_WHEEL;
+ wheelCollFilterData.word1=COLLISION_FLAG_WHEEL_AGAINST;
+
+ //We need to add chassis collision shapes, their local poses, a material for the chassis, and a simulation filter for the chassis.
+ PxConvexMeshGeometry chassisConvexGeom(chassisConvexMesh);
+ const PxGeometry* chassisGeoms[1]={&chassisConvexGeom};
+ const PxTransform chassisLocalPoses[1]={ident};
+ const PxMaterial& chassisMaterial=material;
+ PxFilterData chassisCollFilterData;
+ chassisCollFilterData.word0=COLLISION_FLAG_CHASSIS;
+ chassisCollFilterData.word1=COLLISION_FLAG_CHASSIS_AGAINST;
+
+ //Create a query filter data for the car to ensure that cars
+ //do not attempt to drive on themselves.
+ PxFilterData vehQryFilterData;
+ SampleVehicleSetupVehicleShapeQueryFilterData(&vehQryFilterData);
+
+ //Set up the physx rigid body actor with shapes, local poses, and filters.
+ setupActor(
+ vehActor,
+ vehQryFilterData,
+ wheelGeoms,wheelLocalPoses,6,&wheelMaterial,wheelCollFilterData,
+ chassisGeoms,chassisLocalPoses,1,&chassisMaterial,chassisCollFilterData,
+ chassisData,
+ &physics);
+
+ return vehActor;
+}
+
+void createVehicle6WSimulationData
+(const PxF32 chassisMass, const PxVec3* wheelCentreOffsets4, PxConvexMesh* chassisConvexMesh, PxConvexMesh** wheelConvexMeshes4,
+ PxVehicleWheelsSimData& wheelsSimData6W, PxVehicleDriveSimData4W& driveSimData6W, PxVehicleChassisData& chassisData6W)
+{
+ //Start by constructing the simulation data for a 4-wheeled vehicle.
+ PxVehicleWheelsSimData* wheelsSimData4W=PxVehicleWheelsSimData::allocate(4);
+ PxVehicleDriveSimData4W driveData4W;
+ PxVehicleChassisData chassisData4W;
+ createVehicle4WSimulationData(
+ chassisMass,chassisConvexMesh,
+ 20.0f,wheelConvexMeshes4,wheelCentreOffsets4,
+ *wheelsSimData4W,driveData4W,chassisData4W);
+
+ //Quickly setup the simulation data for the 6-wheeled vehicle.
+ //(this will copy wheel4 from wheel0 and wheel5 from wheel1).
+ driveSimData6W=driveData4W;
+ wheelsSimData6W.copy(*wheelsSimData4W,0,0);
+ wheelsSimData6W.copy(*wheelsSimData4W,1,1);
+ wheelsSimData6W.copy(*wheelsSimData4W,2,2);
+ wheelsSimData6W.copy(*wheelsSimData4W,3,3);
+ wheelsSimData6W.copy(*wheelsSimData4W,0,4);
+ wheelsSimData6W.copy(*wheelsSimData4W,1,5);
+ wheelsSimData6W.setTireLoadFilterData(wheelsSimData4W->getTireLoadFilterData());
+ chassisData6W = chassisData4W;
+
+ //Make sure that the two non-driven wheels don't respond to the handbrake.
+ PxVehicleWheelData wheelData;
+ wheelData=wheelsSimData6W.getWheelData(4);
+ wheelData.mMaxHandBrakeTorque=0.0f;
+ wheelsSimData6W.setWheelData(4,wheelData);
+ wheelData=wheelsSimData6W.getWheelData(5);
+ wheelData.mMaxHandBrakeTorque=0.0f;
+ wheelsSimData6W.setWheelData(5,wheelData);
+
+ //We've now got a 6-wheeled vehicle but the offsets of the 2 extra wheels are still incorrect.
+ //Lets set up the 2 extra wheels to lie on an axle that goes through the centre of the car
+ //and is parallel to the front and rear axles.
+ {
+ PxVec3 w;
+ PxF32 offsetLeft;
+ PxF32 offsetRight;
+
+ offsetLeft=0.5f*(wheelsSimData6W.getWheelCentreOffset(0).z+wheelsSimData6W.getWheelCentreOffset(2).z);
+ w=wheelsSimData4W->getWheelCentreOffset(0);
+ w.z=offsetLeft;
+ wheelsSimData6W.setWheelCentreOffset(4,w);
+ offsetRight=0.5f*(wheelsSimData6W.getWheelCentreOffset(1).z+wheelsSimData6W.getWheelCentreOffset(3).z);
+ w=wheelsSimData6W.getWheelCentreOffset(1);
+ w.z=offsetRight;
+ wheelsSimData6W.setWheelCentreOffset(5,w);
+
+ offsetLeft=0.5f*(wheelsSimData6W.getSuspForceAppPointOffset(0).z+wheelsSimData6W.getSuspForceAppPointOffset(2).z);
+ w=wheelsSimData4W->getSuspForceAppPointOffset(0);
+ w.z=offsetLeft;
+ wheelsSimData6W.setSuspForceAppPointOffset(4,w);
+ offsetRight=0.5f*(wheelsSimData6W.getSuspForceAppPointOffset(1).z+wheelsSimData6W.getSuspForceAppPointOffset(3).z);
+ w=wheelsSimData6W.getSuspForceAppPointOffset(1);
+ w.z=offsetRight;
+ wheelsSimData6W.setSuspForceAppPointOffset(5,w);
+
+ offsetLeft=0.5f*(wheelsSimData6W.getTireForceAppPointOffset(0).z+wheelsSimData6W.getTireForceAppPointOffset(2).z);
+ w=wheelsSimData4W->getTireForceAppPointOffset(0);
+ w.z=offsetLeft;
+ wheelsSimData6W.setTireForceAppPointOffset(4,w);
+ offsetRight=0.5f*(wheelsSimData6W.getTireForceAppPointOffset(1).z+wheelsSimData6W.getTireForceAppPointOffset(3).z);
+ w=wheelsSimData6W.getTireForceAppPointOffset(1);
+ w.z=offsetRight;
+ wheelsSimData6W.setTireForceAppPointOffset(5,w);
+ }
+
+ //The first 4 wheels were all set up to support a mass M but now that mass is
+ //distributed between 6 wheels. Adjust the suspension springs accordingly
+ //and try to preserve the natural frequency and damping ratio of the springs.
+ for(PxU32 i=0;i<4;i++)
+ {
+ PxVehicleSuspensionData suspData=wheelsSimData6W.getSuspensionData(i);
+ suspData.mSprungMass*=0.6666f;
+ suspData.mSpringStrength*=0.666f;
+ suspData.mSpringDamperRate*=0.666f;
+ wheelsSimData6W.setSuspensionData(i,suspData);
+ }
+ const PxF32 sprungMass=(wheelsSimData6W.getSuspensionData(0).mSprungMass+wheelsSimData6W.getSuspensionData(3).mSprungMass)/2.0f;
+ const PxF32 strength=(wheelsSimData6W.getSuspensionData(0).mSpringStrength+wheelsSimData6W.getSuspensionData(3).mSpringStrength)/2.0f;
+ const PxF32 damperRate=(wheelsSimData6W.getSuspensionData(0).mSpringDamperRate+wheelsSimData6W.getSuspensionData(3).mSpringDamperRate)/2.0f;
+ PxVehicleSuspensionData suspData4=wheelsSimData6W.getSuspensionData(4);
+ suspData4.mSprungMass=sprungMass;
+ suspData4.mSpringStrength=strength;
+ suspData4.mSpringDamperRate=damperRate;
+ wheelsSimData6W.setSuspensionData(4,suspData4);
+ PxVehicleSuspensionData suspData5=wheelsSimData6W.getSuspensionData(5);
+ suspData5.mSprungMass=sprungMass;
+ suspData5.mSpringStrength=strength;
+ suspData5.mSpringDamperRate=damperRate;
+ wheelsSimData6W.setSuspensionData(5,suspData5);
+
+ //Free the 4W sim data because we don't need this any more.
+ wheelsSimData4W->free();
+}
+
+
+void createVehicle6WSimulationData
+(const PxF32 chassisMass, const PxVec3* wheelCentreOffsets4, PxConvexMesh* chassisConvexMesh, PxConvexMesh** wheelConvexMeshes4,
+ PxVehicleWheelsSimData& wheelsSimData6W, PxVehicleDriveSimDataNW& driveSimData6W, PxVehicleChassisData& chassisData6W)
+{
+ //Start by constructing the simulation data for a 4-wheeled vehicle.
+ PxVehicleWheelsSimData* wheelsSimData4W=PxVehicleWheelsSimData::allocate(4);
+ PxVehicleDriveSimData4W driveData4W;
+ PxVehicleChassisData chassisData4W;
+ createVehicle4WSimulationData(
+ chassisMass,chassisConvexMesh,
+ 20.0f,wheelConvexMeshes4,wheelCentreOffsets4,
+ *wheelsSimData4W,driveData4W,chassisData4W);
+
+ //Quickly setup the simulation data for the 6-wheeled vehicle.
+ //(this will copy wheel4 from wheel0 and wheel5 from wheel1).
+ driveSimData6W.setAutoBoxData(driveData4W.getAutoBoxData());
+ driveSimData6W.setClutchData(driveData4W.getClutchData());
+ driveSimData6W.setEngineData(driveData4W.getEngineData());
+ driveSimData6W.setGearsData(driveData4W.getGearsData());
+ PxVehicleDifferentialNWData diffNW;
+ diffNW.setDrivenWheel(0,true);
+ diffNW.setDrivenWheel(1,true);
+ diffNW.setDrivenWheel(2,true);
+ diffNW.setDrivenWheel(3,true);
+ diffNW.setDrivenWheel(4,true);
+ diffNW.setDrivenWheel(5,true);
+ driveSimData6W.setDiffData(diffNW);
+ wheelsSimData6W.copy(*wheelsSimData4W,0,0);
+ wheelsSimData6W.copy(*wheelsSimData4W,1,1);
+ wheelsSimData6W.copy(*wheelsSimData4W,2,2);
+ wheelsSimData6W.copy(*wheelsSimData4W,3,3);
+ wheelsSimData6W.copy(*wheelsSimData4W,0,4);
+ wheelsSimData6W.copy(*wheelsSimData4W,1,5);
+ wheelsSimData6W.setTireLoadFilterData(wheelsSimData4W->getTireLoadFilterData());
+ chassisData6W = chassisData4W;
+
+ //Make sure that the two non-driven wheels don't respond to the handbrake.
+ PxVehicleWheelData wheelData;
+ wheelData=wheelsSimData6W.getWheelData(4);
+ wheelData.mMaxHandBrakeTorque=0.0f;
+ wheelsSimData6W.setWheelData(4,wheelData);
+ wheelData=wheelsSimData6W.getWheelData(5);
+ wheelData.mMaxHandBrakeTorque=0.0f;
+ wheelsSimData6W.setWheelData(5,wheelData);
+
+ //We've now got a 6-wheeled vehicle but the offsets of the 2 extra wheels are still incorrect.
+ //Lets set up the 2 extra wheels to lie on an axle that goes through the centre of the car
+ //and is parallel to the front and rear axles.
+ {
+ PxVec3 w;
+ PxF32 offsetLeft;
+ PxF32 offsetRight;
+
+ offsetLeft=0.5f*(wheelsSimData6W.getWheelCentreOffset(0).z+wheelsSimData6W.getWheelCentreOffset(2).z);
+ w=wheelsSimData4W->getWheelCentreOffset(0);
+ w.z=offsetLeft;
+ wheelsSimData6W.setWheelCentreOffset(4,w);
+ offsetRight=0.5f*(wheelsSimData6W.getWheelCentreOffset(1).z+wheelsSimData6W.getWheelCentreOffset(3).z);
+ w=wheelsSimData6W.getWheelCentreOffset(1);
+ w.z=offsetRight;
+ wheelsSimData6W.setWheelCentreOffset(5,w);
+
+ offsetLeft=0.5f*(wheelsSimData6W.getSuspForceAppPointOffset(0).z+wheelsSimData6W.getSuspForceAppPointOffset(2).z);
+ w=wheelsSimData4W->getSuspForceAppPointOffset(0);
+ w.z=offsetLeft;
+ wheelsSimData6W.setSuspForceAppPointOffset(4,w);
+ offsetRight=0.5f*(wheelsSimData6W.getSuspForceAppPointOffset(1).z+wheelsSimData6W.getSuspForceAppPointOffset(3).z);
+ w=wheelsSimData6W.getSuspForceAppPointOffset(1);
+ w.z=offsetRight;
+ wheelsSimData6W.setSuspForceAppPointOffset(5,w);
+
+ offsetLeft=0.5f*(wheelsSimData6W.getTireForceAppPointOffset(0).z+wheelsSimData6W.getTireForceAppPointOffset(2).z);
+ w=wheelsSimData4W->getTireForceAppPointOffset(0);
+ w.z=offsetLeft;
+ wheelsSimData6W.setTireForceAppPointOffset(4,w);
+ offsetRight=0.5f*(wheelsSimData6W.getTireForceAppPointOffset(1).z+wheelsSimData6W.getTireForceAppPointOffset(3).z);
+ w=wheelsSimData6W.getTireForceAppPointOffset(1);
+ w.z=offsetRight;
+ wheelsSimData6W.setTireForceAppPointOffset(5,w);
+ }
+
+ //The first 4 wheels were all set up to support a mass M but now that mass is
+ //distributed between 6 wheels. Adjust the suspension springs accordingly
+ //and try to preserve the natural frequency and damping ratio of the springs.
+ for(PxU32 i=0;i<4;i++)
+ {
+ PxVehicleSuspensionData suspData=wheelsSimData6W.getSuspensionData(i);
+ suspData.mSprungMass*=0.6666f;
+ suspData.mSpringStrength*=0.666f;
+ suspData.mSpringDamperRate*=0.666f;
+ wheelsSimData6W.setSuspensionData(i,suspData);
+ }
+ const PxF32 sprungMass=(wheelsSimData6W.getSuspensionData(0).mSprungMass+wheelsSimData6W.getSuspensionData(3).mSprungMass)/2.0f;
+ const PxF32 strength=(wheelsSimData6W.getSuspensionData(0).mSpringStrength+wheelsSimData6W.getSuspensionData(3).mSpringStrength)/2.0f;
+ const PxF32 damperRate=(wheelsSimData6W.getSuspensionData(0).mSpringDamperRate+wheelsSimData6W.getSuspensionData(3).mSpringDamperRate)/2.0f;
+ PxVehicleSuspensionData suspData4=wheelsSimData6W.getSuspensionData(4);
+ suspData4.mSprungMass=sprungMass;
+ suspData4.mSpringStrength=strength;
+ suspData4.mSpringDamperRate=damperRate;
+ wheelsSimData6W.setSuspensionData(4,suspData4);
+ PxVehicleSuspensionData suspData5=wheelsSimData6W.getSuspensionData(5);
+ suspData5.mSprungMass=sprungMass;
+ suspData5.mSpringStrength=strength;
+ suspData5.mSpringDamperRate=damperRate;
+ wheelsSimData6W.setSuspensionData(5,suspData5);
+
+ //Free the 4W sim data because we don't need this any more.
+ wheelsSimData4W->free();
+}
+
+void SampleVehicle_VehicleManager::create6WVehicle
+(PxScene& scene, PxPhysics& physics, PxCooking& cooking, const PxMaterial& material,
+ const PxF32 chassisMass, const PxVec3* wheelCentreOffsets4, PxConvexMesh* chassisConvexMesh, PxConvexMesh** wheelConvexMeshes4,
+ const PxTransform& startTransform, const bool useAutoGearFlag)
+{
+ PX_ASSERT(mNumVehicles<MAX_NUM_4W_VEHICLES+MAX_NUM_6W_VEHICLES);
+
+ //We're going to create an 4-wheeled vehicle then quickly copy components to make an 6-wheeled vehicle.
+ PxVehicleWheelsSimData* wheelsSimData=PxVehicleWheelsSimData::allocate(6);
+ PxVehicleDriveSimDataNW driveSimData;
+ PxVehicleChassisData chassisData;
+ createVehicle6WSimulationData(chassisMass,wheelCentreOffsets4,chassisConvexMesh,wheelConvexMeshes4,*wheelsSimData,driveSimData,chassisData);
+
+ //Instantiate and finalize the vehicle using physx.
+ PxRigidDynamic* vehActor=createVehicleActor6W(chassisData,wheelConvexMeshes4,chassisConvexMesh,scene,physics,material);
+
+ //Create a car.
+ PxVehicleDriveNW* car = PxVehicleDriveNW::allocate(6);
+ car->setup(&physics,vehActor,*wheelsSimData,driveSimData,6);
+
+ //Free the sim data because we don't need that any more.
+ wheelsSimData->free();
+
+ //Don't forget to add the actor to the scene.
+ {
+ PxSceneWriteLock scopedLock(scene);
+ scene.addActor(*vehActor);
+ }
+
+ //Set up the mapping between wheel and actor shape.
+ car->mWheelsSimData.setWheelShapeMapping(0,0);
+ car->mWheelsSimData.setWheelShapeMapping(1,1);
+ car->mWheelsSimData.setWheelShapeMapping(2,2);
+ car->mWheelsSimData.setWheelShapeMapping(3,3);
+ car->mWheelsSimData.setWheelShapeMapping(4,4);
+ car->mWheelsSimData.setWheelShapeMapping(5,5);
+
+ //Set up the scene query filter data for each suspension line.
+ PxFilterData vehQryFilterData;
+ SampleVehicleSetupVehicleShapeQueryFilterData(&vehQryFilterData);
+ car->mWheelsSimData.setSceneQueryFilterData(0, vehQryFilterData);
+ car->mWheelsSimData.setSceneQueryFilterData(1, vehQryFilterData);
+ car->mWheelsSimData.setSceneQueryFilterData(2, vehQryFilterData);
+ car->mWheelsSimData.setSceneQueryFilterData(3, vehQryFilterData);
+ car->mWheelsSimData.setSceneQueryFilterData(4, vehQryFilterData);
+ car->mWheelsSimData.setSceneQueryFilterData(5, vehQryFilterData);
+
+ //Set the transform and the instantiated car and set it be to be at rest.
+ resetNWCar(startTransform,car);
+ //Set the autogear mode of the instantiate car.
+ car->mDriveDynData.setUseAutoGears(useAutoGearFlag);
+
+ //Increment the number of vehicles
+ mVehicles[mNumVehicles]=car;
+ mVehicleWheelQueryResults[mNumVehicles].nbWheelQueryResults=6;
+ mVehicleWheelQueryResults[mNumVehicles].wheelQueryResults=mWheelQueryResults->addVehicle(6);
+ mNumVehicles++;
+}
+
+void setTank4WCustomisations(PxVehicleWheelsSimData& suspWheelTyreData, PxVehicleDriveSimData& coreData, const PxVehicleDriveTankControlModel::Enum tankDriveModel)
+{
+ //Increase damping, especially when the clutch isn't engaged.
+ for(PxU32 i=0;i<4;i++)
+ {
+ PxVehicleWheelData wheelData=suspWheelTyreData.getWheelData(i);
+ wheelData.mDampingRate=2.0f;
+ suspWheelTyreData.setWheelData(i,wheelData);
+ }
+ PxVehicleEngineData engineData=coreData.getEngineData();
+ engineData.mDampingRateZeroThrottleClutchEngaged=2.0f;
+ engineData.mDampingRateZeroThrottleClutchDisengaged=0.5f;
+ engineData.mDampingRateFullThrottle=0.5f;
+ //engineData.mPeakTorque=1500;
+ coreData.setEngineData(engineData);
+
+ if(PxVehicleDriveTankControlModel::eSPECIAL==tankDriveModel)
+ {
+ PxVehicleGearsData gearsData=coreData.getGearsData();
+ gearsData.mFinalRatio=16;
+ coreData.setGearsData(gearsData);
+ }
+}
+
+void SampleVehicle_VehicleManager::create4WTank
+(PxScene& scene, PxPhysics& physics, PxCooking& cooking, const PxMaterial& material,
+ const PxF32 chassisMass, const PxVec3* wheelCentreOffsets4, PxConvexMesh* chassisConvexMesh, PxConvexMesh** wheelConvexMeshes4,
+ const PxTransform& startTransform, const bool useAutoGearFlag, const PxVehicleDriveTankControlModel::Enum tankDriveModel)
+{
+ PX_ASSERT(mNumVehicles<(MAX_NUM_4W_VEHICLES+MAX_NUM_6W_VEHICLES));
+
+ //Create simulation data for 4W drive car.
+ PxVehicleWheelsSimData* wheelsSimData = PxVehicleWheelsSimData::allocate(4);
+ PxVehicleDriveSimData4W driveSimData;
+ PxVehicleChassisData chassisData;
+ createVehicle4WSimulationData(
+ chassisMass,chassisConvexMesh,
+ 20.0f,wheelConvexMeshes4,wheelCentreOffsets4,
+ *wheelsSimData,driveSimData,chassisData);
+
+ //Copy the relevant tank data and customise.
+ PxVehicleDriveSimData tankDriveSimData;
+ tankDriveSimData.setEngineData(driveSimData.getEngineData());
+ tankDriveSimData.setGearsData(driveSimData.getGearsData());
+ tankDriveSimData.setClutchData(driveSimData.getClutchData());
+ tankDriveSimData.setAutoBoxData(driveSimData.getAutoBoxData());
+ setTank4WCustomisations(*wheelsSimData,tankDriveSimData,tankDriveModel);
+
+ //Instantiate and finalize the vehicle using physx.
+ PxRigidDynamic* vehActor=createVehicleActor4W(chassisData,wheelConvexMeshes4,chassisConvexMesh,scene,physics,material);
+
+ //Create a tank.
+ PxVehicleDriveTank* tank = PxVehicleDriveTank::allocate(4);
+ tank->setup(&physics,vehActor,*wheelsSimData,tankDriveSimData,4);
+
+ //Free the sim data because we don't need that any more.
+ wheelsSimData->free();
+
+ //Don't forget to add the actor to the scene.
+ scene.addActor(*vehActor);
+
+ //Set up the mapping between wheel and actor shape.
+ tank->mWheelsSimData.setWheelShapeMapping(0,0);
+ tank->mWheelsSimData.setWheelShapeMapping(1,1);
+ tank->mWheelsSimData.setWheelShapeMapping(2,2);
+ tank->mWheelsSimData.setWheelShapeMapping(3,3);
+
+ //Set up the scene query filter data for each suspension line.
+ PxFilterData vehQryFilterData;
+ SampleVehicleSetupVehicleShapeQueryFilterData(&vehQryFilterData);
+ tank->mWheelsSimData.setSceneQueryFilterData(0, vehQryFilterData);
+ tank->mWheelsSimData.setSceneQueryFilterData(1, vehQryFilterData);
+ tank->mWheelsSimData.setSceneQueryFilterData(2, vehQryFilterData);
+ tank->mWheelsSimData.setSceneQueryFilterData(3, vehQryFilterData);
+
+ //Set the transform and the instantiated car and set it be to be at rest.
+ resetNWCar(startTransform,tank);
+ //Set the autogear mode of the instantiate car.
+ tank->mDriveDynData.setUseAutoGears(useAutoGearFlag);
+ //Set the drive model.
+ tank->setDriveModel(tankDriveModel);
+
+ //Increment the number of vehicles
+ mVehicles[mNumVehicles]=tank;
+ mVehicleWheelQueryResults[mNumVehicles].nbWheelQueryResults=4;
+ mVehicleWheelQueryResults[mNumVehicles].wheelQueryResults=mWheelQueryResults->addVehicle(4);
+ mNumVehicles++;
+}
+
+void setTank6WCustomisations(PxVehicleWheelsSimData& suspWheelTyreData, PxVehicleDriveSimData& coreData, const PxVehicleDriveTankControlModel::Enum tankDriveModel)
+{
+ //Increase damping, especially when the clutch isn't engaged.
+ for(PxU32 i=0;i<6;i++)
+ {
+ PxVehicleWheelData wheelData=suspWheelTyreData.getWheelData(i);
+ wheelData.mDampingRate=2.0f;
+ suspWheelTyreData.setWheelData(i,wheelData);
+ }
+ PxVehicleEngineData engineData=coreData.getEngineData();
+ engineData.mDampingRateZeroThrottleClutchEngaged=2.0f;
+ engineData.mDampingRateZeroThrottleClutchDisengaged=0.5f;
+ engineData.mDampingRateFullThrottle=0.5f;
+ //engineData.mPeakTorque=1500;
+ coreData.setEngineData(engineData);
+
+ if(PxVehicleDriveTankControlModel::eSPECIAL==tankDriveModel)
+ {
+ PxVehicleGearsData gearsData=coreData.getGearsData();
+ gearsData.mFinalRatio=16;
+ coreData.setGearsData(gearsData);
+ }
+}
+
+void SampleVehicle_VehicleManager::create6WTank
+(PxScene& scene, PxPhysics& physics, PxCooking& cooking, const PxMaterial& material,
+ const PxF32 chassisMass, const PxVec3* wheelCentreOffsets4, PxConvexMesh* chassisConvexMesh, PxConvexMesh** wheelConvexMeshes4,
+ const PxTransform& startTransform, const bool useAutoGearFlag, const PxVehicleDriveTankControlModel::Enum tankDriveModel)
+{
+ //Create simulation data for 4W drive car.
+ PxVehicleWheelsSimData* wheelsSimData=PxVehicleWheelsSimData::allocate(6);
+ PxVehicleDriveSimData4W driveSimData;
+ PxVehicleChassisData chassisData;
+ createVehicle6WSimulationData(chassisMass,wheelCentreOffsets4,chassisConvexMesh,wheelConvexMeshes4,*wheelsSimData,driveSimData,chassisData);
+
+ //Copy the relevant tank data and customize.
+ PxVehicleDriveSimData tankDriveSimData;
+ tankDriveSimData.setEngineData(driveSimData.getEngineData());
+ tankDriveSimData.setGearsData(driveSimData.getGearsData());
+ tankDriveSimData.setClutchData(driveSimData.getClutchData());
+ tankDriveSimData.setAutoBoxData(driveSimData.getAutoBoxData());
+ setTank6WCustomisations(*wheelsSimData,tankDriveSimData,tankDriveModel);
+
+ //Instantiate and finalize the vehicle using physx.
+ PxRigidDynamic* vehActor=createVehicleActor6W(chassisData,wheelConvexMeshes4,chassisConvexMesh,scene,physics,material);
+
+ //Create a tank.
+ PxVehicleDriveTank* tank = PxVehicleDriveTank::allocate(6);
+ tank->setup(&physics,vehActor,*wheelsSimData,tankDriveSimData,6);
+
+ //Free the sim data because we don't need that any more.
+ wheelsSimData->free();
+
+ //Don't forget to add the actor to the scene.
+ scene.addActor(*vehActor);
+
+ //Set up the mapping between wheel and actor shape.
+ tank->mWheelsSimData.setWheelShapeMapping(0,0);
+ tank->mWheelsSimData.setWheelShapeMapping(1,1);
+ tank->mWheelsSimData.setWheelShapeMapping(2,2);
+ tank->mWheelsSimData.setWheelShapeMapping(3,3);
+ tank->mWheelsSimData.setWheelShapeMapping(4,4);
+ tank->mWheelsSimData.setWheelShapeMapping(5,5);
+
+ //Set up the scene query filter data for each suspension line.
+ PxFilterData vehQryFilterData;
+ SampleVehicleSetupVehicleShapeQueryFilterData(&vehQryFilterData);
+ tank->mWheelsSimData.setSceneQueryFilterData(0, vehQryFilterData);
+ tank->mWheelsSimData.setSceneQueryFilterData(1, vehQryFilterData);
+ tank->mWheelsSimData.setSceneQueryFilterData(2, vehQryFilterData);
+ tank->mWheelsSimData.setSceneQueryFilterData(3, vehQryFilterData);
+ tank->mWheelsSimData.setSceneQueryFilterData(4, vehQryFilterData);
+ tank->mWheelsSimData.setSceneQueryFilterData(5, vehQryFilterData);
+
+ //Set the transform and the instantiated car and set it be to be at rest.
+ resetNWCar(startTransform,tank);
+ //Set the autogear mode of the instantiate car.
+ tank->mDriveDynData.setUseAutoGears(useAutoGearFlag);
+ //set the drive model
+ tank->setDriveModel(tankDriveModel);
+
+ //Increment the number of vehicles
+ mVehicles[mNumVehicles]=tank;
+ mVehicleWheelQueryResults[mNumVehicles].nbWheelQueryResults=6;
+ mVehicleWheelQueryResults[mNumVehicles].wheelQueryResults=mWheelQueryResults->addVehicle(6);
+ mNumVehicles++;
+}
+
+void SampleVehicle_VehicleManager::switchTo3WDeltaMode(const PxU32 vehicleId)
+{
+ //Get the vehicle that will be in 3-wheeled mode.
+ PX_ASSERT(mVehicles[vehicleId]->getVehicleType()==PxVehicleTypes::eDRIVE4W);
+ PxVehicleDrive4W* veh=(PxVehicleDrive4W*)mVehicles[vehicleId];
+ if(mIsIn3WMode)
+ {
+ switchTo4WMode(vehicleId);
+ }
+ else
+ {
+ veh->mWheelsSimData=*mWheelsSimData4W;
+ veh->mDriveSimData=mDriveSimData4W;
+ }
+ PxVehicle4WEnable3WDeltaMode(veh->mWheelsSimData, veh->mWheelsDynData, veh->mDriveSimData);
+ mIsIn3WMode=true;
+}
+
+void SampleVehicle_VehicleManager::switchTo3WTadpoleMode(const PxU32 vehicleId)
+{
+ //Get the vehicle that will be in 3-wheeled mode.
+ PX_ASSERT(mVehicles[vehicleId]->getVehicleType()==PxVehicleTypes::eDRIVE4W);
+ PxVehicleDrive4W* veh=(PxVehicleDrive4W*)mVehicles[vehicleId];
+ if(mIsIn3WMode)
+ {
+ switchTo4WMode(vehicleId);
+ }
+ else
+ {
+ veh->mWheelsSimData=*mWheelsSimData4W;
+ veh->mDriveSimData=mDriveSimData4W;
+ }
+ PxVehicle4WEnable3WTadpoleMode(veh->mWheelsSimData, veh->mWheelsDynData, veh->mDriveSimData);
+ mIsIn3WMode=true;
+}
+
+void SampleVehicle_VehicleManager::switchTo4WMode(const PxU32 vehicleId)
+{
+ //Get the vehicle that will be in 3-wheeled mode.
+ PX_ASSERT(mVehicles[vehicleId]->getVehicleType()==PxVehicleTypes::eDRIVE4W);
+ PxVehicleDrive4W* veh=(PxVehicleDrive4W*)mVehicles[vehicleId];
+
+ *mWheelsSimData4W=veh->mWheelsSimData;
+ mDriveSimData4W=veh->mDriveSimData;
+ mIsIn3WMode=false;
+}
+
+
+
diff --git a/PhysX_3.4/Samples/SampleVehicle/SampleVehicle_VehicleManager.h b/PhysX_3.4/Samples/SampleVehicle/SampleVehicle_VehicleManager.h
new file mode 100644
index 00000000..e1c1bc86
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleVehicle/SampleVehicle_VehicleManager.h
@@ -0,0 +1,226 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#ifndef SAMPLE_VEHICLE_VEHICLE_MANAGER_H
+#define SAMPLE_VEHICLE_VEHICLE_MANAGER_H
+
+#include "vehicle/PxVehicleSDK.h"
+#include "vehicle/PxVehicleDrive4W.h"
+#include "vehicle/PxVehicleDriveNW.h"
+#include "vehicle/PxVehicleDriveTank.h"
+#include "vehicle/PxVehicleUpdate.h"
+#include "foundation/PxFoundation.h"
+
+#if PX_DEBUG_VEHICLE_ON
+#include "vehicle/PxVehicleUtilTelemetry.h"
+#endif
+
+using namespace physx;
+
+namespace physx
+{
+ class PxScene;
+ class PxBatchQuery;
+ class PxCooking;
+ class PxMaterial;
+ class PxConvexMesh;
+ struct PxVehicleDrivableSurfaceType;
+}
+
+class SampleVehicleSceneQueryData;
+class SampleVehicleWheelQueryResults;
+
+class PxVehicle4WAlloc;
+
+//Collision types and flags describing collision interactions of each collision type.
+enum
+{
+ COLLISION_FLAG_GROUND = 1 << 0,
+ COLLISION_FLAG_WHEEL = 1 << 1,
+ COLLISION_FLAG_CHASSIS = 1 << 2,
+ COLLISION_FLAG_OBSTACLE = 1 << 3,
+ COLLISION_FLAG_DRIVABLE_OBSTACLE= 1 << 4,
+
+ COLLISION_FLAG_GROUND_AGAINST = COLLISION_FLAG_CHASSIS | COLLISION_FLAG_OBSTACLE | COLLISION_FLAG_DRIVABLE_OBSTACLE,
+ COLLISION_FLAG_WHEEL_AGAINST = COLLISION_FLAG_WHEEL | COLLISION_FLAG_CHASSIS | COLLISION_FLAG_OBSTACLE,
+ COLLISION_FLAG_CHASSIS_AGAINST = COLLISION_FLAG_GROUND | COLLISION_FLAG_WHEEL | COLLISION_FLAG_CHASSIS | COLLISION_FLAG_OBSTACLE | COLLISION_FLAG_DRIVABLE_OBSTACLE,
+ COLLISION_FLAG_OBSTACLE_AGAINST = COLLISION_FLAG_GROUND | COLLISION_FLAG_WHEEL | COLLISION_FLAG_CHASSIS | COLLISION_FLAG_OBSTACLE | COLLISION_FLAG_DRIVABLE_OBSTACLE,
+ COLLISION_FLAG_DRIVABLE_OBSTACLE_AGAINST= COLLISION_FLAG_GROUND | COLLISION_FLAG_CHASSIS | COLLISION_FLAG_OBSTACLE | COLLISION_FLAG_DRIVABLE_OBSTACLE,
+};
+
+//Id of drivable surface (used by suspension raycast filtering).
+enum
+{
+ DRIVABLE_SURFACE_ID=0xffffffff
+};
+
+//Drivable surface types.
+enum
+{
+ SURFACE_TYPE_MUD=0,
+ SURFACE_TYPE_TARMAC,
+ SURFACE_TYPE_SNOW,
+ SURFACE_TYPE_GRASS,
+ MAX_NUM_SURFACE_TYPES
+};
+
+struct SurfaceTypeNames
+{
+ static const char* getName(PxU32 type)
+ {
+ static char surfaceTypes[MAX_NUM_SURFACE_TYPES+1][64]=
+ {
+ "mud",
+ "tarmac",
+ "ice",
+ "grass",
+ };
+
+ return surfaceTypes[type];
+ }
+};
+
+//Tire types.
+enum
+{
+ TIRE_TYPE_WETS=0,
+ TIRE_TYPE_SLICKS,
+ TIRE_TYPE_ICE,
+ TIRE_TYPE_MUD,
+ MAX_NUM_TIRE_TYPES
+};
+
+struct TireFrictionMultipliers
+{
+ static float getValue(PxU32 surfaceType, PxU32 tireType)
+ {
+ //Tire model friction for each combination of drivable surface type and tire type.
+ static PxF32 tireFrictionMultipliers[MAX_NUM_SURFACE_TYPES][MAX_NUM_TIRE_TYPES]=
+ {
+ //WETS SLICKS ICE MUD
+ {0.95f, 0.95f, 0.95f, 0.95f}, //MUD
+ {1.10f, 1.15f, 1.10f, 1.10f}, //TARMAC
+ {0.70f, 0.70f, 0.70f, 0.70f}, //ICE
+ {0.80f, 0.80f, 0.80f, 0.80f} //GRASS
+ };
+ return tireFrictionMultipliers[surfaceType][tireType];
+ }
+};
+
+class SampleVehicle_VehicleManager
+{
+public:
+
+ enum
+ {
+ MAX_NUM_4W_VEHICLES=8,
+ MAX_NUM_6W_VEHICLES=2,
+ MAX_NUM_4W_TANKS=2
+ };
+
+ SampleVehicle_VehicleManager();
+ ~SampleVehicle_VehicleManager();
+
+ void init(PxPhysics& physics, const PxMaterial** drivableSurfaceMaterials, const PxVehicleDrivableSurfaceType* drivableSurfaceTypes);
+
+ void shutdown();
+
+ //Create a vehicle ready to drive.
+ void create4WVehicle
+ (PxScene& scene, PxPhysics& physics, PxCooking& cooking, const PxMaterial& material,
+ const PxF32 chassisMass, const PxVec3* wheelCentreOffsets4, PxConvexMesh* chassisConvexMesh, PxConvexMesh** wheelConvexMeshes4,
+ const PxTransform& startTransform, const bool useAutoGearFlag);
+ void create6WVehicle
+ (PxScene& scene, PxPhysics& physics, PxCooking& cooking, const PxMaterial& material,
+ const PxF32 chassisMass, const PxVec3* wheelCentreOffsets4, PxConvexMesh* chassisConvexMesh, PxConvexMesh** wheelConvexMeshes4,
+ const PxTransform& startTransform, const bool useAutoGearFlag);
+ void create4WTank
+ (PxScene& scene, PxPhysics& physics, PxCooking& cooking, const PxMaterial& material,
+ const PxF32 chassisMass, const PxVec3* wheelCentreOffsets4, PxConvexMesh* chassisConvexMesh, PxConvexMesh** wheelConvexMeshes4,
+ const PxTransform& startTransform, const bool useAutoGearFlag, const PxVehicleDriveTankControlModel::Enum tankDriveModel);
+ void create6WTank
+ (PxScene& scene, PxPhysics& physics, PxCooking& cooking, const PxMaterial& material,
+ const PxF32 chassisMass, const PxVec3* wheelCentreOffsets4, PxConvexMesh* chassisConvexMesh, PxConvexMesh** wheelConvexMeshes4,
+ const PxTransform& startTransform, const bool useAutoGearFlag, const PxVehicleDriveTankControlModel::Enum tankDriveModel);
+
+ PX_FORCE_INLINE PxU32 getNbVehicles() const { return mNumVehicles; }
+ PX_FORCE_INLINE PxVehicleWheels* getVehicle(const PxU32 i) { return mVehicles[i]; }
+ PX_FORCE_INLINE const PxVehicleWheelQueryResult& getVehicleWheelQueryResults(const PxU32 i) const { return mVehicleWheelQueryResults[i]; }
+ void addVehicle(const PxU32 i, PxVehicleWheels* vehicle);
+
+ //Start the suspension raycasts (always call before calling update)
+ void suspensionRaycasts(PxScene* scene);
+
+ //Update vehicle dynamics and compute forces/torques to apply to sdk rigid bodies.
+#if PX_DEBUG_VEHICLE_ON
+ void updateAndRecordTelemetryData(const PxF32 timestep, const PxVec3& gravity, PxVehicleWheels* focusVehicleNW, PxVehicleTelemetryData* telemetryDataNW);
+#else
+ void update(const PxF32 timestep, const PxVec3& gravity);
+#endif
+
+ //Reset the car back to its rest state with a specified transform.
+ void resetNWCar(const PxTransform& transform, const PxU32 vehicleId);
+
+ //Switch the player's vehicle to 3-wheeled modes and back to 4-wheeled mode.
+ void switchTo3WDeltaMode(const PxU32 vehicleId);
+ void switchTo3WTadpoleMode(const PxU32 vehicleId);
+ void switchTo4WMode(const PxU32 vehicleId);
+
+ PxSerializationRegistry* getSerializationRegistry() { return mSerializationRegistry; }
+private:
+
+ //Array of all cars and report data for each car.
+ PxVehicleWheels* mVehicles[MAX_NUM_4W_VEHICLES+MAX_NUM_6W_VEHICLES];
+ PxVehicleWheelQueryResult mVehicleWheelQueryResults[MAX_NUM_4W_VEHICLES+MAX_NUM_6W_VEHICLES];
+ PxU32 mNumVehicles;
+
+ //sdk raycasts (for the suspension lines).
+ SampleVehicleSceneQueryData* mSqData;
+ PxBatchQuery* mSqWheelRaycastBatchQuery;
+
+ //Reports for each wheel.
+ SampleVehicleWheelQueryResults* mWheelQueryResults;
+
+ //Cached simulation data of focus vehicle in 4W mode.
+ PxVehicleWheelsSimData* mWheelsSimData4W;
+ PxVehicleDriveSimData4W mDriveSimData4W;
+ bool mIsIn3WMode;
+
+ //Friction from combinations of tire and surface types.
+ PxVehicleDrivableSurfaceToTireFrictionPairs* mSurfaceTirePairs;
+
+
+ //Initialise a car back to its start transform and state.
+ void resetNWCar(const PxTransform& startTransform, PxVehicleWheels* car);
+
+ //Serialization
+ PxSerializationRegistry* mSerializationRegistry;
+};
+
+#endif //SAMPLE_VEHICLE_VEHICLE_MANAGER_H
diff --git a/PhysX_3.4/Samples/SampleVehicle/SampleVehicle_WheelQueryResults.cpp b/PhysX_3.4/Samples/SampleVehicle/SampleVehicle_WheelQueryResults.cpp
new file mode 100644
index 00000000..858a7bd4
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleVehicle/SampleVehicle_WheelQueryResults.cpp
@@ -0,0 +1,73 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#include "SampleVehicle_WheelQueryResults.h"
+#include "vehicle/PxVehicleSDK.h"
+#include "PsFoundation.h"
+#include "PsUtilities.h"
+
+
+//#define CHECK_MSG(exp, msg) (!!(exp) || (physx::shdfnd::getFoundation().error(physx::PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__, msg), 0) )
+
+
+SampleVehicleWheelQueryResults* SampleVehicleWheelQueryResults::allocate(const PxU32 maxNumWheels)
+{
+ const PxU32 size = sizeof(SampleVehicleWheelQueryResults) + sizeof(PxWheelQueryResult)*maxNumWheels;
+ SampleVehicleWheelQueryResults* resData = (SampleVehicleWheelQueryResults*)PX_ALLOC(size, "SampleVehicleWheelQueryResults");
+ resData->init();
+ PxU8* ptr = (PxU8*) resData;
+ ptr += sizeof(SampleVehicleWheelQueryResults);
+ resData->mWheelQueryResults = (PxWheelQueryResult*)ptr;
+ ptr += sizeof(PxWheelQueryResult)*maxNumWheels;
+ resData->mMaxNumWheels=maxNumWheels;
+ for(PxU32 i=0;i<maxNumWheels;i++)
+ {
+ new(&resData->mWheelQueryResults[i]) PxWheelQueryResult();
+ }
+ return resData;
+}
+
+void SampleVehicleWheelQueryResults::free()
+{
+ PX_FREE(this);
+}
+
+PxWheelQueryResult* SampleVehicleWheelQueryResults::addVehicle(const PxU32 numWheels)
+{
+ PX_ASSERT((mNumWheels + numWheels) <= mMaxNumWheels);
+ PxWheelQueryResult* r = &mWheelQueryResults[mNumWheels];
+ mNumWheels += numWheels;
+ return r;
+}
+
+
+
+
+
+
diff --git a/PhysX_3.4/Samples/SampleVehicle/SampleVehicle_WheelQueryResults.h b/PhysX_3.4/Samples/SampleVehicle/SampleVehicle_WheelQueryResults.h
new file mode 100644
index 00000000..fc5dc032
--- /dev/null
+++ b/PhysX_3.4/Samples/SampleVehicle/SampleVehicle_WheelQueryResults.h
@@ -0,0 +1,82 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#ifndef SAMPLEVEHICLE_WHEELQUERYRESULTS_H
+#define SAMPLEVEHICLE_WHEELQUERYRESULTS_H
+
+#include "vehicle/PxVehicleSDK.h"
+#include "vehicle/PxVehicleUpdate.h"
+
+using namespace physx;
+
+//Data structure to store reports for each wheel.
+class SampleVehicleWheelQueryResults
+{
+public:
+
+ //Allocate a buffer of wheel query results for up to maxNumWheels.
+ static SampleVehicleWheelQueryResults* allocate(const PxU32 maxNumWheels);
+
+ //Free allocated buffer.
+ void free();
+
+ PxWheelQueryResult* addVehicle(const PxU32 numWheels);
+
+private:
+
+ //One result for each wheel.
+ PxWheelQueryResult* mWheelQueryResults;
+
+ //Maximum number of wheels.
+ PxU32 mMaxNumWheels;
+
+ //Number of wheels
+ PxU32 mNumWheels;
+
+
+ SampleVehicleWheelQueryResults()
+ : mWheelQueryResults(NULL),mMaxNumWheels(0), mNumWheels(0)
+ {
+ init();
+ }
+
+ ~SampleVehicleWheelQueryResults()
+ {
+ }
+
+ void init()
+ {
+ mWheelQueryResults=NULL;
+ mMaxNumWheels=0;
+ mNumWheels=0;
+ }
+};
+
+
+#endif //SAMPLEVEHICLE_WHEELQUERYRESULTS_H